jets3t-0.8.1+dfsg.orig/0002755000000000000000000000000011552214122011475 5ustar jets3t-0.8.1+dfsg.orig/libs/0002755000000000000000000000000011550446574012446 5ustar jets3t-0.8.1+dfsg.orig/servlets/0002755000000000000000000000000011550446652013361 5ustar jets3t-0.8.1+dfsg.orig/servlets/gatekeeper/0002755000000000000000000000000011550446574015500 5ustar jets3t-0.8.1+dfsg.orig/servlets/gatekeeper-web.xml0000644000000000000000000000564711550446652017004 0ustar jetset Gatekeeper GatekeeperServlet GatekeeperServlet org.jets3t.servlets.gatekeeper.GatekeeperServlet TransactionIdProviderClass org.jets3t.servlets.gatekeeper.impl.DefaultTransactionIdProvider AuthorizerClass org.jets3t.servlets.gatekeeper.impl.DefaultAuthorizer UrlSignerClass org.jets3t.servlets.gatekeeper.impl.DefaultUrlSigner BucketListerClass org.jets3t.servlets.gatekeeper.impl.DefaultBucketLister AwsAccessKey YOUR_AWS_ACCESS_KEY AwsSecretKey YOUR_AWS_SECRET_KEY S3BucketName YOUR_BUCKET_NAME SecondsToSign 180 GatekeeperServlet /GatekeeperServlet jets3t-0.8.1+dfsg.orig/bin/0002755000000000000000000000000011550446574012265 5ustar jets3t-0.8.1+dfsg.orig/bin/synchronize.bat0000644000000000000000000000357711550446574015342 0ustar @echo off rem ------------------------------------------------------------------- rem Environmental variables: rem rem JETS3T_HOME Points to the home directory of a JetS3t distribution. rem rem JAVA_HOME The home directory of the Java Runtime Environment or rem Java Development Kit to use. rem ------------------------------------------------------------------- rem Check the JETS3T_HOME directory if not "%JETS3T_HOME%" == "" goto gotJetS3tHome rem Find the home directory, assuming this script is %JETS3T_HOME%\bin set MY_JETS3T_HOME=%~dp0\.. if exist "%MY_JETS3T_HOME%\bin\%~nx0" goto foundJetS3tHome echo Please set the environment variable JETS3T_HOME goto END :gotJetS3tHome set MY_JETS3T_HOME=%JETS3T_HOME% :foundJetS3tHome rem Check the JAVA_HOME directory if not "%JAVA_HOME%" == "" goto gotJavaHome set EXEC=java goto noJavaHome :gotJavaHome set EXEC=%JAVA_HOME%\bin\java :noJavaHome rem echo JetS3t path: %MY_JETS3T_HOME% rem echo Java path: %EXEC% rem ------------------------------------------------------------------- REM Include configurations directory in classpath set CP=%MY_JETS3T_HOME%/configs REM Include resources directory in classpath set CP=%CP%;%MY_JETS3T_HOME%/resources REM Include libraries in classpath set CP=%CP%;%MY_JETS3T_HOME%/jars/jets3t-0.8.1.jar set CP=%CP%;%MY_JETS3T_HOME%/jars/synchronize-0.8.1.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/commons-logging/commons-logging-1.1.1.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/commons-codec/commons-codec-1.3.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/commons-httpclient/commons-httpclient-3.1.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/logging-log4j/log4j-1.2.15.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/bouncycastle/bcprov-jdk14-138.jar REM OutOfMemory errors? Increase the memory available by changing -Xmx256M "%EXEC%" -Xmx256M -classpath "%CP%" org.jets3t.apps.synchronize.Synchronize %* :END jets3t-0.8.1+dfsg.orig/bin/cockpitlite.bat0000644000000000000000000000376511550446574015300 0ustar @echo off rem ------------------------------------------------------------------- rem Environmental variables: rem rem JETS3T_HOME Points to the home directory of a JetS3t distribution. rem rem JAVA_HOME The home directory of the Java Runtime Environment or rem Java Development Kit to use. rem ------------------------------------------------------------------- rem Check the JETS3T_HOME directory if not "%JETS3T_HOME%" == "" goto gotJetS3tHome rem Find the home directory, assuming this script is %JETS3T_HOME%\bin set MY_JETS3T_HOME=%~dp0\.. if exist "%MY_JETS3T_HOME%\bin\%~nx0" goto foundJetS3tHome echo Please set the environment variable JETS3T_HOME goto END :gotJetS3tHome set MY_JETS3T_HOME=%JETS3T_HOME% :foundJetS3tHome rem Check the JAVA_HOME directory if not "%JAVA_HOME%" == "" goto gotJavaHome set EXEC=java goto noJavaHome :gotJavaHome set EXEC=%JAVA_HOME%\bin\java :noJavaHome rem echo JetS3t path: %MY_JETS3T_HOME% rem echo Java path: %EXEC% rem ------------------------------------------------------------------- REM Include configurations directory in classpath set CP=%MY_JETS3T_HOME%/configs REM Include resources directory in classpath set CP=%CP%;%MY_JETS3T_HOME%/resources REM Include libraries in classpath set CP=%CP%;%MY_JETS3T_HOME%/jars/jets3t-0.8.1.jar set CP=%CP%;%MY_JETS3T_HOME%/jars/jets3t-gui-0.8.1.jar set CP=%CP%;%MY_JETS3T_HOME%/jars/cockpitlite-0.8.1.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/commons-logging/commons-logging-1.1.1.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/commons-codec/commons-codec-1.3.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/commons-httpclient/commons-httpclient-3.1.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/misc/BareBonesBrowserLaunch.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/logging-log4j/log4j-1.2.15.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/bouncycastle/bcprov-jdk14-138.jar REM OutOfMemory errors? Increase the memory available by changing -Xmx256M "%EXEC%" -Xmx256M -classpath "%CP%" org.jets3t.apps.cockpitlite.CockpitLite :END jets3t-0.8.1+dfsg.orig/bin/uploader.sh0000644000000000000000000000463511550446574014442 0ustar #!/bin/sh # ------------------------------------------------------------------- # Environmental variables: # # JETS3T_HOME Points to the home directory of a JetS3t distribution. # # JAVA_HOME The home directory of the Java Runtime Environment or # Java Development Kit to use. # ------------------------------------------------------------------- : ${JETS3T_HOME:-""} : ${JAVA_HOME:-""} # Check the JETS3T_HOME directory if [ -z "$JETS3T_HOME" ]; then # Try to find the home directory, assuming this script is in $JETS3T_HOME/bin SCPT_DIR=`dirname $0` if [ "$SCPT_DIR" = "." ]; then JETS3T_HOME=.. else JETS3T_HOME=`dirname $SCPT_DIR` fi fi if [ ! -d $JETS3T_HOME/jars ]; then echo "Please set the environment variable JETS3T_HOME" exit 1 fi # Check the JAVA_HOME directory if [ -z "$JAVA_HOME" ]; then # Test whether the 'java' program is available in the system path. java -version 2> /dev/null if [ $? -gt 0 ]; then echo "Please set the environment variable JAVA_HOME" exit 1 else EXEC=java fi else EXEC=$JAVA_HOME/bin/java fi # ------------------------------------------------------------------- # Include configurations directory in classpath CP=$CLASSPATH:$JETS3T_HOME/configs # Include resources directory in classpath CP=$CP:$JETS3T_HOME/resources # Include libraries in classpath CP=$CP:$JETS3T_HOME/jars/jets3t-0.8.1.jar CP=$CP:$JETS3T_HOME/jars/jets3t-gui-0.8.1.jar CP=$CP:$JETS3T_HOME/jars/uploader-0.8.1.jar CP=$CP:$JETS3T_HOME/libs/commons-logging/commons-logging-1.1.1.jar CP=$CP:$JETS3T_HOME/libs/commons-codec/commons-codec-1.3.jar CP=$CP:$JETS3T_HOME/libs/commons-httpclient/commons-httpclient-3.1.jar CP=$CP:$JETS3T_HOME/libs/misc/BareBonesBrowserLaunch.jar CP=$CP:$JETS3T_HOME/libs/logging-log4j/log4j-1.2.15.jar # Convert classpath for cygwin bash case "`uname -s`" in CYGWIN*) CYGWIN_CP="" for cp_path in $(echo $CP | tr ':' '\n'); do CWIN_PATH=$(cygpath -w -a "$cp_path") CYGWIN_CP="$CYGWIN_CP;$CWIN_PATH" done CP=$CYGWIN_CP esac # OutOfMemory errors? Increase the memory available by changing -Xmx256M MAXMEM=-Xmx256M # Run application with special arguments on OS X (Darwin) systems. if [ `uname -s` = "Darwin" ] then "$EXEC" $MAXMEM -classpath "$CP" -Xdock:name="JetS3t Uploader" org.jets3t.apps.uploader.Uploader else "$EXEC" $MAXMEM -classpath "$CP" org.jets3t.apps.uploader.Uploader fi jets3t-0.8.1+dfsg.orig/bin/cockpit.sh0000644000000000000000000000502311550446574014253 0ustar #!/bin/sh # ------------------------------------------------------------------- # Environmental variables: # # JETS3T_HOME Points to the home directory of a JetS3t distribution. # # JAVA_HOME The home directory of the Java Runtime Environment or # Java Development Kit to use. # ------------------------------------------------------------------- : ${JETS3T_HOME:-""} : ${JAVA_HOME:-""} # Check the JETS3T_HOME directory if [ -z "$JETS3T_HOME" ]; then # Try to find the home directory, assuming this script is in $JETS3T_HOME/bin SCPT_DIR=`dirname $0` if [ "$SCPT_DIR" = "." ]; then JETS3T_HOME=.. else JETS3T_HOME=`dirname $SCPT_DIR` fi fi if [ ! -d $JETS3T_HOME/jars ]; then echo "Please set the environment variable JETS3T_HOME" exit 1 fi # Check the JAVA_HOME directory if [ -z "$JAVA_HOME" ]; then # Test whether the 'java' program is available in the system path. java -version 2> /dev/null if [ $? -gt 0 ]; then echo "Please set the environment variable JAVA_HOME" exit 1 else EXEC=java fi else EXEC=$JAVA_HOME/bin/java fi # ------------------------------------------------------------------- # Include configurations directory in classpath CP=$CLASSPATH:$JETS3T_HOME/configs # Include resources directory in classpath CP=$CP:$JETS3T_HOME/resources # Include libraries in classpath CP=$CP:$JETS3T_HOME/jars/jets3t-0.8.1.jar CP=$CP:$JETS3T_HOME/jars/jets3t-gui-0.8.1.jar CP=$CP:$JETS3T_HOME/jars/cockpit-0.8.1.jar CP=$CP:$JETS3T_HOME/libs/commons-logging/commons-logging-1.1.1.jar CP=$CP:$JETS3T_HOME/libs/commons-codec/commons-codec-1.3.jar CP=$CP:$JETS3T_HOME/libs/commons-httpclient/commons-httpclient-3.1.jar CP=$CP:$JETS3T_HOME/libs/misc/BareBonesBrowserLaunch.jar CP=$CP:$JETS3T_HOME/libs/logging-log4j/log4j-1.2.15.jar CP=$CP:$JETS3T_HOME/libs/bouncycastle/bcprov-jdk14-138.jar CP=$CP:$JETS3T_HOME/libs/java-xmlbuilder/java-xmlbuilder-0.4.jar # Convert classpath for cygwin bash case "`uname -s`" in CYGWIN*) CYGWIN_CP="" for cp_path in $(echo $CP | tr ':' '\n'); do CWIN_PATH=$(cygpath -w -a "$cp_path") CYGWIN_CP="$CYGWIN_CP;$CWIN_PATH" done CP=$CYGWIN_CP esac # OutOfMemory errors? Increase the memory available by changing -Xmx256M MAXMEM=-Xmx256M # Run application with special arguments on OS X (Darwin) systems. if [ `uname -s` = "Darwin" ] then "$EXEC" $MAXMEM -classpath "$CP" -Xdock:name="JetS3t Cockpit" org.jets3t.apps.cockpit.Cockpit else "$EXEC" $MAXMEM -classpath "$CP" org.jets3t.apps.cockpit.Cockpit fi jets3t-0.8.1+dfsg.orig/bin/cockpitlite.sh0000644000000000000000000000475311550446574015142 0ustar #!/bin/sh # ------------------------------------------------------------------- # Environmental variables: # # JETS3T_HOME Points to the home directory of a JetS3t distribution. # # JAVA_HOME The home directory of the Java Runtime Environment or # Java Development Kit to use. # ------------------------------------------------------------------- : ${JETS3T_HOME:-""} : ${JAVA_HOME:-""} # Check the JETS3T_HOME directory if [ -z "$JETS3T_HOME" ]; then # Try to find the home directory, assuming this script is in $JETS3T_HOME/bin SCPT_DIR=`dirname $0` if [ "$SCPT_DIR" = "." ]; then JETS3T_HOME=.. else JETS3T_HOME=`dirname $SCPT_DIR` fi fi if [ ! -d $JETS3T_HOME/jars ]; then echo "Please set the environment variable JETS3T_HOME" exit 1 fi # Check the JAVA_HOME directory if [ -z "$JAVA_HOME" ]; then # Test whether the 'java' program is available in the system path. java -version 2> /dev/null if [ $? -gt 0 ]; then echo "Please set the environment variable JAVA_HOME" exit 1 else EXEC=java fi else EXEC=$JAVA_HOME/bin/java fi # ------------------------------------------------------------------- # Include configurations directory in classpath CP=$CLASSPATH:$JETS3T_HOME/configs # Include resources directory in classpath CP=$CP:$JETS3T_HOME/resources # Include libraries in classpath CP=$CP:$JETS3T_HOME/jars/jets3t-0.8.1.jar CP=$CP:$JETS3T_HOME/jars/jets3t-gui-0.8.1.jar CP=$CP:$JETS3T_HOME/jars/cockpitlite-0.8.1.jar CP=$CP:$JETS3T_HOME/libs/commons-logging/commons-logging-1.1.1.jar CP=$CP:$JETS3T_HOME/libs/commons-codec/commons-codec-1.3.jar CP=$CP:$JETS3T_HOME/libs/commons-httpclient/commons-httpclient-3.1.jar CP=$CP:$JETS3T_HOME/libs/misc/BareBonesBrowserLaunch.jar CP=$CP:$JETS3T_HOME/libs/logging-log4j/log4j-1.2.15.jar CP=$CP:$JETS3T_HOME/libs/bouncycastle/bcprov-jdk14-138.jar # Convert classpath for cygwin bash case "`uname -s`" in CYGWIN*) CYGWIN_CP="" for cp_path in $(echo $CP | tr ':' '\n'); do CWIN_PATH=$(cygpath -w -a "$cp_path") CYGWIN_CP="$CYGWIN_CP;$CWIN_PATH" done CP=$CYGWIN_CP esac # OutOfMemory errors? Increase the memory available by changing -Xmx256M MAXMEM=-Xmx256M # Run application with special arguments on OS X (Darwin) systems. if [ `uname -s` = "Darwin" ] then "$EXEC" $MAXMEM -classpath "$CP" -Xdock:name="JetS3t Cockpit-Lite" org.jets3t.apps.cockpitlite.CockpitLite else "$EXEC" $MAXMEM -classpath "$CP" org.jets3t.apps.cockpitlite.CockpitLite fi jets3t-0.8.1+dfsg.orig/bin/synchronize.sh0000644000000000000000000000433611550446574015200 0ustar #!/bin/sh # ------------------------------------------------------------------- # Environmental variables: # # JETS3T_HOME Points to the home directory of a JetS3t distribution. # # JAVA_HOME The home directory of the Java Runtime Environment or # Java Development Kit to use. # ------------------------------------------------------------------- : ${JETS3T_HOME:-""} : ${JAVA_HOME:-""} # Check the JETS3T_HOME directory if [ -z "$JETS3T_HOME" ]; then # Try to find the home directory, assuming this script is in $JETS3T_HOME/bin SCPT_DIR=`dirname $0` if [ "$SCPT_DIR" = "." ]; then JETS3T_HOME=.. else JETS3T_HOME=`dirname $SCPT_DIR` fi fi if [ ! -d $JETS3T_HOME/jars ]; then echo "Please set the environment variable JETS3T_HOME" exit 1 fi # Check the JAVA_HOME directory if [ -z "$JAVA_HOME" ]; then # Test whether the 'java' program is available in the system path. java -version 2> /dev/null if [ $? -gt 0 ]; then echo "Please set the environment variable JAVA_HOME" exit 1 else EXEC=java fi else EXEC=$JAVA_HOME/bin/java fi # ------------------------------------------------------------------- # Include configurations directory in classpath CP=$CLASSPATH:$JETS3T_HOME/configs # Include resources directory in classpath CP=$CP:$JETS3T_HOME/resources # Include libraries in classpath CP=$CP:$JETS3T_HOME/jars/jets3t-0.8.1.jar CP=$CP:$JETS3T_HOME/jars/synchronize-0.8.1.jar CP=$CP:$JETS3T_HOME/libs/commons-logging/commons-logging-1.1.1.jar CP=$CP:$JETS3T_HOME/libs/commons-codec/commons-codec-1.3.jar CP=$CP:$JETS3T_HOME/libs/commons-httpclient/commons-httpclient-3.1.jar CP=$CP:$JETS3T_HOME/libs/logging-log4j/log4j-1.2.15.jar CP=$CP:$JETS3T_HOME/libs/bouncycastle/bcprov-jdk14-138.jar CP=$CP:$JETS3T_HOME/libs/java-xmlbuilder/java-xmlbuilder-0.4.jar # Convert classpath for cygwin bash case "`uname -s`" in CYGWIN*) CYGWIN_CP="" for cp_path in $(echo $CP | tr ':' '\n'); do CWIN_PATH=$(cygpath -w -a "$cp_path") CYGWIN_CP="$CYGWIN_CP;$CWIN_PATH" done CP=$CYGWIN_CP esac # OutOfMemory errors? Increase the memory available by changing -Xmx256M "$EXEC" -Xmx256M -classpath "$CP" org.jets3t.apps.synchronize.Synchronize "$@" jets3t-0.8.1+dfsg.orig/bin/cockpit.bat0000644000000000000000000000406311550446574014412 0ustar @echo off rem ------------------------------------------------------------------- rem Environmental variables: rem rem JETS3T_HOME Points to the home directory of a JetS3t distribution. rem rem JAVA_HOME The home directory of the Java Runtime Environment or rem Java Development Kit to use. rem ------------------------------------------------------------------- rem Check the JETS3T_HOME directory if not "%JETS3T_HOME%" == "" goto gotJetS3tHome rem Find the home directory, assuming this script is %JETS3T_HOME%\bin set MY_JETS3T_HOME=%~dp0\.. if exist "%MY_JETS3T_HOME%\bin\%~nx0" goto foundJetS3tHome echo Please set the environment variable JETS3T_HOME goto END :gotJetS3tHome set MY_JETS3T_HOME=%JETS3T_HOME% :foundJetS3tHome rem Check the JAVA_HOME directory if not "%JAVA_HOME%" == "" goto gotJavaHome set EXEC=java goto noJavaHome :gotJavaHome set EXEC=%JAVA_HOME%\bin\java :noJavaHome rem echo JetS3t path: %MY_JETS3T_HOME% rem echo Java path: %EXEC% rem ------------------------------------------------------------------- REM Include configurations directory in classpath set CP=%MY_JETS3T_HOME%/configs REM Include resources directory in classpath set CP=%CP%;%MY_JETS3T_HOME%/resources REM Include libraries in classpath set CP=%CP%;%MY_JETS3T_HOME%/jars/jets3t-0.8.1.jar set CP=%CP%;%MY_JETS3T_HOME%/jars/jets3t-gui-0.8.1.jar set CP=%CP%;%MY_JETS3T_HOME%/jars/cockpit-0.8.1.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/commons-logging/commons-logging-1.1.1.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/commons-codec/commons-codec-1.3.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/commons-httpclient/commons-httpclient-3.1.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/misc/BareBonesBrowserLaunch.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/logging-log4j/log4j-1.2.15.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/bouncycastle/bcprov-jdk14-138.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/java-xmlbuilder/java-xmlbuilder-0.4.jar REM OutOfMemory errors? Increase the memory available by changing -Xmx256M "%EXEC%" -Xmx256M -classpath "%CP%" org.jets3t.apps.cockpit.Cockpit :END jets3t-0.8.1+dfsg.orig/bin/uploader.bat0000644000000000000000000000362411550446574014573 0ustar @echo off rem ------------------------------------------------------------------- rem Environmental variables: rem rem JETS3T_HOME Points to the home directory of a JetS3t distribution. rem rem JAVA_HOME The home directory of the Java Runtime Environment or rem Java Development Kit to use. rem ------------------------------------------------------------------- rem Check the JETS3T_HOME directory if not "%JETS3T_HOME%" == "" goto gotJetS3tHome rem Find the home directory, assuming this script is %JETS3T_HOME%\bin set MY_JETS3T_HOME=%~dp0\.. if exist "%MY_JETS3T_HOME%\bin\%~nx0" goto foundJetS3tHome echo Please set the environment variable JETS3T_HOME goto END :gotJetS3tHome set MY_JETS3T_HOME=%JETS3T_HOME% :foundJetS3tHome rem Check the JAVA_HOME directory if not "%JAVA_HOME%" == "" goto gotJavaHome set EXEC=java goto noJavaHome :gotJavaHome set EXEC=%JAVA_HOME%\bin\java :noJavaHome rem echo JetS3t path: %MY_JETS3T_HOME% rem echo Java path: %EXEC% rem ------------------------------------------------------------------- REM Include configurations directory in classpath set CP=%MY_JETS3T_HOME%/configs REM Include resources directory in classpath set CP=%CP%;%MY_JETS3T_HOME%/resources REM Include libraries in classpath set CP=%CP%;%MY_JETS3T_HOME%/jars/jets3t-0.8.1.jar set CP=%CP%;%MY_JETS3T_HOME%/jars/jets3t-gui-0.8.1.jar set CP=%CP%;%MY_JETS3T_HOME%/jars/uploader-0.8.1.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/commons-logging/commons-logging-1.1.1.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/commons-codec/commons-codec-1.3.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/commons-httpclient/commons-httpclient-3.1.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/misc/BareBonesBrowserLaunch.jar set CP=%CP%;%MY_JETS3T_HOME%/libs/logging-log4j/log4j-1.2.15.jar REM OutOfMemory errors? Increase the memory available by changing -Xmx256M "%EXEC%" -Xmx256M -classpath "%CP%" org.jets3t.apps.uploader.Uploader :END jets3t-0.8.1+dfsg.orig/jars/0002755000000000000000000000000011550446574012454 5ustar jets3t-0.8.1+dfsg.orig/RELEASE_NOTES.markdown0000644000000000000000000012241211550446652015306 0ustar JetS3t Release Notes ==================== ------------------------ Version 0.8.1 - Apr 2011 ------------------------ ### TOOLKIT General: * StorageObject and its subclasses (e.g. S3Object) now include a convenience constructor that accepts byte array data. * Fixed incorrect file path for XMLBuilder library in shell scripts. * Fixed issue in FileComparer utility that prevented locally-deleted files within directories from being noticed and removed from the remote service. Also affected JetS3t's Synchronize and Cockpit apps. See https://bitbucket.org/jmurty/jets3t/issue/69 * Greatly reduced memory usage in FileComparer file comparison utilities when working with large numbers of files. * Service credentials classes now always return ProviderCredentials from #load methods, where the actual credentials instance is AWSCredentials by default or GSCredentials if explicitly loaded. * FileComparer utility now skips/ignores 'special' files on the local file system, to avoid problems synchronizing system directories that contain files that are not really data and cannot be synchronized to a storage service. S3Service: * Added support for the Multipart Uploads feature, including the utility class MultipartUtils to make it easier to use. * Added support for the Website Configuration feature, which allows static S3 bucket to behave more like a dynamic web site with custom index and error documents. * Added support for configuring buckets to send Simple Notification Service (SNS) messages. ThreadedS3Service: * Added threaded service subclass of ThreadedStorageService for features specific to Amazon's S3, namely multipart upload. CloudFrontService: * Added support for custom (non-S3) distribution origins (API 2010-11-01). This improvement involved changes to the CloudFrontService API which are not backwards-compatible, so code that relies on the prior version will need to be updated. ### SYNCHRONIZE * Improved batching algorithm to reduce memory usage when working with large numbers of files. * Added support for the Amazon S3 service's Multipart Upload feature, which allows large files to be uploaded in smaller parts for improved transfer performance or to upload files larger than 5 GB. * Added new property `upload.max-part-size` to synchronize.properties file, to allow the maximum upload part size to be configured when using the Amazon S3 service. The maximum part size defaults to 5 GB. * Improved file comparison logic so object metadata is only retrieved from a service when it is required. * Removed support for `--skipmetadata` option. This option is no longer necessary since metadata retrieval is more intelligent, and is not desirable because metadata retrieval is no longer optional when comparing objects uploaded using the Multipart Upload mechanism. ### COCKPIT * Fixed nasty bug that prevented directories from being included when uploading files. ### KUDOS TO * gillouxg on BitBucket for patches for Multipart functionality. * Tim Sylvester for patches related to Multipart Uploads. ------------------------ Version 0.8.0 - Oct 2010 ------------------------ ### TOOLKIT General: * New generic bucket, object, and multi-threaded service classes for interacting with either of the S3 or Google Storage services. * No long compatible with JDK 1.4. JDK 6+ is now required to run JetS3t. * Removed antiquated and unsupported SOAP S3 service implementation from toolkit. * FileComparer and related tools are now compatible with both S3 and Google Storage services. * FileComparer tool, and therefore all JetS3t apps, now uses a trailing slash to denote directory placeholder objects in S3 instead of the custom `application/x-directory` content-type. This should improve compatibility with other storage management tools, especially Amazon's AWS Console. JetS3t Property File changes: * Renamed `s3service.internal-error-retry-max` to `storage-service.internal-error-retry-max` * Renamed `s3service.stream-retry-buffer-size` to `uploads.stream-retry-buffer-size` * Renamed `s3service.defaultStorageClass` to `s3service.default-storage-class` * Added properties for new ThreadedStorageService: `threaded-service.max-thread-count` `threaded-service.admin-max-thread-count` `threaded-service.ignore-exceptions-in-multi` ThreadedStorageService / SimpleThreadedStorageService: * New multi-threaded service classes that allow operations to be performed in bulk on either the RestS3Service or GoogleStorageService service implementations. GoogleStorageService: * Google Storage (GS) service class added to provide specific support for Google's storage provider. S3Service: * Added support for bucket policy documents: set, get, and delete. * Methods for setting and using AWS DevPay credentials moved from S3Service to RestS3Service. CloudFront Service: * Added support for setting Default Root Object for CloudFront distributions. * Added support for API version 2010-08-01 and invalidation of objects. * Modified CloudFrontService#signUrl and #signUrlCanned to accept raw resource URL or path strings, instead of expressing all resources as HTTP URLs. This allows for URL signing of HTTPS and RTMP streaming resources. SOAP implementation: * **REMOVED** from project. ### COCKPIT * Added explicit support for logging in to either the Google Storage or Amazon S3 service in the startup/login dialog. * A CloudFront distribution's Default Root Object setting can be configured in the "CloudFront Distributions" dialog. ### SYNCHRONIZE * Directly supports new GoogleStorageService, allowing synchronization with Google Storage accounts through the native API. * Choose target service end-point with the new `--provider` command argument. ### KUDOS TO * Claudio Cherubino of Google Inc., for significant refactoring work and the addition of full support for the Google Storage service. * David Kocher for a patch to implement Default Root Object support in the CloundFrontService, and for his invaluable testing and feedback. ------------------------ Version 0.7.4 - Jul 2010 ------------------------ ### TOOLKIT General: * Added support for the new Reduced Redundancy Storage (RRS) class for objects. This discounted storage class can be applied when an object is created, overwritten or copied. The storage class can be set per-object, or a default value can be set with the property 's3service.defaultStorageClass'. Storage classes can be disabled altogether for services that don't support them using the 's3service.enable-storage-classes' property. * Added support for buckets located in the Asia Pacific (Singapore) location `ap-southeast-1`. * Eucalyptus-friendly generated URLs (#14). JetS3t configuration properties 's3service.s3-endpoint-virtual-path', 's3service.s3-endpoint-http-port' and 's3service.s3-endpoint-https-port' are no longer ignored when generating signed or torrent URLs. * Bash shell scripts now support cygwin by automatically converting classpaths to Windows format. * Improved configurability and flexibility by removing dependence on the VM-wide static Constants#S3_HOSTNAME constant value (see API Changes below) CloudFront Service: * NOTE: These changes break backward-compatibility for some of the CloudFrontService and related class interfaces. * Updated service to support API version 2010-06-01 which adds support for HTTPS-only distributions (a.k.a. RequiredProtocols) * Updated service to support API version 2010-05-01 which adds logging support for streaming distributions. API Changes: * Removed support for methods and metadata attributes that have been obsolete (and deprecated) since version 0.6.0. * Deprecated static methods in S3Service for generating signed URLs. The new non-static method equivalents should be used from now on to avoid dependency on a VM-wide S3 endpoint constant. SOAP implementation: * **Deprecated** in preparation for imminent removal from project. ### COCKPIT * Added support for the REDUCED_REDUNDANCY storage class to the Preferences dialog (set default storage class for uploads), the Copy or Move dialog (set the storage class for destination objects), and the Object Attributes dialog (see the current storage class property of objects) * Added support for buckets located in the Asia Pacific (Singapore) location. * Added support for creating HTTPS-only CloudFront distributions. * Removed overly fussy string-length checks in credentials dialog. ### SYNCHRONIZE * Allow synchronization with third-party buckets that are not owned by the user, provided the user has the necessary access to that bucket. ### KUDOS TO * Alexey I. Froloff for Eucalyptus-friendly generated URLs patch. * David Kocher for patches to allow advanced users to provide their own RequestEntity classes when uploading objects, and to improve HTTP retry handling. ------------------------ Version 0.7.3 - Mar 2010 ------------------------ ### TOOLKIT General: * Added support for the new S3 Bucket Versioning feature, and for Multi-Factor authenticated deletes. * S3ServiceMulti#downloadObjects method now automatically verifies that the data received matches the ETag MD5 hash value provided by S3. JetS3t's applications, and any third-party clients that use this method, will therefore get automatic data verificaiton of downloads similar to that provided (in most cases) for uploads. * Removed methods incompatible with JDK version 1.4. CloudFront Service: * Updated service to support API version 2010-03-01 which allows streaming distributions to be made private. * Fixed bug parsing that prevented AWS Account Numbers from being parsed from XML responses into a DistributionConfig object. ### COCKPIT * Fixed bug that caused Cockpit to create buckets in the US Standard location regardless of the location selected by the user. ### SYNCHRONIZE * When an encryption password or credentials file password must be entered by a user at the command prompt the characters are no longer echoed to standard output when run on JDK 1.6 or greater. ### KUDOS TO * Bennett Hiles for echo-less password input for Synchronize and removal of methods incompatible with JDK 1.4. ------------------------ Version 0.7.2 - Dec 2009 ------------------------ ### TOOLKIT General: * Added support for private and streaming CloudFront distributions (see the "CloudFront Service" section below) * Changed default thread and connection count settings to improve reliability when tranferring many large files and performance when performing object administration tasks. Default property settings for maximum simultaneous admin threads and HTTP connections are increased from 10 to 20, while the default number of non-admin threads is reduced from 4 to 2. * Improved compatibility with other S3 tools by setting the following properties to true by default: `filecomparer.ignore-panic-dir-placeholders` `filecomparer.ignore-s3organizer-dir-placeholders` * Added new property `filecomparer.ignore-s3organizer-dir-placeholders` which allows JetS3t to ignore directory place-holder objects created by the S3 Organizer Firefox extension when uploading or downloading files. * Added a new property `filecomparer.md5-files-root-dir` which allows MD5 files generated for file comparison purposes to be stored in a custom path, instead of within the same directory structure as data files. * Added support for the property `filecomparer.skip-symlinks` which causes symlink/alias files to be ignored by JetS3t applications when deciding which files to send to S3. Although "soft" links can be detected and ignored, hard links cannot be detected and will be treated as ordinary files. * Added support for the TargetGrants setting of logged S3 buckets. This allows you to set default ACL access permissions for S3 bucket logs generated by the service. * JetS3t's JMX instrumentation delegate is now re-initialized each time a new S3Service is created, allowing users to enable/disable JMX logging by adjusting System properties after a JVM has started. Note that it is still not possible to enable/disable Bucket- or Object-specific event logging after the JVM has started. * JMX logging for JetS3t can be enabled on Java 1.6 systems by including the "jets3t.mx" system property, since the "com.sun.management.jmxremote" property is no longer required to turn on JMX support in the JVM. * Improved the Windows batch scripts to correctly detect the JETS3T_HOME location regardless of the current directory when the JetS3t script is run. CloudFront Service: * API support for creating and managing private distributions: - create and manage Origin Access Identifiers as required for private distributions. - generate canned and custom-policy signed URLs for private distributions protected with mandatory request signing. * API support for creating and managing Streaming Distributions. REST Implementation: * Added sanity-checking of HTTP header values as obtained from an S3Object's metadata map. Non-ASCII header names and header duplicates caused by capitalization mismatches now fail early with descriptive S3ServiceException errors. * Fixed bug in signed-url based uploading that caused automatic ETag verification to fail with a NullPointerException if an ETag value wasn't set prior to upload. * Fixed NullPointerException in error reporting when REST service is run without a network available. * Added property setting `httpclient.connection-manager-timeout` which allows users to specify a timeout when an S3 operation is waiting for a connection to become available in the HttpClient connection pool. The default setting of 0 means wait indefinitely. ### SYNCHRONIZE * You can now set custom metadata information when uploading objects to S3 using Synchronize property names prefixed with `upload.metadata.`, for example: upload.metadata.Cache-Control=max-age=300 upload.metadata.Expires=Thu, 01 Dec 1994 16:00:00 GMT upload.metadata.my-metadata-item=This is the value for my metadata item * Synchronize can be told to continue even if local files or folders included in the UPLOAD command are missing or unreadable, by setting the `upload.ignoreMissingPaths` property to true. Normally Synchronize would consider this an error and halt. WARNING: This property could be dangerous if used unwisely because it could cause legitimate objects in S3 to be deleted due to problems on the local file system. Beware! ### KUDOS TO * Christian Mallwitz for informing us of the %~dp0 script variable that greatly improves the Windows batch scripts. * Jawahar Lal Nayak for: - a patch that contributed to the new TargetGrants support for logged S3 buckets. - bug report about the NPE error condition when the REST implementation is run on a machine without a network connection available. * Benjamin Schmaus for patches to configure the REST connection pool timeout, and to make HTTP response headers available for failed REST connections via S3ServiceExceptions. * Justin C for a patch that inspired Synchonize's ability to upload files with custom metadata using `upload.metadata.` properties. ------------------------ Version 0.7.1 - May 2009 ------------------------ ### COCKPIT * Fixed a menu display bug that caused the bucket and object action menus to appear behind other GUI elements on some Windows systems. * The Logging Status settings of CloudFront distributions can now be managed within the CloudFront Distributions dialog box (see the Tools menu). * New "Switch login" Service menu item allows uses with multiple S3 accounts to quickly switch between them, once the initial log in has been performed. ### TOOLKIT General: * Added support for JMX instrumentation of S3Service functions. To enable JMX set the system property `com.sun.management.jmxremote`. Instrumentation for S3Bucket and S3Object MBeans is disabled by default, to enable this reporting set the following system properties to `true`: "jets3t.bucket.mx", "jets3t.object.mx" * Added simplified constructors for S3Object, so the object's bucket need not be specified in advance. This is most useful when uploading data. * Added method getAccountOwner() to S3Service which allows you to look up the ID and display name of an S3 account's owner, even if the account contains no buckets. * Tweaks to improve support for using JetS3t with the open source Eucalyptus cloud computing service. REST Implementation: * Fixed a configuration error that caused the REST implementation to be limited to 20 simultaneous connections, regardless of the `httpclient.max-connections` property setting. Now the JetS3t property `httpclient.max-connections` sets the global connection limit, while the optional property `httpclient.max-connections-per-host` sets the per-host connection limit. CloudFront Service Implementation: * Added support for the new Logging Status feature that allows log files for activity in your CloudFront distributions to be sent to an S3 bucket. ### KUDOS TO * Laxmilal Menaria of Chambal.com Inc. for a patch that contributed to the new S3Service#getAccountOwner feature. * Doug MacEachern of Hyperic.com for contributing the bulk of a JMX instrumentation implementation. * peter_griess, askwar and leebutts (java.net users) for identifying bugs and providing patches or solutions. ------------------------ Version 0.7.0 - Jan 2009 ------------------------ ### COCKPIT * Added ability to view and manage Amazon CloudFront distributions using a dialog box. * Added support for configuring Requester Pays buckets. * Improved support for DevPay credentials, which can now be set and saved directly in the login dialog box instead of only in a properties file. * User preferences can now be remembered on your computer, so they do not need to be re-set every time you start Cockpit. * Improved dialog box for generating Signed URLs. URLs for multiple objects can now be generated at once. ### SYNCHRONIZE * AWS credentials and the cryptographic password can now be provided via prompts on the command-line, rather than merely through a properties file. * Added the --credentials option, which allows AWS credentials to be loaded from an encrypted file rather than an insecure properties file. The encrypted file can be created with the AWSCredentials API or the Cockpit application. * Synchronize will act as an anonymous client if empty values are provided as the AWS access and secret keys. When the S3 connection is anonymous, only public buckets will be accessible. * Fixed a bug that prevented Synchronize from recognizing duplicate file names when uploading to an S3 subdirectory path when using the --batch option. * Synchronize will now prompt for HTTP Proxy login credentials if required. If proxy credentials are pre-specified in the jets3t.properties file, you should not be prompted. * Improved handling of uploads of many files where the files must first be transformed (compressed or encrypted). In this case, files are now transformed and uploaded in batches, where the batch size is set by the synchronize.properties setting 'upload.transformed-files-batch-size' ### TOOLKIT General: * Added initial implementation of CloudFront service. * Added property `cloudfront-service.internal-error-retry-max` for defining the retry limit for CloudFront internal service errors. * Added support for configuring and accessing Requester Pays buckets. * Added property `httpclient.requester-pays-buckets-enabled` for defining whether the RestS3Service supports Requester Pays buckets by default. * Improved support for accessing S3 using DevPay credentials with a new credentials class for defining and storing these credentials: AWSDevPayCredentials * Added a class (AWSDevPayProduct) to represent a DevPay product, and to load information about pre-defined products from the properties file devpay_products.properties. * Improved the interpretation of .jets3t-ignore files so that child paths or arbitrary paths can be specified and ignored. For example, to ignore all CVS directories you can now add a single ignore path at the top level: **/CVS REST Implementation: * Added support for proxy authentication settings in jets3t.properties: "proxy-user", "proxy-password", and "proxy-domain" * The service's HTTP proxy settings can be updated an reapplied on-demand using a range of #initHttpProxy methods. * Added property settings to allow the default HTTP and HTTPS ports to be changed, which can be handy when running the service through a proxy for testing: s3service.s3-endpoint-http-port, s3service.s3-endpoint-https-port * The HttpConnectionManager and HttpClient objects used by the REST service can now be reinitialised on-demand using the #initHttpConnection method. * The underlying HttpClient and HttpConnectionManager objects can be accessed to provide greater control and flexibility after a service is created. * The automatic time adjustment performed in response to RequestTimeTooSkewed errors will now work through proxies. ### KUDOS TO * David Kavanagh for sample code that helped improve HTTP proxy support and configurability. * Nikolas Coukouma of Zmanda Inc. for patches to significantly improve support for Amazon DevPay in the library and Cockpit applications. * Allan Frank for a patch that helped improved the Synchronize application's handling of uploads. ------------------------ Version 0.6.1 - Aug 2008 ------------------------ ### COCKPIT * Added support for copying or moving objects within and between buckets. * Added dialog to assist in moving/renaming multiple objects within a bucket. * Added support for updating objects with new metadata values. * Fixed issue where downloading items to a directory containing many files and directories (eg 250K+) would cause Cockpit to fail with OutOfMemory errors. * Added a Confirm Password field to the encryption settings, to help prevent problems where a password is mistyped. * Cockpit can now generate valid signed GET URLs for DevPay S3 accounts. ### SYNCHRONIZE * Synchonize now recognizes when you have specified a partial S3 path when synchronizing DOWN. A partial path is one that does not exactly match a directory path. Partial paths can now act as a prefix test that identifies objects in an S3 path, where only the objects in S3 that match the prefix are downloaded. For example, in a bucket that has a Docs subdirectory containing objects named with a timestamp prefix, the S3 path "my-bucket/Docs/2008" will identify the objects in the Docs subdirectory with names beginning with 2008. * Added --batch option that causes Synchronize to compare and download/upload files in batches of 1000, rather than all at once. This option will reduce the memory required to synchronize buckets with many objects, and will allow file transfers to commence as soon as possible rather than after the slow comparison process. * Added --skipmetadata option that causes Synchronize to skip the retrieval of object metadata information from S3. This makes synchs much faster for large buckets, but leave the app with less info to make decisions. * Added --reportlevel option that allows the user to control how much report detail is printed, from 0 (no reporting) to 3 (all reporting). * Added --move option that deletes local files after they have been uploaded to S3, or deletes objects from S3 after they have been downloaded. * Property settings in the synchronize.properties file, or in the file referred to by the --properties option, will override properties of the same name in jets3t.properties. This makes it easy to create task-specific properties files. ### TOOLKIT General: * Added support for the new Copy Object functionality that allows you to copy, move, rename and update objects in your S3 account. These operations are available through the S3Service as the methods copyObject, moveObject, renameObject and updateObjectMetadata. * Added support for conditional copying of objects, based on ETag and Modified Date comparisons. * Made it easier to verify that your data is correctly stored in S3 without corruption during transit, by calculating Content-MD5 hash values by default in commonly-used S3Object constructors and providing S3Object#verifyData methods that make it easy to verify data downloaded from S3. * Added basic support for accessing DevPay S3 accounts. DevPay user and product tokens can be provided to the S3Service class directly using the #setDevPayUserToken and #setDevPayProductToken methods, and default token values can be specified in the jets3t.properties file using the settings "devpay.user-token" and "devpay.product-token". * Modified Bucket Logging Status changing behaviour to update ACL settings of the target bucket before (re)directing log files to the bucket. * Fixed bug in RestS3Service that caused failures in some circumstances when buckets were created with the `US` location. * S3Service instances can now be configured individually by providing a JetS3tProperties object when constructing the service. The property values in this object can also be updated programmatically after the object has been constructed. * FileComparer now supports an optional setting that makes it assume local files are the latest version when there is a clash between the modification dates and hash values of a local file and an object stored in S3. This option should only be used as a work-around for users who synchronize Microsoft Excel files to S3, as these are the only documents that exhibit the mismatch. To enable the option, set the jets3t.properties item `filecomparer.assume-local-latest-in-mismatch` to true. * Added support to FileComparer for listing objects based on prefix "partitions" that allow a bucket to be listed by multiple simultaneous threads. This can speed up listings for large buckets containing many virtual subdirectories. To use multiple partitions when building S3 object maps, configure the jets3t.properties item `filecomparer.bucket-listing.` to specify a delimiter string and a traversal depth value separated by a comma, eg: filecomparer.bucket-listing.my-bucket=/,2 to partition the bucket my-bucket based on the '/' delimiter to a depth of 2 virtual subdirectories. REST Implementation: * Added support for the new Copy Object functionality, and conditional copying. * The XML parsing code now copes better when object names contain a carriage return character. A work-around is applied to prevent the Java XML parser from misinterpreting these characters, a fault which could cause some objects to become un-deletable. This new feature is enabled by default, but can be disabled with the jets3t.properties setting `xmlparser.sanitize-listings`. * Changed default AuthenticationPreemptive setting for HttpClient connections from true to false, to improve compatibility with NTLM proxies. Preemptive auth can be turned on by setting `httpclient.authentication-preemptive` to true in jets3t.properties. * Refactored repeatable input streams implementations to recognize and support standard InputStream objects that can be reset. Thanks to Keith Bonawitz for the idea and patch for this. Multi-threaded Service: * Added a new listObjects method that performs a multi-threaded listing of a bucket's contents. You provide an array of prefix strings which serve to divide your objects into a number of "partitions", and the service performs these prefix-based listings in parallel. See src/org/jets3t/samples/ThreadedObjectListing.java for example usage. * Added a new notification event ServiceEvent#EVENT_IGNORED_ERRORS that provides information about exceptions that were ignored during a multi-threaded S3 operation. Exceptions are only ignored if the JetS3t property `s3service.ignore-exceptions-in-multi` is set to true. ### KUDOS TO * Shlomo Swidler for numerous improvements to the project's technical documentation and code. * Keith Bonawitz for a patch to improve the handling of data re-transmissions using reset-able input streams. ------------------------ Version 0.6.0 - Feb 2008 ------------------------ ### COCKPIT * Added support for buckets located in Europe (EU location) * Generate signed GET URLs based on virtual host names. * Encryption algorithm can be changed in the preferences dialog. * Progress dialogs modified to fix display problems with JDK version 6. * Fixed bug causing encrypted files not to be automatically recognized and decrypted in some cases ### SYNCHRONIZE * Added --properties option that allows an explicit properties filename to be specified on the command line. * Added --nodelete option that keeps items on the destination that have been removed from the source. This is similar to --keepfiles except that files may still be reverted with the --nodelete option. * Added --noprogress option that prevents progress messages from being printed to the console, for cases where these messages pollute log files. This option is similar to --quiet, except the action report is printed. * Added the --acl option that allows Access Control List settings to be applied on the command line. Value must be one of: PRIVATE, PUBLIC_READ, PUBLIC_READ_WRITE * Added property setting to ignore missing source directories when uploading. * Progress status messages shortened to fit into 80 character width consoles. ### UPLOADER * Improved skinning capabilities. ### COCKPIT LITE * New Gatekeeper-compatible client application that allows almost all S3 operations to be performed by a client via Gatekeeper-provided signed URLs. ### GATEKEEPER * Extended interfaces and default implementations to provide URL signing for all operations performed by the new Cockpit Lite application. * Improved support for web proxies. ### TOOLKIT General: * S3Service class can now generate POST forms to allow web browsers to upload files or data directly to S3. * Added support for buckets located in the EU. Due to this change, the "s3service.end-point-host" property is now obsolete. * Added a default bucket location configuration setting in jets3t.properties: "s3service.default-bucket-location". If you do not use an explicit bucket location when you use the bucket creation API method, the bucket will be created in this default location. * Fixed bugs that caused uploads greater than 2GB to fail (Expect: 100-Continue is now supported) * Added the Bouncy Castle security provider to the suite, increasing the number of cipher algorithms available for encrypting files. * The method S3Service.listObjectsChunked now includes Common Prefixes in the result object returned. * Corrected the metadata name for the original date object metadata item, which was originally mis-typed as "jets3t-original-file-date-iso860". This name is now "jets3t-original-file-date-iso8601" (added "1" to the end). JetS3t tools remain compatible with the original metadata name. * The FileComparer class used by JetS3t applications can now be configured to use pre-generated .md5 files as a source for MD5 hash values, removing the need for hash values to be calculated for every synchronization operation - and potentially saving a great deal of time when you are synchronizing large files whose content changes rarely. This feature is controlled by a group of propery settings in jets3t.properties: filecomparer.use-md5-files, filecomparer.generate-md5-files, filecomparer.skip-upload-of-md5-files. * File listings as built using the FileComparer.buildFileMap() methods can be set not to include place-holder objects to represent empty directories (mimetype "application/x-directory") with the new configuration setting uploads.storeEmptyDirectories. REST S3 Service: * Added support for configuring TCP window sizes. In jets3t.properties, the settings httpclient.socket-receive-buffer and httpclient.socket-send-buffer are applied to the Socket send and receive buffers used by the underlying HttpClient library. * The REST implementation can now automatically cope with RequestTimeTooSkewed errors caused by the client computer's clock disagreeing with S3 about the current time. If this happens, JetS3t will look up the time according to S3 and compensate for the difference between the S3 clock and the client's clock. * Rudimentary upload bandwidth throttling using the jets3t.properties setting httpclient.read-throttle, which is specified in KB/s. * Proxy settings are now configurable via the jets3t.properties settings: httpclient.proxy-autodetect, httpclient.proxy-host, httpclient.proxy-port * Upgraded HTTPClient library to version 3.1 Multi-threaded Service: * Administration actions can have more threads assigned than upload/download actions with the new configuration setting s3service.admin-max-thread-count. These connections run much faster with more threads and as they are light weight they less likely to fail with higher thread counts. * Fixed S3ServiceSimpleMulti class to work with download sets larger than the number of available HTTP connections. Objects' data is now cached in temp files automatically. * The S3ServiceMulti@downloadObjects methods will restore the original last modified date of downloaded objects if the downloads.restoreLastModifiedDate configuration property is set to true. As these methods are used by the JetS3t applications, setting this property to true will allow file dates to be retained across synchronizations performed by Cockpit and Synchronize. The original last modified date must be available in the object's metadata item named "jets3t-original-file-date-iso8601". ### KUDOS TO Alexis Agahi for a fix to BytesProgressWatcher. Pradyumna Lenka for an example update to support the EU bucket location. Andrea Barbieri of Moving Image Research for suggestions, feedback and quality control. ### SPONSORS: The JetS3t project has been generously supported with sponsorship from Moving Image Research : http://www.movingimageresearch.com/ ------------------------ Version 0.5.0 - Jan 2007 ------------------------ ### COCKPIT * Login credentials can now be stored in S3. * Added a dialog for configuring Bucket Logging. * Objects can be filtered by prefix and/or delimiter strings. * Third-party buckets can be added without first logging in. * User can cancel the listing of objects in large buckets. * Files being sent to s3 are only opened when necessary, removing the potential for too many files to be open at once (exceeding an Operating System imposed limit). * When uploading files, specific file/directory paths can be ignored using .jets3t-ignore settings files. * Access Control List permissions of uploaded files can be set to PRIVATE, PUBLIC_READ or PUBLIC_READ_WRITE ### SYNCHRONIZE * Progress status messages are displayed for long-running processes. * Files being sent to s3 are only opened when necessary, removing the potential for too many files to be open at once (exceeding an Operating System imposed limit). * When uploading files, specific file/directory paths can be ignored using .jets3t-ignore settings files. * Access Control List permissions of uploaded files can be set to PRIVATE, PUBLIC_READ or PUBLIC_READ_WRITE ### UPLOADER A new applet/application to allow third parties without AWS accounts or credentials to upload files to an S3 account. The Uploader provides a simple wizard-based GUI allowing end-users to provide information, choose the file(s) they will upload, and see upload progress. The Uploader is highly configurable via the uploader.properties file, with settings to configure: user input fields, explanatory text messages, names/images/tooltips for buttons at each stage in the wizard, basic skinning of the Uploader (an example HTML-like skin is included), and branding. The Uploader is designed to work closely with a Gatekeeper server, which provides the Uploader with signed URLs to allow it to perform uploads. ### GATEKEEPER A new servlet that acts as a Gatekeeper server for S3 operations. The servlet receives requests for S3 operations (GET, HEAD, PUT, DELETE) and responds to these requests with either a signed URL allowing the operation, or a message stating that the operation will not be allowed. Basic decision-making functionality is included with the Gatekeeper Servlet, however it is straight-forward to obtain more advanced control over the Gatekeeper's behaviour by implementing the relevant Java interfaces. There are specific interfaces for: allowing/denying requests, signing URLs, and assigning unique transaction IDs for a request. The Gatekeeper is designed to work closely with the Uploader application, providing it with signed URLs so the Uploader can add items to an S3 account without the end-user having any access to the AWS account credentials. ### TOOLKIT General: * Properties for many aspects of jets3t behaviour can be set by the user in a properties file. * Support for getting/setting Server Access Logging for buckets. * Improved encryption mechanism, which now uses PBE-based encryption and allows users to set their preferred algorithm. NOTE: All changes *should* be backwards compatible, but due to these changes there may be an increased risk of data loss for encrypted items. * New methods to chunk bucket listings, allowing for better handling of buckets with many objects. * A limit to the maximum number of simultaneous communication threads (ie those interacting with S3) is now imposed. This limit can be set in the properties file, and defaults to 50. * Signed URLs can be generated for GET, HEAD, PUT and DELETE requests * Fixed bug where object keys/names with special characters were not correctly encoded. * DNS caching is limited to 300 seconds. * When an object's data comes from a file, the file can be opened only when necessary rather than being opened as soon as the object is created. * Added documentation for advanced options settings and logging REST/HTTP implementation: * Requests that fail due to S3 Internal Server error are retried a configurable number of times, with an increasing delay between each retry attempt. * The REST/HTTP implementation is now less fussy about object key names, and will allow unusual names such as full URL strings etc. * Can detect (in some circumstances) a browser's proxy settings when run inside an applet context, and allows for callbacks to a credentials provider object when authentication is required (eg for proxies requiring username/password) * Signed URLs can be used to perform GET, HEAD, PUT and DELETE operations without the need for knowledge of AWS credentials. * Added a utility method putObjectWithSignedUrl to upload objects to S3 using only a signed PUT URL (ie no AWS credentials are required). * Configurable user agent string. * Sends an upload object's MD5 data hash to S3 in the header Content-MD5, to confirm no data corruption has taken place on the wire. SOAP implementation: * Tests for data corruption on the wire by matching ETag returned by S3 with expected MD5 hash value. Multi-threaded Service: * Signed URLs can be used to perform GET, HEAD, PUT and DELETE operations of multiple items at a time, without the need for knowledge of AWS credentials. ### KNOWN ISSUES General: * Uploading or downloading multiple large files can result in connection errors if the network connection is flooded. The chances of such errors can be reduced by using low values (eg 2) for for the jets3t.properties settings s3service.max-thread-count and httpclient.max-connections. Cockpit: * Copy & paste and Drag & drop doesn't work on some versions of Linux, making it difficult to enter AWS credentials. ### SPONSORS The JetS3t project has been generously supported with sponsorship from the following organisations. * Moving Image Research : http://www.movingimageresearch.com/ Moving Image Research (MIR) is a technology company with deep roots in media science offering software, network services, and consulting. ### CONTRIBUTORS Thankyou to the following contributors, who helped make this release possible: * Moving Image Research, Andrea Barbieri (http://www.movingimageresearch.com/) * Angel Vera (gunfus) ------------------------- Version 0.4.0 - Sept 2006 ------------------------- Initial public release. jets3t-0.8.1+dfsg.orig/configs/0002755000000000000000000000000011550446574013145 5ustar jets3t-0.8.1+dfsg.orig/configs/synchronize.properties0000644000000000000000000000412611550446574017637 0ustar ###################################### # Synchronize application properties # # This file should be available on the # classpath when Synchronize is run ###################################### # Service Access Key (if commented-out, Synchronize will ask at the prompt) #accesskey= # Service Secret Key (if commented-out, Synchronize will ask at the prompt) #secretkey= # Access Control List setting to apply to uploads, must be one of: # PRIVATE, PUBLIC_READ, PUBLIC_READ_WRITE # The ACL setting defaults to PRIVATE if this setting is missing. acl=PRIVATE # Password used when encrypting/decrypting files, applicable on with the --crypto option. # password= # If "upload.max-part-size" is set, files larger than this value will be split into # smaller parts no larger than the value and uploaded as Multipart Uploads. # 5 GB is used as a default value if this property is not set, since this is the largest # object size supported by services. # NOTE: The Multipart Upload feature is currently only available in the Amazon S3 service. #upload.max-part-size=5368709120 # If "upload.ignoreMissingPaths" is set to true, Synchronize will perform an upload despite missing # or unreadable source files. If set to false, Synchronize will halt if files or paths are missing. # WARNING: Be careful enabling this option, as it could cause legitimate objects in S3 to be # deleted if the corresponding local files cannot be found or read. #upload.ignoreMissingPaths=true # Maximum number of files to transform and upload at a time, when file transformation is # required (eg. when files are gzipped or encrypted during synchronization). # When commented out, no batching takes place. #upload.transformed-files-batch-size=1000 # Custom metadata to apply when uploading new files to S3. Use the prefix "upload.metadata." # followed by the metadata item name, an equals sign, and the metadata value. For example: #upload.metadata.Cache-Control=max-age=300 #upload.metadata.Expires=Thu, 01 Dec 1994 16:00:00 GMT #upload.metadata.my-metadata-item=This is the value for my metadata item jets3t-0.8.1+dfsg.orig/configs/test.properties0000644000000000000000000000053011550446574016236 0ustar # test.properties - Used for running JUnit tests via ANT # # Fill in this properties file and place in the JetS3t project # directory to run the `ant tests` target. aws.accesskey= aws.secretkey= gsservice.accesskey= gsservice.secretkey= jets3t-0.8.1+dfsg.orig/configs/log4j.properties0000644000000000000000000000123011550446574016274 0ustar log4j.rootLogger=WARN, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%c] %m%n log4j.logger.org.apache.commons.httpclient=WARN log4j.logger.httpclient.wire.content=WARN log4j.logger.httpclient.wire.header=WARN log4j.logger.org.apache.commons.httpclient.HttpMethodDirector=ERROR log4j.logger.org.jets3t=ERROR log4j.logger.org.jets3t.service=WARN log4j.logger.org.jets3t.service.Jets3tProperties=WARN log4j.logger.org.jets3t.service.utils=WARN log4j.logger.org.jets3t.service.utils.Mimetypes=WARN log4j.logger.org.jets3t.servlets=DEBUG jets3t-0.8.1+dfsg.orig/configs/jets3t.properties0000644000000000000000000000653111550446574016502 0ustar ######################### # Low-level configuration of jets3t toolkit behaviour. # # For detailed documentation, please see: # http://www.jets3t.org/toolkit/configuration.html # # Properties set in this file will affect services and applications # using the JetS3t library. ######################### ### # StorageService (apply to both S3 and Google Storage services) ### storage-service.internal-error-retry-max=5 ### # ThreadedStorageService (multi-threaded wrapper for S3 or Google services) ### threaded-service.max-thread-count=2 threaded-service.admin-max-thread-count=20 threaded-service.ignore-exceptions-in-multi=false ### # S3ServiceMulti (multi-threaded wrapper for S3 service) ### s3service.max-thread-count=2 s3service.admin-max-thread-count=20 s3service.ignore-exceptions-in-multi=false ### # RestS3Service ### s3service.https-only=true s3service.s3-endpoint=s3.amazonaws.com s3service.s3-endpoint-http-port=80 s3service.s3-endpoint-https-port=443 s3service.disable-dns-buckets=false s3service.default-bucket-location=US s3service.enable-storage-classes=true s3service.default-storage-class=STANDARD # Virtual path for non-standard servers, such as Eucalyptus #s3service.s3-endpoint-virtual-path=/services/Walrus ### # GoogleStorageService ### gsservice.https-only=true gsservice.gs-endpoint=commondatastorage.googleapis.com gsservice.gs-endpoint-http-port=80 gsservice.gs-endpoint-https-port=443 ### # CloudFrontService ### cloudfront-service.internal-error-retry-max=5 ### # REST/HTTP HttpClient properties ### httpclient.max-connections=20 #httpclient.max-connections-per-host=5 httpclient.retry-max=5 httpclient.connection-timeout-ms=60000 httpclient.socket-timeout-ms=60000 httpclient.stale-checking-enabled=true #httpclient.useragent=My User Agent String #httpclient.read-throttle=50 httpclient.authentication-preemptive=false httpclient.proxy-autodetect=true #httpclient.proxy-host= #httpclient.proxy-port= #httpclient.proxy-user= #httpclient.proxy-password= #httpclient.proxy-domain= httpclient.requester-pays-buckets-enabled=false # TCP window size hints for kernel #httpclient.socket-receive-buffer=65536 #httpclient.socket-send-buffer=65536 #httpclient.connection-manager-timeout=0 ### # GUI application properties ### gui.verboseErrorDialog=true ### # Upload properties ### uploads.stream-retry-buffer-size=131072 uploads.storeEmptyDirectories=true ### # Download properties ### downloads.restoreLastModifiedDate=true ### # File/Object comparison properties ### #filecomparer.skip-symlinks=false #filecomparer.use-md5-files=false #filecomparer.generate-md5-files=false #filecomparer.md5-files-root-dir=/custom/path/for/md5/files #filecomparer.skip-upload-of-md5-files=false #filecomparer.assume-local-latest-in-mismatch=false ### # Encryption Algorithm used by JetS3t applications. # # This setting does not enable encryption in the JetS3t toolkit as # a whole. For this, refer to the Javadocs for the EncryptionUtil # and ObjectUtils classes. # # Note that some cryptography options will only be available # if the Java Cryptography Extension (JCE) Unlimited Strength # Jurisdiction Policy Files are installed. ### crypto.algorithm=PBEWithMD5AndDES ### # XML Parsing properties ### xmlparser.sanitize-listings=true ### # Amazon DevPay Settings # # Default values for DevPay user and product tokens. ### #devpay.user-token= #devpay.product-token= jets3t-0.8.1+dfsg.orig/configs/simplelog.properties0000644000000000000000000000121111550446574017247 0ustar # Configuration file for logging when the Commons Logging is set to use # org.apache.commons.logging.impl.SimpleLog (in commons-logging.properties) # Default logging level for all loggers org.apache.commons.logging.simplelog.defaultlog=warn # Show long logger name? org.apache.commons.logging.simplelog.showlogname=false # Show short logger name? org.apache.commons.logging.simplelog.showShortLogname=true # Show date and time? org.apache.commons.logging.simplelog.showdatetime=true # Logging level for named loggers # org.apache.commons.logging.simplelog.log.xxxxx=info # org.apache.commons.logging.simplelog.log.org.apache.fop.pdf=trace jets3t-0.8.1+dfsg.orig/configs/cockpitlite.properties0000644000000000000000000000141411550446574017573 0ustar # URL to access a JetS3t Gatekeeper servlet implementation, which # will authorize and sign all requests on behalf of Cockpit Lite. gatekeeperUrl=http://localhost:8080/gatekeeper-0.8.1/GatekeeperServlet # If specified, the named skin implementation/package will be used. #skin.name=html # Example of configurable login fields. Login is not required by default. field.0.name=WelcomeMessage field.0.prompt=Welcome to Cockpit Lite

Please ensure your Gatekeeper service is configured and running before attempting to log in. field.0.type=message #field.1.name=UserName #field.1.prompt=User Name #field.1.type=text #field.1.default=anonymous #field.2.name=Password #field.2.prompt=Password #field.2.type=password #field.2.default= jets3t-0.8.1+dfsg.orig/configs/uploader.properties0000644000000000000000000002031311550446574017073 0ustar ### # Uploader's required properties ### ## Specifies the URL of a server-side Gatekeeper service. gatekeeperUrl=http://localhost:8080/gatekeeper-0.8.1/GatekeeperServlet ## If true, an XML summary document is stored in S3 for every upload transaction. This is not available in the demo configuration. xmlSummary=false ### # Applet parameters - parameter names the uploaded expects the applet tag to provide ### applet.params= ### # Upload File Constraints - an error message is displayed if the files chosen for # upload do not meet these constraints. ### ## How many files may be uploaded at a time. file.maxCount=1 ## The minimum size of files, in megabytes file.minSizeMB=0 ## The maximum size of files, in megabytes file.maxSizeMB=250 ## If specified, files chosen for upload must have one of the listed file name extensions. #file.extensions=txt,html ### # Skinning ### # If specified, the named skin implementation/package will be used. #skin.name=html # HTML Skin LookAndFeel properties skin.html.textColor=#000000 skin.html.backgroundColor=#ffffff skin.html.font=Verdana-PLAIN-15 ### # Branding - Sets the application's title bar and footer details. ### gui.applicationTitle=JetS3t Uploader gui.applicationIcon= gui.footerHtml= JetS3t Home gui.footerIcon= ### # User Input Fields # # Properties to define the input fields presented to the user in the first wizard step. # Fields must be numbered from 1 to n, in the same order they will be displayed in the uploader. # # All fields to be displayed must have the following properties set: # field..name : Unique name for the field, which will be used in the XML file. # field..type : GUI element to display, one of: textarea, text, password, selection, radio # field..prompt : The prompt text to display to the user in the GUI # In addition to the above properties, field items of type 'selection' and 'radio' must also have: # field..options : A comma-separated list of options the user can choose from. ### ##################################### # The field names AwsAccessKey, AwsSecretKey and S3BucketName are "magic" field names # that allow the user to specify their AWS credentials and the target S3 bucket. If these # fields are available, the Uploader will self-sign URLs instead of requiring a server-side # Gatekeeper service. # # These settings should only be used for *demo* purposes. field.1.name=AwsAccessKey field.1.prompt=Your AWS Access Key * field.1.type=text field.2.name=AwsSecretKey field.2.prompt=Your AWS Secret Key * field.2.type=password field.3.name=S3BucketName field.3.prompt=S3 Bucket Name *
This bucket must already exist in your S3 account field.3.type=text ##################################### ## Some example fields... #field.4.name=FavouriteColour #field.4.prompt=My favourite colour is #field.4.type=radio #field.4.options=Blue,Green,Red,Puce #field.5.name=Location #field.5.prompt=Where are you? #field.5.type=selection #field.5.options=Earth,Elsewhere ### # Configurable text items displayed in the GUI, separated into sections by screen. # # Each screen has a title, and images/text/tooltips for the back and next buttons. If no text or image is # provided for a button, the button will not be displayed. # # Where a screen has additional non-standard elements, these are listed in the screen description below. # # The screens 'title' text item, and any additional non-standard text elements, may include variables # that will be replaced when the text is displayed. Replacement variables are prefixed surrounded with # ${} and can include anything in the Uploader's properties, parameters provided or user inputs. In # addition, the following information is made available by the Uploader: # File constraints: # ${maxFileSize}, ${maxFileCount}, ${validFileExtensions} # File(s) chosen for upload (only available after screen 2): # ${fileNameList}, ${filesSize} ### ## Screen 1 displays user input fields, as configured with the 'field.' properties. screen.1.title=
Step 1 of 4.

This is a demonstration version of the JetS3t Uploader.

Although the Uploader normally requires a Gatekeeper server to provide signed URLs, this demo version allows you to try it out in stand-alone mode by using your AWS credentials.

screen.1.nextButton.text=Next screen.1.nextButton.tooltip=Next screen.1.nextButton.image=/images/nuvola/32x32/actions/forward.png ## Screen 2 prompts the user to choose a file to upload, by drag-and-dropping a file into a drop zone or by selecting it with a browse button. ## Screen-specific text items: ## dragDropPrompt : Instructions for user to drag-drop file onto pane, or use browse button. ## browseButton.text : Text to display in the file browse button. screen.2.title=
Step 2 of 4.
Please choose the file you wish to upload.
screen.2.backButton.text=Back screen.2.backButton.image=/images/nuvola/32x32/actions/back.png screen.2.backButton.tooltip=Back screen.2.dragDropPrompt=
Drag and drop a file anywhere in this window, or use the Browse button below to select a file

You may upload ${maxFileCount} file(s) at a time

The maximum file upload size allowed is ${maxFileSize} MBytes
screen.2.browseButton.text=Choose file screen.2.browseButton.image=/images/nuvola/32x32/filesystems/folder_blue.png screen.2.browseButton.tooltip=Choose a file to upload ## Screen 3 displays information about the files the user is about to upload. ## Screen-specific text items: ## fileInformation : Text with information about the file to be uploaded. screen.3.title=
Step 3 of 4.
Please confirm the details of the file you have chosen to upload
screen.3.nextButton.text=Upload screen.3.nextButton.image=/images/nuvola/32x32/actions/up.png screen.3.nextButton.tooltip=Upload the file(s) you have chosen screen.3.backButton.text=Back screen.3.backButton.image=/images/nuvola/32x32/actions/back.png screen.3.backButton.tooltip=Back screen.3.fileInformation=
You have chosen to upload the file:
${fileNameList}

The total upload size is: ${filesSize}

To upload the file, click the Upload button

To choose a different file, click the Back button
## Screen 4 displays the upload progress information. ## Screen-specific text items: ## connectingMessage : Message displayed while uploaded makes initial connection to S3 ## hashingMessage : Message displayed while uploaded hashes the upload file. ## fileInformation : Text with information about the file being uploaded. ## cancelButton.text : Text to display in the Cancel upload button. screen.4.title=
Step 4 of 4.
Uploading file to server
screen.4.connectingMessage=
Connecting to the server

Please wait
screen.4.hashingMessage=
Generating MD5 hash of file(s)

Please be patient, this may take several minutes for large files
screen.4.fileInformation=Uploading ${fileNameList}, total size : ${filesSize} screen.4.cancelButton.text=Cancel upload screen.4.cancelButton.image=/images/nuvola/32x32/actions/cancel.png screen.4.cancelButton.tooltip=Cancels the current upload ## Screen 5 displays a thankyou message after a successful upload, or an error message if something has gone wrong. ## Screen-specific text items: ## thankyouMessage : Thankyou message to display when the upload completes successfully. ## errorMessage : Error message to display if/when an error occurs. screen.5.title=
Finished
screen.5.thankyouMessage=
Your file has been uploaded to S3

File uploaded:
${fileNameList}
screen.5.errorMessage=
Sorry, an error occurred: ${errorCode}.

Please contact us at a@b.c for help
jets3t-0.8.1+dfsg.orig/configs/commons-logging.properties0000644000000000000000000000126611550446574020365 0ustar ### # Configures the logging implementation used to actually display log messages. # Only one implementation can be chosen, the others must be commented out. ### # Use SimpleLog for logging - quite configurable (using simplelog.properties), no extra library is required. # org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog # Use Log4J for logging - very configurable (using log4j.properties) but requires the log4j library. org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger # Use Java's build-in JDK14 logging - not very configurable, no extra library is required. #org.apache.commons.logging.Log=org.apache.commons.logging.impl.Jdk14Logger jets3t-0.8.1+dfsg.orig/configs/mime.types0000644000000000000000000003563311550446574015172 0ustar # This is a comment. I love comments. # This file controls what Internet media types are sent to the client for # given file extension(s). Sending the correct media type to the client # is important so they know how to handle the content of the file. # Extra types can either be added here or by using an AddType directive # in your config files. For more information about Internet media types, # please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type # registry is at . # MIME type Extensions application/activemessage application/andrew-inset ez application/applefile application/atom+xml atom application/atomicmail application/batch-smtp application/beep+xml application/cals-1840 application/cnrp+xml application/commonground application/cpl+xml application/cybercash application/dca-rft application/dec-dx application/dvcs application/edi-consent application/edifact application/edi-x12 application/eshop application/font-tdpfr application/http application/hyperstudio application/iges application/index application/index.cmd application/index.obj application/index.response application/index.vnd application/iotp application/ipp application/isup application/mac-binhex40 hqx application/mac-compactpro cpt application/macwriteii application/marc application/mathematica application/mathml+xml mathml application/msword doc application/news-message-id application/news-transmission application/ocsp-request application/ocsp-response application/octet-stream bin dms lha lzh exe class so dll dmg application/oda oda application/ogg ogg application/parityfec application/pdf pdf application/pgp-encrypted application/pgp-keys application/pgp-signature application/pkcs10 application/pkcs7-mime application/pkcs7-signature application/pkix-cert application/pkix-crl application/pkixcmp application/postscript ai eps ps application/prs.alvestrand.titrax-sheet application/prs.cww application/prs.nprend application/prs.plucker application/qsig application/rdf+xml rdf application/reginfo+xml application/remote-printing application/riscos application/rtf application/sdp application/set-payment application/set-payment-initiation application/set-registration application/set-registration-initiation application/sgml application/sgml-open-catalog application/sieve application/slate application/smil smi smil application/srgs gram application/srgs+xml grxml application/timestamp-query application/timestamp-reply application/tve-trigger application/vemmi application/vnd.3gpp.pic-bw-large application/vnd.3gpp.pic-bw-small application/vnd.3gpp.pic-bw-var application/vnd.3gpp.sms application/vnd.3m.post-it-notes application/vnd.accpac.simply.aso application/vnd.accpac.simply.imp application/vnd.acucobol application/vnd.acucorp application/vnd.adobe.xfdf application/vnd.aether.imp application/vnd.amiga.ami application/vnd.anser-web-certificate-issue-initiation application/vnd.anser-web-funds-transfer-initiation application/vnd.audiograph application/vnd.blueice.multipass application/vnd.bmi application/vnd.businessobjects application/vnd.canon-cpdl application/vnd.canon-lips application/vnd.cinderella application/vnd.claymore application/vnd.commerce-battelle application/vnd.commonspace application/vnd.contact.cmsg application/vnd.cosmocaller application/vnd.criticaltools.wbs+xml application/vnd.ctc-posml application/vnd.cups-postscript application/vnd.cups-raster application/vnd.cups-raw application/vnd.curl application/vnd.cybank application/vnd.data-vision.rdz application/vnd.dna application/vnd.dpgraph application/vnd.dreamfactory application/vnd.dxr application/vnd.ecdis-update application/vnd.ecowin.chart application/vnd.ecowin.filerequest application/vnd.ecowin.fileupdate application/vnd.ecowin.series application/vnd.ecowin.seriesrequest application/vnd.ecowin.seriesupdate application/vnd.enliven application/vnd.epson.esf application/vnd.epson.msf application/vnd.epson.quickanime application/vnd.epson.salt application/vnd.epson.ssf application/vnd.ericsson.quickcall application/vnd.eudora.data application/vnd.fdf application/vnd.ffsns application/vnd.fints application/vnd.flographit application/vnd.framemaker application/vnd.fsc.weblaunch application/vnd.fujitsu.oasys application/vnd.fujitsu.oasys2 application/vnd.fujitsu.oasys3 application/vnd.fujitsu.oasysgp application/vnd.fujitsu.oasysprs application/vnd.fujixerox.ddd application/vnd.fujixerox.docuworks application/vnd.fujixerox.docuworks.binder application/vnd.fut-misnet application/vnd.grafeq application/vnd.groove-account application/vnd.groove-help application/vnd.groove-identity-message application/vnd.groove-injector application/vnd.groove-tool-message application/vnd.groove-tool-template application/vnd.groove-vcard application/vnd.hbci application/vnd.hhe.lesson-player application/vnd.hp-hpgl application/vnd.hp-hpid application/vnd.hp-hps application/vnd.hp-pcl application/vnd.hp-pclxl application/vnd.httphone application/vnd.hzn-3d-crossword application/vnd.ibm.afplinedata application/vnd.ibm.electronic-media application/vnd.ibm.minipay application/vnd.ibm.modcap application/vnd.ibm.rights-management application/vnd.ibm.secure-container application/vnd.informix-visionary application/vnd.intercon.formnet application/vnd.intertrust.digibox application/vnd.intertrust.nncp application/vnd.intu.qbo application/vnd.intu.qfx application/vnd.irepository.package+xml application/vnd.is-xpr application/vnd.japannet-directory-service application/vnd.japannet-jpnstore-wakeup application/vnd.japannet-payment-wakeup application/vnd.japannet-registration application/vnd.japannet-registration-wakeup application/vnd.japannet-setstore-wakeup application/vnd.japannet-verification application/vnd.japannet-verification-wakeup application/vnd.jisp application/vnd.kde.karbon application/vnd.kde.kchart application/vnd.kde.kformula application/vnd.kde.kivio application/vnd.kde.kontour application/vnd.kde.kpresenter application/vnd.kde.kspread application/vnd.kde.kword application/vnd.kenameaapp application/vnd.koan application/vnd.liberty-request+xml application/vnd.llamagraphics.life-balance.desktop application/vnd.llamagraphics.life-balance.exchange+xml application/vnd.lotus-1-2-3 application/vnd.lotus-approach application/vnd.lotus-freelance application/vnd.lotus-notes application/vnd.lotus-organizer application/vnd.lotus-screencam application/vnd.lotus-wordpro application/vnd.mcd application/vnd.mediastation.cdkey application/vnd.meridian-slingshot application/vnd.micrografx.flo application/vnd.micrografx.igx application/vnd.mif mif application/vnd.minisoft-hp3000-save application/vnd.mitsubishi.misty-guard.trustweb application/vnd.mobius.daf application/vnd.mobius.dis application/vnd.mobius.mbk application/vnd.mobius.mqy application/vnd.mobius.msl application/vnd.mobius.plc application/vnd.mobius.txf application/vnd.mophun.application application/vnd.mophun.certificate application/vnd.motorola.flexsuite application/vnd.motorola.flexsuite.adsi application/vnd.motorola.flexsuite.fis application/vnd.motorola.flexsuite.gotap application/vnd.motorola.flexsuite.kmr application/vnd.motorola.flexsuite.ttc application/vnd.motorola.flexsuite.wem application/vnd.mozilla.xul+xml xul application/vnd.ms-artgalry application/vnd.ms-asf application/vnd.ms-excel xls application/vnd.ms-lrm application/vnd.ms-powerpoint ppt application/vnd.ms-project application/vnd.ms-tnef application/vnd.ms-works application/vnd.ms-wpl application/vnd.mseq application/vnd.msign application/vnd.music-niff application/vnd.musician application/vnd.netfpx application/vnd.noblenet-directory application/vnd.noblenet-sealer application/vnd.noblenet-web application/vnd.novadigm.edm application/vnd.novadigm.edx application/vnd.novadigm.ext application/vnd.obn application/vnd.osa.netdeploy application/vnd.palm application/vnd.pg.format application/vnd.pg.osasli application/vnd.powerbuilder6 application/vnd.powerbuilder6-s application/vnd.powerbuilder7 application/vnd.powerbuilder7-s application/vnd.powerbuilder75 application/vnd.powerbuilder75-s application/vnd.previewsystems.box application/vnd.publishare-delta-tree application/vnd.pvi.ptid1 application/vnd.pwg-multiplexed application/vnd.pwg-xhtml-print+xml application/vnd.quark.quarkxpress application/vnd.rapid application/vnd.rn-realmedia rm application/vnd.s3sms application/vnd.sealed.net application/vnd.seemail application/vnd.shana.informed.formdata application/vnd.shana.informed.formtemplate application/vnd.shana.informed.interchange application/vnd.shana.informed.package application/vnd.smaf application/vnd.sss-cod application/vnd.sss-dtf application/vnd.sss-ntf application/vnd.street-stream application/vnd.svd application/vnd.swiftview-ics application/vnd.triscape.mxs application/vnd.trueapp application/vnd.truedoc application/vnd.ufdl application/vnd.uplanet.alert application/vnd.uplanet.alert-wbxml application/vnd.uplanet.bearer-choice application/vnd.uplanet.bearer-choice-wbxml application/vnd.uplanet.cacheop application/vnd.uplanet.cacheop-wbxml application/vnd.uplanet.channel application/vnd.uplanet.channel-wbxml application/vnd.uplanet.list application/vnd.uplanet.list-wbxml application/vnd.uplanet.listcmd application/vnd.uplanet.listcmd-wbxml application/vnd.uplanet.signal application/vnd.vcx application/vnd.vectorworks application/vnd.vidsoft.vidconference application/vnd.visio application/vnd.visionary application/vnd.vividence.scriptfile application/vnd.vsf application/vnd.wap.sic application/vnd.wap.slc application/vnd.wap.wbxml wbxml application/vnd.wap.wmlc wmlc application/vnd.wap.wmlscriptc wmlsc application/vnd.webturbo application/vnd.wrq-hp3000-labelled application/vnd.wt.stf application/vnd.wv.csp+wbxml application/vnd.xara application/vnd.xfdl application/vnd.yamaha.hv-dic application/vnd.yamaha.hv-script application/vnd.yamaha.hv-voice application/vnd.yellowriver-custom-menu application/voicexml+xml vxml application/watcherinfo+xml application/whoispp-query application/whoispp-response application/wita application/wordperfect5.1 application/x-bcpio bcpio application/x-cdlink vcd application/x-chess-pgn pgn application/x-compress application/x-cpio cpio application/x-csh csh application/x-director dcr dir dxr application/x-dvi dvi application/x-futuresplash spl application/x-gtar gtar application/x-gzip gz application/x-hdf hdf application/x-javascript js application/x-java-jnlp-file jnlp application/x-koan skp skd skt skm application/x-latex latex application/x-netcdf nc cdf application/x-sh sh application/x-shar shar application/x-shockwave-flash swf application/x-stuffit sit application/x-sv4cpio sv4cpio application/x-sv4crc sv4crc application/x-tar tar application/x-tcl tcl application/x-tex tex application/x-texinfo texinfo texi application/x-troff t tr roff application/x-troff-man man application/x-troff-me me application/x-troff-ms ms application/x-ustar ustar application/x-wais-source src application/x400-bp application/xhtml+xml xhtml xht application/xslt+xml xslt application/xml xml xsl application/xml-dtd dtd application/xml-external-parsed-entity application/zip zip audio/32kadpcm audio/amr audio/amr-wb audio/basic au snd audio/cn audio/dat12 audio/dsr-es201108 audio/dvi4 audio/evrc audio/evrc0 audio/g722 audio/g.722.1 audio/g723 audio/g726-16 audio/g726-24 audio/g726-32 audio/g726-40 audio/g728 audio/g729 audio/g729D audio/g729E audio/gsm audio/gsm-efr audio/l8 audio/l16 audio/l20 audio/l24 audio/lpc audio/midi mid midi kar audio/mpa audio/mpa-robust audio/mp4a-latm m4a m4p audio/mpeg mpga mp2 mp3 audio/parityfec audio/pcma audio/pcmu audio/prs.sid audio/qcelp audio/red audio/smv audio/smv0 audio/telephone-event audio/tone audio/vdvi audio/vnd.3gpp.iufp audio/vnd.cisco.nse audio/vnd.cns.anp1 audio/vnd.cns.inf1 audio/vnd.digital-winds audio/vnd.everad.plj audio/vnd.lucent.voice audio/vnd.nortel.vbk audio/vnd.nuera.ecelp4800 audio/vnd.nuera.ecelp7470 audio/vnd.nuera.ecelp9600 audio/vnd.octel.sbc audio/vnd.qcelp audio/vnd.rhetorex.32kadpcm audio/vnd.vmx.cvsd audio/x-aiff aif aiff aifc audio/x-alaw-basic audio/x-mpegurl m3u audio/x-pn-realaudio ram ra audio/x-pn-realaudio-plugin audio/x-wav wav chemical/x-pdb pdb chemical/x-xyz xyz image/bmp bmp image/cgm cgm image/g3fax image/gif gif image/ief ief image/jpeg jpeg jpg jpe image/jp2 jp2 image/naplps image/pict pict pic pct image/png png image/prs.btif image/prs.pti image/svg+xml svg image/t38 image/tiff tiff tif image/tiff-fx image/vnd.cns.inf2 image/vnd.djvu djvu djv image/vnd.dwg image/vnd.dxf image/vnd.fastbidsheet image/vnd.fpx image/vnd.fst image/vnd.fujixerox.edmics-mmr image/vnd.fujixerox.edmics-rlc image/vnd.globalgraphics.pgb image/vnd.mix image/vnd.ms-modi image/vnd.net-fpx image/vnd.svf image/vnd.wap.wbmp wbmp image/vnd.xiff image/x-cmu-raster ras image/x-macpaint pntg pnt mac image/x-icon ico image/x-portable-anymap pnm image/x-portable-bitmap pbm image/x-portable-graymap pgm image/x-portable-pixmap ppm image/x-quicktime qtif qti image/x-rgb rgb image/x-xbitmap xbm image/x-xpixmap xpm image/x-xwindowdump xwd message/delivery-status message/disposition-notification message/external-body message/http message/news message/partial message/rfc822 message/s-http message/sip message/sipfrag model/iges igs iges model/mesh msh mesh silo model/vnd.dwf model/vnd.flatland.3dml model/vnd.gdl model/vnd.gs-gdl model/vnd.gtw model/vnd.mts model/vnd.parasolid.transmit.binary model/vnd.parasolid.transmit.text model/vnd.vtu model/vrml wrl vrml multipart/alternative multipart/appledouble multipart/byteranges multipart/digest multipart/encrypted multipart/form-data multipart/header-set multipart/mixed multipart/parallel multipart/related multipart/report multipart/signed multipart/voice-message text/calendar ics ifb text/css css text/directory text/enriched text/html html htm text/parityfec text/plain asc txt text/prs.lines.tag text/rfc822-headers text/richtext rtx text/rtf rtf text/sgml sgml sgm text/t140 text/tab-separated-values tsv text/uri-list text/vnd.abc text/vnd.curl text/vnd.dmclientscript text/vnd.fly text/vnd.fmi.flexstor text/vnd.in3d.3dml text/vnd.in3d.spot text/vnd.iptc.nitf text/vnd.iptc.newsml text/vnd.latex-z text/vnd.motorola.reflex text/vnd.ms-mediapackage text/vnd.net2phone.commcenter.command text/vnd.sun.j2me.app-descriptor text/vnd.wap.si text/vnd.wap.sl text/vnd.wap.wml wml text/vnd.wap.wmlscript wmls text/x-setext etx text/xml text/xml-external-parsed-entity video/3gpp 3gp video/bmpeg video/bt656 video/celb video/dv video/h261 video/h263 video/h263-1998 video/h263-2000 video/jpeg video/mp1s video/mp2p video/mp2t video/mp4 mp4 video/mp4v-es video/mpv video/mpeg mpeg mpg mpe video/nv video/parityfec video/pointer video/quicktime qt mov video/smpte292m video/vnd.fvt video/vnd.motorola.video video/vnd.motorola.videop video/vnd.mpegurl mxu m4u video/vnd.nokia.interleaved-multimedia video/vnd.objectvideo video/vnd.vivo video/x-dv dv dif video/x-flv flv video/x-ms-wmv wmv video/x-msvideo avi video/x-sgi-movie movie x-conference/x-cooltalk ice jets3t-0.8.1+dfsg.orig/configs/devpay_products.properties0000644000000000000000000000061711550446574020500 0ustar ######################### # Define DevPay products that can be loaded through the # AwsDevPayProduct#load method. # # A DevPay product is specified using XYZ.name and XYZ.token # properties, for example: # # example.name=Name of DevPay product # example.token=YOUR_DEVPAY_PRODUCT_TOKEN ######################### example.name=Dummy in devpay_products.properties example.token=only_a_dummy__not_real jets3t-0.8.1+dfsg.orig/build.properties0000644000000000000000000000140411550446652014724 0ustar version=0.8.1 debug=on build.source=5 build.target=5 dir.build=build dir.src=src dir.libs=libs dir.configs=configs dir.scripts=scripts dir.applets=applets dir.servlets=servlets dir.resources=resources dist.file.service=jets3t-${version}.jar dist.file.cockpit=cockpit-${version}.jar dist.file.cockpitlite=cockpitlite-${version}.jar dist.file.synchronize=synchronize-${version}.jar dist.file.uploader=uploader-${version}.jar dist.file.gatekeeper=gatekeeper-${version}.war dist.file.guisupport=jets3t-gui-${version}.jar # Comment out the lines below to exclude contributions contribs.include-mx keystore.file=my.keystore keystore.storepass=storepass keystore.keypass=keypass keystore.alias=my_alias # Workaround for potential bug in ANT 1.8.0 build.sysclasspath=ignore jets3t-0.8.1+dfsg.orig/build.xml0000644000000000000000000003261611550446652013341 0ustar JetS3t : Toolkit and application suite for Amazon's S3 online storage service Welcome to the JetS3t ANT build script. The build.xml script will allow you to rebuild the JetS3t suite from the source code included with the distribution. It should make it easier to make your own additions to the library, to build your own versions of applications or applets, and to make JetS3t work the way you want. The first thing you may want to do is recompile JetS3t using the latest version of Java. To do this, modify the debug and build.target properties in the build.properties file and run the "rebuild-all" target. ANT TARGET DESCRIPTIONS rebuild-all : Rebuild the JetS3t Jar files for the library and all applications. compile : Compiles the JetS3t source code, but does not produce Jar files. This target is useful as a quick test to make sure any code changes you make will compile correctly. clean : Removes all the temporary compile/build artifacts help : Displays this help message rebuild-service : Rebuild the library/toolkit files rebuild-cockpit : Rebuild the Cockpit application rebuild-synchronize : Rebuild the Synchronize application rebuild-gatekeeper : Rebuild the Gatekeeper servlet WAR rebuild-uploader : Rebuild the Uploader application rebuild-cockpitlite : Rebuild the CockpitLite application repackage-applets : Repackages all the applet applications. This replaces the contents of the applets directory with applets built from the latest code, and signed with the keystore configured in the build.properties file. repackage-applet-cockpit : Repackage the Cockpit applet repackage-applet-cockpitlite : Repackage the CockpitLite applet repackage-applet-uploader : Repackage the Uploader applet init : Sets dynamic properties required by the build script. unzip-source-code : Unzips the JetS3t source code from src.zip. This target will be called automatically if necessary. zip-source-code : Zips the JetS3t source code to an archive file with a version number: jets3t-src-${version}.zip Keystore file ${keystore.file} does not exist. The build script will now create a generic keystore on your behalf for development and testing purposes. If you intend to make the applets publicly available, please create a keystore with proper information and modify the keystore settings in build.properties to refer to this official keystore. jets3t-0.8.1+dfsg.orig/README.markdown0000644000000000000000000001250111550446652014210 0ustar JetS3t ====== JetS3t is a free, open-source Java toolkit and application suite for Amazon Simple Storage Service (Amazon S3), Amazon CloudFront content delivery network, and Google Storage for Developers. For further information, documentation, and links to discussion lists and other resources, please visit the [JetS3t web site][jets3t]. There are also [historic release notes][jets3t-releasenotes-hist] summarizing the changes in past JetS3t releases, and [pending release notes][jets3t-releasenotes-pend] that include details about the up-coming release. [jets3t]: http://www.jets3t.org/ [jets3t-toolkit]: http://www.jets3t.org/toolkit/toolkit.html [jets3t-releasenotes-hist]: http://www.jets3t.org/RELEASE_NOTES.txt [jets3t-releasenotes-pend]: https://bitbucket.org/jmurty/jets3t/src/tip/RELEASE_NOTES.txt [jets3t-cockpit]: http://www.jets3t.org/applications/cockpit.html [jets3t-synchronize]: http://www.jets3t.org/applications/synchronize.html [jets3t-cockpitlite]: http://www.jets3t.org/applications/cockpitlite.html [jets3t-uploader]: http://www.jets3t.org/applications/uploader.html Running Applications -------------------- Each application can be run using a script in the _bin_ directory. To run an application, such as Cockpit, run the appropriate script from the bin directory for your JetS3t version ("x.y.z" in these examples). Windows: cd jets3t-x.y.z\bin cockpit.bat Unixy: bash jets3t-x.y.z/bin/cockpit.sh Configuration files ------------------- Applications or library components generally read text configuration files, which must be available in the classpath of a running application to be useful. Example configuration files are located in the _configs_ directory. The run scripts in the _bin_ directory automatically include this _configs_ directory in the classpath when running JetS3t apps. The configuration files include: * `jets3t.properties` Low-level toolkit configuration. * `synchronize.properties` Properties for the Synchronize application * `uploader.properties` Properties for the Uploader application * `cockpitlite.properties` Properties for the CockpitLite application * `mime.types` Maps file extensions to the appropriate mime/content type. For example, the "txt" extension maps to "text/plain". * `commons-logging.properties` Defines which logging implementation to use. * `log4j.properties` When Log4J is the chosen logging implementation, these settings control how much logging information is displayed, and the way it is displayed. * `simplelog.properties` When SimpleLog is the chosen logging implementation, these settings control the logging information that is displayed. JAR files --------- The compiled JetS3t code jar files are available in the _jars_ directory, and include the following: * `jets3t-x.y.z.jar` The [JetS3t toolkit][jets3t-toolkit], including the JetS3t service implemention which underlies all the other JetS3t applications. * `jets3t-gui-x.y.z.jar` Graphical user interface components used by JetS3t GUI applications such as Cockpit. These components are not required by the command-line Synchronize tool, nor by non-graphical programs you may build. * `cockpit-x.y.z.jar` [Cockpit][jets3t-cockpit], a GUI application/applet for viewing and managing the contents of an S3 account. * `synchronize-x.y.z.jar` [Synchronize][jets3t-synchronize], a console application for synchronizing directories on a computer with an Amazon S3 account. * `cockpitlite-x.y.z.jar` [CockpitLite][jets3t-cockpitlite], a GUI application/applet for viewing and managing the contents of an S3 account, where the S3 account is not owned by the application's user directly but is made available via the Gatekeeper servlet. * `uploader-x.y.z.jar` [Uploader][jets3t-uploader], a wizard-based GUI application/applet that S3 account holders (Service Providers) may provide to clients to allow them to upload files to S3 without requiring access to the Service Provider's S3 credentials Compatibility and Performance of Distributed Jar files ------------------------------------------------------ The class files in these jars are compiled for compatibility with Sun's JDK 5 and later, and have debugging turned on to provide more information if errors occur. To use JetS3t in high-performance scenarios, the classes should be recompiled using the latest version of Java available to you and with debugging turned off. Building JetS3t from source --------------------------- The JetS3t distribution package includes an ANT build script (`build.xml`) that allows you to easily rebuild the project yourself, and a default set of build properties (`build.properties`) that you may wish to modify. The following ANT command will recompile the JetS3t library and applications: ant rebuild-all To repackage JetS3t applications or applets with your modifications for redistribution: ant repackage-applets Servlets -------- The JetS3t application suite includes a servlet implementation of a Gatekeeper to offer mediated third-party access to your S3 resources. The deployable WAR file for this servlet is located in the _servlets/gatekeeper_ directory.jets3t-0.8.1+dfsg.orig/resources/0002755000000000000000000000000011550446572013525 5ustar jets3t-0.8.1+dfsg.orig/resources/images/0002755000000000000000000000000011550446572014772 5ustar jets3t-0.8.1+dfsg.orig/resources/images/nuvola/0002755000000000000000000000000011550446574016300 5ustar jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/0002755000000000000000000000000011550446572017063 5ustar jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/0002755000000000000000000000000011550446572020523 5ustar jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/laptop_power.png0000644000000000000000000000163111550446572023743 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<+IDATxÚbüÿÿ?% €˜(A¾ÿKLYüüü x($Qw  óöúùïóõôíêëëäÑæææËýýüÊîîíØùùöþððïÔÔÉl###ó2³°:üþûò÷?vAnA1yyE a}U>^ë?¿5\yµu뎵—.]èªÒ @Œ 0ðº€á?3‡Ôÿÿ¿™xx8ÿÿúõ—ãý»|¼¼<Ê Êjêòþþ¾êþüglnî<¾sçvß{÷®¾ p|ÿñ…áû÷Ïyù8ÿöÿñ¯?<Œÿsó01ss|ÿÉüèŻߋfÍZÓØÐð@JJ”!::Üh™H/@½ðÿÿ?†ÿÿþ0þüùÝWßH'UUCÛRDTR˜•ƒáÇÏ? ïßû£¨¤~ýýÛç"§N_gxÿî50Ì~²ôÄ€ÿØ89Äšm¬"‹íX$$9øù˜îûõ—áË–wltŸ¿øÂpùú†ãG/0ˆˆŠýé °~ò(©ë9—z¸3~úüŸáúŸ ÿ³3°íàäf`àæa``ge`áaxóNŽA@ÄÈ~ÓÔº €ÀÜ{úà‹˜üÏÇ_?—Óä*gx÷îÃ=¶>†¸ž<ºðÏvæ¿ ~}axöôƒ §2»œ±²0ĉŠ‚õ„`àb``Ófddc¦0¹M†»é: ¯X¶pˆh000E±°pWÙ¶¬,Œ bb"`½ÄHin Šs#@€7‡4ôúÍÀÀÊÂÀðïHš™•ÁEPŠ{Öo6¦_~üvfdd|Í´ô?Pž €˜€ª4X¢ù/Â\†j@<7ò0ˆñ21ñ±2íc ˆ!L@÷0”–ï×øùó·sU¥ƒ4ç/††•ï”x˜ª½¥î>þÂðh03ÃÆ gn~dxñþ @± ¢“õÏß??ü*«M¿pñMì”ÉöŒ*™R ;μaxþþ7CVÉ‘_‡Î¿ÜÍ%ÀöLÿ™Ù~²0Ý XÀÀ7`%¬\yýèÅ˯»:»¬ù#e^¼ýÁðåïÿ ßÿf}cÿóˆáÐíl@ÌÍÊ@ ¤Ì Á° aüÏÀÂ6ëÆ7öA!Û¶dcxòì;+33Ðý@#l Pfº¤ó€x7<3± åÒ¿ÿ¸9˜ý$•ø¦~edxûñË/[`fzÉ ƒÿ,ÿÁ. FJ³3@€÷Q0Âh2˜ÁIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/artsmidimanager.png0000644000000000000000000000213111550446572024373 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ëIDATxÚbd ð˜20p30ügc`ä“pÑ×\óä ã…7ï¾3T ?³1;æâ`Ì&ÍÀÀ"ÉÀÀÄ&ga$¸2ÃUJ@€GáÜO7A¾ÿ–$$$/üüüþýýýÿþþÿúúøþûñðî÷ßâèÿÿÄüþ3>%™XG%õ9-±ÁçKˆÅÈÈ(!//ä 6VVnnniiff&†½Û–0Ä$”œÿûëçYÉÖ¸D'Ö'»8yDDÄäÅØ4ˆåäɓ߫ªª8EDD444””âããxyyþ3 ¿gäÐòµÉSQáa8yò)ƒ„¤ƒ ƒ˜0 ?@±XYY1äççÃËŸŸè .0›õÿ—ÿþþ×’÷å×Öe}pëû÷¯˜˜Y¸¹8DùØØˆåرc Ož Ï^?`øùë'+Ë?€b9zô(ãG€þ’d0Õ×fxñƒ‡á§N<Ó_†7_xA¬ ÊÀðíÇ/†×ß0üúÿ 1ÿþÿùý €Xôõõ€¡Î ÈÏË þþƒš<ÃY`Lþó!VFV`*ùÿƒáÎÝ» Òò¼ lll Ÿ?~ø@,æææ éééð@|üø Ãö«_þa`øôèL Ì\L Ÿÿ°0¼ù÷ˆì|~ýùÏðêõ›¯IJdɆ‹/‚QUU…A\TˆáÅ~†ÇÀP{ùê#àcô9X…D”Õå„…>~üÂðæÅ³Ä"..Î`hhŒw^))gMM†pÏo Göo`HËi\ôPÀˆ‘7:NÐÙšÁRK–‘á/ÃÓ§/Þ¿} €XØÑ!,,ÌÀÁÁ¤E89x¤¥eØÙ9Þ=ËÀÈÌø€áÙ†Ÿ®ß½x*µT_Û‰‡™•…áÂÉË /_Ü;@,ïÞ½c¾|ù2'''ƒ””$ƒ¼¼<0@!yŒ•…py!¡óµéùÍÉG·­{ØÏõÝFwë–µGýü° €uttÎÙÚÚêþþýû/302‚ÿg`üÿ‡éу›¿÷<›Œ%H™[_Ðûë—OÛ™ï:@€K)D¨Š è„IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/configure.png0000644000000000000000000000172411550446572023214 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<fIDATxÚbôððd``øËÀÆÆU¦¤¤Q($$(ðáǯ7o^Yóñã»æ'ŒŒŒ ¸@±üÿÿŸáׯ¿ œœljîî¾jjZ ïÞ½çxóæYúÊ• lîܹæÉÊÊú—Ĭ­­SÂÍÍ“ôúõ³‰wïÞ—Uçççg”gPQÑ»páŒÌ¯_ßWƒ\r: fOOÿM‘‘IÖ·n]—ºuëZîƒwTÔÕ5ÔEEE€†ˆ2<~üTüÚµK›€Êßþýû†ÿýûÇðçÏ?€A¾ÿ  ""']]hO—ÙÙÓ½ååâ úúúûûûúúùùùøøøøõõööööˆåÝ»×ßß¾}Ë!--ËšZèõìÙ#/kk[–ÿ ¬¬Ì ¿ÿazÿþ½00¨€6þðè‚ÿ ?~ªab fNNve}cY “Å €¶sc…™áÓ§o êêjloß¾3¿zõÊi Ÿƒè Á¿€°03û…‡ºªªj‰IKKÍ´™hÃbYY1 kGžú]¿~åпŸ‚ ¹„‰‰‰ €˜¥¥¥>=þtÛ±ceîÝ»/tåÊÕ¿GŽeRUUgVR’GЕ ––Ö\À ¼råò^ KžÃl@1èëë2hii1ÈËË1] ***ìÈÇÇøôÅ‹wÿ‘Á»wÿ'$¤½äää´dbbdàà`c f q`”üÌff–w,,¬€j/]ºtþÈíÛ÷ýlmíyxy¹¾ÿ ô3ƒ‹‹÷³g/½Ï;{‚™™ñ1@Á …0€üý÷ï_ë)ÐÏïÝ{deeÇÅÀÀ —Ï ¼ îîn<<ñ¿víò!€ÂjÀŸ?Àb@/>;þì;wîÙÛ»rñññ0mgøüù'C\\4×Í›7ƒˆ‰`ddz‹ùÔ¦MküËÊò_|úôKÜ@&†{÷0<þâ@á5@G×­[”——ñŠ•• _""‚:´? €XˆÇ7o^ç•ðkç‡ï/]¾|1˜Áž”>y’m%ÃGIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/kalarm_disabled.png0000644000000000000000000000233211550446572024325 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<lIDATxÚb,f``àb`TPÓb+Ö¶øïÏÇû‡÷î™o×e¨ûÁÀpÜIœ±ÕÜå¿'‹ó¿û—˜nž>úoêoWå~3õ £ºy(ïJ‡äúܢߞücbø¡À0í톧֒ÿµTô*õþ1¨„1X*®c±˜7ëŸÂ÷ÿ[Ù€ÂA¾ÿfG›T€ @ïþëÿíÿ$&E&1; ñóòþÿÿ%ò9ÏÕþÎ÷ÿÜA¾ÿ5_Hùó÷ßÃÿÿ 6 (Kdý /üþëÿ ²à—ïÄçøùþ&# !FÎæ·ˆåêª'Žÿú¥bœÈ Ã!ïÅðäc#ƒ”+;#Ã/ G}fø+¯ÎÀË­ÌÀÍšËpvÁ»o¯þ»ÿù+Ã=V A¾ÿØøÏ 6û5Le"¡éùÖĽþûçåý ö /æþÊÿ®±‹Þ ˜ýA¾ÿíû1>1=ú ,!*¯Ç¹»ÕÅÁîìèþ ó L'*H 8üA¾ÿ ûþûü3GJÜåç¶¡‘ýţܔåßâ$Üè#,Fc94½zˆ…õ7ßÿ?þ2°þ`þû÷?Ã? ~õäËÛ œ/ªç2<ݺ—áHo%Ãw'†[¥¬ãËø5U™WW×A¾ÿÿèìÙÞÌÿùðúûìåãD\e&@Þ£š9C7ò‰4:UÚ¥¤Ðáá±A¾ÿ7ýñÿî *Jç9 ó÷: 1Ö½»Í¿"0>*,, Ó¥¤ù ´´¦áýýoA¾ÿCôêÜóÿ@"@Ë ûþ-õ÷î囋ãÝüôýöÇŸÍÍõÕùùsþþÙA¾ÿ;ùïöáøE ½È áêÎÇò›š*îÛ÷ÚåêËÓòó ÷ýý+ðïïȈٞ”xõÃ*aà=ÝöoÝ·G˜ßß>$òiÛ>FÍ×þ3ÜýÌÈp™—™Aˆƒ›A_˜QC^NæÝß¿fA¾ÿ ÿþ@éÙçê`ýá·Þ™ úO92‰'þØÓ¿õ¯öüâüýñkùù A¾ÿ9ùüøùóê² ÅúüúððÉæîôùõÿ8Ëæ¾âú_ ÿþ±ëíûÌòùû%ãîíÆÝÝm t¡ŸQ*R‡­IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/camera_test.png0000644000000000000000000000156311550446572023523 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?% ƒqp @ðÈ•~µ-“:,Ýׯ\Nf‡Ø6ÔZ:¦ÄxÕ±Õ˜ÒÿÇâ0ìÚü rˆ‰$ë@Žýý;A]YjW¤µ…•+ß?€"Ú WEÿ11Ìv·Ð›_ëé(sñÚóî¼J –ÿ ÿÁð ¨æ% ÿþü3ã㜟좥 ¡Ìбû<ñÓ2¹™6‹ïÕ_¿ÿÝüüøÃS½ÿþ³þøû'UNM°§ÂǘÓF\€¡|çy†]Ô3±³Ìb`üÇ@L|ÌÜŸ} ¸ÙVþþóO¬“Nÿküå`Xææ¨4uj˜§•¸$Cãžk »ö>ïgûÏÒÄÀ‰=€bzvçûL 1†ì@+kF.†uÿþ10þùýÏ•WœeWj°AHƒ«;ƒ8CïÁK Û¶¿\Åþ›¹œ)äA¾ÿ0æîôûdqIJ þÇ×âe"* avW:J"3øþóŸÉЮ­é¸úý]ü÷üúýùÿüA¾ÿ0!ðíî÷3W0<÷S6.*#îüé±ÔÓ±ªìÑòYìýýû ù A¾ÿ/"ÿýôûòï[/'0$ÿïýê¿ÝÖ®¥ñàÿíMàüüù ö ôˆYHC›õÇã/ŸÿYñ«~UâagaøôÿÃé'÷¶.ýþæ÷S–&ŽßWþ3ÿƒxšñ ÌôŒˆ‰ã;ç?¶ŸŒÏø¶ž>ýžá9ㆋ¯î3ì\úë˯Û\1ÌÌ §ñ%0€bbþËÎÂÿؽ>ÃýðÄíç GW1ÿú~Y ¨y'¡ @ÌjFÀ(ef`bdüÎôCìÍm‹×yë˜ÿLûÏö‡áóo†ÿ,À ö#†ÄHiv0P­!3•Žð#IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/player_end.png0000644000000000000000000000172211550446572023353 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<dIDATxÚb”tY|óûçç?<ùÔÁÀËz™‰áÏ?F Œÿ@€‰þýý'« ÷Ÿƒ… €˜Ü­eå6Mõ wñTÝËðû3ï¿b ÿÿ3  Aÿÿüe`ú Á Ÿrê©‹É[™É Ó×ß ¿LŒ%fõy u·¸Ö(©Šføñ7á×.d3þƒ Ðq ÌÀÂðÿÝ·¿^|ú÷ €˜Ìâ+eµØo¿fbPUep´Wfçåô}úô“å·ß_303Þxˆ.Sÿþ óJˆfüffe f³„J w_30Ü{ÃÀðé/+ƒ–ž4ƒž¡¼â_†ÿ!O½Uý÷ó÷=&Æ—À9ç¿0»ˆHÆo&6€b3N¨VQ`øä5†WŸ¾c`øÉÁÉ ¦¯È"¯"©ÿùËÏð¯>ò1üþ} hР ü,¢Ù˜ÙþË·_@›š¿‡÷ó`hi~Yó(i!‰‹7«¯<ðáÙËV Âó@?ý @±üªz÷èt íÌ hèßÏ@o1211ð«k2È+h?¸pkÙÃ#'/þûÿ (ÿ €X@1ö÷/$Ú±fP é/¿@Îbc`æä&FA`8€µ 8\€V³° z¬ ¨„• poî˜ÁðûïvÖ÷àPDÍ`—r5ss02 /73Ë××ïÖ.8÷÷Ôî‹ÿýúÝ´õ; JÔíf`ú åüe`äá`bããaú @ŒbžËŸüÿõçÁ뻯ëؘö2°åØ£ë˜Á1²²@䀿ÿäÄ¥ù²s°°Üð.`8¦·IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/tab_remove.png0000644000000000000000000000162311550446572023354 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<%IDATxÚbüÿÿ?% €X6p³ÛËÙk-¸wëùŽ O?ç~geaÓÓÔX ¡¬¬Öµüûïß/212‚ÿûû—MS‹‘‰‹‹‡ €X~²dU•((Þùœñº ˜‘…‡Ÿ7¤²2$ٳ槟?3˜™˜þÿùÃÀ+)ÅÀ6 áj€b–þñûþÕÛ·-œlÅÅeLô-ÌuYùùšºº.í¹w¯þ7#ãsŸGA]X¬d++333@1gþg~þîÁ‹{ŒwÎEi*¨0±ùÁ°nñ¢k=ŠýÌÄtLPE…AXJŠ•l#(Ì  æpF&QMy–eæwº/wœbøpæ"ƒŒ Ë_QÑïgß½;È&$ü‹¨ù÷¯_ Ý ÿþýö? @±ÿm´ÒýöáÃ$NÞ_|¬\Œy?±fÉÉeì~ñüÕ3†™À0‹Ú¤ÿ12þÒÿ™ŽÙ 4è<@±R5”U`xËðÞʈAÏ/‘•‹•‰áɶm /oÞbxÁ̬¡¦º,ÀÇÏžƒäFvvV ÓYvîÜ•xúôi[€b¹¯eÉò#.šAWO‹ÁR@_ßœά\ÃÀ>kîs9À NNN ßÁ^¼x¡pñâ5n€báúÿ_TL]…G@ìÏ¿ÿþ㘛AxܦŸ>ÿ`:wîØÏLÀè…óg¯xy…lˆEAAQK— Gmø4H\D„!55>–¨ëÕ«7à€ƒaPSSaøþý÷€b‘’’fâäâ†î?xâøýû7ƒœ¼,ƒ²ŠÓ`ñÿSá¿ô? !ÿ€.acxÿþ+@±000ad+@~ûö LC4ÿƒãÿàèüÉ’ `T²Á5ÁÆÆ…!jþÓ+@±…¦ Õ?þ+EHüÿF¸ë`™žÀÔÈÎ @,/_~|ºmÛažß¿ÿþ‡HÑ_(8˜ÓA†ƒR#0‹¾}ûí+@€.ƒ<^éºó–IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/undo.png0000644000000000000000000000130311550446572022171 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<UIDATxÚbdÀ¬ŒåíXY7|üøñÙôë×½ð€bBpUS³SRºP»m›'§8@(ÈK^¾~[sóÿÿoßþÿÿæÍÿF§JJñ@ñãÒ@0'óçí´jÕÿÿ7nüÿíÚÿÿW®üÿñâÿGË–ýŸùd86½Ä´AßZVö@QU•//ß? ÿbЯ\a¨Z¸ðÀ=^Þ€cgÏ~„@L,¿;ÇÆ px/_20¼~ ¡_¼``xö ‚?fåæfè÷ósPzùr² ˆùÖ§O'ïŸ;÷™•Õ][NŽáæM†·oÞ½ƒöêÄÀ'O¸€´öŸ?ª789?ß{ÿþ8È€b·?}:þúùóí= 5óòâ`iøðá0P8Ÿ®.ëïß 1ˆ°²2|ùôÉꙸø¬¯_ f˜S|üøô;ûœ›'OZ꺸Èósq1Ì[·îf×éÓ‰;W¯þþ[BÂÈ $„áêU‰Ÿ?Ù·øð¨ç@ayù¦m••ÿýýÏÀÄÌôõk--/}3çÿ[ÛÿYRR{@â„Ù))¹ÙHH$¡§Ð ~~ïÿ·´üŸ¢¨ø(Ä @ ¤Pº6yòÿÚÚÿu54lˆ™Tî¼QêÿÿKuuuÏž­ &2Àñ«W'¼c`ýöM €È2à˜ØÓ.0ÿ®@Ìäðøù󗜜fÿÞ`Ú±ùPªlïMIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/ledorange.png0000644000000000000000000000201111550446572023161 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<›IDATxÚA¾ÿ„$ïûðôýýö>÷e+>ôððóðíîÈýü›¼÷ÿÿÿˆ… þÿû/óŸ¡KÁB=R=-ŽAÖ΋GDŠ(ÆðíÃ+Ž{úžÜ¶Æ÷Ú…›ë™8Kîõ3³“ÿoåØþü\e•ëáé4£›AÆ*˜KP–…›ˆ¹øÅ¤Õuômux˜ßiÞ½~ßõ×o¦ÌÌ ïˆÙQ‹ãÿç¯ìã5½,3˜ÙÄ~ý9 ˆVüûÅÀðç#Ã÷W ,ÿ1(i1°¹/zåÚ+%&fÖ-Äòë/£ŠcŒ‰Pñ—w Ì8~C `ú ô#Ð@Cß30üxÉÀð÷=ƒØg†›b?}.äö fFÆ =]6¶gwîe`PæzhØ ffˆ.úóh?¹ÈÀrï ƒ… 7ïŒYÄ"ÀÉh£ Ï TTtbP1P£ŒP±Ðì à².úù†áÙy†3»€®ùÁ (ÂÎ üŒÑ €XøØø8¹þ@¢â÷'†³@Ca`Sb`à‚¸àÐù¯ï30¼zôP-PŠé;@±°þþÃÀÈÌVÇÀ Â>>jbX$…€aÉÀ 1è &“‘ €Xþ¼ýýåç?6N6nˆk@®æ€ÒÌP±P€aÉðbÈF†Ï¿X~ÓÇ÷¿Nÿû÷H3ˆýˆaâ Œ@1Æ .|œ6mš@±€”èèh)EGG3<¼{‡áߟ¿@iF°F @# a`bUPcX¶l±H €Àpp°ý;sæ*Sö¤# üò2 œì@ÍÌŒ ÿügøñáÇ'†/ï>¼fbø÷æ Ÿ89XÿôØ»~þúÉÀ¬jÁ i®Ï ÈÆÀÀÌÄÀðý7Ãû/ ¯^00ü~ðáýo&†Î1|ÿþè(°~€ò+ +ƒ¼è_u!Nf& “ÿÕ|ä``àÈ ƒ?@<ÿÍÀ €‚À„B\ ‚ *œÿxþýdxø—ƒáÍ/F†~1|dfàdeààç``dú # ˆ@´’‹Aõ/ƒ™Ð/vV†7Ÿ1œ»ñœáÑé# ?%l¸X™ÎgGX'@11@)ãÓˇ k'”0Ä šéÌ™³_ãâb ¥ lhâœnIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/kaboodleloop.png0000644000000000000000000000205411550446572023702 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<¾IDATxÚbüÿÿ?£É, Íðë/3ÃÏ ÿþ3°ò².R—t»uåEϯï¿2°³¾f`ªûÔÃÉÊðïB&@11  Ã_ æ¿Y~ÿeøÿëŸJm³‹xN•K·´ºÄ~†ßòþüãÄgýýÇÄðïO8;G¯8(3## 3“êƒl ²– òÚgÞ™xaÿå´W^õ]¾¨ë;@1‚½`4ƒáÏß©fêÉÚ¶: œB‚ Ì,L`óö;#';;PË¯ß ¯/]e8¾íìù/G“₟ò•,õ’5ì~}ðôÉg†ß?10332ˆ 0|ûËÈðhPîÃ˯ ož~eøûŸáH+@ ã/ I6f–b`Ø8ëìÿs»Ï_ù÷ÿÿcVËÜöpA^1.†Çw>0œÙwõϵc×þüð­™‘›ý H/@ ààdÿöäÃÛ›¿Îï>÷þ×—VÀøÂÈÌpH”ý‹íÙ×v¬»¼çãÓ÷38XÖå!A@°0(døú›èg&^öÛÀXô'k‡„8·ó‹Ûo&5­eàfûÁðã$¦¸ÙþŸÏ` hôõ£ˆÈý”üþ“•á×?{! ÃÏ¿bàâXÊÀ T&F? ¼ÐzP<~â™F {8Îb*úôÍŽŸ+ÃÉ[+ØÚE•­¥r»àÏßÀ‰Œ••ir@¦µœˆ8æåç@g <ýú§ÏÌËZ©ê¬çeîªÇ«®+ÆðíÃOÆ ªÀÀ\ô¨ˆŽ­–´‰¯1ÃO 7~/>÷ ¤ €À°³1O‘°ÖMÑÕáPgx 4o/ÐFVpo?¿ÿ²°±2ˆÈ 3œºÍÀp}׆WßÌé °LLŒöªªÂb¢ €¾øñä]^N&q Kþ‚“ø†¯ïß3Ü9|áæK;€Þ­é H,èÏàaúý3F\^,ßÀQ_ÃÀZ ˜68þ|øÁ°²wë÷ß¿ÿÜåŸWo¾~üüö˪,,S±òëÿÙt€bá—f<¿÷rÕó;»“¯–L ‰2P³6“b¸~çí­ß¯¿ZÄÊÀÇ y`v¥( ° ˜ôgsÞo (½{Çðè鬬 ßÅĘxxÊÈðï/(Ð!16€êœ@áçëÖ30&§0ˆùÌðè’¿ŒÌ ò,L ¿{:>Õ±ù1üùÏ7 €Àaðšú>¼zÍð;=ƒAîÃ{† ×ÕÍÀÞ×ÏðñÛ1.NÁiS¾Ý{Àð—言ðò „Ã%(Àð?;‹á!ÐI?këDKг3~–U2¼xþœá½“+³”40&á. °þ@ýô˜ù*kÞ9¹1ðè3üû ñ/GJÃ=c}3&†?¿$ ð”jþ°0ÛZŸþþð $ÆÎÀecŒ:†0ÍP=Ä?VèM& AI ˜Þ™ÿAb”þAbÌècãgI°^€'ŽŸ:?›ßŒ˜›ÿ€t€¢ó?,f Yù?ÂfFf&¦“‡]cÈ1f0¹Hv;Ò׎IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/mail_send.png0000644000000000000000000000213211550446572023160 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ìIDATxÚbüÿÿ?% €Xü0|ýò›á?# 3+Ãßßÿ~ýúÇðhö·/¿%˜™Y|Õuä3~ÿzϲe}»ÿŸo03±   #.ú ÔùãÇo6¶pCéGUo†ë7ß2?º6åÉãÓ5ÌÌì`å7à?þùõè Fm– +{%ggeKs96Æ7 /ß-c00re ŽK™2ñÆ|F¦w™ˆdãïß¹þýcÒâÉÐ7’õwvR01–dàábþîÅG†›o®0ÊØ0ÄÇ:‹¯[«™öôñÎrFN€bðõ›ï±rmwßÉïgÏ¿ýÿåÛ¿ÿÿþþÿÿëçÿÿ?ü³|ÿõÿ×ßÿAàŸš¾ú6ƒ†“@1TVí{ríÆçÿï?üûÿíÛÿÿŸ>þÿÿå3PÓÿÿøðùÿ“§ÏÿÿãçO°!ÇŽ½ÿ¯,SÐÈ  ÉA¾ÿòòøÒ ÿõõþûüúøöú³Û¼ÍäÏ üý  ý3 mßÞA¾ÿ>í Y//øøõóñïýýü›Áší Þ=E&ýïùîîçíß,@ ðíû+A¾ÿ Kâððù%00-ùùüòóñ $$³Ð²ÊíÀÞòàÑæÝËåÖÐÎèÞåÅþãA¾ÿ&'Pýîîõö L12 ":#;ÿ1 ß4اìÛÆìúú#åöñùïûˆ ”Ú™þo?pðöÎÇ¿3°ÓÃ`ýóF–áÁ~‘/×°,úpû]„ Ä¯›rrb _p1üùÆz A¾ÿÿåæëš¼»ÝLef, úùÆÉì­®Ç꿿ʪìèð ùðÍòÍ1$õñùåýüÓˆ¤œÿýÙwøÈÝœ'N\º½uëÎuï?¼›ÇÂÂ{‹ŸGˆá3Çk†Ì_l¿ 2Iþýùáï+©Ç ÿ? `rgÀÎÎöÿýûåÝ=K÷½zõdó¿¿_r°33°²p2¼â»Âð˜v~q¾xuûó^.vŽ?XNµ= ¤<ÄÀÄÄt›““í6Ð0†_?™b™ôöàÜÂÀüoÕÿ{|f__ fþýÉ´“ûï€%^¹ëVâIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/ledpurple.png0000644000000000000000000000214111550446572023221 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<óIDATxÚA¾ÿII|   óñó>ðñóe> îïòóëëïÈûýû›¼÷ ÿÿÿˆ… þÿÿ'óûß¿.MEÅHKs5]S9!aFFF†wï¾pœ=~Ûwã†Ã¾Ç/_^Çøï_)PüÈ€ðïÿ?9&Ö•¾ºæþÆ þÎ`®¨ÃðXðE@±°òÙ(}b`ýÃÉðdãWÆo¬ ÜFL Ì¢L ŒìL@øõáï›ÿ _/ücx¼ë+ÃVÏò ¢†ÄÂÇÄÃ'ð‘—“›å;ç ¬ ÿN³1°©üc`ùñÂ[†_w˜¾<ù ´ˆ ¨èÅ/, ü¹Ø@Æ8ƒ03Qª$ðÿ_2W,mbõÉÃYý1¼ô ã2° d ¹à‹{!_J€ñ[õQÖgjÒ¶bùÇûÿ £+'ÏK>fvVa` Š5pB|ðhØÿ L/^zÃÉÀú›…á'÷O†ÏÌ_Óû?ŸO¼zÇÀ tP³«4Ë30°)A±‹,ƒÄ…jÙ‹¼`xùçÍe€búøþã¬#‚çþ‹ýf`çÚ,ÌvH›"ÔˆPŽƒH‹ýeØËwŒáÇÏ_3ˆ‰í7Ëþ_άݬw€G¨èl& óYÄ€¶)@lg–Šñ司vha8òçÌ>¶?¬›ˆYNÖâ÷—_Μþ{É•S’]Ô€_žO˜™hÈ;Ì@M¬À˜ãâÿŸÖ°b˜øeùýÿßþÇp0³=A¾ÿ 'ÿïõùø¸ÆöÑ"×ã'  ý÷þððôÈé֑竢涺úõü]  ØÿÿˆÑÔ8SŒ _ÿ}gøóç÷?FFO6¶,iQ#n~PB|ûíãϧïið×éÀü±‘…õ3'#0; 0i-Hõ u\ØIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/mail_generic.png0000644000000000000000000000217411550446572023651 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbtwŸÅÿþýcRQÛÆÆö^wÍšõͯ^ݘÃÎÎ÷çß?^^^!†ÿ?2|ÿÊÌðó×- ÚŸ@Œ Ä,%åÆðû÷_†oß~1pq±æfg[g¥¥9ñ›xùò/ìÁƒï?~™“‹‘ñßßL ÿ¾eøÿÿ/Ø€bVPð†ÚÎ ¨»44TŸÄWPfôõq100 úðñWȳçïžüüñòß¿€ü@ÌÊÊ> þügÐ×—\›“c«ÃÆÂÆðî ç ?02(+‰0zz:Š©ª¨…¿ÿÅûù³Ï¾ÿxz›‘‘h@1ËÊz2ð𰥦$[çÊʈ3¾zÔôÞï_ ß¿30¼öæõnNNF)}é÷Ÿ9CïÜÞÿæÿÿWg€*A¾ÿÿ!KK+‡-+"èçööþóóøêêðåçíçèíïîñææñ=@/W[JÉÉ¢dñïä˜ÿÿûˆECSr¦’‚¬ðžÝ?{ ´í=ÃÛ÷¾~ý —ÿ lì¬À@fdÐÒ×`HJÒeøô•‰ABZ_õãûýÀ0¸@,Ò’¶Ïßüa8|è*ÃÛ7XY™øø¸DD…89Ù~übdààcHJÔdfŠ10èêóܼÂíÄÀðõ@1«ª8g¤¥Zó9»(3¨¨K0ð003³3°±q1ügæfàáçaHŒUbPSä‡ 'ÃógŒŒ;vìFÃÛÄÌÄ(nemc§¥¢ÄÅ $ÏË`h Æ ­)t;ï?Ì ž®â Zü ß¾ƒ ° èÿõ‹ƒaß¾\Ÿ>]_@@dDÕ5ô¼””$¿|f`øû‘—ANއAO›ŸAD˜“áËWF†_@Ûü:hÈ?F†ãGîs>~|à(@1sr~“ˆÕ3Ñâøýd:PáwbF`à1£’ß š¿]À/ L'ï™™íßþ €˜¾~ûtãÊåË7^½ùÌðñ7ÐW@§¾ûÆÀðH¿Ò_€þ²10ƒƒá? ÃÇ÷¿N|ÂpóÚ]& ÿˆè8†‡÷Ÿïxÿ­¹‚/Ã`ãj`b‚¸æý³¯ ÷ï9NVF]õO: ›NÞîfýö4P˜ƒõÇ_f–o>ÜêÌ F þÅÈÿg d`xv‰aÇ;†&]=†_ªßþÿÍÀÌÈÈÀÄÍÊpïÀk†®ëÏâ400J2Ü\òŠAcÍF€‚¸€éïwöïÌ;ÿ„2lábxùòß»ß~²10üeº‚™í''Ãf_î·ÿü”.30s2ýi °L ¿þÝÿÊÌüX)Ÿ¡ÚY¡äÃM¦ÿ@͘þ3 abøÏøYP–aí¦‹ 7^¥1pÿûù¤ €ÀüabdøÏÆÆ Àö“A†‡…•W›øýA˜h(«"Ãÿ¯Áb6èJF.I  ;(R€nƒ¿@ ü?@üû/Ä1]& €‚t#‹ã/V° H¤dÀ?;þû„áûO Èÿ?`ß@ ø2¨”éß?° ˆú÷¢ù'Pó÷_ ÀP‚Ì”†Bœ @P/9LL¡ÿgÿ1äw°€ ^dºb@A 0pp1üûƶåLj¿@šÿ#0Èeÿ#ÐÅ¡á@ð@d`bfø ÔRøxÿ ®aŒ`Jóî…ÿÿ2üøÉÌðèÔ@9 å ¿¶ÿ„†É÷ŸL ÿ€¡ûˆ6à÷)V†ç¯0lÜt"#0”V‚0(&þüùÄ o13p}¸Á +ÎÆp‰c1€•…U@SŠ!œï&ów7€Y šþAÃJÿ(áÌÄ   Å𓙬 €ÀÄ»ËÏî1Ï_,Äðãß?~`HÀüüH€£ŒÿƒñƒßL ÷™˜}ò ¤ Àå+XJi‚µIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/mail_new.png0000644000000000000000000000140111550446572023016 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<“IDATxÚbüÿÿ?% €X@£F,ƒ‰ÕÒÔ§(›™ÿ¡˜‰‘áÓ÷ßz&L¯~¹j@ `ø÷ŸÁÚXC/ÍM([¿30°¬^ÂádvÔf®o¿1¼zõl;È[(õá÷ßÿ ‚Bœ Ü<, üïþ6 ))ꢹ…²Â­[oþÿºDÿýËfÿøù—áÆ7 i™F <¼ì ¿ÿ€ ûˆ €ÀØY©¨˜˜HmàÄêäoß¾3¼xþžáЕ¬\ì ï€~xÿ"@`ØØÙ€ÁÀÈpùò i °³A¡ö—áÙ³— êjb ìì ß6ÿÙþ  @L äD^^!!.† çï3|úÌÀðîÝ_†K2HI 2°³³0üüõè+þ‡p@]ðó'Ãç/ |ü| ’R޽ÊÀÌÌÈ`a)ÏÀÆÆÉôÃïßÍþ¡@`¾gbøð ¨èÈA%&v6VV6.†·ï8AóóX#È€?Hé €À¼xþƒáúÕ¯ Ÿ¾üG!3330þ0ܾýìWf¦ÿ ~f°¦"˜ `fØ€æþÒp#çàþw=©oÀPúŒ¾ß@kþÝ Š2ÿuL¹øy~ýAõ@ xþŸk›¢teH€Ô7¨3ÿ!ùù?8Þ¾~ƒ$¬ÿàHbÅ@AR" Ó÷_L¬/þAÁüúê_d>(z?€¢äL  FŸ5c8Y¾ÄËjèG3ügdþÍ¢Èy –ÁÿúõóÏ“£Ëþ}÷`9@1Rš …¥(… Û“IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/fill.png0000644000000000000000000000144111550446572022155 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<³IDATxÚbüÿÿ?% €˜(Ä&Á”Ÿ¯/ÈE üïß?†?~H©©©mJý¾{÷®# ËO&&&;;;˜<@auÈ ¤‘©©é®ÚÚZ“œœKaaáÿþÅP @(üºdòŸ?Âö·µµiKII1hii1TTT$ððð´ÿúõ‹nŒ@õÄÕËÄììß¿ýÃÍ]ÚÏðèÑ#†M›61¨ªª2ðóó3øøøTÅ€ÝùöíÛS e‡b@bâ‰Ïb·o¿pu5puueøôéÃçÏŸÁøÕ«W wîܹŒAHH(âÅ‹ /Þx÷î@A øóGý033×{{ic]]°ß¼yô‰!&&¬h#ÃóçÏ@šoÞ¼ùþÞ½{‰œœœ'ˆ¤ø)/ïT^QѬ\\['&š„ùù‰ƒ ŒÐÑÌÌÌ`±/_¾0¬^½úñÕ«W݈÷¾|™Äzÿþ¯˜«W¹­Z•¸q×®ß …?þGÿþ¬ä†Y…Ý6à ÃÍ+ KyoÞ<}|ïÞ”#G‚miDÆ0éÄ?@à09ò:CÎþñ£ç÷ï‹v<¨ÄÆÊZ¯¨¨Èðû÷ooœ>}šáèÑ£UÀ@m Xr|ÅÀpãÃ`RyJ™ÿöíÛ'mooŸÂÇÇûK—.}b Р5 ÃlÀ[ þÄÀÀ TÒÎÁÀðä"& !?~þÌ<~ü¸¸/HPã•—/_Ʋ²²^€@`2€8˜ÞÔ æ?@¿ƒ“)Ó` ÅCû0V>ÓD(PóKä @Œ”fg€¡*UP7IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/kmixdocked.png0000644000000000000000000000215411550446572023353 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<þIDATxÚA¾ÿG>#ïòìéó þÿÿÿÿ¦ Oîìï^Ýóó§Ììâ ÿ%9 &ˆ‰øóç77W¼¼\°©© GÕ½÷/Yx9Dþ312»•ˆÔÜ€ÿ`ÌÌÀÈÈÖÌËËëëîî\& ÀÅ (ÄÇ ª,/ÅÅÄ(Ì)­ÃÍ&,ý÷ÿŸF.€b‚hfdàdþÅÀõçÃÛ_ØÙXåCB§«ª*²31ýdâgááeaUeb`I“âU¿ÍÌĬÅÈÈl@p01íÿÿ“áÓ§¯ìúúº3rrR¤Ÿ•u•%bb² ½dxÿþ;ÀÄÀÉÅÉÀÆÌÌÍþëû96&NNF`8| –?ÿu8[Èyê&JK™«‹2ò©3œ>s“AAŸÁÂÂhÐm†gÏž1ˆ‰Š0ýÍÄÂÌñH²21²°ÿûûï=@±”U{dyúˆó20,g¸Ošaã¦;@ÿ²3üýËËðóç_ í\ ?~`ºôÏP†ØFp|1þ &†ÿ3¼;ÀÀpëÛkü _¾}gøòù ÷o?Þ¾ýÈðàÁ°óš~üøþû? 0¡ýýÿáﯿ 9A¾ÿÓÌÞðç Ý3íóøóîïòóóöëëåññèðîîòõõò ûþøøð÷èýÿˆéøé»þ<|ÉðïÊ;®;wQñáÐö÷ï¿ú™AUU†““›áù³ O_Þ¾ûþÇcÏ¿||ÿã3ÐïA¾ÿ¼Àä™Uàñ%ü÷êüâöñï &.< ÿÿøûûûäãçóòúûÚúñ`ñûýµþÿýIÿÿý©A¾ÿô÷ýº°×î.F רÎ$ØÞÚù÷ïLDDBûûëôõöÕ×ÖåõýõúûöÒßöÜñ &÷ûóyˆ˜„À‰Y•Ÿ‹™•áé÷ßïÞ}x»þúõ‹?øøm””4˜¿|ú°xÉ‚m8¹çýcc8úçßO{v±@ú@±`Ï‹Œ?þþýÛºbż³oÞ¼ZÀÈø÷û˜D$>d`ûϺ ¨æ 0W2“SùiúIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/rotate_cw.png0000644000000000000000000000150211550446572023214 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÔIDATxÚbüÿÿ?% €X@c ç ë/37Ãßÿþ3030‚$¬ï ÿ˜„™J,íÔZîÞ~±óÅ) ¬ ¯ÿ/ýÏ@,(Æý¢ÿœ¹„ÙÍùø9Ô™îûû÷Û¿?ÒÊ‚A‰.ì_¼õ›5k÷ÎWÞu< FÀ.`ù)À-ÂÞi㮣«'ÇÅÃÅÁvüû÷••…‰…‹áÃ÷Ï ³§î=ù¨áµ@A\ðç· ß¼ð4ó@yi)†_?þ101ÿ‡ÀÌ Tò÷ç?ÞþûÅ ¡ÀÍ ¤)e’ °Ì\¬‰ÎºBÂ" ¯Þ}eøñç+ë'Ÿþ32‚ ùûó/ƒ”Œ+ Ãñ£7Nï¸7•!œ €ÀHªˆÊ 1¼}ÿƒáÍÛ× VÝ<ðá×Ïy¯ü4šÂΠÁr€•½2´ÈHçáù ‡Vߘþëë\^€À'Â%÷ý'È™ßNm}|ÿíœ×þŒÜÌŸ>ýû”æa¼ù{Ù'Õÿ·V÷]©ûróë–g>Ïa`aÇ?@ øýëÿ¿O?~2üþ÷“áÛc {¿38þÿþ— (åÄlÿßþýÁðþã§_ç201°0ü‰ÿ?”û@`@öhÀŸ¿þýadƒü—š@©âßnP„!HþX lÀÏßÀþñ‹áϯŸ y¹^3H‰­exö $ŒKÆõ¸R"@Á¼ÀðùÛ/†¿€üüÏÄ  ´ÿ7ÃË÷\@iN|I € ^øó—ñËOóüúò7Ðâÿ¬D倂ð‰‰í#ÃS†ÿ?ÿ3üþ"ÊÄð(ÌÈN"PŒ$ ® 6þzË–Èð›éÛÿ×<- ŸÞ20¼}’úò!>ˆ‘Òì `Yvôú îIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/mail_find.png0000644000000000000000000000216511550446572023155 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚb ZÀðõë_†ÿÿþþýÅ LL¬ ÿþ11|ûú[…“‹Ý[WG)ëÑ£;ŸwìhñûûïË3FFV 4ðÿ?Ä_¿~krpr‡ëéKE¹¹«¨ªªÉ2œ:¯ÈpöüʰÏN``à« d¿ÿeøóû¿ 7/o¼žž’‡•¼Š¹™;+Ãùk,$]Bs—/>¼êÿÿïÏ€îd ÓþüÃùÿ?£??_ª¶ŽB Š€¢<#ã†Ïß0œ¿ùƒ_–AFT‚!(ØKi×öe oßœmc`àd F7±uMS36u5†w¯¯1ܺ÷ŠáÛ?~ «˜^¿|ÃÀúð2ƒ —ƒƒ­ƒ‹kTÄÊåçç10üyA¾ÿ77WÁ9<843#! ñîÛÖàð1" !åñÖ̾/+&¶µÄæúúßÈA¾ÿ00XH+1##ñöû×Õäííèú6 ýþÿßâîúêÔGG;ÛÛÔÔĸˆYBÂý•²’Lˆ­“ Ã_f†O|² _~ÿgøö‡‘á3¿þ df6V†.2893üø##¶w÷áûÄôç÷¯ÃÇ\ßöõÍ/.6Vv& F íŒ ¿€i‚•‘A’‡AY’áëw†®I—–¯Üq†…ùçy€baaeúöðá«ùçN?òpqáºÿôƒ(Ç/aN6†o?Añ ´ÙB@C¯?{ðmÇž›ß¯ŸløÆÅ»÷Ýßϯˆéß?`ŠcØvðÀÝ¿ÿ°1r31|xp…A˜AFŠE€æüüÅpùìI™3ûÍz»dEÌÛí¯-þ~eA¾ÿ##MÿÿîîôúSEF'àÙßèæé þüèãã»±¬ c3ÖÐö ïìÏ5úíA¾ÿ%%NþÿýÝïîù: #··Ô庴ª½ðéÖóÖÐÎú½»¶ÐÅ«ª‘CüíCw+)úGåÁìíîöû̈…ƒ’¦98½|ùª²°¨éÄÓg××hkñ_yúøÛ‡ß8>ýùó…íÏß?Œ+×?züuË<Ùjcƒ>Ó Ç*Îý x^`dd¹äìŸ??ÏS+0ÊXXÙ~01ÿúÁ ”ûËÎÂðõãúCë~3ëþ9?[¯ÙX@¯T« €0r#333Ð &dƒárŒÀìýÿïšÛ~rý`¹Øûþ÷y€¿S{øYÛÃIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/mail_reply.png0000644000000000000000000000210511550446572023362 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<×IDATxÚbüÿÿ?% €ýý0|þü›“ƒƒáÏ¿¿ @Äð„ÿñ?†?þÿûÏè¡­%›ñ÷Ï_…­[[‚~ü|ušå7Ã÷; Ä‚nâ üÔøóç_fÖ0Ué{ESS†GÏ®ÝÚVréìΈÿ2ÿÿøÁ@`¡šÿüþËðçÏ%&&Öxm]™ +e5KKy†sÿ0(j°2Gú\9{Ìñ·äƒ}ÿùÿ0 (~ÿþËÎÀðK“›3QQY*ÂÜLQÂÄTšAB‚™‡áæõ ß10Èr³2¸8›pm2òJ=Ë8}Ão€bafb°—“JTV• 1³TæÖÖfbd`cc``ºïÇ? ŸüfWàf`¢«ÆÊêãrvç¼y¬,7ˆEP€k“‹†‚޶,ƒˆ('/÷_6&6V&°·nÝøÁ (À ,ÀÄÀËÁÀðêㆷ¼ûEj²“?Ù÷ €XYq (Üyþ™áê­w \l@…Ül Bœ ÿÿ1ó?ƒ¶.ƒÃû&®ŸÆ aÀÏ ì"À°aâ#€byùâ}÷§7?l­\T¿þÏÀôç'Ã`þè?`ÑÔäz‰‰aÿé +÷®aдdø¡õ˜¡mÝQ†gø>Ëï¿?9p}³‘‘´Ÿ°ÓNNp°²200330¬Ýµ›aëÉ­ ú^ 'Øö1ìê¿ÄÀºËáÏ–‰ÄÄÌÌòåþƒ—‹Îžzôƒ‡¢ @‰ dÈÁSÇVì_Á äÇÀ0÷ã†SO0¼_ν†áÃ?Í\oûˆé0Åýÿÿoý¡ƒ7÷¾{ûƒ‡¢‘—b‹ Ã»ç¼ Kldxøáƒ¸’8ƒ¢¾¼Ô[‘3b¯”¯3³ÐhFFÆÿï?|ýÆÏÏhj&Ê2àñ£_ +–_ü½táÑC§mxrý “(¿€»ñ[>56YŽÏ|ÁŸÞü~A¾ÿ%&OüýýÛóôþ9%³²Òõ„…£¸¨«§zãâæ„ûÿêÌöþ·õÝ ö4÷%âý ô úá8ˆÑ×o!$W123ÐOóW/¯Å<~ò`×ÿÿÌÛþ3|ûËÅ.Æðù÷}†·|ïXØÿ1ñèjeryÀþõ¸à€‚g&F&f†_¿¿ž|òôüÉÿ98Ø…ü¨9 \Ì{¿\ä}ÈþQ¹Ÿé÷w€>gkXðišÜIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/mix_midi.png0000644000000000000000000000136411550446572023032 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<†IDATxÚbüÿÿ?% €˜(Ä"&&¶GRRÒêÊ•+¿ ?~ÌÀÈÈÈ ##ÃpéÒ%mmm0ûêÕ« /_¾d044d¸pá3Pó·oß. މaŠÖ@$ä.z˜À@L /¬ ˆŒH¡¿×÷žÞû»÷FD8çPk¥µFDPJa­ÅoŒª’™˜sNÜý~Ð8&)€0 ©t£ÿ­‚ZñÈ&‘muw¨*N‡ªzÇ輌$2föwk ÀáÛ„ â7°`ÿ-1jòJ áȽî6¨*¬‰ë×3ã|Ðm$¤Ï2_±€€\ ¬¬ÌðEEEÁ’ t*ЛŸ_€AQQ‰kJJJ ||| ÿþýgÀñœÂ@ì±õÓz¸ÿŠZ<:@BÒ36 Œ@Jæîµpïp„¶ì5AF•‘Ôâ”àá ‰,¬¬ ‚`óòr]ÀÂÀÉÁÎÀÇÏ  ..N !<@¿³‚Ù @zp()‚PD»]n«ã‰Aá&þWI©IZÌêMgL_4 Î9RRŽ}û»³2[KlÆûÂÉÒžZ3«÷ˆ\LãP>DNv6y†ÿ¿3pJŠ20€Lþ÷‡AYè…?Ì/ ÂB|À@bøÿ烬œ 8 þþý‹ €Xÿÿ†8…á/#3ˆþñ63ˆøTÇö0^À˜« 6Т¿ Äòëû'æÏon0°ãùÏŸŸð@à þ™ Ìúõý#3@1 òs7ÔVÐZõ#ÄFF& «˜/\{p €)ÍDqn0òA³x;IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/ledlightblue.png0000644000000000000000000000200111550446572023664 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<“IDATxÚbdP]ÄÀÀÂÄÀÀÇÅÀ ÈÉÎðí‡ãϯ©â<Œvb|,|Œ@ðæÝ·Ï/^=ñ÷÷ßÙ Œ {X™¿3p°20üÿÏ@, 0ðï¿ Ãï]Æzb‘qÎ Î" â‚ ŒŒ ¯?|ç8xö…ï‚u7|Oœ|¸Žáï¿R Ä=Äv£³ ÷Ê„x‹Š(E>„¹ÈàÑ—ß ½ ®0ÌœsâÚÏ?ÿüØXî3ƒPÃÆ ^¡z^%ñê \ÌL ß~Uÿ: hû_ ýÈ÷“á÷f-=I†·ØE¯œ} ´x @±0þúkâ.óÏX…áý & åüì /10°þaz™áýõÃ' !ŸbtØŽ>öùuû¾@1³‰v‰»ëi½e†¥0à­ÿA4~ÿÑüèŠo@®½e`ØôŠ‘…áçÍ{¢ÄÂ-Æc#®!ÁTÃpè%(8x¸Ù€.`‚øý7Рo@ƒb`8ð‚h²Ã>C€báçåããeg`: ¨ù6PÑW m"@—°3B ø ÔðîÃÓï@1fi ¿±p0°òq³ ƒ #ÐQ ÚÌ ²ù/Ðf¨ åj”Ê ¤Y|ºŠ™‘ €X~ÿgøÂÇ𛓃…A@Ó9€Š™ ¬¨˜ˆA–0ƒbH³äï×o¿ˆéÝço'¾¾xÇ Î Lˆ@Ûæ001 H³@ÅØ@.&@  ëž¿bxÿâÓe€búóåû¬ë'n3ð2þaàb‡ØÊ ÑÈÅ`C˜! Lì Ìÿ®¾ÆðãûïÄ”ÙõÌݵç^eà†>;D!Ô íÀ´cÊñó10\9vƒáÒ‰»û€&o fÙ€ß ßž¹uñ‘+7‹¨º–(7D3Ð¹Ì çÙœÜ ÿÿc8¼ûÂ9GïÿËŒ’'ÄÌ ìt'óûßß~ï8wæ¡ÒƒûoԹ؀)˜‘XY™Á9îç· W/|€bbþÃÌÀøƒËEÕcûÒé+[¤Œ¥6ŸÚŰïìa cs}=}†C‡1ìÝ»—áíÛ· >|`ü7À. Fæd65î?ü“£úk¾âÙùp;C_ÃÉ-,Œ T$å¾ÿÁÀÍÍ ÖðúõkPü3 1¬[·î'@±øx¯‹´ŽÒV–Pbh¹Ñİëî_#Gw+†ï3¼½ù!Ê=áÍû·àÀyä|^^^pZ &Ãí‡Rw".„2\~z™AàCõ¾j†ø-‘ Ü‚L Ï^½føÔŠPŒÀÒ +@±üûÿ—ý7ço.†/ß¾0üüü“ûƒ³ƒ0Ãñ{ç-^ô…™‰ ï0Œ¦M›6Ý FÇNç#ñVqæÆJÆ,yûsöŸÝÏ0'bƒ “òÿÃ7μëoéšøíæëÓ =hY”šÎC ƒcsΜ] >÷ëý6'äÿ®ë{ÿ›&ÚLg°1cWb`e`§@:”#Á¦3“ó—ÿßþ^xýã•­‚“¢®„áßãWÎÿXd]Óÿ?ß±|ecøÿöÃ&D¶Å(,@ ÀEKiDO8bIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/news_unsubscribe.png0000644000000000000000000000212111550446572024603 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ãIDATxÚb¬©™Îð÷ï_†_¿~300ücxýú-ƒ¯$#õýû+AA^Gaa qq!1!!~þ‹¯½:uê¢##ÃkF @, mÿþ3|ûö]‰ƒƒÍH^^ÒZQQÚWFFBYAAŠ——‹……‘Èæeàçç‘:{ö’æß¿ÿ^3112 !TT­¯¯â ª*§!//ÁÀÆÆÊðçÏ/ «~2|ýú‰áóçÏ@CØDD„”U€. ~òäÅ!€b:Ý\EE<#$ÄèŠo ·nÝbføþýÃÿÿ @[y€Dr_¾ýøÉ !!Π¦¦d{ÿþV&&¦ßĤ¡¡ÐíèhÊðâÅ+†?~3|úô&ÿ888ÁÎfgçd($,ÄðôÙ†kׯ1èëkjpr²¹3332++ë[ Æ÷ ¿ÿa––ôƒáË—/ >|`xòä ß?=|Äp÷î]†ÓgÎ0ÈÊIqªª*EÕ±ÓÝ»OVß¼uŸ™™‰áãÇ@C~ƒ˜˜˜ü_ØX9øùøž?{Îð[®®¶ÀH° fcsÿÂBÜqbâüÌ_¾~c`efgøý¥ÿAñÃŽ¡ÿÀÀ””bàä⮪¢Æ ¯§ÍúâÅk€bbúðöâÝ{/öüúËÀÀôÓ_ ±LÀÿÿŸ‘á0,@®øúõ+ÐK_éCŒÁß7ˆAZRšáÙ³× ?þü @ÌYçpp ó(*¨ýÆ÷Û·~¼}ËÀÈÇ´þƒ”hD……@QwäÈI†3æ/¿qãv@±HXZ¶Ykð{¿¼zŠá‰ˆ,ƒØÕ3 ŸZ_±€‚Ã`Zø ô;Û7ï¶nÛýl×®ÃeÀä·”“““ €X@‘þègþkMì¾oÛÊðÇÓ—áÝ›× œ2² ¬, Âü‚Àx̰}û¾µ=­ì-`ª‡ @1Û?yvü«¾™Óo‘—S20&Å1§?КIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/connect_established.png0000644000000000000000000000220311550446572025224 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbü¿˜…aþ!F†¤Ù¿@€‹‹›áÛ·¯`6'ß× ùÿ1° 2´[F”°ñŠýÿ÷÷/;ã}§¿ *`jâääTøÿÿßï_>?þÇðÿÀCæO~†gA¾ÿx8þü˯üFàÍóáå׿Üôí/úüÚ¯ØÿïÀ3"ÔŽ²ðÚ•ÊTˆ…•õÿ²Ço?Ý_ÿÖ|¦[P˜ì+æG ߘäÿ~gøùåÃ{ û¿Ž7÷½û â–_€š0|}x–áÁÒcß9ÿ3¨ãÿõ¼´„ß>aædþÌÈÄðá'ÃΧ^ ï$\ 44€QÃÅðãÎ#¥ÿSäÃ…¦12üýùáû³o GÃwA¾ÿøäûÒëçýLúõþñõþñùíË÷KøúýôòñóêíãìÓþ ) è´ØøìÕï‚A¾ÿöâøl´wæ\bw¶·ý€¤ñhÅ5 íìðóîïì®±ööÖîüöÇäقˉýùý¼Œ9ÿ?<ýå×c5f&[LjpÞ¯ŸÞ2°Cúå‹ ÌlŒ gNî¿hÁúô•˜žŽËß×ßÎVŸ>ùéýÏ`\A¾ÿúÿë  ·¬¬–r»ÈÄôôòúåúøÊÉÏyFñsȌы¿å¶Côùˆñb)ƒûq`fúû—á÷†^]^^Þ_L,,W>ò‰,Û¿K/:ƒï«­¬`hèΓÛ?ý ê}JþÄÂÄðŸãÿ†ÿ@Í ÀÆÆº€‘”/˜~²±3¤ÞÊ`ûç™§š“àѦ3§š#`šA €Ðs#0MøÎÂÆvêƒþ˧ ¿$¸ù_νöéÄËôE þ!©0ìÁ7Ú²¥wIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/irkick.png0000644000000000000000000000205711550446572022507 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÁIDATxÚbf¿ÿ2üû÷OˆÃ™™™XXXÞ²³³Éýúõ‹ï÷ïßÂ@5瘘˜Vñ ë F$L€¸X@@àŠˆˆÈm ¬¬¬ÿ@r@ÍÌþüyûúõk•?ê5÷-9’ f...†ÿÿÿÊ$%%׊‹‹ó ªŠ‰‰ýáååý ÄŒüüü¼@yU Ú/@Wÿþý{ PÏ=FFÆçÄÌÃÃ#d´ ­•––ÖÚþH_ºD‹O@@†—O‚‡››hÐq !¢@, tÑþŸ?¦° €˜É@Û>ÊÈÈmþÔü’›Û‹‘…e݆@Ã0±²~aãàåáâºô Т@¼ºD €˜6¥ 8 tª¼¼üENnnfnî’û÷_Û¸Y˜ýÂy–w¿ŸãÑÒ:ÆÆÌœÉÅÉy ¤è‚+_¾|± &nnîw@oˆñk{6.®öì}Éqòxª£ ÿUÛ¯_®2;– 4ð%;×<6vv; 7^]&ÂÆÆö €˜€ÄGPhóññ}ääââFÎUÆãDžؘëí…yx¬X™y€ñTÿîÄ af P=;0>c‰È~ @@š…È` b`bffüÁÄôëÞ÷_÷®œº#}R/îqüÿÿ‹“í?0½€Ô‚0(-(5ðŠg~F†ïÀ7qvú|‚¡tÛý@üÈ–qvþÌÅÃcÆÂÌüˆü@- d @LÀT&üáÇ7À{óæÍ1 »d¥¬¬Xž 00üb Âg‚¦¦ ÿå>¼ ˜ZÅ€±ð耹àܧOŸT@)íËçÏ ?þþÂÊÉÉÀËÀ §ÄÀ . Ä@Ãô€Èð(T«´ô-ÐBU Þóô2óR`Ö}ûöíë?ÿ|õü9ýիxXXDt„„XäYØN½¿nÃë§OþþûwàÝ»w¯€ê‚ôÐL€L ðòõëÓïîÝûÿðÄ .~~QM%%%`@q00ˆ>9s†áå›7ÿ_¾zu¤¨g"H/@±0@ÀI çü‹·o™:ôè/&.!!M``PÿÿŸš÷b¯ø÷MX˜¨¶”IAˆ‰~102þåF%P''#£ðþ¼ú÷ï ƒ°Àß¿œÂ¯_3ügfþ Ó ¦wdÐøzâÊIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/krec_record.png0000644000000000000000000000130311550446572023506 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠébKGDÿÿÿ ½§“ pHYsHHFÉk>.IDATxÚ•“_HSQÇ¿»s¸ÂAL‡A©Ìd$éÓÀ!¾¥³|9åƒ/ÑC`«‡”UˆÐ«Ä² zÉNÛ$"Ô,-›+¬­4n+*ZÿP$ûõ»Û\ÚÃZ?øpÏŸßùÜsÎý]$“IH)³œæÎåêê;§§i%)Ê×`ÎY,!¿0+ˆ°à¼Fs$>6FßffJbÙë%«^© ¸V_þ25EŸÝî’ÈðQ®·¶fŽ Q¡ öz››×?¸\ô?øívꢯ¤l¿m2ѲÓIïù¶KÅ×Ð@…P‡níè ¥ÞÞ’xÛÝM“Z- 1¤ ö«‚ûåå³Z)ÞÖV”76ù šä5ýBœRï@¹ ,=à‡ŠB!£‘¢55««ÛB´¶–ÂUUä/+#5wøÙ#D£º8Y|¶‰Ëæ8Y%ÄÛÝ<ÇL]À,F¼,8l^óÄ¿ˆ1W€ï\¶B)ë¹wûF€tŠÞáðÜà%JA°,ÚÝÜ}ÂçûÄÉ+y2Løu˜7vNÕnù™þ MpÀ\à£ÝjÜÀÈàpn£Büv4lõOtEXtSoftwareAdobe ImageReadyqÉe<IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/view_remove.png0000644000000000000000000000130411550446572023554 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<VIDATxÚbTU¯¼®gª¤òó÷ÿÿþ20üýÄÿ 4ˆÿÊÿó*•ûËÈÄøêÆÝÇÄbãa(ãPÊòðDÃ/þƒÀ?¡ø÷ˆÜß lÜ Œ+7ŠË»Oÿþíßó–áÓû ÌÌ ÿ€6üÚD $þýGˆ± ^ ý•™ƒáë׿ÿˆåãç¿ ñZ Z Œ Pg€˜ŒP£RŒŒÿ¶_þ;ù@±üfdbàä`eäã`Àþöè”@ší?;û?†@½Äò÷?ØÙX5Ý rúß¿j šÁ]ð’ÿ˜ˆåДÿÿ£i“`M C`šÿüð j3@±üc`šÝpÀ4ÿýûNÿºèï_F <@ÃÓ³!šA@lþóÂÿÃÄÿ˜€¡ÉÌ@,.øÿÙù 0dÈ_¸óAa¢ÿ0Å@j€–Ë`ÄÀ\€Ðôáï¿0WüE1àÈ @ˈé/ÐØ8€üô÷$Áá´ýÏHH]@@/ý`ø N ,Ì ¤Ä@[þý TLû€yh+þ ¤¹Yÿ1p2þªgb NN¦ý÷™n¿yLšË8€„d¦À€û Ä,@Íw>°2üfgg –Ÿ¿Ú¸ó?Çço€®fç´P 6F2H˜)˜¾½|@Œÿÿÿg ¥q>˜„IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/view_sidetree.png0000644000000000000000000000161711550446572024072 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<!IDATxÚbTU¯¼®gª¤òó÷ÿÿþ20üýÄÿ 4ˆÿçB ̆ñ™_ݸû €Xl< eŠBY>ƒhøÅ?100³BØï?A4ÿúáÿøÍÀÀÆÍÀÀ¸r£@±¼ûôïßþ=o>½ÿÁÀÌÌÀð¨ð?Ðf†§ÏÞƒm”—cøõãÿÿÿX€r¼ ÿ¾2s2|ýú÷?@±|üü—!^‹ÁAK˜‘˜˜˜æÎ¹Âðãû†X?NVN~Nn ÖŒ@9F†—¿0¤mþÇ@L¿™89Xù80+Ÿ7+ Ãö;€ÞûÅÀ÷û ÷Û®ìºä/Ã?V€bùûŸ ìllà/ÐML,l ¿ÿþeX¹vƒÞ› ¦r³¾}ãbø$¸‡‘ƒ‹ €˜þ]ðäi$ç223ügÄ‚ À@:ýŽéá&6½ÄòhºÝ F ~& +@ÊÂàdc ínÏðê¤3¯ û_!†??o2Ëo° 0\À Q`@C lÞç÷Ÿ~IH1pz82påþû –¿@üÿ‡¬ùÃ_`JÅ 挸áåçc`øð‰áÅÉ ßXþþQʳ0Ë Sa.€iþ÷äpí o°0|ùò…áÀÑ3 ê¯î0(ü›ÂðëÉ5Àpàb ¦¿À€B$Fh+++ƒž¾ÃçO^Ü>Ï úëƒÀï× ÿIó?0åÐ @?þù‰4Æÿ ,ÌÀÔvИ¿˜þÿfprvaprb`øvÕ’áõ^5n1AAa†ÿ¿Þ0 ''ÓþûL ·ß¼gøùè þ1+0)_xÈÏðë×?†çËÞ1|ùö›á?»<ñJ`Ê`¸{åÃof&€bt[y—[LBîó·?ÿÿÿgç4P˜ÓÐù (fdøþèB Í‹-P 3èÛËgÄøÿÿJ@€>5;iÀXÉ©IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/view_nofullscreen.png0000644000000000000000000000170511550446572024763 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<WIDATxÚbTU¯¼®gª¤òó÷ÿÿþ20üýÄÿ 4ˆÿÊÿó*•ûËÈÄøêÆÝÇÄbãa(ãPÊòðDѯß@üŠÿ@ðO(þý"þ¨†›qåF€ ÍA €0 Á5MÅ‹ÿÿŒà‹T(¤¶‰¹,ìiônîçqÑž—"uÅ“‰ñ,Djî­ ‚öΞkeÃlÆ/€X>~þ˯ÅÀà %ÂÀÈÄÂðïÁ&N61q V  ÀÄðûí+†?¿1p©(Å~1l¿ô‹!}ó?€búÍÈÄÀÉÁÊ ÈÇÎÀõò6×®4¶wxÙ€˜ƒŒÙ˜Þ>cx<1“ááE^nNvv e@½Äô÷?Ðݬ Ÿ¯ßb¸ÑÊðŸ÷Ã_.°½ÿîÿ òÍÈÁÏ $p‹áuK ÃÏóçÀt@±üšöó÷ \& Ò* ò `M ¿ƒ ù Œ6 NÇ> o2üýðšá/ÿo†À@ – Ì ~ýdà36bs°F¨õ`Í Cþþ='¯{(ÅÀÊðáÏé@y&€‚¸ÔŒàb„êÿó¤ïÿÀÞçpŒÅ˜ÿƒÅ™ˆåÐÿ™Ùþ\9Ïðõ&ÐÿÂr Ü& ̼¼`›ÿñ á¿?}eøtù÷÷~J½Èngb ¦? ;™˜ˆ‹áÓö^†/»Ò¾R}*©*©IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/kgpg_edit.png0000644000000000000000000000123011550446572023160 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<*IDATxÚbüÿÿ?% €@¤¤dˆ‰‰[ÀÂÂ"Kª^€á‰ëïÜyù¿²²êº"9 VÃc@1wn_*š4yÂqee•PdEö@€Ç6€……ùþ¡ƒ[­¶lY—ž“S²RUU5¦à7ÿÂc@1Áìì oÞ¼˜{îÜñô¼¼òÕjjjа€Ë1333022‚éׯŸÏ¾télfAQÕZM]]Ÿ? ZïTp@Œ €PSSeàæåeà`àáà`àà`g‘SN–þþ«Góù=Ö­/œùð±3¶@ ° nß¾Ãðþâ%¾ïßîe"f¶93O /žÃgjfÂâïk¢ÈÀ†Í÷Þ¿¿äOb`…Âùå ×ûoß/˜:…Á@ZœocGóJ~¾Ftˆ9%²± C¤¯C Ä% û”ÄÿšÜõÿÕª¥ÿädæ‚‚ ¦ €Г2#{²± ÈâT ®e`XqA[æÿ×i]ÿ¿ìÚü?P^v.,ü#†@Æíûõ ì&¨’·ß|rôåœ) ìo1ÌìlN2à/© ¬Qüˆ_ñw„«¾žûðê꣣/çNa}ÿ˜!VK)$@`g€Ò¶Ðåâp þÅ_øõئYHðyMxñµsß?ÄHiv0ÈÿÄ–5±AIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/tab_duplicate.png0000644000000000000000000000177011550446572024034 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ŠIDATxÚbdÈ`@€@ü‹‘á÷Ÿ••‰½›í7»á—§ï‹X/ügde`ø Ä ÿˆ™Áɾß@ü“A¨Ùœáƒ*ÃÇ b¬Â¾y‰Ñnÿ™üÜ{ñŠ™õÃf°€ba`D2àƒ07w«¡†‡‚ŒŒãŸ_ÿþs³ðp(²0(ZYHòŠò,ܶé²ìßÿÚ@zˆ‘!ªù/ƒœ¤˜ÈºˆgcIU>†ÿœ¿òÿþþÿËðöÝVv ˜¸V^ýàÌk/æ3Ävò_Nn¶:Goã÷"¯nܺÁðòæW†ß߀¾úÇÈÀÁÄ c4”ýÃÝÝ?Ýú¼‚õ<Ð €A¾ÿ ý ôô+#EãçæØîíÃüóðÓôÿÏù qÿ E×Èëð÷̇ Š$  A¾ÿ<î<Ê Êÿâßíêàìíýöÿâ¢úþæöñ6Ø£òøt Ï( ÷ùøÿÿÿA¾ÿý&@÷@qôêõ÷ÿäâ/ü€óôòŒ ?%ý= ÿì dýþ öûøþÿ¶ÿÿ¦ˆ…“»µ¼¤4DMIõÿ·ïßAqùŸƒiÛî.3gÎz©¢$[¬4ŒáÃçO ßj~ýúÅpåÊ•À‡Ÿ .N~!iY^a>F^>P|€#VFZh«'7;7ÛoþýûÖ ¢™™YÙ™™Ù™ˆ…——_“™™ “0Ivv6 f--­4nóç¯mþÁðçÏo þ tã?^^AIIÆÙÄ8}úü_ ¬ þüÌß¿~üøV ÒbƒS6PÍ¿ÿÁjØÙY6oÞý €XØØØÿ‚R<rŠ+`b¦¿ \\\`dÀß¿ÿÀòÌÌŒÀlÂþ €X˜˜ØÀš@)„A€ ˜†A ÿþýÕôj;ƒ øÿŸ¨Ž… €X888Y`°²²€ýô>P0 ÿe€Àv„f{¤èJf€byýúã«Ý»Opmûÿ÷ï¨_ÿB²ÏÈø¬a3ˆ¹’‘ñÝ»ß užˆÒ.TWIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/history.png0000644000000000000000000000221611550446572022731 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< IDATxÚA¾ÿ)¥ úþF!%\%= èíõóÜâòÇÝÜï¤÷ü·ûýýõùÿÿˆf+‹”Š`§Ÿ§JЉ/ƒ0Ëo†_Ÿ?1üÿ÷_€áÝV† ¾2¬ßr{É“[oˆ<@Ì â! @Ž€²†Èʤ8£P™ÿo¤_1XèH3üùú”“ù+ƒ±¦,ÃçÇ·~ü`зÔÒ{þì£Ù›ÇŸ¶0°2} foNIÞI¡±ÁÚ|,~3HJ°3HËJ1ˆˆ 2HI‹3ð003c`føý™G^Fþþí— _žÚ@Ì,,&]B,Ÿ™<Õ¾3èk1‹ˆ2€;;Ð¥ÿEDÅD¸ÿ¾d8sý-«ˆ¤öÃãwΓ 8·¨(‹µÜ†¯ž1>|–áÓ§/ LLŒ 0ÀÄÄÄ @W02°q22˜Jý``b’JA¾ÿ<ÿG<% *ÐÑÙ»»Ç"#**%óïþëþñîð Jµãò3A¾ÿ ûõòÞÝà+/-55-""ÒÖÞ³·ÀÚØ !ÿ øùøäáÝúü ˆå?#;Ã?†¿¿ÿ0üýóìdaaG#u†“Ûö0Ü–•c0±2b†+Ã÷oß~þü Ôó—á?@±üýúë³  ¿ š¦77P˜,€ÑõçèQs#seexXüÆ;''ƒŠª.÷…Ï ß?ü ¦oo~œøþ›™áÈ© ÷Üa™ð÷ü9†ÿ’’ Hš!€‘áñÃ{ GO_cøö—áÛËoˆéóó‹žÞûõïúk&†ïß^¹qáÐ%̺ºpmÿþý%:0ýóû†ë/ž=úÅðáÑ×ùÄÄÀÎ}àÔî—+_±h2¼{ùáö­{ ÷yxÀ¾}ûÁðõÛ7 £îß¿Çpûú†×ŸØÞÕÛöróV®­A¾ÿjûûóþÅÛÞÿ8- úüóò ×××ååæ ÝÚßâêøÔó •—ìÌîÞð_ 눙/”B¾|{ϰýÄ&YVYi!†/Ÿ>1üúôÒ?6†×Þü“bØyMšaêÌ›ßÞû”ÌÀòç!ÐS ÄÈ {èKf`ºåÒœl ÿ8ü$”¹â•XL¤D™9€®gxñúïÏ÷ÿ\xzçûB†Ÿ¾ã ÿÿ0D;|•fÖŒ&IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/view_detailed.png0000644000000000000000000000170111550446572024033 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<SIDATxÚbTU¯¼®gª¤òó÷ÿÿþ20üýÄÿ 4ˆÿÊÿó*•ûËÈÄøêÆÝÇÄbãa(ãPÊòðDÃ/þƒDñO(þ ÿñ››qåF€by÷éß¿ý»ß2|úø“™…‰á?Ðô@kþ@&„ÿBƒø,@‚ÈúÊÌÉðõëßÿÄòñó_†xmFGM!†_2ü:‘™‡‘™‰……¨ùÐÀ¿`6###ØÐ¿ [/|gHßü A¾ÿû îæö¦kî«SãÖ íêåûøó òðëëéåëèäüøóþˆå/3Ã?&†ß¯_1~ZÁÀ%ø—áÏÛW ¯ßaX¼d%ƒƒ««æM;^½zÍðçÏ'kC&1'°Äò¨ùßïß ,2’ Ÿ~|øÍ ­È ÂÏ••ÂÀÊÊt2#CDDÃ_`ØüF/'ö«¿þ112 È”??~00JÉ3ÕÌû‘ÂÀÀkú ´€“á04ÿ£Š…éXd0@É aýÿÅY9¼*L«óÉ#yôð ¿³™oE`ùÍ4.?ö+;ÿÏž¬šÌðíß;IÏB~u †_?mü6ä(]ó‡…õ0f€  °ÿ™!úôƒÀ·© Ÿþ¾ fxÎ/Æ0Î]]{{;†eËV2¼~ýˆÖ&Ú ÌÂŽÀÔÀÄ@ÀXðè/Æ× ÿßÿd`2d`ˆ‹‹b`afÚüÎ@ý»@˜—…aÿÃ_@/21Ë_ 3þ}ýÄÀ ¯ÊÀ_€ÿ7ЭüÌ@÷þ`ÚÑÄ.Äöû_  ¸Yÿ2p0Ó4ЀbáäádÚ‘áöë ¿YØ!!ýãPã?p¦(S9A y Æ;X~³³3Ë‹ÇÏ_mÜùŸãó·?ÿÿAÓ=HÑ?h.üL©@B2 ÿe `"øöò@1þ‡Å!™ Àmh˜:{ܺ“IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/finish.png0000644000000000000000000000171011550446572022506 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ZIDATxÚbüÿÿ?% € §30|úÅÀÀÌÌÀÀÈÈÀðÿ¿ëFο :ïž~Éøÿóßf Äf&†¯¿ò,0½†@< €˜ Æ5þùÇÀðýÃÛÜ*ÿed(—cäc“ßµûž0òÎ ñ  ãÿÛwß&¬ÈpòþO1Q^6.n.~žÿ ,,ÿ6\ãF#C^¦é3/ƒ—-½ôßpD&)€@ +ã†þÿ¡":(8bõÖKM~c5Ú&4 ¶ïDG˜¾÷’ƒÚ3„Kñ=ãc¯Ê32ðr33„Z‹0«ýfàãã``ae13ùgž}øÆðëÓ/}&†Z{n†U˯2,]reÐØ-@ýþÄòöË/Ö3·>2X¨ó3˜«1€’—“…A[—!mÁs†s÷¾1TH0ä{ð1Ì›s!'ïõïßÿ¦ ªf` F&£™Øÿÿ7dbdøLÿ¿øÅd¨$hµr¶ 粌Õì4x*ªO0Lr~?ÃÆ`F¦÷ ÿÝ, –ÿÿ|ÿLÀ„È´á뉯ÿøÏø_½&L†áðÉW ö{¿;ú´¨¢…•å'ÃDþ xÂf¥É_ÿA1³±3s¾ú»¢ýÔ)O}{ÿ³„å0Ã/h2þÏÓË @@‚,@® ó÷¯¼ ÉØ+ýôÆû²¿?þÎgàg{ÏðñH0ÏÀu¼âGÄHiv0=.IÞlxIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/fileexport.png0000644000000000000000000000152211550446572023410 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<äIDATxÚbüÿÿ?ƒ¹¹ÕjssÛv6–_ÿ10üý÷ˆÿ1üb üßÿ@öÿ¿ @îŸ?˜~ÿa`9zdÿ»w¯» ¸¸ø†dff3ˆˆr±p°³0•2ü*égfd``eÒ ðýûO†S'¯3ðò¹€ø8c@ˆ]2©ÿ¦AÄÄîmï~@D®Ù¤Ú–Ží±?q ¡°™’ÔTJá›î@`þýû÷äf&F :8ÙþhÐO þ rÿóÏaQnn.°‹ˆâ0FFFf9$ ´ú?TÐÏ  °¹ ì$† 0@`˜™!š™™™ ‚Ì`} Œ@.P-ÈÐ_@Í Žf„Z6€¨’‰‰‰……n23ó†ÿ`ë€ ™A1ñìŠ@ÈÈ„0 € 02üʾ|ùÀ¨ú¦ÿ¢ïß0 & F&†ß¿~Õ3à  °¬Àxúñãý{ÏÑô ìšÿ`M ÐÀøôÿ_ ÜA ‚» €À011mý4ä+ƒ––,ƒˆˆXño`è12þg`gç`xúôÃâÅëLM͈€½ ÄóÈÉÌÌ, üü »wfxÿþ3ƒŒŒƒ°°(Ð@°ÍBB‚@›Y€jÿ½@P@œü÷ï†wï>1ìÚu¨AJJ†áë×/Àôƒáóçï@CÀ®ý ôÄ€‚F#Ø¿€qõîÝW111 Ÿ‰áõë@oýÆ 4àXã¯_€z a@°0`æââ{”êCBB@áÆðíÛ/p4‚‡‰‰•AZZ(Î tH-Øû6àÂ…‡98¸-?þôÿû÷wÀdÊ Êu`W’8È‹Ÿ>}bøòåP ”Þyµ¤$• €A (@u²J鸡IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/edit.png0000644000000000000000000000133611550446572022157 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<pIDATxÚbüÿÿ?ƒZhÇžo{&† Œ ÿ)4TÆÀÌÌÈð(ÏÀÈÈ´mïÉ3WZÈ€‚ûÿý‡ÿãeõËOƒ(€b™þïÿ¿ß úÊ­' ÓVìǰæ Å›3ÞaàúÇÌöõ#ŸÒOËqŽB‘7/|{ùóïŸKL@oc,4ù2AÓÃH´Íd`Ò2‚< ~v Y‘Í òÿË .Åp{?C_öü÷_¿O f`80È@410B\R _†_@ö›¿Ž>¾Åpîü.ÆÏ7ÿ‰h˜}ä–ýÎpï »ÐãGßçËUP*bM\Ybø¡Ë÷=¸Ïàüû;Ãê_ŒŸ_?¿Ïr™ €)ÍÎxÃIÕ\ƆšIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/irkickflash.png0000644000000000000000000000212411550446572023520 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<æIDATxÚb¼,,ÌðŸþþe`ø÷Oäÿ¿áŒÌÌFŒ,,oÙÙ?‚¤þÿúÅ÷ÿ÷oa šs LL«€ø 30刅Lþÿ/f¼Â""²h€0#+ë?°¿¿ÿÿçϹ¿¯_«üýøq2P]/Pø H € üÿo ÔPÊ")¹h€3)/ïk  ÈŒ@òüÿôI‘‰“ó ã‡ëÿ¾|Y ti'#ã9€b:E€d³Ðj úÌß™EEO2³±Y333+þÿÿŸáßß¿?þ e|ûV è-]†ß¿×ü}ÿ¾hq&@ ˆ:ù2«¤¤ “€À)©7ìììþÌ Kþüý{¨ˆ…Åà/G4Ç> ­Â@=*@ï]þóúu4@A¾ÿ1¹ 6Å S t©¸¸éæÍÏþ..¹UGGÐôù­ÿýý:óóËïïGˆ‰‘›ûP³¿fæà°gçâZ°|ÏÞ—‡OO5—á¿jôõËÕÝÇŽ¥®Ü¿ÿ%×<&vv;`,½ºD„í @11±±}d†6 ßGf..Žß W/?.ìÁÆ\ï$ÌÃcÇÊÌ#ÉÀP¿÷Ä á?@9`ذ311}dbúží5@¼ÀÈÈÆÆÀú‹™™ñÓ¯ûßÝ»rêŽô9`4¼``¸Çöÿÿ/vv6FPzªc`Z & <Pó¿?øÑõ…›ÛÜÌÙéóa†Òi oöñ7 ÛÁÙù3 0œþ33ÿÆ?P(ˆï_Âÿ>|xóÿ˱_oÞcec“u²²bºé?ÃOA ¦¦gf¦¦ LŒŒrÀè;LbÀ¨ÍÈÄ$@L@[ÏýýôI˜ÒÞþûüYåïß)\œœ @ÍzÊ â2@Ìdsrq10åþ|ú¤LÚoÿ~ù¢ tÁy€b†èR`´èþ~ûö5Ð>ΰaõj!!9FFv S·¬[ÇðíéSÆÿü}÷îÐB]^€bÄ`&™ð÷í[…ÿ¯_Ÿ~xïÞÿý'N0póó‹j*)1( h€è™3gþ½yóÿÏ«W§ÿÕõLé Xf: ôÏyæ·o™×:ô÷)0|õ…„4ùùùÔ)Q˜Aó*PìÌÿ´„…™j›^ÿÒ@LH¹ñ×FÆ¿|À¨a`àä&Ù‡>|yõïß`xÿýû—óâë× lÌÌ šA ÀÈjñÀrÍjIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/attach.png0000644000000000000000000000200211550446572022465 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<”IDATxÚbüÿÿ?% €X[€Ôw6>!.n†?þüúÇðûçV1ÁE\‚œü÷Ï\›`èeÞÿòñ›[ÏnÜOfäeyÇÈú—‰ €˜œ€üa`fçd`bec`ø÷ŸáÇÇÜŠÂóÒ&†D~úͬ*¥&ë–ë,ªb¢©ñìö3ãÏ^`ädþÄÈÎÌ@üúú‹[\AhaæÔаc‡Ÿ10þúÍ`äoÀ0¯lõ…×o~°»¦¸j¿|ðÜêã³;™xÙ?ÜN†?¹dÔÄÖ$õøÞóñçou+†¥ukö½½tÑûÕ­{;ßýa‹°‹ôQzÿü•Ç·¯¶Ô€ß 3 +*¬OìôsÛµî'+#ƒª¥2Ã’š[>\¿ÆÀÆò_E¾âßßßÚ·®=ýkì-÷ñÝG7€bb`ÅÂ) M[Ú}œv¬ºÆ (ÀÁ lªÄ°¤rÙªO·®E5ÿR–Z˜™!¡¬ÈÃðúþF&&i€biÖs·ÚQë¡¿iá ~Qeq†…%‹æ~}|;ƒ›CX]a™oN´Ï©#Wÿ~ôˆÁ-5‰çÈÞcïŸ\ÚA¾ÿ%;.¯UzG/¯Í ' £sž–øéãl +$­IkW@Æ·Ìÿ÷ìîÿ:TR¾´¸çéØÑLýÎA¾ÿ"9#)×Õí¥sŸ…úñè| 1*©DdT8¿®Áÿý7OIº«®ÖïÞÔ\ Ïþˆåׯ¿ÿ™Ù¹„”x¶w®Ùþë˧.>E)µõΩÁúû×fàãdƆ ÃÎåËN~~x#ŠKð4 # ó? çç×? LìÌ"Lü<¥r¦º Ö!ŽZ‡ÖaãgTWcؾpþ–ïÏo'ù†)ù£sÙåol‚œLÿÿ½ÌÁðýÛo Aœ §vžaPÑ”fà—`Ø·xþÒßf1°ð|b`¦V&f ýÿ @1±qs°JËp3¼õ™áË—ß ¿þ23<¿÷‚AËDƒ™W€aÏ‚Y~¼—ÆÀÊñ [f –ë'o¿`fc•fådùûþõÇÿ¿ÿüg`bffzöüå¿Û‡·7üýúº¨ùŽ\ @Œ”fg€„mT!3JzIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/artsenvironment.png0000644000000000000000000000143211550446572024465 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<¬IDATxÚbüÿÿ?% €X` FFFTA+N5!vQ!öL+mÁö‡Îüu{N9Ìb€bÂ0’h&·›8„ÿï??s`¨ã„XF~ó<Fa˜r€BÀ­ÈÀÀ¯ËÀ ` ´QŠáÿ? ÚÂÆjW˜l½D_“‡‡ÁÕRžƒEDæ €pmdåg``bjü ÑüŸAÛ7%r?×ûo„„”¥ù$dL`ÚaXÓ?¢ùß?iUßð&΢o_aøó÷/3 3ƒ° 7ƒ”„ˆL@Á‘áÏ/f`be`áUUö_(lá©|þÐwoß0<{þhþNV!~n˜6€‚À!¥Q(¬lh- §¥+£¤¦(¤¨Îzø&ƒ¡ƒ »+3+ÃÝ{÷äää8XYaún€SJUŸ –Ã÷ŸÀpÆè‡Ï Ê’ R ï¯}YÁðùóF&&†¿~ü…é xèó¾z#Îd¥þ17ƒÏÌÀðí×?†óç.0ðòò0üùóáó§·aúnÀ½³ûÏŠmþúúçÇß~¼ÿËðûÃw†Woþ3¼ýò¨ñ5ƒ’’"çÏ_^?ü¦ €à^ؾfþ„Ç/˜Tï<ûóÿ߯o_YEä„ù¥¥?pó3ت‰1¨ªÊ1°°°2¼xù†áéã»aúnÀ§wÏwÛÔ¢ ‰G`H0=çÑ­daõÉ“Oõg1zí/Ã¥ËW>¼~¼¦ €@iš@†²”Ñ(z?€¢äL  FŸ5c8Y¾ÄËjèG3ügdþÍ¢Èy –ÁÿúõóÏ“£Ëþ}÷`9@1Rš …¥(… Û“IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/tab_new_raised.png0000644000000000000000000000176311550446572024204 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<…IDATxÚbtssgøþÿ?ƒùÙ3 ïÞ1übb€ƒÿÿ8XŸYþýáåPUp’^ûæÈó ?î|ž*,À*úÿû¿GVÎTy_D„á ##Ão ¦_ÿ!ø;PNHSªI3Â~ï×? þîj✂V€A¾ÿEEH2óûûûÿ÷÷÷ÿíííÿìììÿÕÔÔÿ\bdªBLRŒÄÌÑÿ÷ø÷ÿæ¿·ÿðãàÿúÿÿÿ¥®µÿ?CF\˜D˜X™˜ih9ÿcÇä¯?ÿþ s³1p°s0ˆ:x00ƒƒœA(ÆÃÎÍ@,**ªÿÿgäZ»v#X3ÐpPdøýûƒ††–=Ðà?,,¬ @¯2üýõ‹á?0ªYYYøøø„„ÅìˆEGGWÝ×× @®`ffb& feàææàcbbÌ d&&D:WT”g—   ÐfvHz*aAÀ´31# Ç€bÙô˜H@þ†ø* t ƒ¼ #8„a°²r2  ÄFF¨ ®`aa{ÙE068ÿ0ƒ\ÍÉ @,ïß}èÐ%6 ØO˜ [ !|˜× .``yùÇßœÿ2½0ØQeˆuXIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/player_start.png0000644000000000000000000000170011550446572023736 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<RIDATxÚbTñYzŸ‰‰‰ãÎãO6,,Lwþá¯o?@ †ˆ€ÙÌÌ ÿ€ŒÏ?ôù%ù˹8ŒˆÉDOZÜÂXF‚ñï_vNF fü÷—üjüýW„áçŸzGW•=§yGzÙËËËë/ÿþ°übü´èÿßÿ þ3üüõUó¯?œ þG*jJ”¦Çh„z©1Hó³0ÌÚz÷@±¼º”d!Ð¥þœþbHàÿ? ®Bb|¥Þ¾º®Aþ: B\ §Ÿ10<üÂÀðåÇ€byÿ d!##Ð…þ1ˆÍðû·3;[‰µ‡V¤»‡”¼ÃíO@M/ÒÀ ø4ûûo€bù$ÿ3½ Ôù¨ùÏqF–Ly]Å;Ca9M9†?nÝ‚„%$ÿ ù ´ €X ¾ü ´‘‰áï¿P~)ñZM;C]u†ÿ™îßj‚x@aõ(øè[€ðïÿ¿ÌŒœœ+ä­Ìô 4¸8n¾3Äf4@^ÿ t@±@£è?#£03ÃW&6†ÿ?!6222` á@È €@æ3123ÿýûùsÈÝM;ò¯¯Úøêóƒ \Ü@‡p10°0C1 *fb†@, [˜Ø98^ÿÿûoÒ—¶Ü~ö¢ê£–J¤š­(ôÿú÷OˆW@êA6ó-`@,œl Ӏ鈙™ hôß?îýûó;åÅùkKßÝyX©j­ëªm«Í %ÅËðèï¿ ~à冸 €˜¸€p³ƒƒ(À Œ&&°“XY÷ÿúòÝÿêÖq»§l¼rûèUaî? òR â Ü & fNH@31320< uf¦ï ¬Ì‹ß?ym»wþÞº5}[^<¹úAZô?ƒœ$;Ðr€bâåbbáãÆÁF& FvVfV RÜ1±³~ºªù᥇. [7Ï]>qïïÏ/ß½ÁÄ@ŒÒ>Ë0³óÓGï­^¸ ‰§ÿ ¿¿ÿ„˜ôÐKÿÁ9šù¿ÿ9Š( ׳p±)Ë' LÉxnIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/kmixdocked_mute.png0000644000000000000000000000160711550446572024407 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbTRÒ`xúô ƒ¨¨?¿Û7/89¹XYÙ„€b|l¢“DDD’ß¼y·þçωë×/øÊÄÄ€0222üþý›…‹‹«INN.ÝÐP‡EEE!(惬 €pðë×/  Ò¼¼Ü‹ÅÅ…ØØX45UØÙÙüÕVþþýËÀÂÂêÕ¥¢"Ïòë×' ùÄÄD€†òé"« þýû4àŸnttÄ´ØØPîÛ·o1üüù.@ͼ ||<üÈêÅ€ÿÿÿ1|ûö]ØÝÝmn^^¶â‡Ÿ<¸ÇÀÄÄÄÌ œ ÜÜ@“@±üÿÿèߟ@ßYY9L€šÓ**JLß½ûÎðýû{†¾1¼~ýè²?@ÿ³ àB± €XÛBBÂÝÕÔ4ÅääDLLŒ8^¿þÔøšAR’ÁÚÚ‰áñã; ÷ïßgPPPf`ffF1 €Xªª*3ÝÝ=^¼x´ñ'ÃÅ‹7@N—•Fã Øo ÿùbQûè’¿ÿ‘  –/_¾ý>qâ í[÷A¦3ù T6DX˜›áýûO ÷îÝgÐÓ“À”ÿüÙ€b9}âÔ‡ÿf¢<+02“ œ¤¥A)óÃË—€Î·†Õo†·oßþB6 €˜Î^8}éÇϯÀxgä†ÏŸ>0üúùƒáÓ§¯ ?~ö‰A]]è†ÏŸ?3¼zõò#²ÄrþüéiŸ>µ(100#äïçÿÿ0ËÉ©©is}ü(  ³ßýδý=0@ßF6 €€©ìç¾ë×/8êêz ï>¼e¸uwCàÍÛ—üеµµzç7ß?¿nÞ¼Åp÷îíÃÈį 0 `¹‰4ù\³ûIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/revert.png0000644000000000000000000000205611550446572022541 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÀIDATxÚbdˆbg`øû“მی¬ÿ7üùògÃûÿ Œ,Œ ,<ÿ~Ÿða`¸éÆÀÀðÁ$ @110üg`øÁàä¤ë¶¹Ö«Þžù “ÃÓÿ Tþÿþ/ñû/PåF¨Æÿh˜ €Xýñt7ñZ1¡°…ïï7&†7og~ÿÿ5Š••…éëï¿Î=>zùÙ߯+˜_ÝÄ Õ´˜‰ñÿßÿˆÑ¸Àüᔚ¹],sD+0Èp)]øìÈ¿¿þ¼ä`˜7wÇ{#m{†¿0üýû‡áòË ‡¶ß» @,o>~¼ùèÁs96)Q¶" ož}axÿý3Ð"&.&†·üO"’M.»Ï.Å È! 4úCóŽ— çoTA¾ÿñíÅËÍÓ4X%dû“©Æ ùóæÔõÝÔïçèó0#)ííôÊåÚÓò÷A¾ÿ*ïñî깿ÑÇÚèØ,O†YfL79¢®®' +îëñðò÷B2:õ÷úÑéÕÍìùˆ‰á7'3ßÓ7/¾'î_òN€M†áÓ?p©è28Û1|Úöÿ/ƒ™¦)P/à÷þüýÏ@, »KA"@ü„ìYAm`ü‚âbH~Pÿ??ÊÄÌ _~ü``†+3+à€,ÒÁ À AK!"é¿'*¡… ”Ã>ü ËÙbïFš{¼!¢õ šÄü ¹Êo!ÄZ¨7”èßãUb X‚€Ñ?Šw\cb`}ÿAŸáëF†_¿!r@} î°1|cçeSdºé?@±0 O~]Äò÷C†åN&v`t1ÐÛÌÌÿrzÿ1ùt80þ} @LÈ€lø 4€‘é?8¤óšþ1œ¸LMÀ@ý ôÒ·ï¿DDøù™~h@¡¸è)Æß@?ÿú÷Ý»¯ Ïß20¼zó›áÍf†ï?@Òxxø¸21| XÎ{á3;Pˆ•á0¹6d~dàåabøð™™Q@1))AVF`B €@ª¡ÚYÞ¿ûyüôâ#Ñ|b<ÌwLÿÿS’çdxúø?0íÿg`fbÛpòÜ%†XÞ}gdúpñî%€ž'vdhÆIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/cd.png0000644000000000000000000000161711550446572021622 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<!IDATxÚbüÿÿ?% €X@„‘áRf&&&F†Ÿ?þ*KJóæ‰ûÈÈñÉýþýïßý;î\¾ôrõÛ·ß'³±±¼ù÷ï?ÃÙ³‘ ˈfH™™)*>I·7$TUBTŒ“‘‰áÏof Ö|÷úsÝÂ…×Ã7mº“ÎÈÈx¦ €À¦,a03[ºjÝÃÿŸ¾ýÿÿæÃÿÿ¯øùëÿÿß¾ÿÿÿ×ïÿ`0cÆõ/’’0½Ä±AÆ?Xcª‡—Ã«× Ÿ?10üüÉÀðû7Ø ÿ00|üÈÀðˆê¸-¬Ýf300sƒôØqIî\ßuÑÏ_ ÿü*~ÏÀpõÃík ߿ŀ†¼}ÇÀpç1ƒ{`˜Ž°°EH/@ ÐÓóç`øÔø™á Рëçÿ1°³ÿ¾2œ?ÅÀðæ˯@ÃäÔ¹ÔµAzl€´ ¯,33ÈS@ÌÊÀðô)ƒ˜Ä†)3f]غsãm~þß ž]T XV q)%e^€ÇÂß¿ÿÿ‚MJþý †_¿”•¤yEE…Øýʱ5ÿ‡XòŸ¤ç8Ø€‡>ܘñ7 ¿±Œ ýkœ ®ÁÊ €üô“…AB 6 üütåÃw@zì…Ë—Þ,»vá+Ã_ MâB@?J30˜Xc…Y˜…AF¨‘b;;Ð%÷o¾f¸yuÇ@ xúôîœuk_WÚ"ÈtÞ?†o@[$€|qˆf·˜Y ѺnñüÓ_¾^] Ò @`þüùôiÞ¼¼ÄéSÎ~bç``à⟡):@88U/š¼ùÍÝmY@ѯ y€§&%¥:0›™YÎ<9yÁ¹£Ç>ü?yþÿÿ«þÿ¿ Ä'¯ÿÿ¿xÝËÿ^Ý'€î2CNÅÄ"”•ëîÝk‚‰s ZG:û+(**ÿFѽ;7î\¼°{ãç/WÀm†@Œ”fg€¡ÁPÊÕôVðIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/connect_no.png0000644000000000000000000000210311550446572023350 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÕIDATxÚbüÿÿ?% €˜(Äø! ê ñ3ÿ0üøÏokmÛf`h ÀÆÆü÷êÕkÏ?½ôׯ?S%%¥Þrrr1üºXñ?ƒÛ?†ß@Çãÿé, üÿ‚šþêÜåØ¿`î$)1!nf– ;vìdhkëÞòüùËTÁ¿¡h ø4 €˜X<8™´ï¼c-²qó7Ò•eex÷ùÃûÏD…ttµtt´ÕŽ=ÉûíÛ·-ŒŒŒ ¼@ 2ÿgøô@17„²ÏeЕ(·3aÑ0å<È xkÃûû?±ë0póp1pqq0ÈÊH3¼zõFþʵ›'¹¹j2üdøÃÈÀ ~€A¾ÿx6ýâ· öÂÇòõ.ÚÞáçõ ÷öøüüü »»¼ÅùóÏ ÷þþ ÷A¾ÿ+û·Áä(!8 úóäûÝÊÈù·˜ ,;ô)=ïôðîç#()¡ (ÉññgA¾ÿÿªÖ.)íôþâììý¹ìXÎ8.à±GS\áÈÔ›ÄÒÿ’ËÏ÷TìŠ}~00£ŠŠâA¾ÿêËô…ˉ÷fâ )1<õõêü3 úüùíñ#PaQ×}ÿþú[Y`EEñÊÊõññêA¾ÿáe¥›¤Z;mkœ.(#ÿûô'áÙæ¾•K33%8ÿÜÙ))èÎΤ¯¯ÈÖþþdA¾ÿz4ÿ¨æþÍÑûíé#0 ÚÛçç÷úõÐèô漨 (ùõ öÆÆ¬··îÉòòjɈÀa`cbbøðîCÎö­{ös ‰jsýüñ”ÿöÍ¿&oÓÌù¿²¾Ø½•áçÇ] üü âBoò_¾ €XÓ533Ó—ïÿþ/d~ñ‚AíúI;ÉO+½Õt9Þ30\aøÿÿâß¿M™Õ¸¸E%$|Öß½» €™ 蔿@W~ÿÆ ý<ßϯª’’ÌÖ Ͼ10ìýƶõ$+«Ïþo_¿ýù“A’A–‡G A¾ÿu3¼Ú Ü  ñïîêùáçêýðùõÿ?ËæÁàöcÐï÷÷Çõúú8äíí ÅÝÝm +Ÿv‡p¶HIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/color_line.png0000644000000000000000000000153111550446572023354 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ëIDATxÚbdçeƒÿL ?X~³1þ Ä@|V Â?Y$™xþn``ý'ÿïkË¿uÄÄ@ ©úƤÄÍ÷{›]î3¾Œ'â b_–1|gr fv¨*F -@•ÿ˜˜ â"ý•UGøÏfŸ’‡::æ>ò03¼àûÉòÿ6—9@6à;‹Ðßm>EÔ¥t?1°|•`ˆ‘-dø)ø‰áú‰w"Ä‚×é¿Õ¹EnõÉz®,­õèQO¹JVö? Ÿ¶½c`xÀµ €pð‹I›Cä÷f‡¤Šbjß¾3*42ücýÂPÜ?áø\îÙ ìl™„=3™³‹ÿØf÷LQJý;ÛO1† ¹f ™ŸŠ{¦2_Ä9•+›ùÿ_€Bs0þ2˜2‹üܨàÿV\Xö7ÿoq†Å:†¯ÿß3”õNg8»ŽkG90 ƒtªÍ„mpø(Ì#ñ‡A’YŒ!T©Žáó¿× %}Sÿ]ØÄÛÉÀÀ^ÅÀôdØV°fk æÍ,V„Yÿ0È5'¨51|þûŠ¡¨"Ã…íœM LÍH €X˜~53É0püšÃ`òK”ï?ƒ*§C®^=Ãç?Š&Lúwuw5PsÿÿÁ@@üºá¯½«ž–?/ƒ —4C…i=÷¿ò'Lø{õ0[  {Ó?¬á @, ̸…“¦{3¬øvŠ]ˆŸáÓ¯‡ ÕSû~Ü?ÃYÈÀÌ1›Í0@ hÔg’u’5dÈÒÊc¸{å>CnOϧû—ز˜Ùg00þǛֈ…•¹ìÜõ !Ó*¡ýüѹ[WÖ}ÿöo-0¹aøûŸ`> F†4¦+À„s›áûŸ™ _.303<Ú `6ÿÁ ÉÆ¿@Ù˜­²63„þ ¤9 Àq(ôÙ¹ÙõŠIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/button_accept.png0000644000000000000000000000156311550446572024066 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?% ƒqp @ðÈ•~µ-“:,Ýׯ\Nf‡Ø6ÔZ:¦ÄxÕ±Õ˜ÒÿÇâ0ìÚü rˆ‰$ë@Žýý;A]YjW¤µ…•+ß?€"Ú WEÿ11Ìv·Ð›_ëé(sñÚóî¼J –ÿ ÿÁð ¨æ% ÿþü3ã㜟좥 ¡Ìбû<ñÓ2¹™6‹ïÕ_¿ÿÝüüøÃS½ÿþ³þøû'UNM°§ÂǘÓF\€¡|çy†]Ô3±³Ìb`üÇ@L|ÌÜŸ} ¸ÙVþþóO¬“Nÿküå`Xææ¨4uj˜§•¸$Cãžk »ö>ïgûÏÒÄÀ‰=€bzvçûL 1†ì@+kF.†uÿþ10þùýÏ•WœeWj°AHƒ«;ƒ8CïÁK Û¶¿\Åþ›¹œ)äA¾ÿ0æîôûdqIJ þÇ×âe"* avW:J"3øþóŸÉЮ­é¸úý]ü÷üúýùÿüA¾ÿ0!ðíî÷3W0<÷S6.*#îüé±ÔÓ±ªìÑòYìýýû ù A¾ÿ/"ÿýôûòï[/'0$ÿïýê¿ÝÖ®¥ñàÿíMàüüù ö ôˆYHC›õÇã/ŸÿYñ«~UâagaøôÿÃé'÷¶.ýþæ÷S–&ŽßWþ3ÿƒxšñ ÌôŒˆ‰ã;ç?¶ŸŒÏø¶ž>ýžá9ㆋ¯î3ì\úë˯Û\1ÌÌ §ñ%0€bbþËÎÂÿؽ>ÃýðÄíç GW1ÿú~Y ¨y'¡ @ÌjFÀ(ef`bdüÎôCìÍm‹×yë˜ÿLûÏö‡áóo†ÿ,À ö#†ÄHiv0P­!3•Žð#IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/kgpg_key3.png0000644000000000000000000000166211550446572023117 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<DIDATxÚbüÿÿ?% €X@Dxx:ãúùêbŠÂ1šrîê&òªo¿¸}n÷­=÷n¼¬@ÓÄÅó– LÐHŸ¯X7?)õ—"›èwç€÷¦fïŒ&W|{ÍþŸñóÿ¿ÿþýÿÏøŸ‘‘áÛçßï¿|ÿ¾¤ €à<ÿÁÏ,ðK“áû{F†Gϸž½Tbá=ÆÜ²ãK 33#жÿ˜YÞÝý۰æÝZ ¶€ ù¿VAF÷ï¾`ÐÓÑ`àåå``dbfx÷³–áÖXc…{ 20°°30¼Ò\\ ¿¿0½é °ººš´t´Ο9Ïðõë'WWK†Ã‡Ï0¼ÿðšáÕÙo+¶¿®ÿñúÇ}Ž¿Dßg8ÃÁÀ ÿ™áÈ 6àÇïWØXXÌ-ŒDDxüo úú ž`v®e{*pÁèáù ÿ={t›ãïO†ßîaýôìu€&Ó'Ïç¿~ý’•h60>|ø2ˆ2pp0²¸{ØE†&„_‘suøSÛHâ‡[ ~ô€AZRŒ-ÄÏ=ÏÆÌà4##£ Ì€b‚Ò¿?~™zæÌ¹#·nÝê_`@ò1((Hÿ:sæšÙ¡C§zvïÞìýûw ÚÚê2ü|<<ÃÁˆ‘<þ¿¿ÿ™ÝË—o“?}úÔ¥££+¨§§étëÖý˜7o>”¾}û‘åÍ›wÝ,,¬/€^ÛùàÛg°.€»(æ033ýÿöíçœ n…_¼xá7/ƒf PJˆ……ùÏ›7 _¼xÝù÷ïß[Gnë °Gî Ðo LLŒ þüÝýèÑó·nÝfPWW‘”’«Š1-ZÂŒ’¬ ÷®_?`bÄÀðöíç óç/Þúó烿;#Èt˜& €‚"Ã… Ç._>ÅðéÓ0¨þÏÇß':tâÆ»wŸÎ…þÁ4¿zõŒáß?0— €)ÍÎMY–ûÞçIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/stop.png0000644000000000000000000000201011550446572022205 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<šIDATxÚbüÿÿ?% €X@ÄRFF†_ š¢ªj‹…ììo\¿íý›7Q>‚ŒÿÃÀÀÍÉË»H1,,èÙ©S7]¾÷átÐr€b¹`!PóVc“ïÜþÿÿùýÿ/Nœú¿HBòàD Æ ¬Ó„„wÜßàÿßGwÿxxÿÿÇ5 ¦ ½6`³ºÆÅO·šçµýÿ©)þÿÿÞuÿŸŸ=ÿ–ˆèÞÉÜ<[9úÿëáÝÿ/JˆýÜPúÿÍãGÿ§Þé °ÇRÒþÿy¨™ÿÿ')†ÿoÙþÿܹöÿ££ÇÿßÛ¿ÿÿç»þ_çýŠ“áÿ!6æÿ_¯\ü¿¥¤ä?H/@1Âàñ¶­»^Ü~ÆÀ6e>Ãov†ß?1¼HŠdàÿøœAñýð †__?3üddbP™=“áÝï WÖ®;Ò @`Ìe`Y$)uðùÅËÿíXóÿ4Ûÿ;" ÿo(pý¿,Ïûÿ /ÃÿÃ@ÛŸÌùÿЫÊʧ‹d@zìf†7ŸŸ?óÙì`·û9¯ƒàÌe xx~|ùÆðóóg†_ìì r3®34c˜ok{ôÅÝ»î¬ O@z°HÇ(€0 .ÖÿÿÔE›ÚÄB¶ ëcœ ¥Uä: dØÕrty¹¦Ã ¥ÛªóÿÁ@`ã™—CXd½ßŽ]¾¢ ?ņ1üz÷á+Ãofv†ß¿3\މe`¼s‹!ñÀg!)©-@D@zl§¨ØÏU+Ý…þ~f¸Äðûˆ@Û¥ûf2(Ì\ÄðdÐ¯ß §þ^¿Î»j•´ôJ^€ èç$«®Äp'$œáû‡/ ßÿ03(N™Íð_߈ᷜƒæ¢E ¿XX~ýúÅp 6–—‡‡A?" ¤ €Àå¿~ä7AvvV ¡ˆb3Ë§Ï ¿9_˜˜8<¼-˜™Þ ¥5f ÊŸ™„…88ØþÃè7Ðå6àÞ½7/™Y¸EýE0x™@š@Qøïƒ ùÏðîÝw.Fe ðã@ ¸ré¶á™“7ø¿}ÿû_\œ;9*Ö­Œ‹‹ ÿ p¬ ÀÄ‚ ¯Þ0]4à'3@ `ffzÁÊÆø‚õ#0Ú˜Î?}òá+ (pÿÈ D¤/_zôê?`L3œ>õø@1Rš™ˆâ¼@`ÏÓûö‘ĸIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/tab_new.png0000644000000000000000000000174411550446572022654 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<vIDATxÚbœ ÈÆ€ ˜X¹X˜þËþzù릞§ÔNnn®k9HI±+0}ýûòß_êˆÙ_„™h3³ügàâ Ô‹vØþñá‡ï .žÂ¢ÂïÎ?cQË–YôýÚ·w>ÿ=ÍÈ2‚ˆÙøû_†/_!øó× >ÿ`–2Q Ò 1 fczËÇÎÏÈ#æÌçÈøãÿ··›ßNfÿýïËŸÿ 0 @ÌnlŒ@g³00²²00±²¸ªº¥ÿ}ó™IÖ\@^>ÔŒ‰Ï€‡‰áóæW[ž\ÐäPd|ý—…‹ùƒh€b¹mfÎÀÿþ5ƒüëg@?0›*»ǰþýþ“™é70P¾ f`´åÑeçþgòñò·?þ3­‡@A¾ÿ,2æÖ õ÷Æê­Á®ÿüþ%3'%øáÕüæåöôé¯ìÈõŒçVÉ ¤ˆ$þʽ A¾ÿ&""÷ø÷õýý Ú ûøÿïù»ÿ¯Þ¾ûÿ¨úû'ü·µuP &66.NNNp€°±³3p²³1p³00ˆ±23œ‘Ñ8w‡[ô ÷Ÿ_ \Œ¿˜þÿcøý÷X-##P/@±ˆŠŠërp@ øóçÐp $0¸¸¬¼<ËxØÙ„>ÁJ<ŒP@oƒÂŸAEEu)@1ΚµèWjj,ë¿ÿà€è¿@›˜˜ †~ýú$ÿïß_ ø_0ÍÍÍŰaÃÎ?ÄÂÄÄòh+r~`: h#Ä5L \\œP $ÎNÎ̈……… ® „‘Ù0ÅÈšabàDÄÌÂ@,ììœ,0M,,ÌP[Aš0è¿!6ƒØ ï±±±3ËË—_îØqœûïßßÿÿ‚<ÃðhȦÿP›þCÙ›ah!ã»wß¿c\•—”J2IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/2uparrow.png0000644000000000000000000000201511550446572023006 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ŸIDATxÚbüÿÿ?£éB†¯?~ÿa``af``úÇÀðA“_˜}9ÇË׿bØØÎ00±åX8¸Ø9þïpb &làÛ31Ö •ÕŽú–¡nê,l\kþüqƦ €0 øý×[Q‰oCc»Ú FE†ýϤ¤\Ý丄…W1üû‰® €üâ?ÿc4µ—µöyHÞc”eX¿ý-÷¯¾q‰1HØ8ñˆ‹Ícø÷/ Ù€‚ð¨ûûï #s‰ùí½|OYÄvîzÎðùÌ®ç\·ö>Rúóœá» ƒ¤µ ‡€ŒÄL`X•2üÿÖ @`˜ÿýË Q›>w®7Ëo^A†;1ÜÙµïѿ߼?~ýíúèä±ÛŸŸ2|fàfµ³fW“ïbúÿ¿¤ €A± î¶ôM©%'ÃÁo¶®9íÇ_á œÜW€ÑÂÀð÷ çÒRZfl"" ¢\ž\½Åðm­#@ `3Ÿ]ÍÁÀìúó/ã¿?ÿÿ?úÇÌTÏÀÈö™m@X€ý÷W’…µž…M™……é?ó‘¿[lkl£ÑL†Ï¿˜ ¹8ÿ3°²”…¨1ƒ™…ã/;×dÆ?ÁÍðì*6Žÿÿ·Ù1 $€ ‡¨h#;/(ýí÷õPÊy÷—•áè‘Ǻ œœ© ìì¿€Þùt М`­‰V>~n~P &±ÿ‹bÃÕs,<ŒÞ‹ë3k*Ç1þû»(ζ€¨Žƒ¬ € p£˜Dÿüagú÷oMnšvŒ¥§!ÃÜ£L ×§ É ¥£ÈÄȰèAp¸°q‚µÄPœþø#ÉḬ̂»2SßËÚC—a͹ÿ //_eàys…èd&Iie{ffÆ= ÿªÀÒ@A øóWMŒŸcCW™‰­“Þ«¿n½ÌðõéãÞŸ¯žµ¼»ÅÀñç7‹¨ƒ²’;'ëZ`â3i °¢Bë'4š›¹ú*2»ùaϦK Ïn>iaà`+ùý—©öÂÕ×å?ŸÜùûá͆?<" *Jzlœ¬ë@z À㘽éñŸkŸü}öêÇÏO¿6203÷ÁÜø©ëÑÓÏï˜ßßïüø”‹‹—›™ù?++H Àí<‘à JIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/kgpg_gen.png0000644000000000000000000000176711550446572023023 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<‰IDATxÚbüÿÿ?% €˜(Ä"™µxø<ÕŒd¼5ÌLß=ûüþµ—§ï]|:ùçÏ#84ÿb€à¬±%´Ý]‘O^‚M€áÿÕÿﯨ6ÙÌç¾xñ#P¢ìß ‚™áˆ @`~ ºîÃ_A&> vFVF7 q]Òþ¯_³{3ýý”cdü÷hÂ?Æÿÿ~ýû`Ùë=—/¼K P nN—ø“ËͰbE²Ú•ÿÿB<ÿ¿=àýÿëïÿÿO€ø”~Ä@ñÿo¹ÿ¿YÁû¿@˜u@] úçWÑlv?>Ñ'¬?}c`ºèn†¿@‡¾¾ÅÀðô ƒ¸"ÃÉm O4 dod8þü-C@ xû•‰‘ƒ_‰ãÔ}5†7t8˜ß0qÝc`|xùý•Å/Ž\ºÃ0O¡£ ¸µ;×1}g`zÀÅðï@ 8ú7í»ƒ‡º¥ƒ° Ãï?ÿ^¼|Ë0sÏܽïÿïÍgv’ÿòï/³õémŸ¥˜r=fXºÕ!ø}ÁÎE 6€•Wøÿç/¾|d```caÒÿ|¬?{[yüytÿÛ –)ìf÷XoîRm‹a8{à/O*@ øóû'߆ [Wéëkêøø8hÄ^½úÀÀÍÍÇ,ÄÃÇóãç½7 ïo>½Åðÿ÷k†ËÇŸ2¨8‹0Hx*3)ýd¸p–‡ÁPð@]ÀÎΩªªÈð÷ï†53Ùßî=zòãýÅSwýU?2r‹0ñ2ò È2‹p30rÝ`°Ò¸~›õáW€p÷îýŽ/_¾Øˆ‹‹hsqqð}úôéÝ»wŸÞ|ð¬†ùÙû;æ®´K·\#ªÄ$ËtãÃFÆ/,ÏÙôùÐûj€ðñã§Êwï>0ܸqGœ™™Iðï߯þ30¾cäâ(ƒˆ<¿ƒ¨ž‚ò¡âMÍæe&Y·û¯LÒȖκsü〇++  óKFFÆ@úˆÏÍ4Ÿ}ܾ9{¹á׿¶}¾ýö×ë«ß»¯fÝ1úûûßc€æ0kÁ÷ЙIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/view_left_right.png0000644000000000000000000000146611550446572024417 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÈIDATxÚbTU¯¼®gª¤òó÷ÿÿþ20üýÏÀðç„þ äÿÑÿ b0 cdb|uãîc€b±ñ0”q( eyø ¨¨áÿøa³²30|üÌÀðýÃO Øï?Pùß lÜ Œ+7ŠË»Oÿþíßó–áÓû ÌÌ ÿ€60021üZu÷þkIIAN6 kþ1-f`¼@ú+3ÃׯÿËÇÏâµ´„ €‘‘™áó§o õ»òÜäDþÿ…Èåÿ3l¿ü›!}ó?€LAÀ Ã,¤Â´ÿ?©]änÙyNÚæh|{p¯ d[âµFxÍÿ‘…Nïäx²¿bùûŸ âl4TËðè’ üúý¬lÐÿ!ùh @±üù÷ÿlà?Ðß@Gÿ‡ØüçÄ€Lþ?f&€bùÇÀÌð»~†ÿÌÌ`ÃÿýÿD&ý¿ÿ2Íeb pà2€è…ÿ@É¿@ÿ]ðbÿcËÓ_"$¿#ÈfF`ÀAœþçÈÖ?`„AÑüh9@±üúæ‚ÿÿ!6Ç9(A!ÿìd´öÈ @ˈé/P<ŒŒ°¸À@yá?ÐÿÿÁÂhûŸ?à€%8€“Á BImÕúÿ¿‹:9ß8È„ ^À¿‡†¥1ØRÁuþIõ@{/¬VÒ®báäádÚŸ‰áö›÷ÀôôÐ ÿ¶ÿ:õʆ¾Œ <\¿Àyá0àþ1 Pó¬ ¿ÙÙ™ˆQÐmå]n1 ¹ÏßþüÿÔ P˜€Â’™áÛP´S$`ÀAÌLŒ ß^> ÆÿÿqÅ!q Àw>nº"Ê¡IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/decrypted.png0000644000000000000000000000171411550446572023215 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<^IDATxÚbüÿÿ?ƒ¿ üøñ‘››=ÒÀ@¯P^^I………ñáÃ;÷Ž;4õíÛ—s™™™ÿÁÔ9r„ €˜È0QQ‘ºÐ¥¦¦6&_¾|çýôé3·½½»~^^É,iiÙÞ¿ÿ"ka °Ì,¬`ÌÊÂaiiYóÿ?âÅó·>¼×pïÞº}}í+ØX¹¢£“s988£þÿòl@ øÏÌÁÀÀÄÂÀÆÁ%våúíƒ[wl™ùöÝ»”ßÿÙ.~þõçÚ÷R–¯XpLIQY]];éÏŸ? þ3ƒ  aÉzŠá#»4ÃÕoJ“><}5éï¿? bߤ9®2|çøÁp›‰ýëµûOö¿ýøÅJZNUîÈ™³²N¢ƒôرß÷Dxß «0ÝþóŸÌLÜ,¿Ù™þ10±±2¨q}ùÄü„ñõó ¿qûJ¿ÑÒäþú¨õ=@ ’—Ý®j ¤óïÏïß`ÿøÏÈÄÀÂòá?†¿?þS6aaca^Æ ¥ú]’EIyãýë¯n%õl€¢Ž¬±fH÷oì Þõ|ò–áýý› ÿþ|a–æe`ø Túã!#ò °3±Jê‚ôØ€ÿ¿¾ÿeøôœ™áÇ7†?ïØ?1\Ørˆ!¡ñÃ¯ß ³Jxll¤€0 ÿÃÀðëÃÿŸ¢àø ˆÿ~20ü| ”øÁÀð÷=0FÞ3¼¸û–áÃ3 y@ùç·¾30˜<ºh(0±1üÿÃŽ€Àð˜¸þ¼b ¿0a°±ä`púÈðè#`œÿ†ÈÎÿ!®øÿ¬ €Xà©ñ+Ä€’Ÿ>\ü ú4ûÓMQ#N Á p³ÙD @/€Ù@¿ÿЦ¯_„åòš¸±ÁÈÀ't:;#Â&HB ˆ €QÅÀŒc–ïÓX˜8…8Ù!Ò@o0üå!h;Ü6€à ’ÀPf¥kˆBFTðÆøv'Ø 6àáW8·‰(üùÍõ¡øÏJR.½®ÌÀ`ç6IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/back.png0000644000000000000000000000162011550446572022126 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<"IDATxÚbüÿÿ?% €X@#cüÄÿ€ +3ï¿ Lÿ-Ä•fýåbáxûá§;#Ãýÿÿþ1ü©ãgcø1ƒ €˜°ûë¯(ìö Õ<ºa…¿®©¤ôÿ·ß„þýøÍðÿÏ_¥Ä‚¡ùÿ_'QÞ ]vº‰±: ŒÌL ¿~ýýÁðóÏW.sjÊÉ€ÿ@™ÅÎ.ªM3&;sò(Š0,¹þŸ!Hå󯿀Ô"ÂëtN3N ! Œf˜ö!Ö•56r哺lÀÉSOºÕ´¶Ú1|}ÿ‡aÑѯ ÿ~þb†—&+;Ðùÿÿp0|ùÌÁÀÉüAL€¢Ÿ €ÀüûÇÔØÖ~D ˜F’ÚÛ¬¤Ø1T­xÇÀÏû¡1@–á囟 ¯?þ``fâÆà†»Ï¿1<~ý¤ € Èô‡áÿ¿´ŽŽ#¯îÜ{W8 ¾|ÿñâÿÿðþûx¡ø—áÐæ? 47ë_†ïA €ÀŒï C ø$êþþ‡ÃÿÞù X å8&ƒ$`*¹ôÿßE»\œ$cl¢A-ÒÚ€(z¿mβ#ÔàJ:Á|IŠ Úî_±pòp2í¿ÏÄpûÍ{`zg{á/(î¡Ìÿ ÉL [ÿ1 Pó¬ ¿ÙÙ™ˆåÅãç¯6îüÏñùÛ ËÁ9íƒ úH™”Â@™˜H¾½|@Œ ÿR é6³;?´÷úIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/messagebox_info.png0000644000000000000000000000172211550446572024401 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<dIDATxÚbüÿÿ?% €X@£Ñ †?þþc`øùWƒ‘ƒ5_T\È_PWäïo†÷o>¾{ÿôÕ¶?~ô300]fø Tû‘áÿûJ€bA1î×ßt%…>__}.U†O_~1|ùöáçVñ›·^$žÞ{&öåõ›Õ@+û€ªÿ€´€ŸÓÍ fäfX1ðq²1<}ò™ÁBò;ïßÿv]e`“fà ñb9µC óá±c@ ¬] mÄÖüã·–Š–ü„ÜtknV6†ûO~3üüþ•ÁL“ŸÁZGáÿŸï Ož¼cøññ5ƒ‚™ƒ€’zߟF ­ Fæooa>V†‡@Í€~|ðŠ™¡oý+†o?þ2Ü~T 쟿3|†¹€¦óÇ{w+¢¡6€_T ð%£$Ã'þÿúËðüõ¿ ?~21ügøÇÀÆò—áÅÛ¿@À†|yÏ𛙉ƒ_À¤ €À ð ŸôŸá̵ ¡&, ßüaøÃþ›¡0@˜ èɼiÏ.½ÿÅðÿ߆§¯ß0°s³30qrò€ôØ€ÿÀècaüÃpóñ7†éïþ0èJ13\cøÅ`ö“AYš…áó÷? /ß|Õg†ß?¿2°sµýù>€ðõç÷Bÿ~Š1²ücøŒºÃg0ˆò=Ë(ÄJhïßeøüê ÈÎÿÿÀþþòõH/@cáã‹·Û?½F#01ýjüÍðû÷o†ÿ€ŠAø/0ÊÿñŸ_ ÌÌŒ Œ@Kþ¼ÿp¤ €Àüúö³ÿÙ…ËäDYÀ^aøýƒ“ñ09h1+HÑ`êûÉÀÁ-Àðóî£ÿ~ýhé H:`a¹ôüÚ½ŠOÏ3ÈKñ1pñ²1„yI2üøËÌpûùo†/%aEQ6Q†÷^0üz|¿ ˜¤ƒ´$%2ÎÄ0ñá‰ó¬B¯Þ·‰©©0î»ø™aÃÑ·À4ñ›“•™áÿw ºk÷¾?yØdµõ€s!@!’2#Ð파ïnÜÝóéî£Òÿ\üî lì<ÿ€öÿ0À¾ÚôZ7På b¸6€b¤4;/u[Ó?&A×IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/ledblue.png0000644000000000000000000000167511550446572022654 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<OIDATxÚbüÿÿ?% €X@£ÎAa ~û•áÅ×q^Ö8=n#A>6Þ7o¾¼tñå™7/ÞΪ^ÏÀÀ Ôõ ˆëˆn##Ã÷ßò¢2ÂÓ‹2=ÃÄ$X€¢ ÿ¸î=þá»tÕ]߉]Ç׿õ: hÈ 6€b{A{1ƒÙj9å˜w7ûýÿÝ÷ÿÿ¿üüÿÿ×ßÿÿÿþƒÐ_~ýÿÿö÷ÿÿ«û/«¾ä CŽ8H?@1AígføÉ5;ÈÉHI\˜…áé[†@~ýÄ?¾é_žíTPädðÍ Õf`ažr7@AÂà?Cðn·ëÏXÞ|b`àec`í÷ß ,@+þýð hÐ{ ¡ŸôÍ÷@ÊqŒ77»Øvþ”?’Ò »þgкÅÈ`©ÀÀðó+Ði@þ øþ è æƒw€øñV M¦§Î‰1@TÄè7 'ÖË@…@›Ô€>àºà¿ÿmFÎ  ÞªçgdøÅÆÉÀ&ªo@`˜¹yøød¸D€†Üy ô/Ð+< ¬P@áò†0¦Ù€bOÙ±Ã+À@`XØÿçajàbv Ù€Îg9L@ Ü@ƒYªþ‚Ä8()<ûùþ@ øñíÓiQŽ¿^ìÌ ì@“¹€˜ƒ ¢dÈ?`ü† 33$Ê€bùñ—áî‹sgŸo<ùëÍS. ØY!š¹€.áá„`í0CAò\¼À@½yáÛÇÝ lÀÿ—_7_Ûrt#Û¯_ ì@Ål,o€ áå‚x ¤,´„ùã_†kÛ&m``x² €` éÿ»«ÒN]y…åû_N`€²°B“B³€ Š3~üÃpdJ÷ÕOïf‚ô"_1½|pe¦ëºªÂµww]cøûùØÿ Ì ´?3ÜÜz‘a]uÖº'·ë\qÎ ÄÊ ŒÒsAúÈ] ÄgXÙSXÔ9FJIϘ‹—Ÿïë§÷ŸžÞ½pöýÛ=KmCÎÎçÃ4/EfïIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/kgpg_term.png0000644000000000000000000000160111550446572023204 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?% €X@D6cjhÃ$fQÆÿ>0±p ‹|¹užçù®Mwm6³q¼çãæd`aaÁÀ·nÝb &ò2 ®I RªLŒ;Wü[gè£$VïªÅÈÈdø÷×/†_¿~3üþŠÿþý v@] ©É`Ç4JX‘5¸TÌšKN’ƒSAÊ@µRù ƒ/333³1ÿøùóPk@ àâbàcøÃÀ  ñÙÑö­ P„áƒ}°«K’_š ˆÿÿþ1üÿÿH0òñ2Ú¤µ €À<{ÆpŸ‘A‹èªÿÿ™ØþÿÆð•‰™á1ÃK†Ÿ€Ò@ÈÈÈð¨èÒ½Û Ü`/Ø€›wN¿¾È %*´ø÷}†‡û_0\ùÃËÀýé8ãß ÿXXYÎ?Ï ø[”!HÁl@A xÊ»u%ƒI‚ƒ6'+ÃÁõffx¦ó…áÊÞ} @ß3°3r0üýøŸáéù‡ ±îI LŒàðg &(ñùÌ1†…®9@—}ûÏÊ nÀðç3ƒ*“>ƒÄo5†—÷1¼{ 7^VvvHx@1Áć ›œgø bÿÿóŸáúÝ[ –JÖ 2¼J j"š ¬ü l‚| <œ ÿ™€áMÄOQL bœü@Çdbdfø ´ìÂã[ ÷¾?gøÏÂÈ #¢Èð÷Çv ùya1 €À€Âó0¼Wÿ÷GDK!Í!ŠABAˆñï?† üÿ/8*ÿýûËÀŒ‹ç¯€  ˜?~ýgx L 8™~ýøú{qiÅô/J2ßX˜˜à‰ˆ™Äf&$&†ï?~ü Nb ¸˜ ñß/  ?32Ü9úöÖÏËò¯ÿùÆÀÎÊŠ–`|f°>€‚LC·–Obˆ¸sýÏä㻞$ƒ¤ÙØØX±d"fb‚„?@1Rš ËÂû>IUIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/kalarm.png0000644000000000000000000000227311550446572022502 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<MIDATxÚA¾ÿu b*2k$ü!ùíýÆÇÃÊåd ù7–1<IþåÚãÐËþšÙñý˜÷óˆåŸš÷ïB¶@IÍÏ ÿ10\ ò18þ¹Ç°™õ/ÃwUce;F ê¬ÿUt޲v­žÈèrôbì×àš‘ÃÇl ŒA¾ÿÆöÙÔæõýY–2øfôyÏÉÁ ú÷øøÝØý ø@ ÷ñÅ»«ÿ±ÀÒÿŠA¾ÿ6à*Py=Iú“  üø÷¬­ óöÿüüþùûýý#ú´úéð ã×sˆI@翬¬ƒ!à †<ò ßþeP54dP15a˜=e2Ü•K¾ñ 2032½ò™á‹0Òµ¥乘”0HÆ8Â03¹V6Äÿ?Lj@­š”ìžlûî,. mÄ4¢ÍÄq^<ßË]YSÎhÌÉ ¤hE5Oáþ A¾ÿôÚø÷3îàþöòÿôòòϾ¾WTY*<@ÿþþöö÷ûþöýáîïùôüïA¾ÿîäéãðùùÞú®ûúóññ(:>4FIùøúüûûþ ø¾üïÔÚÔ¹úÿæˆ ¨à×£Ó Ën¯aøÆ*ÚÊÀþþ  — ƒ€´*Ç÷_¾~ýÉðë/Ðÿ,b ÿ.2ð~i`¸}ê÷¿f}ñ €˜½€60ýgxðæ0³„üWQÃmÌ¿8~ÿ•&"v&FF.–/ 2Ì›>2<ÜóðÏÊ) _|a˜ÔÊ@,ÿXÉÿýo†Ý/Î1”üz÷ŠUÜy÷Ÿ‰AÛJ–aN¿'CX zÓÏ{þþ÷Ãg@Á øÁÀúîÈñW û¯þcxðŸ›!3Ô¡«ÂDGB„k-Ãïÿ“€6pb3 €aÈh¹Ä’áó]93+w=>!^#iÁÿßf®yʰëô×Kÿع²8yŽ0ðÃ`$ a€Í2 ÁÁËðƒ©’[B(WÉ@…‡KB’AW†‘Á[óÃ…k&¯ûüáÝ–™ Â<À@üÒ@h°C0'¯3ûtn131y^nV†D[Uþß 3v|e8v—éÄÿy|– }F1 `H2@1ã'^.Æïì,Ì ügøø›aÖOmf Ù L¬ ðð ´0áføý/GB‚«Ô@[LøÎwa†o_”Dÿ3üùù‹aÙ®??~ý`šÇÀÍ\Ó@þÿ×`üÏ0]QEÐARQ†áÜ;v†ï@ßI þex÷êÃÛïþûÏœÇÀƸ¤¦ €\À´]@FLá˜$ÃégL < |¬¿ž<þÉðãób–< ÷>€½ˆn#‡Ä7f†ï_™8ÿ2üùñáÙË¿÷þ3²42°0.•nÀv&&&nÆ_ ŸÞ~ÚʰŒ™¹(u_J xJddf¿õ÷ûw†÷o¿¾jŽe`aŽæƒ; 2+@1Rš ÌÀИyþ˺IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/bookmarks_list_add.png0000644000000000000000000000202211550446572025056 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<¤IDATxÚbüÿÿ?% A¾ÿc%%ú \$d  üüçëëëÙ÷÷¬)G óýýùÛííÌçùù¾ þþˆ1NY™‡—‘±7ØË+Í$(ˆW\œ(ñóî]†»‹3pHJ2(„„00‰‰10üùÃðâΆ½K–|Ûsþ| +Ût€bLSP(Š÷ôìµÊÎf``ff`øù“è66†ÏŸXY!ì¿ØÙ¸¹þ=xÀ°¢¥åÛ¾[·ÜˆE‡—7ÝÜÌŒáéSˆÒ t Æ?÷î1|=žáߣG ¶/_r]a`H E66IæOŸ 6ˆ€X€†¼}ÇÀxèÃÏ£G~|úÈTÉÀ t‰¸¤¤ @±üýüù?ÐI  ¿~!idÚþŸáÅ•+ wOdøûô5(°¾…¹€¾1àâyë@±Üÿüùê·‹-¹TT Άâÿ@[ß_¸À0CW€A §€ hèïÿÿþ2³2<½{áÓœ½ ß¾þÚ@,÷ÿþí>tçÎr_¿Øÿõýûw†_/_20<|ÄðäÇwÆœD†ˆˆ Ý_þ!?n{|ˆa׬­wd¾0Ì  ƒ6îÿò¥âßãÇí¶ÜÜïôùËh0ücüÈp—áõˆÿ30ÓÝ­O§^°ý›yK…á@±}ûïïÿÿv½~ýøýïß“œäå¥x€1òõÆ/@-þ¼fxÆpÈúÉðõç†7ß3Ü|wŸa‹Òÿÿ9þs³ÐÙ¬Àäüÿïßë¯?>ðúï_}my™»‚L ³DDýÄx€†½cøøçï¿?þüüÇðþËÕ¿þZØf`\ `&“ç¿|ÙüäÓgyQ Ií7^ª Z~¾ ÊlÊÀøËÀÈÄLÿøØþþÿ.xëêë37àРKØ¿¾ûñ}ë÷×Xõ¯ÖÛóøî_!#sVeE†ß ߀‰õ'Ãá7þnY~¹åˇ?%„a33ýýûçÇÿ¿{þ}ütáÚãGë0\ú¯'¯«+%(̰z÷ŽŸ+)þþîW'#ë?€ÂjÈ;À\ÁÀÃÀtç¹$ë­CÂïv¹yJò΋G’›÷Éûùá÷lF&V€¨ ™O,6{IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/news_subscribe.png0000644000000000000000000000213511550446572024245 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ïIDATxÚb¬©™Îð÷ï_†_¿~300ücxýú-ƒ¯$#õýû+AA^Gaa qq!1!!~þ‹¯½:uê¢##ÃkF @, mÿþ3|ûö]‰ƒƒÍH^^ÒZQQÚWFFBYAAŠ——‹……‘Èæeàçç‘:{ö’æß¿ÿ^3112 !TT­¯¯â ª*§!//ÁÀÆÆÊðçÏ/ «~2|ýú‰áóçÏ@CØDD„”U€. ~òäÅ!€b:Ý\EE<#$ÄèŠo ·nÝbføþýÃÿÿ @[y€Dr_¾ýøÉ !!Π¦¦d{ÿþV&&¦ßĤ¡¡ÐíèhÊðâÅ+†?~3|úô&ÿ888ÁÎfgçd($,ÄðôÙ†kׯ1èëkjpr²¹3332++ë[ Æ÷ ¿ÿa––ôƒáË—/ >|`xòä ß?=|Äp÷î]†ÓgÎ0ÈÊIqªª*EÕ±ÓÝ»OVߺuŸdÚ‡~ýþ P`üe`bbð_`|a`cå`àçãcxþì9Ã`l¹ºÚ#Á €˜ML\ÿ òÄKK‰0ýøö¬ðç¯_ ÀŽ¡ÿÀÀ””bàä⮪¢Æ ¯§ÍúâÅk€†#ëõ—Ï?{*ñÚîó§¯ ¬@?óqp3üýÿ—á0,@®øúõ+ÐK_éCŒÁß7ˆ››‹áÙ³ ?þü @Ìüú¢?ž¾yÎþ›ç·7§ ;ãW¾¾ýÊ %$ÉðëÏ +þƒ”hD……@QwäÈI†3æ/¿qãv@1m{¼Êüùß›.ÒJBÿ'¿ídT`eøðõ ÃÍçwÀšþÃâÏP¬°3¼yóŽaþüeÏ&Mšt~''çc€bñ3õkL‹ˆu?ñú8ÃÙt™3XY3¼{ð–ã-;ƒ”˜8ƒ/03lß¾oí£GO«€{ ˜jÁa@,*2òâ;Ÿí`˜udÃÜsÎ)œaÈ“)càúà Lÿ€Ü»råFË߿泰€b†™ˆåê‹+/3ÌÒx-yÚ´1$›&18*92<½öŒáу7o?x¹ø?ÿv`zyýÿÿ?t@Ì¿4ÿŸûüîÓ_;eãÇŸ1EëÅ2ÜØùôﵓg|~ó£ôë·ïóyx8¿Ò$×þÓÌÌL`ˆùŸöÿ×—žž;/,$kÇwõé•Gžü#×ÏÁÉþôçïŸ œœì ¸ 0§*«{/áóIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/kgpg_show.png0000644000000000000000000000135411550446572023222 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<~IDATxÚbüÿÿ?% €˜(Ä"V¬Ø¥ÇÌÌèÃÈÈàäjñ ÃN]W÷ñã׸4§¦ú1Ø€oß~mRr 0ï0 ¾Ä»ÿ ì@ 6 €ÀüýûOHýbfn„z†‰Hš 4¿9ˆ·, 8x%##ãFF& NÌP ²ˆ¥xH €À.`bbþ ¤BÿþÅòóçVVv666 8#ÐuAþ‡¸Œá=ÿbv XH/@ øüù#Ó§Oؘ™ÿ3ððp0|ýú‰áÇ@C¸¯‰ˆˆÍûþýÛv~ Ò§þüy¤Eþýûû¤ €À¼yó웫«-»œœ$Ð.°­/^e˜?ÕLQQ‰Mïß¿cºè+È@WŠé· ô“Ê@,Po2Þ½ûè70*Yää$Aa ""Èâ9ñû÷ïý ´ÔÈðçÏßÿÿþýcxúôÅ«û÷Ÿ¥5n °@Iž;÷­üúÕÔŽSö÷ïß /_~`àãbfa‚„ ÃÏŸß4+ƒä浊Ø>>žßnnNaBB|,oß~fÙÈÁÁ4øж' Ïž½ü÷óçO¦ïß¾ûôéÓ !¯^}Šé °,,Lœ¢`@y`èÿgøøñ-Ãw® Pªabx ¤Ÿ2p0|ããâcd&Suu†ß߃ä”ù•Ø€~æãæedàf½ ß« Àpú € È`ú ˜Ü>ÜyzãïïßÀ0‰›ÇðãÏwp ‚⟇…—áæ£[@ÿ°~†8Æ@±@Œ q 8egfp¦ba`.qÕóh1Ñaþû÷?8æXÙ¯>¾ýûé}¿~|¯ºê?ÃOfpn0ÝG…Ï ¯eÜIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/blend.png0000644000000000000000000000060711550446572022316 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?% €˜(IJ<ˆñ™²ƒÀß_ ÿþE¾ñ$ü*¢¿Bž202b`|üá@±(:1ˆ˜e0°2üJ|â·Pü‰ý‰ÿjõwNFV€bùÿl/+Ãs¨!ï¡ì÷PüÉ?øÿ… €B„3ÈCP3!aFÔ Š €(6 €(6 €(6 €(6 €üÁ‚Aü ÿÇÄÄÂÈ Ž(q f§Ht2B1Hão þM_ÑÍÌÈÀ @,OO1¼½²†ÿÏO yÿ  >!áÏhô'ˆA,ÿþgø @Œ”æF€¢8 "®_เéÍIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/1downarrow.png0000644000000000000000000000145011550446572023332 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ºIDATxÚbüÿÿ?% €˜(Ä"ØÍfçb`0øtÌ·¿Ìïþqq‡0°±gø÷_š¨èï? †ÿLÛYØ9$þ³°2ücf»õo™Š>@ P’âµè*µbøÁÌİýøK©ù‹nN``eta`aû Öý÷7óßÓÕt¤þó 3|øÂÈðúõ=^€{áÕ‹¯÷¹™˜B-dÒR  LdÌ>ÿ¯dàêðõOŽ‘ª€ƒ‰‘,Ã/f†¿_‚ôØ€wo¥5g¸õü++Рh~1Þ\†ŸŒþüSá(U7R`¸ôœ‰áÕ›? ï_¾g`øÿ¿¤ € (ijáî½ÏÓj§^aàøùŸARŠÁÜI‡á?ãtf†ÿs´ ¤…ïçfxú–áÓ»O ÿÿý[ÆÀļ¤ € °030r6®ÞýìÊú½O¤!ª¨.à ./jÆ'"`ÿ_P‚áÁk†Ï¿1üùþã3K=Ð `­1àß_ _ÿ¿úÏÎRݽðîŸW/¾1È 12(ê)3Hk(2<}ÏÈðîÆŸŸaÊÌÜÔq5 1€ˆÖ²±mzûñïô©«1Hñýcàábcøò—áí§ÿ ß?~©\ÌÀÈ´ˆ€^k ˆü2 |âÀæe`àe/?qñ㥃§Þ1èË30¼þŒ„OßQùû.PSzB ˆÿ^øÿ² hûÎÀÆ’½z÷Û~ýdЖúËð÷Ó× LL ÍÐ  ¨ÿ”úX˜Ž|ûñææƒ¾}úR1hòvlI €A™‰1ú.º0È%œÀD¾‘•ó?£=Pè#ºæÿs„ˆ‘ÒÜ@çF€^íå⃉Â{IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/irkickoff.png0000644000000000000000000000071711550446572023203 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<aIDATxÚbüÿÿ?% €˜(D±D±D±„Õ€FFÇ —Nȉü<ÊÄø«‹‘ñf<#£6µÄŠt<‡áû[Íÿÿ}LþÿgaüáÃljˆ›¡?˜_¿ÁÀ d?ûóŸáþÀÀ€Õµ„Õ€“ ^þüŸÇÅÀ û¢ùPw6µÄ„CpÏ †Õß | K6©õØÔV˜ŸÁNH+1;ƒé_±@L8Â@P†…EN…™™AÈd`PþÇÀ ŽM-@a5à7ƒ¡Žªª Š¤$ƒ/ÉÀ -lj« 6òŠŠ¬â"" ²@¾ 0X€b&ØÔVd¹¹M•€¶³222ÈùÆ@,ÎÀà„M-@aF^NNåç_¾üùóòåP€3<#7ƒ6µ8\`/âõIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/wizard.png0000644000000000000000000000160311550446572022527 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚb<ÏÀÀö—AÿÃço 7>300020¸ *r-úôáϹßßþx12‚Ű€búÃÈhÆï¤qJÌC÷_ü‹!TÊAe¡ù¼0q&1•ßÿÿ3}ê~Äo°`€bùñÿÿûßÜÔ¦Oز¹çž Ú=¥ ?^žax÷üËÁ¿þÿûÍðŸávWÐÙ×n½Ðõj×Néô6£…38d9>\>Êðöë?Á  ͬ@Ì‚³?ÐØÿ¤¹9?Iøš02²?f`ø½‰Göƒ›Ö÷ç¿“¿|üóçß_†+@õ¿Ñ]@Ì¡ .2v*3ôû«øXÅ€îùµ™áÇ5¦¿Ì \‚¬ ²¢L¼Ÿn|ñøðþÿ>N†û¬P×À0@1îRæy 0á? ŸoaóZò‡aWÉc†oLV ._}øøÁ“úÛŒ[¿}ûöæïoTGÃ:aö=k5nÏ`XØÅưåF¿Âÿÿ׬þG 3ýOÈÿ¿yǾ/ÖfQ¼ÀÐàÀD€bXÉÉÌ8‘iÓLsu¹ß|œ­þ?KFà.#û—Ò²Òÿ;wïþ§®«›Š-s(Ã?fÆÿ_~ÿgøÉÀð÷݇߿_]}ïöþ+GîIÙ›¶o “”dNIJò>tèÐÓOŸ>G6 €˜CY™þ‚Ѐï@ÿN¿z÷ÿÄFŽCÿ„øO¿gb¼¿kûv?EEEæäädß={ö¼üþýû˜7àЀßÄò¿w¾³s|ÍÇËðõÿÿK,ÌÌOwíÚ壢¢Â”˜˜è¹wïÞ—?~ü8 2 €˜Pêccc›ÇÎΞÞÚÚúçÒ¥KÌÓ§OŸ!((˜’ ¸ >"\ÆßØ8Þòó2¼ÿó›áÏŸ? ÿþ=ÄOáà­¥¥Å”à}òäÉ'D”üÆÿ¿ÿ@†<8x𠯱±1³ººº@±0ƒì¨¯¯Ÿ)!!q À´èF]Ý)jhIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/reload_page.png0000644000000000000000000000217311550446572023474 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< IDATxÚbdHg``øÇÀÀÊÈÆð÷׆Œ@üâ?@ÌÁ*ÂÂ̶Žáûïë>üje``yÄÀ*”gJ212éý ÖÈĬ ™¾12Ë²Š‹ôD÷¦YjØíbøõ7‚áÿ?¸€b“Œ ¿ÿâdüÏ"Á/"Ì#*ÍÎÀÎT÷ïïO†JüÊ >V– æ¶ ê‹-Ÿ±ežÑ?æJf–¿ÄÈ4àƒª¨Úìh‡%u †¿Ü_€Žù 6ùßÿÿ@§°3|d}ÊðŽãƒ!‹ÃÅõZçOíûõû{ @±Õ©èKl¬Š.–»"páÔ¿ó â Ò ¬ÿÙ€üšÁÈtÃ÷÷îÿºÅ (£Â 'jÈÀÆÀ.óë÷v€A¾ÿ…aD_¥ø™äDúVÊÎÐòóóêîúúûÿ$#9JN ßó´€¥~µô÷ñp øA¾ÿ,+L þï KW›…ÖáêÞ`àñÿ ö "'¯)*&ÎÃéô©Á™†ÿÿû‘ÿöýA¾ÿq í<"< ÿÙãÞÆÙÁxý’ ùêò   ½üòñôìyÿþÒöý ý ûˆ‘!ŽY–áË_H$2}`øóO‘Kˆ¯á?‹ê÷¯?>ó½bøûO‘áó·G Lj&ól´Ì˜~þúŰçܹÄ ¤Ç l¨døþ/Ù×Ì¿9Ê%Z²unëÝ+w/ò2°|ýLo¾3È ³Éç·¤óþ6¾Â É`Åð2ï+;@±€𙑛ã?û¤‚ÐÂ$SOe6Ý99!¥í¬\LýÿËÃÁÃëä`%~Qj ûO÷~Ü–c8uáâ1€bdg`feæœÚÝšÎlð–aÛ˵ ²LÊ rÜ*ÀdýšÎþ0ýbxúï.7+ƒóÏX†)ÍÛßî?wÐ €€.`þ÷ï/ãçÏŸ>3°}úËðòãG>– ßÿüaøõï'Ø€ÿ@ÈÌÀ ñÇ–á÷=>†–5Ë~>‹ý@A¾ÿ[ üü÷‰a;at"> ½¥ÌúÑãÙÙ þýüéîóëèäá¸ùû÷œìˆ‘!Š œà~#âÃ( e‡Æ û•YëçÞ»sû¢-3ï†À(ûÇú—•û+Ã÷À´Í ÑÃÂÄ@@™ë;Ã`úÿòW‘•]¬–‘Sû÷ŸŸ¾ ß¾¼Tà Ôtí×ïÀ@gƒ`ƒ)nƒô¾®IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/klipper_dock.png0000644000000000000000000000166711550446572023707 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IIDATxÚbüÿÿ?% €/Ê300ÿd`bÏ(wÏHó‰²2b +VlZß¹äÐ:+Y †ßž3|þ·žé2DSŠ(Úw ïþüg –ÿ\Ü®|.Æß9Å%¬eÙuŸI<æ}ÌpÉíwôœ¿¶Ñ¿µ2™î1pÌŸ8íÿåÇÙŒ@”ØÔ8 †ÃÃ$“‡ï^ú?ëÈ›ÿû®>øï8ßã¿è$©ÿR-JÿK—ôÿúþÿÿ gÞþ² ë¿1ƒ!#’óAÞ †ûÞ\Ÿ]›þé¾kÿAàû·ÿï=¾÷ÿÍëwÿaàÞÛÿÿ÷l\ý¹‡ø24ˆéÎÅo«Xïfàe|Æpïõ?NvEEaA†ßÿ¾þf```xÂmÍ`è`¬ÁÊ ‰l@1=zŰðãáÿtž1\»û ,ø1 Í€øÇ†ï?4Õ%®‹y²å˜r!@L1»vüîEÖ{ ¯_ÞgøýbÀßÿÍ?ÿi +$…ÞHú1[hFÉ13(À  & º?W¯þÜÀðâƒã]†;Ï€Ö2mý 1ä k¾g`PÑ’a¸/Ì• Á 3 €˜À1ñ–aÝ‹3×þë‹ÿÏpèÒ§@%_ÑS"@1Rš Îhq­Ý÷&IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/folder_new.png0000644000000000000000000000147311550446572023360 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÍIDATxÚbüÿÿ?% €\6ú30±lÀyw1“áLÕj ëÿÅe@10¸mý €Ä4³šj¤€˜—v€b)<>Ë CÂBžÑ}!— Xì+DŒŒ ÿ€Œ-×€ü˜3º3LºLšáú´é@îK€ðê Ãõ— O4q ¡&^5/ÿÿcf¸1c @àc÷ÿÿâUÿI ñß@ö ˆ Þýd`üÏʰméÞÝ- oRþücøÅÂÅð?þ=üaÓ¬g ®‰R0 Ûß »Ú|>²1¼zü”Á"A€aûìí ŒÏo1ˆ}Îpñšá—€0Y~ úúzßá> ¦ßLlÀÀûÅÐ^ø›Aþ÷I†oÏ¿0Èÿ;Îà龉á?ó+†Çï¿0¼úðƒáÍ×ÿ oýhÀ»oˆ0 ™O7îÝûÉpjîQÛ|cvYFaCF†'+1Ü:ÇÈÀüûÃkó`&Žÿ@12üzåóO„ÄR*»—!0ß‹á÷£o œŠ ,< BßLž1D¸]ax±ú Cí{7f. ‹8À|A2 €XÝ×`¸\y’Á[ú&ƒ¤ž%#×W†ÿ_¿0¼9ö‹áÐII†‚ o…?1°þd`áä`øýÕ€b9ó—;Oäç‡I&IN ןd3dcx{ñƒœ7?ÃÓ" }ß<þ]db`àZÍ ½Gîî}ÂÀp(ñ,(5£)ƒR¬¥â2A‰»û.3–mð•µã§*Ç?9&ö¼ƒ3З@Í÷ïþZðŸAQ–•é7ƒ³£ƒ•µüî]÷×00ó} f›˜C.n&ú’Ì2R¬ Ü\Œ ,,Œ ìl ß~02Ü|Ä +ÇÆÀËÁô1ƒÐ?™%%¼rY‡÷ãU€A¾ÿüüÏHáíöÝâò  ïé÷ÿ͸ R<þô =&<jþøóºh–ë+yy±0s+eaaQ!.~A6†¿?2üß=›AñÉV†/0°i0 }zé œUx>~øÀ@Ì />}ø©k¨/¯)ÌÏÊÀt È+oo3ðœÌ YËÀòí?Ó5+¾0°0¼›?—AÑÆ–AÖ×›ñÂE=€bbeaþöøÑ«¹Ï>úÊà t";У?´’ Ãc_†o«ç3jë3Hˆ2¼ªªdPÔÐ`à•–f¸>eÚÿ}·nõ³²’(áÜýðþ§™©©‚º  00YþiX1ìÙtè••ÿM-e4´8¶\Z¾üý’}ûšÿÿßA¾ÿÿþàãê ÄÄáI]^'üûºÃî­¬ÂÐîºÔÙcò¼Lóì þ#ýæåÒääîì¨þA¾ÿþþµÃÃÜÁ D²ÅØßß°¥–MݰÐ'öz1êÌÌõïÌ=  õ–ÓýýiˆÑÏ8)3113üøñÕè΃+®â_^/L{¼ñŸƒÖõ"j V¿Ÿ10Ü|ÈòëÚî[\ÜZjRLßÅÄ6|ÿ¾ €˜3#ãÿsÀÈët~qð…ã¹¢ŒÆœÀôê3ù?¼ïprûaeYñ˜Ù„YI›ƒC €Ðr##3ÃV6†ï¿.œ?ÜõE™¡õöŽ­ïÿ²4p°þÿöˆ¡`ïïßÜb¯_ëoùú5 ÀéIgêzŸ/6IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/laptop_nobattery.png0000644000000000000000000000206511550446572024620 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÇIDATxÚbüÿÿ?à FF¡ïìLA¿#”üC 8åø^½ÿÂpöìÙ7§o?õà͇•¯6100|e@ ½Ä"–iÈÖjª¶ù"©Ë ¢gÆðýÛw†çO_3ܹó„áçó» ﯟd˜¶lñ’×_¿%312ü‚ðù߀b1”¼ l¼ƒ®_ûÉpâèe†ï¿¾3¼~ûŽáëç/ jšZ Ö"ÿNïXpúû·<†_þ10üý1 €Àð°ÝùÍó+ŠUãŸ2ƒØKn†O~2(~üÎÀþ÷'ÃÿSO^Ÿ8Ïðúù§_þ3üÿò›A[T„A•_l@ `øó›Eð'ÛÞë@¿m`bø|÷Ã' -äæ¿@aFFu!a}Ii†ÿ¿ > &Á’føÇôÃo þ tãO 3A|n fbf ÖWúáPâ€ðþŸ P»(+ÍÄ|!Š¿B5>†Ü ­"#óïÛïß,¿ÿÿç‡$@½ðæ¯Ãëo} Ÿÿ®f¸Ã²›áÐs6†/ bR¬ o}gØüó/ÃÛï_ÿú12ò(³³¯P?ÿúuPëE€‚xñ7Ãß¿Z ¯þ„1ì`öaØ+*Í`šëÅà°h+ƒ¿­Û¯o  ø–abZŸ‘áß߯ä(/¤ €X )_˜?1p0ü`øÈÌÎðæÎÅ—¯Š›_ä2ºxK25)IRÀÎŽáó¾} ß>>Ò @,ˆtÅƬÀÐxÃ/ÉÐpîCÞÍ ·˜ÿ¤\¿‡wµµ^MœÈ°vãÆM·˜˜#:ˆ‰ €Â–ûÿo†×BÒ -OY®Ln`ø{éЋÿ>,XÀ°}ÕªË÷ß¾—zÿþH=@]ÀÈÆÆÂÌÁ F°;¾3±0ð}ÿÎÇóAèûk†G‹f3üùÎÂÀ*"Â`&!¡ýóÕ«ºïÞU•þ ° ~ܺõáϧO l‚‚ yøøÿ`¨d½À)ò˜¸132eF, +ƒ4“¿ŽN¡²ŒÌ ^€»àÝŽ!û‚‚òþéè8}~ñ†WúÎe•· ÌÀÄôò 3CõW†Åxrï×§/r€šn€´3ƒ¨Èf9Yñµ¹ùžÎ!>* ß¾üexùðƒ P÷÷ ·î¾b`dae”—fà•QVzûìµ÷7o÷103¿A¾ÿG  loIH>4Ýáö÷ìé[>øúú* 8'ÂÎéëî÷ %íàÞ-üïò°A¾ÿ6AF0\:1îïåçô3$ ¡¾ñНï [Cìðöîêê1<<RA¾ÿ j+1%ÿüòõüÁÕîËÚô êðúÕàõ3& ëëñûûýêkˆETZÔîüK^†Ÿ2hŠþ†'#ÃËïÜ ¯Ÿþdxÿå7'ÓwU1†w_þ0|øô¨, ?Êù•CDH €Xxù¸ù^~øÏpäì† 69!FdgùÍàgÌÂài,Å !ÄÎ0où#†—þþùÎðæý;®< ,œ\lA¾ÿÿýÿýø÷ú¢Â÷1 ,cHòöý„§ã—²íóöùõ÷òþüøý ÿýˆåÛÇÏ_øþÿæf`úÇðïß/†³w€ñ탈ÃçïlŠ®2Üyø•‘õ/PÃO`‚û ÆL@¯þùôå@1½úê8Ë¯Ï ÜL ÷10°^jZpð#ÃG_˜3ü´áÏo`Ä“PٯׯïÓ—wŸ¦}zpAZ” ˜ä€Š~maùÇào)Èà®ÏÅæ,LL¿!†ÿÊÿùÉÀÎÍËð÷Í'†ßÞÏ ¦ÿÿ½âü:þ_ÄĸŠ2°þÿÇ`­Ãà§ÀÉ`¦ÁÇÀJ÷@›~å8¹Ø¹¾ß¸yŽá߯UA¾ÿ EûûòôÌõéìF$ õñòÎÚóÑßø ³ÝôöóøÎÑæüìèZ݈™Ý èG¦÷?ß}ÚñéÑ3%~n5> !†ÿ3œ¸òáÏFN FnÆ·Àd~þâÉßožF5Ÿ†@12ˆ¶A2$Ãÿï?¹ÞçÈgÖfÆ3(š}úúû׫7÷þ~x3óÿ¿¿Ëþ¿cªa€KÌ¢Zt›ŽIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/down.png0000644000000000000000000000162011550446572022175 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<"IDATxÚbüÿÿ?% €X@£þt Á`bb¨5Òk’åüûïÏ_,PŒ‘áÕÇŸÌ'¯¼žþïß¿,°B ½ÿ/d0؆_ÿ~þÂÊάלeÂàa-Çüå÷†ÿ1ðq03œ¾öŠÁ1z½æ×ï¡VC, ˆ ¸˜þƒlûûÉÅüŸáøK†…g¾ùÁà¥ÆÌ É²€áèõlÌ`ÅÄs#Ì[@o>30\yòáÊÃo ^g:¨dÈíÿ!z€ €À.øÿï¿$Ã÷?" þÿüùóï¯ß@uÿþ20þüÎðÿ×w ‘ì €bß¾üâdøöG èU6N–@­l/û6]1Y ¢ïŒ?þ‹ð³1Üüö“áÇ×ï ?øû×ÿ <\¬ 6F_þüÛËÁÆÌyãÙç×@­š6€ã?£P[‘µ°®ª ïßĸŽþÂðëûO þÁðþÃ?IA1†ÍÖìœlŒ2o?ÿa)Ú€‡Á«—Ÿ“§-½ô[—aãµ ÑK>1l»ô…è|–??^~ÇàÕp‰¡så]a^†Ù«n23üúð…á÷ûO ¿Þ}føóî#×_WK†×w9ß=;g Ò@L0/hë1 ~ùù‹áÎ…@Å_¾~g`üöáÛ†ÿ_00üþÉðíã{†¯>2°ð±sÁôܶ?­øœLEØX˜~|þtÁW†?@Ìòÿƒ€Œ0ƒº'™3ë—¿ÿÁô<ýýä(ÆÈP'ÁðÌ[„áôõ/ o|cøòù/Ãv6†ÿÜ °3<| ëï?á±@pþ3üeøý›AAV……áÍ/†ç¸10|ùÆÀðîb ÝLÌp0Ü Œÿÿ1012€ñ#`Œ^}ÄÀð¨ù?в¿@üÿ/P¨š¬ú/Ü€Bdf„(z´ñç ²¿ÿþüþrX¬›Õ€‚{ñÏff`zâ§1¬Ûø‡(ËÊÆÈÀÂÆL'@mÿX!vþG@pØØ˜îÜùÏ Ìò—áÅË OŸÿe”`&K€^ÿñh90A1²302ÿg„é ¸.]øøçÁà ìœ, <<Œ ÜL \@ÌÍËÂÀ+ÈÌ ÂÆÀ/ÆÎÀÆ Œ•oþÀôÜG÷½¬üõ÷w·b27ƒ°+— ?Ð0 «1ôüö+†—Nüü÷ìVL@Á“2#ã. ùUOX˜!MPš7à'§#3 #0Þ~ÿñçë›·ï>?}²éïÏ/3€!sáÿÿ °>€b¤4;»ç!ð¹½IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/spellcheck.png0000644000000000000000000000150711550446572023347 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÙIDATxÚb````â þ Är `Ä7€ø%g"‰kñ1 > ĶÄ$Ä8 ˆy€ØI¡ ó17«#‰Ç±0›ña€`Äßø T’ ªð'Ôuø’û¡–-a` %¨-ÏXd*T'û1+oâ÷Ì@BˆSô/30T[00Ü F ¨•/¡VaR@ìò0zY†!W™¡¨‡ €Xš€‚ÌPw-jšÌð *Î  F†/@I23wé23k~ùõ‹á)ÃT€bùÊÀ ôìsˆ†ÿP›~14 ^10(=ݬ+Ài(&Îpûñc†£ €þ, A&†Cþ3<þŸ!ÑáÈóï tã†t`ÜÖXëéIËKI2œ>}šáð÷ïSòÅì@5ÄÂÎÄ dÆÎª~øëï•/¢Î¾Ã -  zô=}|¸99ޝ]Ëpôí»‰@éXT³Ù?†¿Ê òî†úúÒO•áÈÇO@W•1C³0p?ÿúÍ*øõ£«jZ&ƒš‚,»’›«ž>ßc‡ŽÍ™Ápè×þßÀhc…jF6 €@€Büõ¿—/|T%E¹¬íYþ?Âpdñ\†Ão¿ô•ÿGÒ„l@1[C¢îÝ—ÿ 2âŸ_X‰+é0ü»zŽáвŠÞ|éÚ\Æ€¤Ý€ÀÉ ÷~} Wýú–çøÑƒ {_|jFa53g#³ˆÙ šx@iýë©woŸšžxõ£h`-²Ÿq`'žÌçå}­µIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/fileclose.png0000644000000000000000000000170411550446572023176 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<VIDATxÚbüÿÿ?% €X@„‡‡'Ãß¿þÿÿÃðùów vv¶|qqIA‘¿ÿ2¼xñòÝ£G÷¶ýøñµÿÿÆË?~üªÿÁ@,0“¾}û‘®§gØÊ¥§§ÇÀÏÏÏðýû/ Â×â/^H\¹rYìéÓG«þ÷µüé &˜ Ín3::Ú¹LMMÄÄD~üø ÿÆÀÉÉÁ ¬¬ÎPTTÃâââÛùëׯ"˜>€»àÇoZÚÚ: ^¿~ËðáÃVVv !¢ _¾|gxøð)Ð5ì ?þaOdxüøAÛ™3Ç÷µž ° þýûŸÊ²éË—/ ººª@nß~ÈðèÑS^CC qq~†÷ï?389ù2³²²V‚ôØüüÂ>üe`bb:—›áþýg êêŠÀpyÈðçÏ? Ê ÷î=c8sæ6ÃïßÿÞúÎ ì Ò @`ððð ?~ü’aÍší ÜÜ\@/ü`¸sç)ƒ’’,Ð °æC‡.5þf¸víÛ7O¸¸xy@zìP²²²5=`xðà!ƒšš*ÐÿZ ì@W0]ÆÂðîÝ[†«WÏ]ð•Oè2p$0Ø?~xÿóç âÀ€úÅ ¡¡4Džäª;w3¨¨È1øû;]ÊÔøˆÿ2|úôñH/@ xûöå¶gÏmbcˆ‰ aÐ××dxöì5Ãôéó¦L™ “§@¯(3”——€m% 7o^é &H4~é¿zõÔ`l0ܼy¨ùÃÌ™ €ô#†W¯ž2L˜0•çÎz—áÆKÿ~þüÖÒ @Œ ¼ ¯¯Çðõëçbmmó3`´þj|LÚÿ€~þJ' BBà¸téÃÙ³GZ€zë€zÿ $3‚kâ™3‡X_½zÞ¦¢¢Ë($$ ö/Û/ æcxúô9ÐæË wï^ïjiêçB€»ÀÀ@E_Aɘö¿™03³” ˆ¸sppó€BÈßÞ½{¹ÿÇïÝ@=G`–þû÷ €)ÍΛðx™èûúIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/about_kde.png0000644000000000000000000000221511550446572023164 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚb Jb†OŸ>1|üø‚ŸŸWMUUmµ††š< +Ç”)“01±xèêêORUU޼yóæýwïÞ;yòø €ba€‚?þ8þþýÛáÝ»õ?þâ/(ðÒuwwbüøñ ÃÌ™ÓT^¼xšíããÎô÷ï‘•+×›=zT €XXYYšÿ:;9Ù®×ÔTç9snÈåËö322þšËøãÇwvvÁ˜©ÞÞnL Ë^¾|Í0wîÌoŸ?Ø@ ..A ~•œúo^¿ÿ¿råæÿûóïÝ{ð¿¥¥çÿ‹¯Áüoß¾ÿŽNú4§d@A¾ÿBBQ))5TT`Öëëíÿó÷þÿ¥·×ÿ¾¿ÈÿúùûÿççëÿÝÝâÿööúÿ÷÷ûÿ……Šþ›ˆEXXŒ‹‹WôËçoÇ?y¥yÿ?'#0P¿1°²²1 q2Ã…áî݇ k×nü&!¡°I_ßDìܹ#¯A¾ÿÀ&'$03-% û¹×Z.üïÿ÷÷øÿûûÿ bbe  ®ÞÞÜñËËÁqˆÉÙÙÞ.7'žßÊÞŠéÝ—¿ ×ß00yÀÀðïï?°­ÀÐg8xà(Ãïßþýcb033bÐ××dqp°fdd A¾ÿiüüÿ øüØðøûø$îùúû»Óé  þÿîî¤þÑÑ˯A¾ÿÙÙ׺ªªªëÛÚÞJHDòû üïúøþûèÛëû÷óôùððìÿÆÆÂ¢ˆERRö’¤¤ü%&Mv¦_ ®Šö\zÍðöÿ')a†çï>1°ü`Дcxõú +Õ+O|0«)@±hj1prrÅGG‡)«*mýÉð÷»Ã¹K/®?ýÆÀË/Ê`¦ Ä (ÆÉð]N—áêµÛ óæÍøtôèÞb`tn –Þ2|ûöIS@€Ÿùýûo 3gÍcxõâɯðÈh6iY†÷ïÞ3lX»úßÊg/þ¦¤¦°êëëcƒ”J·ñs€b°¶ö`å22²Üâíú˜iæ%‚úûgÿ¥¼­[ü;³°·÷8íïùs2ÏJˆÄ i`ºÿvîÜq _ ˆo ‹3<|øèå;Oä.^¼ LPow£ìÄ… §M?~|kTs”ÿ@ƒ­­ƒ””<,S‚³µˆˆPL.^CCÿ¸¸¸ÌN °(E‚ÄÑ@€š®ZÊÎ_IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/history_clear.png0000644000000000000000000000225711550446572024104 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<AIDATxÚA¾ÿ)¥ úþF!%\%= èíõóÜâòÇÝÜï¤÷ü·ûýýõùÿÿˆf+‹”Š`§Ÿ§JЉ/ƒ0Ëo†_Ÿ?1üÿ÷_€áÝV† ¾2¬ßr{É“[oˆ<@Ì â! @Ž€²†Èʤ8£P™ÿo¤_1XèH3üùú”“ù+ƒ±¦,ÃçÇ·~ü`зÔÒ{þì£Ù›ÇŸ¶0°2} foNIÞI¡±ÁÚ|,~3HJ°3HËJ1ˆˆ 2HI‹3ð003c`føý™G^Fþþí— _žÚ@Ì,,&]B,Ÿ™<Õ¾3èk1‹ˆ2€;;Ð¥ÿEDÅD¸ÿ¾d8sý-«ˆ¤öÃãwΓ 8·¨(‹µÜ†¯ž1>|–áÓ§/ LLŒ 0ÀÄÄÄ @W02°q22˜Iÿdàe’JA¾ÿ<ÿG<%BE?»»ÇÏÐ×ùýþýééøëìêðôÚÚßE@.þþú3A¾ÿ'i -âáåëÑÓÙÿœ™æº¼Õ  뢜¾¯Îôüˆé?#;Цßþþùv²°°ƒ½©ƒÌîM R¦ j–f :»72¨Šò0¼œ>ƒýâU†äbo†ªŸ‹ˆéï×_ŸùÔ4õ¸¹xþƒLF×ÿS§Tt4€^àÓ×gfxÉÀ{ê$ƒ\| ÃÏ›wn|ø @ÌLœQ–ÊÆ’Ú|?îÓÒ7`” 3ü;sŠá¿€—»;ÃÇÇ~nÙÌÀ¯©É Œ~CC†ogN0Ì>ö•¡ñIàq€búüüÇ¢§÷~ý»þš‰áûw Wn\gøÇÅÍÀ¤£}Q ­oô X¿~e`غ‘áÒî£ ‹Ec~üü"5 A¾ÿeæêéü"*@)-ï÷çÞñ÷þÿ穪àÝÞ¹¸åäóÕÉë 칇ˆ™A$ë÷ïÏÿŽÞ¾÷ßBRWRŽ‘ëßϟ¸€¡½q=ÏÖÍ bÀüÀøå%ÃcS†_?þ0ˆÓˆ•<#ï¿+ÚtA (…|ùöžaû‰+L²¬"²:2²Â ?c`½yAå÷K†?/ž2lWó`˜à0‡aljO§ìã•We¹óå×o€bd= vf`ºåÒœl ÿ8ü$”¹â•TØMxÿržšÄðûןsK.¼{Ç?OåÅ܃eŸsR„øù½Ï½y_`*9pŸ4Z@ÍIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/2rightarrow.png0000644000000000000000000000204011550446572023475 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<²IDATxÚbüÿÿ?% €<6]fgfâ}ùæ_ Çyvn†>>b``fc`aaÊæe™þîÅ—Úßlì- ÌL `;Ðr€bÒPP›Xa*/+ʱ€á×?°+Ð_, ï?3°þüeWœcÊ ÞÌðñg1Ã/ Þ@9Fv^€búø›ñ¯š±C}¾®ËJ†?x„¸€ ÿ0üþýïß_v†òz;{ù†¯ÿÒ -a`A¾ÿ \p  --!ÃÎð9þÿ®ùùïþþü6<&A<×ÛíEèä÷ÝÔA¾ÿöXïÝáõL÷ 0,# ÅÍñ(°úýöîÖáÝð=ðü MBÔÓìAìéúÌ ßA¾ÿ"\ÎòíøúçîüDâü6.ÿ)ÎÔñ·ðýñìÁäàìIæøQB ÎÐëAòóþÄè…X&¦#_>ýd~õá¯ý¥B öÆ| "<ÿ ®Ýûö—…ã Ã×ç]¯Ÿ¾ö¹þNT€YX˜!ØI€ÿì•wÄÂÀ °?ÿX˜þ~ccføÿè5ã’SŒ RÿYXX9þüf¨PÍÿÏ<쌿¾ÿüǰùÃ7%VvNVv€bÅ#ÿLm5‘Ö¯‚Š ÈaøøìÃûo×0ps41|ÏÀðûŸœ?Ë6e3µ;L¢ Üÿ>1ìXwùõ¯?ã”*¤dû¾ )2}cbf`ýú–áÍÓw»8Ø>>ýÎðá¹ó| =CíÇìR üÌßÞ^½òåׯ© ¬Lˆ‰‰câW>9Ž,¬ ¬ß?2<¿ÿöôf–XÆÿ_€| ó þIª9½â•eàfü Ô|õ÷×w_ ˜˜7‚Ò#@1ýgãäçábàüó…áéÝ—×þþgf`f}Åðé9Ãߟ ä¬Ä*$Ì ÆÿŸáíµ« _~(c`bœË ÄÂÃÅÂÌÃðáÞÍwþüþÅÀÂü˜áç`Rþ´ h+“÷_†w×n2¼{þ®˜x&002‚ó0öˆåÇßî^{ÁûóÇ¿`œ_¹l3Ó_†ÿLL'ŸÞxùëǯVÖz°f$@Œ”fg€KTÄ ­eIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/ledlightgreen.png0000644000000000000000000000206211550446572024044 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÄIDATxÚA¾ÿKõ ò þò>ñe%> ëïïóèéíÈýúÿ›¼÷ ÿÿˆnûG®ÿ]fʆ‘q© ÚN â‚¢ @^}xÇpøÜ †…60=rq3{)×=†¿ÿˆl€'Ÿc8Óñœ ñÿ_}»óx÷íÁÿòyµÿYõõ®2h(333ƒ /ÿ¯â"=½ƒ+ØYy~2|gøÇðŸþ1üeøägøÈÀÀú—ÁÜP‰á3×kÑÓï(101o †_ÿlÄ5cŒìľ0|føÔÈÅÀÖÒ 1ä7PbÈ_ w |Xdwsø<>Ãè@ÌÌêü]v¾ÒZüò_xYÅøX„€Šþ1ˆüÔú袯@ò+ý“áÑÏ› —¿íe`afe¸sò¯(@±ˆ°Ù¨j‹0üýÿƒáì‡= …~1H±©2°3ð003°ƒlÔ /Ýc¸ðáÃï?T xD$ÿ 03¯+Ã?Æß ×~exÅxAˆE𓑍¨ù û?ÏÞþzÆð›ù;/Ã&!v€ÐÁ À AŸïˆé¿KÞy HaX¶ØôM-åPaÖ‹á-¸mÁŸÔÒÛÖDšÆˆ8PHn)ƒ@ Œ4JÝûßSµÅG$ß¶Q}Mf³»xÄKC’>‘ˆlE€ð£Óu+•÷ÄçZYý ¦w¯¾œxrçP#; 0ؘ“Aˆ…€X(&a6 +y€êžß`bxóôëe€búó‘eÖÉí/€4sŽè^ b˜ Íü@Ì tР*Ö¿< 'Ö¿gøùí× €bb`cÚqß뵇W*ã+`b7@®à2 (Æ6V€áäúï g÷<Ùän fyñß ŸÙÏÜ8úÅ•[PTKSŠŸ™¨‰¬?@ÿÙÀ¤õçÃÞµæwœ½ÿýÿ¯`€= f>56ö÷¾ýØqöÐc¥»7>©s°ÎÏŽ‘¿ÿþ0|úð•á܉ ó&œ`X=÷ì®ï?Ä2ðpÜåF€bd05d§–¯ÿ~ýá²<98س$d„DD€ù„‘‘áÝÛ/?Ÿ?~såû·Ó±²ÚŸ8YÁÙ ÀÌ¡Q*_iýIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/view_choose.png0000644000000000000000000000174211550446572023545 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<tIDATxÚbTU¯¼®gª¤òó÷ÿÿþ20üýÏÀðç„þ äÿÑÿ b0 cdb|uãîc€b±ñ0”q( eyø ¨¨áÿøa³²30|üÌÀðýÃO Øï?Pùß lÜ Œ+7ŠË»Oÿþíßý–áÓÇŸ Ì,L ÿ¦3üû´ý/ÃÝûo$%88Ù€ü ) Á d}eædøúõï€bùøù/C¼6#ƒ£¦ÿ¯¿€üg`áådøüå;CC݆ü79†ÿÿ€n‡f&†—2¤mþÇ@,¿¸ùÞ?bx²²Šá;Ã+IßAEvN>^^nF†;2|üðì2#]U..†ÿŒÌ Äò—™áÿ~ýŠAðÍJ. ß¾=ÊÀ©hV °@‚ (ñè Ìl¬ ¾ýcøÃÀÄ@, âßï_ ,Ò’ Ÿ8S~üýà ¬ Æðëÿ_†ÿLÌ`M,,¬ ööÖ ðáò‰Ï ÿ™ˆåЖ??~00JÉ3ÕÍb…#+#ÃÏO?À þ322üùý›áä©s Ÿ?ºàƒš‚8#“"0¼˜ˆå#4äà/0zþÿcd`e…ZÄȦ~ãïÙ³ç €að¿"|¬ ÿÙ”€. °@þïå3†'Ëû¾ý}Ë ë_t‘ ÐL ¿~U012„†€ YÆøûí£_Žeb °ÿ™Ùþ=}Æ ða20Î2|{ÄÀ!­ F°¦_¿ÿ2\¹z…áû÷`H‹ò202J `f `, ø÷—E€‡ñ£Ã ß¹„ÄÖüúŸ ¿~3œ8~ŒáíÛw`,´˜E¤€jˆå/0ÿ}ýÄÀ ¯ÊÀßt€”èÙ~|ýÊÀ 4„íÿO~6†ôøH`ýLÎÿ8€©eÍùï@ýÌ ÄÂÉÃÉ´ÿ#Ãí×~³Ã”Œ~ûýÊi†¾L <\¿Ày,  ãï|à`øÍÆÎ@Œ‚n+ïr‹IÈ}þöçÿ¿ÿàlÄŒ  ”ËÎÎÌðíÇ?pÆg¥j`}{ù €ÿÃâL`ä;t:® ÒdIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/kgpg_identity.png0000644000000000000000000000175211550446572024075 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<|IDATxÚbüÿÿ?% €X@D7czHÃfaÆÿ>2±p‰ˆ~¹v‚óþž÷•¬%Ex…E1þðé'Ëß'ìŸæ\úÏpùéG€ 'ÃàâÄÀqëÓ·UÿÖ·ïW S¶Q¼÷ð{sDaE¤ª‰¥2ã÷g wNí{vpýæÂÿßVÅóƒ]@`45l˜DUØÙƒKE­Ø¤$D¸¥¼Sbj̃³þ~f`øÄÀ`êé %ÀñcÑáå+Îÿgúy¤ €˜@ÃAíoÌeïeØ„¸¸…Åþÿ``x¨ùÃ÷7@ú=ƒ¸²<»²$‹GÍå¥`ØÏŸ1Üg`dÐòÿ##ïoß8Xþ20üjþõ›áÿï¯@êÃç/˜~ü{ñMl@ ¸y—áÌëK Z¢²õlÜwîî~Àðí‹à†ÏXþüüÔü“áË‡Ç 7Nxw÷…Ðz¦_`ì…ëOrv¬b¸r';#Ñ^%TéÌ=ô;ê×ÙS7n]?Ãpóâa†“'¯3ìþœËØúf—Ã?H4(„¹œ w¹/yÿ¯oµùÖ1åÉ»[¯þÿ?píÍÿ1Aÿ7û:ý_~âõÿ ÿÿŸ¹îÓv+ ½ÄKï¾3l~x膿ÿDÅ885tع¸t5…Ôd´”D5\LD$„ô8Ù­­Ø[@úˆf+3ƒ8?0(FþüõáÅw&†;ïáŒA±X¿|`¸úô7íOoØÿJ0(ªsZôØN þóáÙë U„þÃùÅO& ì?2HÞ¼Êðëñc†‡?1¼g‘`ø Lýï~ücé XHþþÏði8þÜyÇÄðS hÀ6 w†—ÒŸžþãgøTüáÙ]·N0ÔÉ2Ü @q‘¿Ø>33ÜÜ}÷êîË‹/ÉyÚ; Jñ ŸÐÊ`adddøôåŸÏ?¼¿³ÿöÁ×——2083Ü í×—M`ˆ¾qéoïù]÷¢þ2œ¸tzê1 {€î`'0|þ}ª|ÎÀÀò‚‰¬ €)ÍÎü4T¸š 5’IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/messagebox_warning.png0000644000000000000000000000165111550446572025114 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<;IDATxÚb\΀üg`PãÝúŸ……óÍÓç~@¡sØÔÓˆbü™‘™)Ϥ¡NŬ¥Qš‘•µø'Ëo : ¬üa`P—27wtfÓ3b33þÁÀ` 4„á ¦áø/³±²”¨„…ò0|ùÆÀðü%ƒšƒ;;[éW Ü74 @(.`€`.ib,i`ÄÀÀÍÍÀ " -"Æ  ¡ît™ë4 Å@,,,Ìiª>¾|ŒÜ øùÞÉÉ20°s0誨p²³±¦Íñ¢Œˆ‰H0Bm Éš…Iê00ˆ‹14ô÷3”wu1üÕÒbæâfP‘•ñýÂÀ` †ŸP @L°è…<g®º§Èv†‡÷ï3ܽvÉÌŒQ@Á˜Ÿƒ‡ƒ½ð;ÐM°@ x€ü.­«&¦ ÏÀ ,ò ƒª¢"ƒ’¬,#''ƒ•ƒÌׯ j‚ÞÀès‚y €˜þ@ã“•‡§PûÛ½kþÊË]%..Î -- IX.Î ¹Ä~2qsqå½Ât @1AãÝQFEÚ‹ÿíc†Ï*Z ¿…Àš ÌÍÍ!^eø›ÀÀðå ƒ2‡#P( ˆ ètV>¾L%&®ß| C~ÿúÍðÿß?iII9 @쟿3ø2üQÖdüþŸƒ=h@¼`+#/Èóå5Ã{ï0†/²Ê ?þþcøËÄÄÐ>u*Cco/Ão `%¥8ã®øõ‡A‘•Å èzW€bá,V`fùuÿïWÏþïÚôð?†oœ\ ™¦F †=Þ¾•áû ?˜˜¾>~Ìðèl  «„YY ˆq«ºâ7K%^Îo/^0üùù›á×f†ßþ1üúý˜~¸þøþÃg†?@M€šþüüt #аóÿþý Æ9\»„%ÅNþûç×/†¿@¿‚‚lþó÷Ãï¿ÿþ‚øÿ@ô_†¿ŒLÀhgÊýe~öûÏ €ld"IZ Y IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/filequickprint.png0000644000000000000000000000225011550446572024257 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<:IDATxÚbôðˆf€ß¿3˜™Ì ögfeýÃÈÂÆðÿÿFFF†Y6­ßºåèÑ“Ñlllÿ`zˆåׯßPæ†?~0ðóó ëñ|ñœáÓ L,L ýœ¢² BB‚"?þffdbúÇÈÀÖA¾ÿÿÿî  üöïð਄ øíÕ´Ÿô<ü ÿ÷õìüûòhÌ 9_ØØ@ôo6NÞ_?_>dàÿà –Í îÍð›WŒÓÈAPRê÷Ïoÿ0üý Ôüè½ß 4€‘áïß@ü–áíÛÂÿÿÉüzv‡[Yhà7†¯62ÜØ´‰AÎÀ¨ò·Ô³çWe~üx Tÿ—¤ A¾ÿ d $…013x"#.òÂ9 ýðÕþâëÉÉð (U Løøù÷ùöÕA¾ÿ~kkox---÷÷öÄËÚçá÷¬ÆCà "3÷0Òò \:5 ÜÜÙBŸž˜)A¾ÿ776Y897õõõêEyçô óøÙÓ®ÍÝ5Ü"ðñôØèß517PA¾ÿ""!ýúùôúþ¿ó±Èã&(Ýÿî7MûÕÆ¹Ñó- #! A¾ÿïïöååî þñü±ÇïØ.ÿm,𰲡ï]úß ì+õ èðøóôúÿˆåÝ»Oÿ®^}ÈÀÁŒP.†|ù? ¯Äøo©ÓÇI†§ëÞ1Üø”ÈPì'Æ LÁ¿?N]øÊðý'P/@A¾ÿý÷ââà®­”  ù<1àøÞûž›øæ%ÐÌÌèöøÒð÷MOZ%$)ÝÝûûA¾ÿ÷÷òèøøï=CFëäòË×Á$0je7 ÿýýûüûÃÃÃööòîˆYYY‘EZZÚA@@Õ@ß„ÁÚˆAìÅM†{2°†t1èÚ[0H‰1ˆ‰K1(**3(+k1pqq0<þèû{&³¢¢Âù{÷n½zõ.ƒ½½•Ã/N~ 7Q}}†ß¿ƒSê¿ÿÀŽÝ3gÎÛ¾oßîò¯_ß/ `€2ÇvVVNë?|ùòùó_&A†÷n3€S,P#0Wƒ++ 3ë³×¯læààd0GæcBËIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/view_bottom.png0000644000000000000000000000166211550446572023572 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<DIDATxÚbÔ7ª¿ll£.óõç¿ÿ20üáÿPúÃo ýÊÿ ¤Ajþ211½¾ÿì÷‹ó—ˆÅÐÁ@Í(%€íÉ3ˆ†_@¿þ@éßHl$qFNæ3^]º¨@,o>üùqñÄ[¶¿ß30110üÚòŸB³1 sBÅ€4##Ð`6†§o¿100±ý –Ïßþ1ä03X©ñ2€Ô@8f0u‚ ™ÀÄøŸáéGßc¿þýgc –¿ L \œ, <Ül ¸P÷¿ÀpøÇÀÂü•ù?Ã?s™YlÀ¿ÿŒ øÀ`Øüc  @ÌÈðÄbff –ŒÌ ßþeø ˆ3¡6BÙÿÿƒœÿÌÿÃIJŽáç@K’¬, ÄÂtÆÚwöíþ À¡qÔø÷784™X9~ýøÉ úå60`2Ü`ÑbxùC’ƒƒ €X~ƒHKU˜A[Lrÿ!þÑÿôß_?>^?Çð_\–Aôå9v¦ âV /gØ ô@±üüÇÈ`¤-Æ`§ÎÕÿ¾|dxósã¿§ ¿Y– 1˜ˆ/gµ>Êpq¿Ûo€âw ÿîºüÿÙ LUÿ™¾}üÅðü½$Ï£ ü?X¸¾0|ùøŠaîA/†€ïWˆåÏ&fFHˆ]Äÿ!i—™áÛû _ŽÏdᆠƒ˜§~ÎðbÓ†”€ƒ ÊJwˆ…™åÞëÿ ï&U`üñ?0ˆÿ þõ˜h^I1ü{ñÁJö0Zó…ñÛ†óWT¾>üþ €X~üüñö÷ “¶ý‚Æ5$3ýýËÈð—…áÇoW†xÑ V‚ï.Î?ÉÀÁõ“K„‰áÅoI†GæËÛ÷sÝ~¤Œê? èéé?Ûo¾ÏÏøÝöÄošö÷¢¨*“!§ˆ0çÕEï›Ì5{ÿÏæ"@±­ZðÇ`Í Ì„ ÿ¾1¼}ùÏðüПþ1°¿~ÍÀpý0F€ÑÁÂÂð÷ʆo{ö0|zó”8%$èÆÏßþþúÍðã7#Ã;`~da8Ë©Êxr'»‚Ã_ ß¿_»ÊðhëÏÿ@IƒS@€áÛK€bùÿý+û߀AÿáõÃ× _ßþbøÅÈÆ°ð¯7ƒÒ£} ‰/2¼zð‚áïÏŸ  Ôÿ¿ÜBB xy_ÿúµ A¾ÿ÷êŒïä&û÷áÐ÷ùûûüó ÿ}ûMþ ù™ADöåèüýýÍôÁîîný¦ˆ˜ÔªÁé”â€é”ùÄÏÎfäg8ñî§ÿ¿…fŠJÀ d8ýãçËÓ¯^ÅÿadÜÉ Ì<ÄÉSŒ YY›áß©ë¯ÞxýýÏ¸Ž™Iäú«×1l1BôÔ©Ô¢1‚IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/kgpg_sign.png0000644000000000000000000000166011550446572023202 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<BIDATxÚbdN âß@üˆñc ~Ä/¸€dó3@#›Œ³á±wŸ¯ýùv¦# €˜AB¾@Ì ÕüˆÿB•Kñ}k ¸ õ¬BÍT­¥wŽgØU3™7Ø ˆÉê¨0ðj˜0øÑ\‚B>M“Ý+ØxX”˜¾ÿÿqÝT€b’ƒJ1#+kÀµïH†ý,2eîsdUyn=e`XÙ\ÒýáÅáeÄ” â|!öšG[Ãþšñ½ÁQk›?;Gœ+ÐPq] l/S`Êá]?ÿÿ?ãÒÿÿÑKŽÙ@ÆØ€X&&‡#UŠÿßžpüÿÿÍÿÿ¿§þ¿ ä¶Šð3ìީʰᨠƒßäÿ·õ/‘üñsPV ˆÙø:³Põë7ÿ7_=ü_œ—“AWJŠ™L¼À´ðŸ‘AQp#ƒ½óFo9‡ï·Øl>ú|hÍP‘b€bÅ 4á®¶C177ƒ7‡’ƒº¹/'0]HóŠ Ã¾iŒÖLzXùõÛ×Ù@Cþc 4Å1Aæ”2h¨8+ƒŸ£3CiL ƒâ¿ÿÌ Œ²’ ww 2teÜÎüøýÇ €b~T©Œ+,ü˜?>ùÇpæé†ó'¶2üü~¦†ù'>!Ño 7޳s>{þc@±€rÝ 6‚f(tÀ IÖ‡n>e8ôb=Ãæßß–~ûûåù«'ÌW€É@ŒÀg 7%A{èGêAIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/editcut.png0000644000000000000000000000155111550446572022672 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ûIDATxÚbüÿÿ?% €X1Ab²²² ¼¼¼`þïß¿™¢££»ÅÅÅÛÚÚÌxxxÞprr‚åˆ Dp9"""`ÌÍÃਨfƒÀß¿’’’¦ÕÖÖ]¸páÔ£GÞ033Ã- 11YyyV¨Kþñ§A¶2€¼gnnžŸŸŸ~âÄ †Õ«WÏdaaa@v5@1‰ˆ‹ƒÜ ¶ „Aš^½~ –äààLOOoûöíÃÖ­[Ï¿}ûö°¦¦&XÝÏŸ?Á4@±ü`§1(8Y@¦21 ²´´LVWW—|ðàêU«&qssÿÚÎÎÏϯ¬¢¢bþéÓ'!€biúþëƒ<3³ÛßÿØ^10lyãÐO´_@¹+W®ü†‹ZDDÄ %%%c [$^ZZZA¾ÿþþ[ 9 H( lÑÑåýý¢K Ž %ãããøøøzzzy÷÷÷ÍÍÍ瘘˜|ÛÛÛžˆ±ÇÝ}0^ÜÖ¯7Ÿ¦£Óg,$d~ïÝ»_j©©¼ç>?{tÎ?—¾]rþèÑ£k/^¼¸èÈ ¯‹—¼¼ó«¯_ß2°±}çäççÐcggßðäÉ…ÛÏŸsÇZZêLÙ»÷ÁÂ5kÊ_½zuèì;èi €JÌÌ–ÿ(/ÿÿ =ýÿuW×ÿ®ÜÜ|¼¼v{BCïïut|+ÅÂŒ/%ƒª¾>›µ°p^¢¼ü\IOqcii/þ··ÿŸ¨©yK^VVŸ~€bÐ25…³5ÔÕ…ö&&>¿žžþ­ÍÀàÄÛ  ?SUUÏ¥Øqé ¤Ì¤ÉÍꤩ)5ašå¯_Ç(ñòž”þÿ_(ÅÄ?±@, Do~ÿ¾ùôÑ#†IŽŽA±·nÝ–üôI6êÑ£l Ôg\. ff`2þòé˜Ã.&öàà•+ŸØ¿Wþúùóÿ¢Û·ë¯ÿú5_<*0¾«îÏIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/endturn.png0000644000000000000000000000156311550446572022713 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?% ƒqp @ðÈ•~µ-“:,Ýׯ\Nf‡Ø6ÔZ:¦ÄxÕ±Õ˜ÒÿÇâ0ìÚü rˆ‰$ë@Žýý;A]YjW¤µ…•+ß?€"Ú WEÿ11Ìv·Ð›_ëé(sñÚóî¼J –ÿ ÿÁð ¨æ% ÿþü3ã㜟좥 ¡Ìбû<ñÓ2¹™6‹ïÕ_¿ÿÝüüøÃS½ÿþ³þøû'UNM°§ÂǘÓF\€¡|çy†]Ô3±³Ìb`üÇ@L|ÌÜŸ} ¸ÙVþþóO¬“Nÿküå`Xææ¨4uj˜§•¸$Cãžk »ö>ïgûÏÒÄÀ‰=€bzvçûL 1†ì@+kF.†uÿþ10þùýÏ•WœeWj°AHƒ«;ƒ8CïÁK Û¶¿\Åþ›¹œ)äA¾ÿ0æîôûdqIJ þÇ×âe"* avW:J"3øþóŸÉЮ­é¸úý]ü÷üúýùÿüA¾ÿ0!ðíî÷3W0<÷S6.*#îüé±ÔÓ±ªìÑòYìýýû ù A¾ÿ/"ÿýôûòï[/'0$ÿïýê¿ÝÖ®¥ñàÿíMàüüù ö ôˆYHC›õÇã/ŸÿYñ«~UâagaøôÿÃé'÷¶.ýþæ÷S–&ŽßWþ3ÿƒxšñ ÌôŒˆ‰ã;ç?¶ŸŒÏø¶ž>ýžá9ㆋ¯î3ì\úë˯Û\1ÌÌ §ñ%0€bbþËÎÂÿؽ>ÃýðÄíç GW1ÿú~Y ¨y'¡ @ÌjFÀ(ef`bdüÎôCìÍm‹×yë˜ÿLûÏö‡áóo†ÿ,À ö#†ÄHiv0P­!3•Žð#IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/messagebox_critical.png0000644000000000000000000000201011550446572025227 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<šIDATxÚbüÿÿ?% €X@ÄRFF†_ š¢ªj‹…ììo\¿íý›7Q>‚ŒÿÃÀÀÍÉË»H1,,èÙ©S7]¾÷átÐr€b¹`!PóVc“ïÜþÿÿùýÿ/Nœú¿HBòàD Æ ¬Ó„„wÜßàÿßGwÿxxÿÿÇ5 ¦ ½6`³ºÆÅO·šçµýÿ©)þÿÿÞuÿŸŸ=ÿ–ˆèÞÉÜ<[9úÿëáÝÿ/JˆýÜPúÿÍãGÿ§Þé °ÇRÒþÿy¨™ÿÿ')†ÿoÙþÿܹöÿ££ÇÿßÛ¿ÿÿç»þ_çýŠ“áÿ!6æÿ_¯\ü¿¥¤ä?H/@1Âàñ¶­»^Ü~ÆÀ6e>Ãov†ß?1¼HŠdàÿøœAñýð †__?3üddbP™=“áÝï WÖ®;Ò @`Ìe`Y$)uðùÅËÿíXóÿ4Ûÿ;" ÿo(pý¿,Ïûÿ /ÃÿÃ@ÛŸÌùÿЫÊʧ‹d@zìf†7ŸŸ?óÙì`·û9¯ƒàÌe xx~|ùÆðóóg†_ìì r3®34c˜ok{ôÅÝ»î¬ O@z°HÇ(€0 .ÖÿÿÔE›ÚÄB¶ ëcœ ¥Uä: dØÕrty¹¦Ã ¥ÛªóÿÁ@`ã™—CXd½ßŽ]¾¢ ?ņ1üz÷á+Ãofv†ß¿3\މe`¼s‹!ñÀg!)©-@D@zl§¨ØÏU+Ý…þ~f¸Äðûˆ@Û¥ûf2(Ì\ÄðdÐ¯ß §þ^¿Î»j•´ôJ^€ èç$«®Äp'$œáû‡/ ßÿ03(N™Íð_߈ᷜƒæ¢E ¿XX~ýúÅp 6–—‡‡A?" ¤ €Àœøûçß&&Æ_ÈšA €X~ÿþÏÀËËáhi%¯Ë”deacÐP“dPT”ðpÓxýúGÄ¥ËO?¯\sñî¹3Ï«J¶12"L –?ÿ2()‹9*+ ³~þÌÀðáïŸ@×þcºŒ‘áñÃo ½ãuvÕ1øÏÈÑu`×õËl¬a. uCiOf&n†7¯þþf`øüåÃÏÎ_¸Ípûîc.n>†–Vcq)í£‡î'|ýö³™••l@± pëhËÊûÊÀðúÕ†›7Ÿ0œ»x‹áÉ“× EÜ<ü Îîº Šò¬ B vNÊY[Ö_^ñŸñ6È'Ä¢¡!ÊÌÈͰ{÷=†Óçn1¼|õ†•AL\˜•ƒA@—ÁÕYl› /#CVšÄ‘w ?¼ÿšÅÀÀÉA¾ÿKMl”âäõ ÃÆÕøøú   D?-* ööø÷âë ÙÌÓÊTªáˆåñ“÷O32tDBÃ5¾|ùÆðåÓO†/>1<:~“…•AMÖ„áïˆæïÀÀeâb`p¶â½¾ê]©êۛ—Ç¬`°¹‰8ƒ?ƒ¼<7ƒÀ®Å 2Gz¤ÎÎfxzà–®@¬ ߀ávgû.Æ–x×ßÔþ3ü A¾ÿFäíí÷0(+$ôýîÏÖ ÷%Wø¬«ÓÐóIIåÊÎøŽfGØüÐíãA¾ÿLøëêòð M 'óó-/çÈÚüöü%< ö«±ÍÓìйCùËþû¥ØæÝð_A¾ÿKüüÿÛëêó+,2.ü ôú62íÄÒ %!þ¦°*ß ü¦ÕýñÕëj¸ˆYXØ‹á0Õ½yýí7S¸®…<Ç`æzõæÃúC_nß_±á³¦·–€Šè7Ž/ÖÞÿûïäc†BV†Å ¤@Ì¢¢Þ  ìõï/󷯿Š °XÞyíqOóþI×.¿ÊS~wtíç»·Ü¥­„N\x°ïâ æ>fH¦ FíéðŒñÿÿŸ?ÿ8~üðóƇ_œ×u™®0žÍðçÿ_'v)‘¥ß¾~ßðãÃ×| Æ_0=ےĪöIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/no.png0000644000000000000000000000163211550446572021645 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<,IDATxÚbd@i ò‚ÂÂJºº"**\LL ®\¹pïÚµ ï?|˜0‹á!²z€BA•ââõ{ÊËÿ½víÿÿþÿ÷îÿÿ7oþÿýúÿד'ÿïIIù_) P¬ €˜aŒuõù)S¦xz2°þýËÀðáÃû÷ oß20¼yÃÀúû7ƒ’ŽƒšŠŠËñã Ç~ýÚÒ@`*%$êSº» d>~„`æwïÀš^¿f`xñ‚áùs> á*’’çÎ1e`8@Ì@?ó{DF®0ÖÖæ`øò…á¡C /®îØÁ Ä 4ÿÕ+†½@Å¿--Ê2pݹÃÀ~þ<Ã×W¯ €vÏ  ‘`gh(Àpì§µ5ƒº›Ã7†½YY @-gÎdàzìæM‹¢"†?ÿþ1h0020Ä‹¦¾¾Ð°³¸¶mcøffÖ`9m8|@ìÇ.0pµ¶2üjþãbig€bââà`xùh²@¿¾Úò Èi„i~ëíÍ iáß@üŸA €˜€&2|þ 1Šo D o%%þcâ'ÿ a@1½~õêÃÏŸPjÞûÿ?ƒåÒ¥p›a.±Ü³‡á¨¾>à&´ö@1=zøðÀã_¿à¶s w¶Ã[¸!Lp^@ð€;q¹µõýÿêêÿÿKJþ$$ôÿhQÑÿóââÿÿ±³ÿÿÃÈøÿ޾þÿùùÿO]}ˆOq3ÃSPX,ýû••ýÿŸƒãÿ ¦,,`@›þãæ?0Dþ?âk@|ˆqCH/@SâY†›?>}z+öç—0ÞäÌo@üJƒðW °‰¡là P8}úÆpýú}†{÷ž0¼ÿhÀ†ÏŸ¿2¨¨È3è1üÿÿÇ• ÜÎÿþgùHPhÐWvv&QQ>qq~f†wï>0|ûöû²7àÏŸÿÿ99ÙA^aàää`øòå'PñO ýáãÇÏ ¯_¿gøþýˆÿÙ€bAæüû÷Ÿ‘ñ?а¿ ¿~ýføúbÀ·o?€rÿ€rL LLŒÈZˆ‰ )bddÓ0öÿÿ X@11Pˆbˆbˆbˆbˆ P£ €à這™‰™áïß?à(e2iÊ1;;3²7àÉ“÷_½z«)))ÊÀÍ J™Œ@Ø€ ˆ ìÐÿîß¿ÏpåÊ©ÈÜ€‡_ø.X°%GPË—K”••…íû÷_Œïß¿ÿÿèÑÃß·n]{{åʹ¯_?›Œl@€£Æç‘T§KIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/cut.png0000644000000000000000000000200011550446572022012 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<’IDATxÚbÔPScøÿû7ßß¿ ̬¬ /€lø dÿþÇÖÖ¶OMM-yïÞ½‘?~üXÅÄÄÄÀT @L P1—££ã¢ ¤ÊËË?÷îÝe Xއ‡‡ €P øÿŸ‰™™áß¿0›€¶vvv~úô‰aÍš5[ÿþ}¤ñçÏŸ`-„áF Óþ t¢B\\\Ðf†M›6ýzðàÁ6QQQAAA°% uÄ‚ÕÝ@Wüýó‡AG[;ÏÝÝ]¨‘á Ýt'‡ÐòœœœªÄ 2†ß@“>ýù#ÎÌÈÈ ¾G|@þÇ?Dœ¼@¶íß¿ŸáÙ³gO]]]“Þ¾}륫«k¥¥¥%¹k×®§Äòè1ŽäIÉìþ°Íùþ½‚åׯ-üüÅ@T¿ÃáîÝ» Á /mfسgÏ÷7nä‹ 'gf©œÜ¤‡Ïž}ux÷Žÿ3ÓĽÌÌaææaŸ¾~e:zô(8pŒŒ˜ÿ½uñâE†ƒ©‹…ÜÜÜûˆ%SY¹’™ùoÎ¥KŽÕllÓjxy-\•¾˜˜0|âçg¸uæ ÛW¯þ?}þüåM •?žÃÇÇ·Àÿ˜a@,B,,BrââÌ‰ö¿~©½xñ‚¡ùÛ·š×®™UËÈH¸zõí–³gk~ÿÞÇÆÎ~“˜Ø`‰ˆù+#£„3e¢  ù“7o8;˜™óž¼.ãåu:ºlÙ—9·o1 ¬ecbz ÒÂìììà4ÂÆÆÆ@,¿~-+8zô†(—Þùß¿çñqq™Ìòð¨×ÿÿŸýѹs¿øþý“ùùá8Îxyþƒ #<ƈYTHèï_§Ÿ10lùÍ̬Úéä4ŸëçÏ¿S½äÁÄ$*óáƒÍ6¶]œÿþ½b&aP¾áÆÂ·_¿À. &Y€ÎzLyêÂÂÖÒÒÜKÏŸ¿ÐúõkÎþÿÿßñ32ò33S8È6 æjüúø1àú_@œ¾ 9ëí—/žS]¡  ™ëÓ§›?}kèûÈÎ~å,»€|Ê@ƒ¾ó@1 3üF+ü÷ïæ­W¯äå?Ögzÿž{2/ï¬Ë¼¼åìÿþýf„i„Ò A1`oa}É^7öIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/message.png0000644000000000000000000000173411550446572022660 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<nIDATxÚb¨`aÙzXDäÿMUÕùì,—Ù2Xd*2ð10001A¾ÿ³û9 Øéà#§oþ ýîüüèÚöúçâñúéçêùéðãöéÞõïÚõðÛîùÜOãçþA¾ÿ þóîîúï÷ÿ0^ì ìåß5ÿõÝþïèýëìà®Óø„î)ꈅAðù±çÞ:¼}õ–¥(ƒ_(þˆ¿13‹1?#·3÷Wf™× ¯?ae`xg”8@,Æ>bÿDÍ`àúÌÌ n¢ôø¨fþÅ_~üþÆðû×g^îÇ o}þ bv€bùÏÄ.&¨®Á ··P @¯1#T3ùú•áÁ㯠&Z¯=þõä þ@,¬ÜÏ>~fàûËÀÄø(öƒáíçï gï|g0PüÁpæÖ†ßÿ3HñeàZðùÃg¿@&ÿ€Â1Ö†à j‘.böÿÿ…EѧBÚÄó^r¹«œ¯ý(… Ê´^VÍ,©pœÆâÍ«™¾ÝpO¤kf!h2ù¿ÐO±0q³rñpýcØ}ú+ƒ‚è/†_@×I ~g0QúÆðÿÿ®7 Bœ¯Xþ„ï}axöhÔ€bùÍÆÄ¡*òßâ/ÇO>N +Aþþ Äï€Ê€š~þÈf|Ïðûý7†×_ÿ½û•á7@±üçfbeeüÉ -ô%Ôþ|J5þyÇðïË[Æ—ÏQùŠáÏ#v†þ½FÓ€bafF6 Ô@PÀþ:õ3X#-{ûô ƒè- «o>e¨ZÈôæ3Ãÿë@… øþ@,Ÿž]gäyØËÀÊÁ ŒUv YLC@ü©yÏÀñ÷Ëk"'3Ü8ðéßb à-P*) FYv†Vk^vE!n~Q1>6n1>vq~vvI!–ooþ1–nzqäñŸ[šnñU ~ H€b $Ä¢ ”ÅlPÌMÏÌP?>ð€ Ü@ŒPI˜f$MLH4#4á|†úý,;qOTåÕwi IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/mix_unknown.png0000644000000000000000000000146611550446572023612 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÈIDATxÚbd``Hâ9@ÌÄK€8ˆ¿2 vff]I6^†ï/Þ3°°ó2üùÁÈÀÀÂÉ@Ì@i! ¾ÄÇ€8ˆ/ñù˜$ù˜ÿ00üùúƒ‰…áß L¬ Ä”ÞÅl@ÜÄ(š¹€JÄ9~ýƒ: »ˆŸñq†@#Ê~ÿg``„ýÿdÿùËÉÀü? €`q7ñM°+#£8ÃV ­ÿþ# üó‡áïï¯fú–½Â‚âfÄ ®b ƒ¸ h•0àøþ²ÿ1ÏÂðï÷oÎÿÿ"#"§ÌªmWýÿç߀‚¹à3„Ûb Q ÔW¨¿øûý‡“’²RwUZ–Q„7÷ïßÿÌ€ àb€øò?'úó¬èw &¶e‚¶Üù-™ùLÞR® _€±ÌÍÀV@,PM½@lÄ"ÀHýÃÀÎ6àﯿ~‚Z|2îšÌ ìÌ Ÿ€š™¡±ñ÷ï_€ba€Ø³ˆO3I0ÿe°efø÷íŸ, K«º—T”¼“0óO¶_ ïÞÿ`øýó/#<2þýû÷ €X8Áì ¬ ÿÿYÿgadf•Òé2 R•áWäbøðõ;ï/ÿÀÖ02b$€baHù(ý‰A•›“½ÙÜC+\×Qáçÿ? ï>~cøó) Á&À0„ †_ÀdÂÄœ¡o£Xìh #"ÎÇðæ÷W†ŸŸ3°ó¥ýeøÉÌ ÀtÁËÅ ">`„Bž• €Òfóós¥ê+1°²²ýúøù'Яÿ~ÿ¦^`Úÿý Èèo KÌx̤X¤ÿ°2p3s³=wå%@1‚“% €˜(½ÏÄo~;Ç×IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/bookmark.png0000644000000000000000000000162211550446572023035 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<$IDATxÚbüÿÿ?% A¾ÿa%%ùÿÿÿns#üüÙêêñÌûû¯+C òÿÿüÃååØÁëë{³îõõA¾ÿ\$$b ¦³^^þóººÿÿÚÚÿÿ××ÿü§§ÿÎAAÿ×XXÿÿ½½ÿÿÛÛÿÿÖÖÿ즦ÿ“??û!|ˆ1AN® Üֶߣ²’››áÛ7 ;;ëW œœ << ?~@ÄED>dè,(øSsäˆ?@±¨ssç;8;30¼yÃÀp÷.##ƒll ïÞ10üý 1ð÷o†ï[¶0ü{ü˜!šƒƒe/o#@±¨ñðHsüù6¤€d ß۷¾lØÀðñ [$yyt¹¸”ˆ…ëçOf†gϸ¸0 9P¿`øvèà<Ì}ÿ€u°Ë‹÷ï¿1ܾÍà )ÉÀðëD–™lëß+W~5þ~ú”áÈA@ ¢™@ÞZøìÛ·ßÄ t ³ãŸ?J\ A ~þdøô÷·'À¶þþ𬠄AîûÄ 7€^è}õê@1?ûóç:ëïßQ–ÿ²1}úÄðòÆ °?¿?yÂðïß?†¿PÍ¿ š%EE~ˆ‹3”={öãÌ·o…Ä tγ£ß¾]üñçO 1 ë/ÞùÂÀÕ2à'ƒNZV–á#0s=ú½éÓ§z Ð\€bàùX̳Þ¼04üÿBJêÿ9 —¯ñ% ¾ÈÄôÿ³ºúÿ³::ÿmÙÙ?•'Á €À€Œà†<ƒZ7÷ÃG&&ÿ_()ý?ÊÈøÿ Ûÿ/ÿhjþ×abzTêQ7€h€sÓš;Û¹+@—|âϦ¦ÿW “c`¸ Tfˆž™ÅM E0ùX03ï:¦«û¶œÜA†ã ðÖÃaP b1 Öd`èºh6)€+;N’.¸à‚|tIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/view_icon.png0000644000000000000000000000174511550446572023220 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<wIDATxÚbTU¯¼®gª¤òó÷ÿÿþ20üýÄÿ 4ˆÿÊÿó*•ûËÈÄøêÆÝÇÄbãa(ãPÊòðPцŸ@ü ¨ñ7Pá¯? ûùÂþ ”û¤Ù¸Wn@Ѥý†S!ÕýïÒ¢™ h¡f‹·~ö¸JÙÖpFd™1½#§È{{j›~¥1nB‡}<Ú¨æú –Ÿÿ2$è01Øk3|Þ·áó­C ¬*Æ bá@]ÿ@€‘áËÁÝ Ÿ®îa`VÐfŒ‹bØqõCÚ– Äô›‘‰“›A…ûî&%щ ÌW1ð±³1ð²3ðƒ07ëí Š"˜Ÿ-bàeb`àêùÔ €:0‚ ¸Ÿ h ô_ŠV#ù÷°‚V«äY66Ñã$ïÁâO›_¼f´ý¢žAÏIjcyH">ÄòhÊÿ¿ÀPaabø\Èpïš7ƒŒ¦3Pó¿ ÿ€ÁÎÈÌÌð×?•áúeay9& áÿ~ `fb ¦ Ì@…ÛžþþͰþÒ †ç?~Bl†Þ_ fºà0ŠÖ^¾ÁpÿóWp˜üjút=@Ãà?Ð) à–}ù˜!]öƒØë;à¸þŽ…ÿ ߀ñ*üô1CªÌ™÷÷¾}ù±”‘™ €˜þ‚\À´âÇ?†oç0°½Ëexwb2ÃïÍ&ýùÍÂðãÈO9 ß/ô2üÆÈÿÿ–Ó sþƒLced`ÿÏÂÀzÂÿ$€JX Ä@i¶ÿì Lôw`*,Pè9€bù tÆ{€ÈßÌðòf*¿¢4ã°fã¿/ üsnßðfàðo†ÿ¿A©‹‰ €€^ZŠ £^|yϰþì!†7_ß1p°12pÝÇÅü‡Ÿáóï/ {nœdxóí ƒ '0ø£fò¡ÏNŽ:<2¼ÿ¾ÿøÍðë×o`Øã‰‘˜þcäÀßÀhûÊ @³±02ÜùÀÁ°çàÍ/ÄòâñóWwüçøôíωLÀHþÌ1Í w1ÓĹà΢`/32|{ù €A!M 0À¸€yÿSÌIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/viewmag-.png0000644000000000000000000000107611550446572022747 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÐIDATxÚbüÿÿ?% €˜(D±ÄÈÀà­,¢2WETÿïß@>ú4÷#Ã&°†¿L±ÿ1&æûO~»ùð~6@1hTh>ºðøâRÁÇwÿ¥º¾ kUk)}=†m·1¼ýþ†•‘•áÿ¿ÿ  ÀÓ Pˆþ10üúû‹Aˆ]ˆ!H'˜ÁAßJ €XؘÙþýbøÅ\ªžáÒËK œLœ ÿþüCà¿@üB3üúæÛ_M!M{U{6¶Äòïÿ?°-lLl ìÌì ìLì 18¿ÿÿ‚iøÎòá „ýïï_€bB„&#®`f`ddD•Gb #ÄŒ0|ÿ󑉑á¨Þ€âÿáð‹ŒAaÄÄÄÄ@,¿ÿÿ9œ¡Â¨‚áõ·× lŒl`§ †ÐÀd€"ˆùëÏ/vaaa ×þ1ƒ~þË»/ï‘ÏÞ¼üo™íý €ã¢ å§H°ý¦¤!Ñö(81AÖHBbб0³1]yxçÏék*ˆ‘ÒÌ@瀢؀²"=ÃÊ0½IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/window_new.png0000644000000000000000000000163311550446572023412 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<-IDATxÚbÔ7ª¿ll£.óõç¿ÿ20üáÿPúÃo ýÊÿ ¤Ajþ211½¾ÿì÷‹ó—ˆÅÐÁ@Í(%€íÉ3ˆ†_@¿þ@éßHl$qFNæ3^]º¨@,o>üùqñÄ[¶¿ß30110üÚòŸB³1 sBÅ€4##Ð`6†§o¿100±ý –Ïßþ1ä03X©ñ2€Ô@8f0u‚ ™ÀÄøŸáéGßc¿þýgc –¿ L \œ, <Ül ¸P÷¿ÀpøÇÀÂü•ù?Ã?s™Xˆå#8 °ÿ@65CõÐ0fúÇð6ÿþ `ef –?@ÄyHöA ѤAÿÈþÏ Œÿ ÿ|aøRÂÊÂ@,˜Q @h†b ';Ã? +>^9ÍÀúç'ÃoIs†/ŒüÀfe –¿@/üC2ääÿ`/ÿúŸ_¿Þ_8ÂÀÀ¯ÄðûêJ ØG >e‹‡6³°0ËF„þÿÿÕ t&0õüÒÏ_¾ÞÚ L=Ü L_ž10s11=¨eÈ3;Ãpz·ûo€bÅ̈Æ@ ô30éýùýèWf†ÿ˜ÞfýÉÀ/û (r†aÞ!/†€ï׈̌˜™Aø?$í²13|{ÿ‘áó± Â<Àhbçbó4Š?gx±é CJÀAe¥;‰ÄÂÌÎÎrïõ†‹÷¿“*(àþ2üïŸÀDóJŠáß‹‡ V²?€éø+К/ Œßþ0œ¿¢Âðõá÷·Äòãçÿ³¼g˜´í0ªÀø8Ó02üe†ÁoW†xÑ V‚ï.Î?ÉÀÁõ“K„‰áÅoI†GæËÛ÷sÝ~¤J/ˆô ‹¶ß|ŸŸñ9ºí‰ß4íïEQU&CNaΫ‹Þ*6™köþŸÍE€bZµàÿŸÄÂLÈ&üaàø÷áåÁ‹Kž\c|¥ÍÆ9õß{~‘§§„’~~ø(ÁÍðë&@€ ¸•øÄ3IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/cancel.png0000644000000000000000000000215511550446572022457 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÿIDATxÚb,—”døþû·¼† à¡ÿÿ /û–òÿß¿lÿþ1°þÿÏÀ¤øïß¿ Ì ÞââËþûw÷á½{QœLL׈ق‡G^އgI¤¹¹™¦&Û·;w¼Ÿþû÷€ñÿÿË, @šá?ÿûç£/$´Ì;5•O^__âõ;?|8 @Ì1ŠŠ»bLL,…óóBC”žÏÍý ¨ù“îŸ?+l‚ƒyÙãâÞ½ÈÀ#/Ï $&¦@ÌêÿÿßÿùჇò“'lŒ@732°1H=ÎöëâÅ ¡_¿"Üܸxƒ42|øÀðÿÔ)†3K–ü¼tèP!@1Û°³_~ôéÓ}¦×¯½ä^½beTÈb`À üô)“Œ¸8‹P3#Tó¿3g.lÜøçÄÑ£Eÿÿü™@Ìv<< ÿÿ¾òäÇ^¼ð’{öŒ…YDx \úú L @|û–áïÉ“ g¶oÿsêÂ…‚ÿNeº €˜m~g†6ß?—_üüyõçë×A’oß2³ abb`üó‡áÿÇ ßšÏîßÿ÷ü;Iÿþý›Ã Š! ÄÂÿõ+P€áPñ6¶ÿ¸¸þ}:óË‹ `ïÁ_ Pÿeaù´ìP „Aé €˜]YYþ‚láàð1–•]cõñ#÷W s?¾~Íðöþ}†@üèw&669fAÁ€×¯^=`€¦€b&†ÿìì^jjKí>}âý´ù?HˆùNjdæà`øtáO +ôää8¬­g323G‚Ô #;»Ÿ‰¦æ»·oy¿?zÄð›x€.{ÄÊúï#ã?%ff–?@çþâ_Àt «¢Â ôî웲‹†–Ö÷ïßyÞ¾Íð j3ÃNΟ¿ÏÆÐG–¿«pppÿºèPþ÷³g &&&ÜÀp› @L?¿~}ôèL&  Øà`x($ôçÜ·oÅÿý[tæú«ïß§>úúõ;'0Æ@Q ¿~1|ÿþ@1›}út𹂘˜/33Ãe~þ?g^½*ìTf Åÿ^yýéÓV..O99ÖÿÀ(>~ôè'çÏdz'ÛëoÞþÂÉiù†‹KøòãÇù€)Œ ”€NfE0 A¡þéýû˜˜<=xðàáõëñÌŒŒ' -½¤H^øIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/ledred.png0000644000000000000000000000174411550446572022474 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<vIDATxÚbÌa``øÄÌ@ÌDßì~10¤r Ûq‹Šò1022~zýúó»7oNüa`˜ T¶‡•á;P-à  ("ó—¡K]C#Ò8*ŠAÙÓ“WF¤Ÿáó³g7÷ìñ=´x±ïÅË—×Õ•220Ü@ d00È00ßéåõÿûáÃÿÿÿþüüùÿljÿ7ýe`¸ÁÀ Ô @Ì& @'xéêzyde1°ˆˆ00üøtÐMÿvüzèãG†—/X~þdPºŠýñcÑ Ož(]± €X€þ²‘c`ˆ19çí[`(}÷çDóׯ @?@ |ÿlÛ7 @ÃO10øÜd`ð f3fæ.-  f6AAˆ þÝ´áÛ7†OŸ š_¿f`x÷Žáç¹s _öìa`fff¸ÎÈ( @,ü6*¬¬ L>0|Þ°h+«Ð=bb llþýlóŸóç>ïÚÅðh° //ƒ0 ‹!@±ð13óñm)eÚöhÓéÓ ÌŠŠ ×€¼tÁ¿»w~?yÂÀôP„¨¨— €XX€ Øþ倯)P‚ñÑ#†/P\À L:& ÷È8#@±ÃøË_vvNÎÏŸÁ¶1rq10ððãh$334‘ü$Ó—/ l@ç³ù?€ò_ÿýû@,~ü8ñ˜‹ËWäT& ßÀ˜“# ŠJk˜˜A†}ÿÎð(÷òÇËÄôýׯYGþúÅÏÏÀ L°Fnn_@€3`6H $4è/ÃA Wþø1 €˜Xÿÿßîãǵ{…„ @†€li€ó Øu……Nú´íÿÿÍÄl ¢Ÿÿž¹üë—+‡„„¨P13ÈPXmk¥  +ÿÃd?/~öì>0Ä=õ €˜µ^ÚùþÇïß;.|ü¨ô€…E¨‘h; ÐÏÿ€!ÿˆ¯ý½3›>ÜõûÛ·X ñ7@™ €¡Qòˆþÿº›Á“ƒ#K\PЈŸ$÷áׯŸ¯>|¸òãû÷é@îFVFÆÏ@CAºN–Rø¼ºIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/viewmag1.png0000644000000000000000000000123011550446572022743 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<*IDATxÚbüÿÿ? 0šÉo ¿¥þ~òåàHUURRáåãdüúçãµ×Wî|cúZþÎÿÝ0=Ä2†Lôxt¤ëyTïÄ6eýßþèÿoßüÿÿïÿÿo?¿ÿŸ¶wúžtžÇÈzÅF­5ÁeÙÿÏß¼ Òóÿü«sÿó÷æýßþÿÔëSÿ¿|ûò_§Zï;²€ba@’BBÞíÙe B¢\ qKcv?º”“áÕ¿W Á*A :>¾x99…@##KUi)qùï?~½õè†ß@%@ƒø#ƒ˜¨Q``ȱ¯_¾Ü~ðàᦟÞÍ  ©ºììü ]=†ïß¾0;“áÚÓ¯ lŒ L@›ÿ bbøõØ\‚Œ1QI²\¼|²wîÜtš?o†&@±˜››EZXš3üþù“áí·¯ â² ï9ù~üþÏðáç†Ï¿~ýÆÐf ¿d¿|`xôõ-ƒˆ´4ƒ©¡y@±()) °²00üøü“á˯ '¾ 3\»ÄÄpç=Ãç?ÿþý‡¦ þò5}gÐ``æàcPPVä –÷ï¿1>}úŽ—ýÃÇ? ës2Ü{xFF( ¡>þãbx«Áà ÀËÊðâÆÏ_~ý –wï>ý»zõ!ÐÏÀpgábÈPøÍðMŽáÛ_f 7 Ù.ädýËÀËô 芟 §.|eøþ“¨— €Xÿ~xôèúµS¹Y88ØX€Aǵ€ì—ÀT»äÃw_ÿ(UM†»wÿ –ïß?½”–üñã=ƒ˜¸ƒ½-//0¥ý'¥ÿÀTù˜™™€yåÃáÇÄa ##ÆðíÛ§wÄòàÁݹ7o^êãŠOcÐÒRdê*þ N`þ€ð_ þL¥¬ JJ:àDvçΕï÷îÝZ@ÌŠŠ çŒ³W¯Þe°··Òãããj&" ­ <ŒAÉ›••™aæÌyÛ÷íÛ]þõëûÅ PRãØÎÊÊiýñã‡/_¾|þ Ë  Üüÿ?( ÿ³A€••…™‰‰õÙë×?6spp2j臠¢³èzIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/pencil.png0000644000000000000000000000131111550446572022475 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<[IDATxÚbüÿÿ?% €X@###¦ 7ƒ¡"Ão ’?¬ ?˜í6›ì÷–_8Zþ3öü?š €˜°ËÔl"àÿZÀô/Õ1úyŸvá»W ÿb@RÄ‚¡Yh“…8Ã/ ¦¿PÍ,óSžL0p~Íðÿ6c+Óù'_'e—ª Äší„!ìÿÍŒìËÝÒNÐjæù«Î£XÌàÆ¦ÂÀüìË2€B tŒªfŽß ¶ñ;´l>2üÓ`ðU(gØ~mÔü£{þî R @P/éÀ ¨ÿÍœ¿;tý_—«š~geÐ`ðP(cØri;C[ö¾m?Ͼ*úÒ @L6ÿ…Fç? æú=AÚå]¾´ÎO6M/ù†µç62tæî_÷ûüg`àýÿs8@A Pö è‚ÿÀøäü=ËêSº Òo_ņ§Ö0tç\ö÷â÷ ¢ßÈÁ@ à„d…]Å=‹¡›ù¿àr†ÿIGõÿŸý:çÉ>çÿŒºìs€*˜Ñ# ¤ €„ó˜ˆ5 ýg˜ÇðßÑÿ£çüÏßmûŸA‹y2®TÒ @p”òeçî:Ñþßs§ÝÿM¯§ýOÜbñvÝø’1H/@Aˆçÿ¿=ø¿ýÖ²ÿ&5@š å^€‚iÌ3Yýÿ[æYß´êgàf°&&#ô„°fì`fŠñÀe‰3 €)ÍÎFà@¿vò!IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/quiz.png0000644000000000000000000000127611550446572022225 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<PIDATxÚbüÿÿ?% €X9½—žÈ*‰KÿþõŸáÏ þÆ¿3ñ†@Ë^œ:{nÃc˜€B1@NY\BÇ@œ‰áúÎÀðá'Ãë Ï^00<ýÄÀ $ÿDY@¡ðçÏ¿¿¼l ÌÌ¿1\¿žáÑà ?}eU³cÒpaxó™á/P ²€bBæ0211þý÷¡:5ˆ¡=/‚AÍÈžAAÛŒaa¹Ñ%- ̬`U(a@¨02þÿýëÓ{·XØØ„%d,||„¤ήkcøöá;3Š£…÷ïï_6v†þ•^½ÿ ¡*Ãpx׆¯Ÿ00±°2@b ÕÄ‚-@3Äe$x$ú*òv,Êðè-=nA.†O~£¨ lqû¨æçÏÿ WŽïeTÒfÐqŒfÐp/bx ŒV´t@,¸0<¼â‹Œ}“>üFá3 ÿaª &lšYÙ.;Àpãìa†§1üºèÿ?ìº AA èÕ3ÛÎÞÅðòùs†ä‰v8“2@¡ðŸ è¦ÿÀ€Œ+lb“Ua0tcøLÖ@1Z$0Šl@ðèÔŸ_d Íb ÌÞîÅk†¯À°û 4œ—Y@¡péø©sožKÉÿùýÿÿ_`&úûˆÿ€’/$S ýgd|~ñð%¸€b¤4;ý)ÌØ1å6,IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/make_kdevelop.png0000644000000000000000000000171511550446572024041 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<_IDATxÚbTU¯¼®gª¤òó÷ÿÿþ20üýÄÿ 4ˆÿÊÿó*•ûËÈÄøêÆÝÇÄbãa(ãPÊòðDÃ/þƒÀ?¡ø÷ˆÜß lÜ Œ+7ŠË»Oÿþíßó–áÓû ÌÌ ÿ€6üÚD@ÌÄL@•Œ ÿþ‹³1/Pî+3ÃׯÿËÇÏâµ´„Ê€¤žÄöá߯o@§ýf`á™6‘ñ?ÃöË¿Ò7ÿc –ߌL œ¬ ‚| 0ðûËg†//_0|¼páß…‹ ߟ={6@R_ŸATO‡Y^‘áû›7 ÿß½cø¹bÃëXY†üƒx™‰ €Xþ10 €¸€… Âàåcø¤þ(Ê3ü””bøkcÇÀ)*ÁðüâU~ Y`”þÆØ`p018 `p ‹0üúñûž= ,×®3ü¹táoÏD†êZ 301ýeàfýÇÀ ŒJF ÄÂÉÃÉ´ÿ>Ãí7ïéè¿ èaa`å±eø{ñÃ÷£~3(ý†úßL ,@Íw>°2üfgg –Ÿ¿Ú¸ó?ÇçoþÿÿÏUJÆÿ¡l ¡ÿa™‚AÎÂÄÈðíå;€büÿ)ÉKE}·­¥ôIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/frameprint.png0000644000000000000000000000141111550446572023373 0ustar ‰PNG  IHDRóÿatEXtSoftwareAdobe ImageReadyqÉe<«IDATxœ…“ÏkG†Ÿ]íJ+W’UT$ܺ®HÓ$줥õ5Š Lšƒ{¥ÿAþ„BϹ’@in¥­! 9Ä”„а¥ÄKq n~8ÞµdY»Þ™/KÁ y`x¿Ã|ß¼/3c?V*PJ#"c,\7Ã¥KWoÞºõÇ…ðgDzÐàÝtÝüíöV·ÛÝNAD,D Ò¿N×u2¶íþ·±_÷¼?tß ¦ €˜ øûûƒ˜¸ƒ<Ð4S~]òM$5ÊoB®f9“ì]Ó2yKviv˜€bBõпÿþý:›(õ烅¡ÉÜ"×L‰?¿xl˜#t”Ô42¥‹xù|˜Xˆ #T aÊ(ÈÄ l –TïÍÍ"Íðøýgv1_žTE3Q6 OþiŒÌŒ²„a###Ã×ßþÿäíݧ)åÁ|åñ7†?ÿÞ~ÿ Æg«ˠä'!Ã*ÍÙ@ð@Eç¯ß¿?~ý”kohî¥í›«¤'áÂzóÉ/ ä_†@ƒ½'ÎÇÀ -¥Åðý Óÿ߯¾~A¾ÿÿÿ ÿRgcjo,G+H %ìõ ÙÞãèéã üöü øôŠ¯Ñ ÏÕÿöý}A¾ÿôÏq"+_cœéîüîðøð÷ó òùåëìí¤Ò¦¬’¯õþèúrìˆéë•OKs1¬ÿ€áÙç Ÿ€þgdøËÀÅúŸèt~1†Ÿß>2üþù—áüÛÓ æÍýÿ騫é@Í»A^ æw~o|)ñ7–Ms'¯8§Ã`ô1£‘…™—››…Máî‡ {NOa81u×ÙÿßþEƒ’ È€bfdgýöíÙÏû,lAÚ‡e™uÄ5X”ĸØظþ1ÜþzŸáØÛ- gnÏ`8=w÷‡ow¿$õ݃>@Á§¦DOУÿË7¦ÿ?ÿùþÿ•·þOXóߨÔàŸ´ßGv¦ý@e^èúˆ™# rR'VÓì×õ? ÷Ž^ýöüÒÓ›¿žþ]”á+Ør#@!+ 0õñJs‹ñ.dbgœ 1EÏlØ@€ µ-ŽkÓãIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/up.png0000644000000000000000000000161211550446572021653 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?% €X@#cšðF†%&ÆRullL,ÇŽ?éªjb``ú¢ê@1AŒR¬L “€œ@ü»;/פëà¾0žýûÃ9ªª¬j€âÓ!r`­PÌÀ@`0°35ƒôþe`øû·8-Õ¤xâg†Uw™>ý``hmµgøû‡!¹³ëèK +ª8X–2‚µ Ü@øûÇÞÁY¹iú†U·™æýÏðýë†ïïÿ0´µ[1ܹû¾líÚëXÙV3°B  ˆ˜œ_Ex¦ÌšìÂuá Ã’ ÿ8þýbàüÿƒaáÑO ëÎ|d˜>ÙŽEVA¨áûoIX8ÔF¦ÿÿªººìtx•DZ10üøñ›áÏ ¾gøûóCåò§ ¾þg˜<ÁN™•¹…á×_°ëbÀ÷?¦^þ¹É z {ï00²üfaþÎðõëw†oŸ‚ùÒ¼ ‹w=cðt“f‹Tà Ò A¾ÿÿÿÿ&˜ÓÇÌçÿ÷ùüÿô÷ûÿÿû÷ÿ”¼ìÿ0Þÿ'sÓÿqœØÿñììÿáäëÿïïíÿÓ×åÿ -œáÿÿÿìŒ?œ,Ý3Î}ýóûù:jÍY¹9Ø!ÄlÌ, ¯Þüd(k;óçûï¿98™9~²A@`Þ~øá¶nÅU!†_ÀPcb¬ËÏÐ ajúùåÃϯßþÿagxýñ'Ãú-w0|ûSÄÀÌÄÆ Äñ¤ € ÁÄxÿ7Û}.`Ès2dFÑW`øøñ+Ã÷Oß¾|æªáaàãüôåÓ¯Ë €z˜!Ñ@,ˆD F) ÉLu¬¸Øþ0p2ÿ&îÿ Øba`cÑðÄ@,&0‰²B³ #Û/`²Œua°Vagøóûƒ¨ ýg@¯°U]ÇȆH|1€á_L w›ç]dP–äþûï$íµ0càag`øööÃý3×~½¼rõ(@±€ø÷_D c C±V÷èÅ¿Œ¬ Ll,l@ €bib,+P3’®ÿ0³1 Ãç7ž_ºÁðöúã¿ß¾›ÂÀÁ± €XX€šù¹€¦‚4üƒ:ã?ÔPˆ¡_}f¸wüòßgnžÿùáSÃ6 ÿ?‚œ@, ‚<@©Ø€þdò_?ÿÈpóÄÿwÏÜ8ýýåÛ) ÌŒ+€ƒý `t (]ð]ÀÁIæ,@úõÓ/ g·_a¸~âÆ™/¯>Ld`eÙÅÀÎþŠáÿ_¨ ÿÃ} @,À¨dƒÔ“ûŸŽn¹ùÿÔ¾k¿<×Ì<ë8Ù¾=‚p nfF†ßvm¸Êp`ËÕŸž¾ŸÇÀʰ hëWpî#ˆQÈyñ3væ÷Ïî¼î:m0u}@he_&¸ @”;ÿC½t>@€ ±&á›aíèIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/button_ok.png0000644000000000000000000000156311550446572023240 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?% ƒqp @ðÈ•~µ-“:,Ýׯ\Nf‡Ø6ÔZ:¦ÄxÕ±Õ˜ÒÿÇâ0ìÚü rˆ‰$ë@Žýý;A]YjW¤µ…•+ß?€"Ú WEÿ11Ìv·Ð›_ëé(sñÚóî¼J –ÿ ÿÁð ¨æ% ÿþü3ã㜟좥 ¡Ìбû<ñÓ2¹™6‹ïÕ_¿ÿÝüüøÃS½ÿþ³þøû'UNM°§ÂǘÓF\€¡|çy†]Ô3±³Ìb`üÇ@L|ÌÜŸ} ¸ÙVþþóO¬“Nÿküå`Xææ¨4uj˜§•¸$Cãžk »ö>ïgûÏÒÄÀ‰=€bzvçûL 1†ì@+kF.†uÿþ10þùýÏ•WœeWj°AHƒ«;ƒ8CïÁK Û¶¿\Åþ›¹œ)äA¾ÿ0æîôûdqIJ þÇ×âe"* avW:J"3øþóŸÉЮ­é¸úý]ü÷üúýùÿüA¾ÿ0!ðíî÷3W0<÷S6.*#îüé±ÔÓ±ªìÑòYìýýû ù A¾ÿ/"ÿýôûòï[/'0$ÿïýê¿ÝÖ®¥ñàÿíMàüüù ö ôˆYHC›õÇã/ŸÿYñ«~UâagaøôÿÃé'÷¶.ýþæ÷S–&ŽßWþ3ÿƒxšñ ÌôŒˆ‰ã;ç?¶ŸŒÏø¶ž>ýžá9ㆋ¯î3ì\úë˯Û\1ÌÌ §ñ%0€bbþËÎÂÿؽ>ÃýðÄíç GW1ÿú~Y ¨y'¡ @ÌjFÀ(ef`bdüÎôCìÍm‹×yë˜ÿLûÏö‡áóo†ÿ,À ö#†ÄHiv0P­!3•Žð#IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/mail_forward.png0000644000000000000000000000211211550446572023671 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÜIDATxÚbüÿÿ?% €X2|þü›“ƒƒáÏ¿¿ @Äð„ÿñ?†?þÿûÏè¡­%›ñ÷Ï_…­[[‚~ü|uš……l@± ›øÿ5þüùW†™…5LEU*ÂÞAÉÔÔDáÑsF†k·¶—\<·%‚áÿw Ól#TóŸßþüù¯ÄÄį­+aa¥¬fi)à ËÊpöâo V†À(ŸKç÷8þüõn#+@±€Bà÷ï¿ì ¿Ô9¹9•¥"ÌÍ%ŒM¥$%˜ø¸Ýf``b`e²]\L¸Ö­rK»x~ù>&&&€bafb°—“JTV• 1³TæÖÖfbd`cc``gj~û¡gç C#5Wauf†€ÀH+—z22¼Ù@ÌV–Q\Ý5ìí”Ø”¹øyšÙØÁ^›²uÃ_»¾}ÃpëÞ}cI޽ûï0½xq3@A¾ÿâ ÜçóÁÅå¾ÀäÄÃèÐÏïàØÚÖõôçIZ*âöÖ~œ…û`_UR#=ˆYZÒý²’T¤‰•"£ Ð aAN..Vpt2003h* 1ì¹°—áÐÝ ®f ŸŸý`Øä(ƒžºË­Ëo9A¾ÿ!"Hæðîù,30' "=BĽӨߪ&>°¯ÃÛÝÙʈY]=à×›7_~‹ øé늀£¸`ÀÄ t 0:1l]p›aÃ¥ |æ Öêò g.] –?À÷ÿÿ¿õ‡ÞÜko§à-)ÅNH\\Àô ÅovmðkÍ®½Ì,˜¹e9ŽÞ9ÊðäÚo†¯_XŽ (+033ý{øèÕœƒï¹$&i±ƒløðîm7®Þ¶ùÔÉû;ø\Þë±:¿fýÁÁðm³Ô¯“Ǿt20ýo &fFpZüó÷Ïæ#ÇîïÓÑ–õ<{îÆ×UË÷ì½rãlÿ[á‹F,N¯Úyüfüù”•áÇ&…wop–1°ýžËÀøŸ €XØØXÁþeggÿûòÅ‹Æìœ†»Ož<Üõ‡ñÿ¶Oþþãc `caûq“™áçFùÛßïsä3pýÝÎ - ÷ž™!öë÷דOžž?ùÿ/7‹'ÃOÁ¯À,ÉzïÿEÑŸ_ßrþý’5—õß &p®€ššY©—ûÌÆIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/kgpg_key2.png0000644000000000000000000000152211550446572023111 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<äIDATxÚbüÿÿ?% €˜(D±ÄÎÈÈð‡YE@ŒÇKIOÜUÛRÅüã›Ïïî\}qþîù§«þ~þ¶ž‹FF( @, ÂÍSv®L¯Ýw615v é¢ñbÏÕçG,ÖÛ¶áçƒPÅÀÐ1ÿƒ4ÿeøû¨ù9@±°9ï~2ósóÙ1¨«2¼yõŠáÒ§ œ¬œ ¹´¬“EÏýûÅÑýóÄ×@#nþüjçòW…ÄòWI“õ‚ ÷Ï3çÿýzóŽÁ'4ÉœE‹áüE †½79üÌæ3Ë|c`xÔË ´û5Ð$A-%±GçÛA¾ÿ@Hz!73$òÝ¿êêí .,ßß@Ó¼ÿ ÷ùñÜÆê)ÏÂÇòíýÈËYˆ…‹õ>ã?M›8..&†/Ÿ?3üøþ•áéÓ× ¢"Œ ‡÷»}8³ûz0Óß_û9¶?–cdøþè& GXnú A¾ÿ&&1¿ëìê= ÿÿþþþóóø 5? 4/Gîò½üÿõóýþûúˆY[Ûøé÷ï¿×¿}ûZãíÛ—J?~|gz÷î Њ Œ@—Џˆ–º’'oäëŸÿ¾~½òWQýó A¾ÿ,,4ÿÿÿóüüÿ¦òòö°ëëëóççëÊááåÎââæåööóÿÿþ %#Nëéë)ñõõ«úøˆY_ßèä¿@62¾úóçßžß¿ÿîüùó×¶/_¾­|ôèåü>(¼ÿè–bRRR@¯±jÝ»û`-£‚Ú+€byô胤¤"…1‚ B¤µÿþ¿}ûöcø³goXŸ>}9ïùóW@þ1&&¦ß À0 FJs#@Qœ™ v<(Úðüå­IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/view_text.png0000644000000000000000000000157711550446572023257 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbTU¯¼®gª¤òó÷ÿÿþ20üýÄÿ 4ˆÿÊÿó*•ûËÈÄøêÆÝÇÄbãa(ãPÊòðDÃ/þƒÀ?¡ø÷ˆÜß lÜ Œ+7ŠË»Oÿþíßó–áÓ‡ ÌL ÿ€6üÚDü‚ÿAÅX€/õ•™“áë׿ÿˆåãç¿ ñZŒ Z"`…ŒŒÿ¤“¬Á& E;/ÿbHÛü €Xþ021ðñp2¼}v›á艳 šZš fff ¯_¿f8pà Ã? §™€:þƒ ÐÐ_?0ë©1pqí`f –? L@¿ÿc`æâbcàââÛÃÌÌ (( ôÈE@þÿã_À@aeçføóí/H/@ øý烢’3@ý-$$ÈàââÈ€ \:ñ‘á?3#@±ü:ƒ‘‰™áÙ£û —®ÞbWP`ÐÔTgx÷î=ÃÅ‹—þ]Ç ”¿!Áúóç/uE   EL  fp0}üô•áé³ ‚‚`§þøñ‹áùóW þü*È+ÿÿÿcøþýƒ¸ ÃV  Ðb€bù4åç¯ß š†: š::`çýþý—AJJœ!**»ûýd¸yô3(> L@“Þ¾zÎp÷þc1qqyy9 >0Ü¿ìPÚø÷ïØ¿€–ÉŠñ]%4€™ €XþMafffxpÿ!ÃŽûÌÌMä>|øŒÆ# €®Eã? óÿ øþヅ¡&³°,(Ñ0ƒBøÎk޼ù~~ûÿÿ÷w ã/ÐÛÀLòëûÿ¿ß¾üÿùéÃÿ¯oßÿÿûîÙÿ{žýçpÝÿ €X8y8™ößgb¸ýæ-8ƒB¨ ìì¿ >ÐVDfúö ã?†;8~³±3Ë‹ÇÏ_mÜùŸãÓ7`¾¦´¿°tÿ¢ Äþ÷)sñ?P¦`bdøöò@1‚¢Œ`„“йæIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/next.png0000644000000000000000000000141511550446572022206 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ŸIDATxÚbüÿÿ?% €X` 6³ÙÇ$x-Þ¼ürïýû?E b‚Øyþ³10°s10ðÙLœ ÌÜ Ü\ ÿgóƒõÌöÿ ¥yV ³ûÜ•”TE60|ø5•áï?1Fü. ¸ÿ€>y÷Ÿ‰AÛJ–aN¿'CX zÓÏ{þþ÷Ãg@Á øÁÀúîÈñW û¯þcxðŸ›!3Ô¡«ÂDGB„k-Ãïÿ“€6pb3 €aÈh¹Ä’áó]93+w=>!^#iÁÿßf®yʰëô×Kÿع²8yŽ0ðÃ`$ a€Í2 ÁÁËðƒ©’[B(WÉ@…‡KB’AW†‘Á[óÃ…k&¯ûüáÝ–™ Â<À@üÒ@h°C0'¯3ûtn131y^nV†D[Uþß 3v|e8v—éÄÿy|– }F1 `H2@1ã'^.Æïì,Ì ügøø›aÖOmf Ù L¬ ðð ´0áføý/GB‚«Ô@[LøÎwa†o_”Dÿ3üùù‹aÙ®??~ý`šÇÀÍ\Ó@þÿ×`üÏ0]QEÐARQ†áÜ;v†ï@ßI þex÷êÃÛïþûÏœÇÀƸ¤¦ €\À´]@FLá˜$ÃégL < |¬¿ž<þÉðãób–< ÷>€½ˆn#‡Ä7f†ï_™8ÿ2üùñáÙË¿÷þ3²42°0.•nÀv&&&nÆ_ ŸÞ~ÚʰŒ™¹(u_J xJddf¿õ÷ûw†÷o¿¾jŽe`aŽæƒ; 2+@1Rš ÌÀИyþ˺IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/misc.png0000644000000000000000000000202111550446572022155 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<£IDATxÚbüÿÿ?% €XJK;øù…ØØØ f100ü¿óãÇ÷+üüürrR‘ïß8ÿâÅËe55i+ËË;¸¸x¾~ýÌðíÛG€bâç›ôïßIþÅ®®–ë55•·…òäå¥âídcc½ý>~|]R÷çϘ«A–³ƒƒ##ÐTî%†a††* rrÒüêꊞúú*<¬¬Ì ÌÌL Ÿ>ýäccãcÐÖÖ)úû÷¯é÷ïßwýÿÿ— €X~ÿþÅÍÄÄ óáÆ÷ï¿1ððp ºŠì-FF†à`^GGË6>>N†70¬^½åÑׯ¿&Ëß¿4$$$WŠŠ ‹‹‰ €mûùóãGï†}:“™AD„—AZZ˜AHˆìt!!a†Çïoܸ| @±A¥ŽŽ¦ž––Ô @î3,[¶âú»w¯ih蘙Yˆƒ\#'' 6`ݺÍ_æÏŸœ©§gø €˜¢&ˆˆˆ üªù—••áØ±“¿**2œ.]:=aß¾­Ë1£ª¡¡§.!!ÌÀÄÄÈð÷ï¦ÿÿYù´µ ÞÓ‡oYÞ½{ÏðäÉk†/_¾]ñ›AFF†MCC_'$$–AOÏèéß¿¿c¯^½òåÿF° ,-õY¦L™ÿáÇ>€b>uêÐê7o^~ÓÕ5²+†ƒ²²†ëçÏ_þJIIsñó ÆXZZØ)(H1ƒ¼òíÛ/†¿2,Z´à(@±xxø?VPPãáçça`aaÆÈPÌØÙY hjªwúô‰A\\”AJJ(÷èÒW ¯_†Ó5†«WÏí qq `„ƒþü%+ +Á.‘––GãÏŸ¿89Ù)ðÃܹ“ïž8q`ÑÓ§—˯_¿?,X0¹@\¼mÅë×o€Q÷–AQQ ˜°8ÊÔø›áógPØü`••F¡PÍ›gW¯^jy €X@Ä­[×W¶·Wpûöí÷ç¼¼Ú¥rròœß¿ÿb¸sçPþƒŽŽ>0a±2<¸çÿáÃ{fÂ2@±0“ ܹssˆ %’Ç(¨qrr1Ìœ9áàž=›ëÃÂz€Òìë×/«†ËF˜Ä’=Ãã • ,-mçqssÛC¥ø€X=;ó&c¿ÚgÉ+IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/reload_all_tabs.png0000644000000000000000000000217311550446572024341 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< IDATxÚbdHg``øÇÀÀÊÈÆð÷׆Œ@üâ?@ÌÁ*ÂÂ̶Žáûïë>üje``yÄÀ*”gJ212éý ÖÈĬ ™¾12Ë²Š‹ôD÷¦YjØíbøõ7‚áÿ?¸€b“Œ ¿ÿâdüÏ"Á/"Ì#*ÍÎÀÎT÷ïïO†JüÊ >V– æ¶ ê‹-Ÿ±ežÑ?æJf–¿ÄÈ4àƒª¨Úìh‡%u †¿Ü_€Žù 6ùßÿÿ@§°3|d}ÊðŽãƒ!‹ÃÅõZçOíûõû{ @±Õ©èKl¬Š.–»"páÔ¿ó â Ò ¬ÿÙ€üšÁÈtÃ÷÷îÿºÅ (£Â 'jÈÀÆÀ.óë÷v€A¾ÿ…aD_¥ø™äDúVÊÎÐòóóêîúúûÿ$#9JN ßó´€¥~µô÷ñp øA¾ÿ,+L þï KW›…ÖáêÞ`àñÿ ö "'¯)*&ÎÃéô©Á™†ÿÿû‘ÿöýA¾ÿq í<"< ÿÙãÞÆÙÁxý’ ùêò   ½üòñôìyÿþÒöý ý ûˆ‘!ŽY–áË_H$2}`øóO‘Kˆ¯á?‹ê÷¯?>ó½bøûO‘áó·G Lj&ól´Ì˜~þúŰçܹÄ ¤Ç l¨døþ/Ù×Ì¿9Ê%Z²unëÝ+w/ò2°|ýLo¾3È ³Éç·¤óþ6¾Â É`Åð2ï+;@±€𙑛ã?û¤‚ÐÂ$SOe6Ý99!¥í¬\LýÿËÃÁÃëä`%~Qj ûO÷~Ü–c8uáâ1€bdg`feæœÚÝšÎlð–aÛ˵ ²LÊ rÜ*ÀdýšÎþ0ýbxúï.7+ƒóÏX†)ÍÛßî?wÐ €€.`þ÷ï/ãçÏŸ>3°}úËðòãG>– ßÿüaøõï'Ø€ÿ@ÈÌÀ ñÇ–á÷=>†–5Ë~>‹ý@A¾ÿ[ üü÷‰a;at"> ½¥ÌúÑãÙÙ þýüéîóëèäá¸ùû÷œìˆ‘!Š œà~#âÃ( e‡Æ û•YëçÞ»sû¢-3ï†À(ûÇú—•û+Ã÷À´Í ÑÃÂÄ@@™ë;Ã`úÿòW‘•]¬–‘Sû÷ŸŸ¾ ß¾¼Tà Ôtí×ïÀ@gƒ`ƒ)nƒô¾®IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/exit.png0000644000000000000000000000174311550446572022205 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<uIDATxÚbüÿÿ?% €X@ÄJFF1øƒ 3S>¯‚¼?¼¼È¿?Þ=|øîųçÛ¾þþÓTsùTm;Ðr€bA6 (˜.cfܧž—Ç%áäÌðæÅ †¯Þ0ˆþÿ#þôÀþÄSë7Ä^»u·¨´b@ øá¥k„Ì0š>“EDŒáÓ£G ÷/]eøûë' ++ƒ‚¹ƒ¿ ïêU‡Î_iëÄ ƒ%ŒŒZ’æ¦gí7oæ`gxwñ"Ã÷þ‹Š‚ ÿ¶~=7Pï¿ÿ \ß1,ݾýï¥ç/Íúþÿ?@L`Ss4‹ Àšï¬]ËðàìY†§§N10ýÏôëÃë§OÞèë3ܹw—áïË7 VRÒÌÀpªé °¼2ââ¿^3¼ß¿“á3ƒŠ‹ ÃÓ' ¿30þýËðÿÉÁÔ4†{W.1°üûÁ ÀÃã Ò @à0à’’þ·m ËûŸ$6ìfx³fƒ´°( 33ƒä—¯ /;;dººŽ 1p=¾ÇÀËÊÂÒ @`þýöóËwF6†ÿ@'ÿ=}‚éÿ?†Ÿ×o‚ƒøÿ·O ?Nœ`øûý›‚ÃÏ[ÀÀåàÇ@ øðîÃûŸŠ²bÌO_30 0üyóŽáÑÎm wodøó›áëÛ¯ BÖ¶ ,<| ÿ_¾døÏÈÄðá×ïo ½ƒ×O_l{ÃÄÃÀòöï#ÇÄ[;XÅ¥~<ÿÊðíÍWn!¥în†Ÿ7®1|»xŽá';ó?‚ô8»õ´ÕÏZ+‹²|¹õŒArÐv^.†¯ë73ü"ŸŸ+Ã//†Ÿn3œd`úwñóWÛeÿÿ &¨?.ݸz³âì³/ ¬"Ü /üÝ~-[ÎÀmlÈÀkaÆð}ëf†kv ¿ïÞb¸ÅÄÂpáó×6 žã ½vÁ`^ø 4è©%%ù656F>`fùûáߟ¿ Ÿ¿~gx L7€~¿ðå[0q5³Ó×B ^€‚ þÎÀ`ÂÌÎ^*ÄÁîÎÎðç/Ð þþÿöê÷ïýÿüí:ù#P+ƒ  FJ³3@€ÖÁc튢BIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/project_open.png0000644000000000000000000000137011550446572023717 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ŠIDATxÚbüÿÿ?% €˜(Ä",R=ÕÑå—úþãÃï? üLÿù‹àÿÑ@>ˆþõûÃÝW§þ¸ë—@`´u¤ ìøÞf`øõ‡á' ÿFbÃø€†00<9{O¤ €À|x÷õ/ÿÛÌ‚Ààøóï?1€BæPö3³1€Å@˜èék¯XŽýüû¤ €Àü²½Œ…„¸YaúŸ‘‘Áf`„{zË™Ÿ “@N€‚4š•ƒ“h<#Q!´â€Ç(°þý#>äÿ‚üò¢ €X ügøÏ€šößÚÏпe"ß/ßz{´¤5Àr쬜€ðhrzúùû'CîŠ†Š„F&F†?Â;"ªÂ«˜˜˜ŽÝ†ê¯ÿà@ ˜=ÏøŸ‰™‘áÍ¿‡ …sZ€ê>204®¬c`†×{iucµP†`€‚ºà?Š ™þþøÃPØÕÊГÔΠ&« ôòÐ&†þ2•FUNa h 0r³#R5+Ж¿?~1Èp 0|byÂ𞕘!ÑÆôÒן?´„õÀ|€ðéË_¦þ­ŸØ!Q æoB ìœo^~ÈÀññ+0õ! øþí/ÃwßÁ|€p}ߵت=7$€tÎpzËøÚýýå†Wß10}{Ãð÷ÏH‚¦ÌŸß~|ú6 € éÇ%à„J ÿÀé™áÍÇ—^ŒLœŽ§O½aø÷˜ ~ƒœ iFvqn}°µ".T-¯IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/view_multicolumn.png0000644000000000000000000000174311550446572024636 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<uIDATxÚbTU¯¼®gª¤òó÷ÿÿþ20üýÄÿ 4ˆÿÊÿó*•ûËÈÄøêÆÝÇÄbãa(ãPÊòðDÃ/þƒÀ?¡ø÷ˆÜß lÜ Œ+7ŠË»Oÿþíßó–áÓÇŸ ÌÌL ÿÿýgø´h ÿÑL ÿŒ ,@y^ øWf†¯_ÿþ –Ÿÿ2Äk10Ø«ó3üÿú—‰“…‘‰ð?ÐêßþåX˜ØA" Û/ÿfHßü €Xþ0±0p²³30m™Áðîù6&YO…ȸ 7¿Ü0áËãÕ %­Ô›ÁÂ@—221Ë_ ¿~220?ÚÆ #°áá~†ûÎ0°rþc073a`ü µ{ûd÷3\áaà6õbøú÷ ㇟  `åee`•w`x{þ›¶-ÿß~½ûÄðWàØ ƒa Š‚^mÇ,Â*AìÁ‹Í l’Ýüg˜fZ¶#Ï ]¨êŒÇAÂ=¨­a!²Ÿ99WÔŒýNÌë•~ÄòhÊPãëûÇß lül ÌÌ ‘ 4ˆÑûó'ÃÏÀ8îß?Ááòû/ 0„™ˆé0 þýabø°n&Ãã¹a 6N‡< Ð` ´œáͺНf…2<]ÓÍÀÆÊ `TC €ÀøˆìO·1ÈŠmgxúŒ‹áØQG`øübÐÑÓeøû›‘íñ~q© ß~g8uÌ›ï;ï_j LLÌ Äôè~fF&n}†¯ç Øù,î>¹ÃpëæM†¿€qÏÆÌðŸW‹áý)]`¨›3<~q—áúµ«@/å˜XˆA!|çÇ5Gßþƒ_ÿ€Ä_¿~þÿóÓ»ÿß>ùÿþÕ×ÿï^½ÿÿå-Píç7ÿWí{ñŸÝuÿG€báäádÚ‘áö›÷ ¿€~ú  ¿ÀLË4 ¿þeøöï ø <0Ôî~âbøÃÎÎ@,/?µqçŽÏßþ€²Ã? — 4$çòÈDæ` 20°012|{ù €ÿƒr  À=ÃÑ–u'IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/view_tree.png0000644000000000000000000000161311550446572023221 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbTU¯¼®gª¤òó÷ÿÿþ20üýÄÿ 4ˆÿÊÿó*•ûËÈÄøêÆÝÇÄbãa(ãPÊòðDÃ/ þù‡á÷û×YìÇo6nÆ•EP4Æ(€0 Œ¶ƒ‹ÿÿŒà‹T .¶FHrSÛ½·½DçCE$²|sú“‚2*iR`vã –Ÿÿ2Äk108h 3õ#Ç·¯Àš„Å$€|& fF&¦¿ ÿÿý«adüϰýòo†ôÍÿˆå7#'+ƒ  9x hƒ¯’,Çc‡~|}ÍÀ«aÈÀ%«Èðû×o6¶ÿ ììÿþõËßÿL`g#66v†Ã'Ï1ü¹ÿ‚ÁøÃ6™+ Ï_v1ÈG3ü Ðÿ!ùh @1ýšòäA$ðÿÿ?.nnQ1AÖOþŸýÇÀúŸ‹áÐýÿþþeøŒ’@[ÿ131Ë?f°‘Á "muw†Ïª ?>}eàòûÁðh3Hþï_F EL t@áýûçO0‹ÃØ€Hÿüõá×§/Àt4€é0]0C“™ €Xþ]ðÿºŒ œœ@}wúÃ×_¸Uå˜xùþüú 6!À¨fb –?@Å0ü†###ØWnÞeàûþŸAêb;“àU†×/ZD}Sþüù 4ä  €–Ó_ 3  ÔUU8¹Ù®ž?ÇÀýù"ƒÈ¯7 Ì?¾Cˆ ) è€zèÃ_pÅ©š†2«=þ•áËq†ïÞ3ˆÛ20ÿûÈÀ vnÖ¿ œŒÿ€ê™ˆ…“‡“iÿ}&†ÛoÞÓ;ÈùÿÁÆ@ÃÿqÆ3üÒ×>1ü9û ˜‘XX€ï|`eøÍÎÎ@,/?µqçŽÏßþü%ٿдÿš Aá Nhÿ!™„A|&F†o/ßãÿÿqH0‘ jÛ’¢Œ×IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/player_pause.png0000644000000000000000000000135311550446572023722 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<}IDATxÚb”p^xÏÉXJäÿÿÿÿ˜Þ}þŽ÷ôÓ9¿¾ýÎd 0ñÿÿ L¬ÌýN&RÙ‚œßÿüû÷Ÿ™™‰éÀ…ˆEM^P¶¿Å…åï?V†+7Þ3O\#ÿëÃw 3Ð& $ ‡b^² «µ©$ëŸ  Qù;9P8†8ƒ M»ôbÐÆ÷o þCm‡ÿ†Ü}Ôôb3È åÄòÈyôâw¿}*`Dµæ@¹¯@µÿ@½øh@±€,ûqXÝ?„z€rL-L=ˆ &4u`üŸ?@V @L €ba@rŒÍˆC1ºwAl€b1˜¡î`d†²ÿcÇ,@9 šÐ(%R€baºA’œZÁ|Æ-#¦f/ƒPíß¿XxÀÆÀ@`¤…¦²‡Fý_$¿üƒP"@d„!)”8€zˆ…ÈZò’X¾¡¹àÄ0F -´]hÀ ¬@Û9 €X89˜Ue!‰d*Ë/f¦ÿÀtøj;Ô€ÿÿYeŘTå€3+03qs02˳ÇïŸÏî:( pvþôù'7Pþ)ƒ'Ô) àúÇÂôxóòóŽîâþöïï¿ÿLÌLŒï½ù `„ÛPâvÄIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/run.png0000644000000000000000000000173311550446572022037 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<mIDATxÚbüÿÿ?% €X@Ä^^†Ÿ\\ ^½b`ççg`æáa¸ÿô)/ ‹4¯œœø›÷ïÅ%%}xy Ο9Sùéïß©L@}‹€– ̤ÿ2üb`àú÷ñ£97‡²Š¶¶…”””+J É ½ÃÆæòáûw° @`þþüÃ%&æa`g«&ii©)niÅ#ÆÍÍÀ½f ÃÿgÏ~Þ¼Éðèºÿ_¾0Ȳ±©>üþ]”‘á5H/@ ñð˜æ¼`/+ÐéLll ¿b>~aøþüÃï{÷~þþÍð è “e˜™58-€x3H/@]òíÍ›«lÀpøÏÂÆðýëO†Ÿ_~0üöKFèº ÿþýcøûãÃÏÄÞ¿cfýÿ_ñ=P lÀëk×7¾=~Äðmï.†×R² ÏŽdxyñü­w÷îÜøöúå^€‚"$>¿úðáæëOŸ ¿ûÆðèç—Ÿ?3¼üùãýûæºc¿9¹ö~zòèÁïÿÿO³ ?aºl;##˜óóׯ{oÞôûúë×£?nùþÿÿ^FÆ›_ß¼~É%-û_áÿ‡w Œ t5#¥Ù ÀÞŒt¼Ô°­ÆIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/top.png0000644000000000000000000000173311550446572022035 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<mIDATxÚbüÿÿ?#cß9u þÄŒ `Àø—áÿ ã?ó1 TÊ~øÿ‘@Á‹XˆCù@Í¿¿ͳªge``;ÀÀÀÄ dƒÔÿb6 ~R@0ö3ÀP/úN//(6VF– or--êÿ v &8‹ Èd¹î;ÐÕkëkíÊV­ô—YºÌO¢·Ç)‡™ùÿ†ÿ¿¹X&°2µÄ|ÌŸ}¹îOi±EP]“-ÃŒó _þg(,²`øùó¯KUõái@‰ ì@w°A  ˆ g1~ýñòTËêì°cXt™aõÿ ?¿~gøóùCe•Ã… ¯ãV­¾q„ƒcÃ?ˆ_âÓ¿þT—“çŸ}äf`bâ`à`ýý…ñÃ_Fpð J’ 232ƒ¸"œÿ4D~r²0ˆñ21ü©gfd' PøI6à?ã?xòüÏÊÄþ˜B¬„l”9~ÿûà ÄÇÊpîæG†ÿ,ŒlpuPâ^V¸C~31^¨šrÎUJ„ã/ÿ`e ‡½|ÿ“å' ÓMnV”Ì`­,&ç·j³IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/viewmag.png0000644000000000000000000000145511550446572022673 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<¿IDATxÚbüÿÿ?% €X@DII1 +ƒ° §¼¼B™ °ˆ##˧o¼÷fÚ×o?fÞ¼y“aÚ´i žžž {÷îeøõëÈr€bˆ‹‰äêYöJ(¨±Êˆð20112<}ûUïÉý»3^Ü¿júéÓ§t Ò¿VVV Œ@ÓwíÚv@ àåávUÕ3ŸÈ¡`ÎÈ%ÄÂð( ò?;¯ŠÃo&öä?Û·Ý õ333Ø€b²rò5?50²0¼ÿÂÀðŠß~e`øþ‡á§ ƒ¹µc++ÏÇ^¿~ÍðóçO°6€[@Ìøý?>†ßš€ø5P㫯ö‡o ïÿ°0H©H‹Š©±£"@±@¨ÿL¬@½jøö‹â:†_~]ÀÊÊÀÀÌŽ-ö¹@"ˆ@  ° >¿}qQœí ƒÃï Ÿ~Bð/ ›—“AŠë/ÃÛÇ·Þ?}óîžP}s@  °Û¶níøýô"ƒƒ’0Ld€XQ‚ÿ¿¸Ì°eã†yÖ¿¿ü T/ ÄUPlÀ†M›7NŸÐÑúñÆQAƯ Òü@€X˜åÃÛk'¾|~Åàkm¨3S˜É ä ¯ #( €â´µ4ã¼}|óTÔ55˜˜™Y?¸÷lÇöm BEx•"Ýãyßmù{6ùBô£ÇŸV¾ª/ê ,I™™U™“ƒ] fQ(ƒÒ8–çÿO˜ýÿ|Ìï÷ZYÞð>h bó‚ƒá•ögÿ›þÿpÄç÷†ã~1Ø[šmÿÏ0eÕA;M!]c+†Çjˆ›æ7n0\{ÇÁPèÈÀÈÈוqa˜µù4 ç5†?üZpõÄ„ÍÙw¿bðu0†k~ûá;Ãk ÖWWa¸ÿè1Ã_$?† »øôƒ‚;8†>}ýÅðõǰ¼$ Ãõ¿þþCè ¸ÿBÛBžáü£o ßþeøùû/\ñóOT„™Qb €àÕ2üj©gå`Ø´ÿ4Ãû¯à ?ÿøÇpüüEaq)/<ß|:‘‡,©¡cÀðòÕn†ÙË72hië0ü ^8–áêZ-a-†3œ pnÈé Í W€ühaçÊ þþÕËÀN ðgøg Πȱ•áÇý i†w OúîdÍ0š‹O€ÁÈÒÁЋW€MÃ…áÀK3MIF†Õ\•3øæ‚ó¶_`PçDI®ÿal„ØŸ?Æ »¶ßehsÿ­ëĹ €AQo~ æ"23O Óð–äþ`Ls9´IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/player_rev.png0000644000000000000000000000165011550446572023401 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<:IDATxÚbüÿÿ?% € ¦10üþÍÀÀÂÂÀðç/Ã?ˆ0ÈÜ?ÿ˜˜™¢™¸Xíÿ³2•ÿÿöç à‚/¿dY8{¸yÙíˆ §Ñ¿ÿÊM™î§±ÐÆH2‰áëoA†Ÿ¿AšÃeÍnq ósTä ìüú""λ§µÖ9az›ƒ´8ßÏÿŸ~He¦9¹©-Ÿ=5P!ÐGè@¦Ä‚¢ñï?1¦ÿŒmfÖ*qÉ)–¬2Ê '_20<{ñ…™ƒŸsuR†­¨³«&ÃË?Ì ;o30|øñ € €òç/'>~ž©Î>Æ6nz /™™®^úÁpõà†¯ÿ™Y²CD…eDÝÚT.!ò @±5 ¯NZS)ÛÌÛŠ…OVŒáð3†7wŸ2<8y‘AHBˆAÓÛ‰á!3;ÃÅ À0…„ó{`p|þÉÀ@,Ìì[”œl,匀NûÇÊðø9ÃÛ·ÞݺàbeÈÀ+#ÉpçÐV &FˆOÿ]ðhÐ`¤ ###×_V†˜@‘ÆÿÿŒ ?Ù˜3€£” & ®ÿŸó?·mï¯Ýüþ0ƒ€'ƒ€´(3ó“ç~~ú ¦(ÊÀÅ´èvVfæá``øxÿÁO€bfôù4jã—¯/¿»óК—OIM”AZQAJEŠáóÇ ¯¯Ýa–b”ædà„jäc`xyëÁO€bfð†¸…•åúŸ¯ßÖ=¿ñPêëë÷š@C•UøÔõån¹ö÷ì–“Ÿ„Åx8Ô´€®äedàrï⃟1àÐmŒàäû‘…yÍ»‡¯^Ü»ðÀPH˜‡OÏP˜áæ¥ç¿úàÊC†/o?ëié‰1(*²1\>ñð'@¡ ^&&ûì÷_w^;y_âËÇZß~fyýúkýÿ¿ÿ潺ýâÅíKOÌÅ%ø¹ß½üø € ™éψFPfeª¿ÿ †ýþËtQ:3»Ë_&Æ4†_¿_€Å¿ýRgäžÄÆÍf@Œ”fg€yÉ1‘²Äm€IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/player_stop.png0000644000000000000000000000066711550446572023601 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IIDATxÚbÌad|"ÊÎ.þŸ™ù?Ãÿÿ DFFÆÿßþøñ €XDØØ$ò™9ääþýøA”~&vv†ß¯_3L[¹R €X€ü@ff..†ÿPÓñ +™98þ1Pí€bùÿïÃçû÷~~þÌðû÷o¢\ÀÂÊÊðÿãG†þ0 ЀŸ/_2üýöáP€ÀÌÌÌÀøý;H/@]ðãùs†7oþˆŒ@o2ÿýËÀÄÄÂÔô èÖÄÅÈPõÄ6‘|@L €¢Ø€¢Ø€b!Ç&(…@±€¨À" `†b^€bE?³ñoœ K1r#Ô¤MŒÄò–áÝt!F¢33,Ý0¾``ø`L;^+ÐhyIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/viewmagfit.png0000644000000000000000000000171711550446572023377 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<aIDATxÚbüÿÿ?% €X@cÈœïÿ¥~2¸0üe°c`âÕagâ•çbæäaæcãcúõó?ÃóWo¿¿óá[Øÿ£Wß ÄœÿlLŒ,çMÕÌÔõ¤ ˜µÅµ´%´TD•DDXX™™ÿ32|þö{ÂÚ…Îͳ§­jt ¸Sþ1 ÆYÅ2g9d€ù‡¿f8úã ÃË/Þÿ~Ïðíßw #ÿ1xˆx0TE¥3ÌÝ¸Þ ¤ € 0þúõÿ—iÑÒ¢3ìLœ ¶1 ^`˜ý|6;3;3íòáãÏO öJ ’2ì 1€ˆ™˜žþüýC5efâSfN¾Z«Z†ß?2l|¹‘•™¬Œí/ÃßþüûÃÀÆÌÒÅ@°0€˜ò稪´&—¶„Ãý÷n½¹Åðçë†_L¿Àª~þûÉÀÂÃÂðïφ/ß¿ý‰< €²éê²ZÓ¶dofbådbH<’ÄpõÓUnn°ÓA¶þB^†¿¿ÿ1¼üðl*@15ÿaHQ•Q›¶.} #놘=± 矟g`ûÅÆðéÓ'IFI7a7†>01 2|ýöáýç_AZìNžéKâ3É É1¸¯wg8ýú4ƒ»ÃÇo$¹¤&™Mb0—0c`úÍÄ Å.Åððå3†ï¿~¼é ° ¾ÿü¾oÖ±Ù þüaˆQ‰aàúÃÅðöÝ[ & †EÎ D.X}rC¿uƒŸ‚ÃåG·€ùýH/@1€“r&•À°9fVüÿŸ~þŸyhæ­­ÿGnþÿôÙ‹ÿFy®ÿœD?MÛ°ø?NlÿÏ` _Ò @ˆhdgð]rhá.6Fv×î€voe/†_@öÆ1œ»~²™…{jþ´ú«ÿý¹òh9+ËV€b™Â˜ 4áÿff`øögW¼]šk‰k>CÒì‚ÿ§/me`¬eø”ûÉ ÍðŸý,+çÿß¿~Ëþ?|í@¡ðè ?L ƒ¶òsˆ¸~|û¾‘«žá/Hœ"ÿ¤Ž• ˜ò¾ý?t• €)Í΃`H°9دÈIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/piano.png0000644000000000000000000000136411550446572022341 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<†IDATxÚbüÿÿ?% €˜(Ä"&&¶GRRÒêÊ•+¿ ?~ÌÀÈÈÈ ##ÃpéÒ%mmm0ûêÕ« /_¾d044d¸pá3Pó·oß. މaŠÖ@$ä.z˜À@L /¬ ˆŒH¡¿×÷žÞû»÷FD8çPk¥µFDPJa­ÅoŒª’™˜sNÜý~Ð8&)€0 ©t£ÿ­‚ZñÈ&‘muw¨*N‡ªzÇ輌$2föwk ÀáÛ„ â7°`ÿ-1jòJ áȽî6¨*¬‰ë×3ã|Ðm$¤Ï2_±€€\ ¬¬ÌðEEEÁ’ t*ЛŸ_€AQQ‰kJJJ ||| ÿþýgÀñœÂ@ì±õÓz¸ÿŠZ<:@BÒ36 Œ@Jæîµpïp„¶ì5AF•‘Ôâ”àá ‰,¬¬ ‚`óòr]ÀÂÀÉÁÎÀÇÏ  ..N !<@¿³‚Ù @zp()‚PD»]n«ã‰Aá&þWI©IZÌêMgL_4 Î9RRŽ}û»³2[KlÆûÂÉÒžZ3«÷ˆ\LãP>DNv6y†ÿ¿3pJŠ20€Lþ÷‡AYè…?Ì/ ÂB|À@bøÿ烬œ 8 þþý‹ €Xÿÿ†8…á/#3ˆþñ63ˆøTÇö0^À˜« 6Т¿ Äòëû'æÏon0°ãùÏŸŸð@à þ™ Ìúõý#3@1 òs7ÔVÐZõ#ÄFF& «˜/\{p €)ÍDqn0òA³x;IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/rotate.png0000644000000000000000000000151211550446572022524 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÜIDATxÚbüÿÿ?% €X@c4#ÃoAyÞiš:ÒA§ŽÜéøùâO#Ã0*bøË&ÀÂðëó ›™á+Ãÿ5ßlP³¨”šàú´tk Yi†¿¶gß¾ô\’™›‰h4ЕŒ_>þ¼ûåóÓ ¶3° \@Œ /HV îJÍvqdøúý'Ã_¦? ?þb`bb‚+üöí'ÃõkOÜ~uÕ§—ß‹þs¼¹ €ÀfÉ)Š; Šó2¾}õ¼úó°7¿u1^ù~øÿ§_€¡ÏýïÖïå¾þ[Œýñ)çD-öÿœ üÜ ½1àÝ?móÿðço~žÍÀÌ(òÿïÿ` ˜³ý{ó÷;#ã¿o÷üûðý×?&†_¿ÿýé ¤a`:WHÿ`øû6_À±ÃŒÀÈÿÃÄúõÇo†¿ÿ~1üøù¬ €`€x{±$4v æâõ@þòq|ùúCý×`4ÿ+ )• ˆ9^b`1ú•…éË÷_ ,Œ?€€}À@,Ĥw&y ÏdþþüÅüå×/f&V†Ÿ~ƒ¼Æ@„ `ῘþaeøÇøŸáóW Ìï~|äë B|ç”ßÌ ÿ?³3üÿËÜøeh7Ç_Áÿ/¸Wƒ#¥Ù À!B3)Ž^zIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/player_fwd.png0000644000000000000000000000171611550446572023370 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<`IDATxÚbüÿÿ?% €ùmæ>üñå÷ÅŸï¾2ð°Ýe`fd`ä``úó¯ýïןçþ2Ìg`cúÍÀTÍÊÌÀðëfa`ø ¤YXˆÉÍBNp^‡‹¯’ªðA†/¿â¾%¾ü°3–ʈÕ™ÉÄĸá×_%\. ¦_þy¸+3Ì™ íᣵhÓ¼ÿ_~*ŠŠð|œÐäÈÐÕì)!É·›áçßXlA¾ÿ2\x$#îü9:"1ÑÔæK  3( 76!îð÷Måßì(ÿÿþÈóÿþA¾ÿ0]x(#Ûêáï.5! ÝÚëÌÑéò ü .4$ -åáíRøóöÙÜA¾ÿ.]x#ãðíöÞëö %äàìÌÂÔìúì (ôñõ[òçí͈™_7¶‚E^™ã͆ï¿ÀaøÈ~ÿ“™WAŠCPáÖñK ï?þføÊ%Êð™‹A\K™‘M@ÐäË׎ÄòèpR`D Y(ýý/3°0ügdÆÚ_ «€ÃçÿL YX|F.€bÊ1p°20p±Í€¦)v.P4ÿc¸ò2Ãç‡d ÕD´TaÇÀðéå†;ûO1¼½zm0Ô (Mˆ 00p²A4sr30||ý‘áÊž³ \ìL ÆÑv üb| ÿ€^»yâ&Ãå'_}{ó¶€K±ð €X€1Á ÂËÀ ÌÇvµ“wö/>ðQVY”;0Ç—……ƒ‰áåãO WúûÔõÍÿþü+f`g»Ãò;+ƒ²<Ð Œ_AvÎÞµúçë‘Â|_¤˜ž¹Ï°¦kã‹›G®æýcbò†üä„@,\ìŒL·Ï>fX9íè‡gן61ð°÷3òpÊ}ÿüM`ÍŒ£ ûמßôçûïz`@]@h F»Ïþ|ûuçÇ»¯Y ÌW@© ¨X˜ù?Ã4Hfú7hëwp°€¢èt € €)ÍÎ ñ'ž§¹IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/2downarrow.png0000644000000000000000000000204711550446572023336 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<¹IDATxÚA¾ÿÿÿÿSÄÓ(&ñüýëòõìñy œ ýV’ÿ øûàú&ˆ…ØYØx ÂäØÔtù6œþÉ9oí«™O^üJu0üg``ddÈ”aîûú…ƒ‡‡“áîS>^€b/?ü ,ôøÒ¹3ŸlÔÙÜœ¤˜$dxÚþýobaf¨ÐS`ÂÍÍÊÁt'ý§ w~þbé F½NÉ®Â%À·²2ZÜH^…‡aîá §®þd`ceù/*ÈÊøíÐ7@ëž¾f¸öç7C3ÃÅÿ“ì†ÿ€F³ßùöŸÙ¹qå—ƒW®ÿ`4dbådøø‹•ñ3P¤ðÉK†Óþ2x0°0\dø÷¬ € |{ËÀðö1Р_þppûu­ÿµþÊ¿ IÖ *Ò ÿþ‚mÞõ—…Á‡áÿ¿Ç _€êß?k ˆÿ~¿ ô܆Çç?1ppEÎÙË´àÊ)`P½~ùÍ&† †7^1¼¹´ì!ÄÕ@@àX†3 ÃÇ× ¿>½Ãõ“AÞ$}ÍY†À@ä`àdlbxsï;ÃÇç@¿°£” ¢l 3c+/»Íï?ÿÿýaa}Âðâú$îg rþ~{ÃÀðî‰ {3« 3Ó&Æ“@­ +þg2üeãd8rú=Ãî·OýúÇÃÀËw›o¿ä¸øØæÿ”qbÆ¥0:Ÿ>ùÄð}® #@Ãàݳ÷µϾdðv•aˆMÒgp °0cçâØÆðŸIèf)!¶mJšÊN|rÒ òr| ß¿ýføõ ˜È€ €À^øÍÈÔ²tÅíï_ýé)¯´`pp–axö…]åÊé[;x8X~)목=fdàgýÃðìΆwo43°°Öƒô$™þäbë=²ÿÅç/ÎN¬(1äp²exô‰]áû†;øøÙ~1¼zðæ÷Çw¿Ê€)j4 ЈJ̺pþcbCÛ•·ºBŸ\ÀÀ&ñ…áâ­Û rL& RŠì ûlûA¾ÿâ  ÜçóÕÚî    ½ÌÈÌé¨:Fè ðÞºâFN?$E©ãA¾ÿéèï‹òìø=:D%÷óÿûù¥¹°×î¾>XÁåÂà³õt^gí&Ö„­ÂæÂñA¾ÿ!"Hæðîù,30' µÅ®ÛðÆ,Q ¤Ê¶öÈ[RF¼± ½ò£6î ЋA¾ÿôßàé¢ÎÊâø ¡¯°´Î³Mõ‡²þÂR\1’Çñ¨ ¬ðþ)ø íA¾ÿ!!NýýþÙñïù856 &þýÐáÒ¹î°ìëë ×ðÒßÙýðèþ׿óëêA¾ÿ""Nÿîðõö Q12 ø'¸ßÿêò,ÝåÉî3í(óSòìûêA¾ÿ%&OýýýÛôôþ9%²²Òö¦ ¾°áÖÛ…èÛûü ,:éíß×÷#ãý!ó úá8ˆÑ×o!83223ÐOóW/¯Å<~r3#Ç6ŽŸ2¿àebcoâw|]ðÇä)×¥Šÿ¸ù˜~2{ßãüzLð@Á3#3ïß_O>yzþä¿ Ü\ ?ñÉòÿó?Æ… ?bÆVËÄøÿÒ—œ³9¾«410ýú`58tX^‡SIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/mix_volume.png0000644000000000000000000000124711550446572023417 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<9IDATxÚbüÿÿ?% €˜(ÄÈ $200ýebø÷èšß, Œ ÌÌäÍÿÃÌÀð‹H320ƒûƒáï×ß ÿØì9øÅJˆ…4ëþþüÁÁðŸ1>*4´‹ƒ— €˜Lrÿþÿ²ÿ110‚0 Ïæ3]Çð(ÿå› 7¿`OQFnmI5û“gÏ?q.øtûjÚZÍUY&‘6¾ l ì Ÿ¿~c Âücªù_!hÏ•_™%¬ìÎðEĘ™§àØýõOœ…‡m¶¬»  £°/Ãg „›ýï@a5àÿ Ç™ÿ¹ ªòMÕ•Vf“gdøðùÃ÷¯?þ üg`f€ÄþŸ¿ÿ¦¿þ 0±²+ÛH”ëøH³2ð00¼y÷…áÿ_li€ €XNºùû]Qž&SU †o¿~3¼ýø}(.Db 4 þÿü£l*U蠟"ªÌÏðæãW†_?þ2013£„Àr>3B“@#›Aˆƒ›­ÝÞW'ÎÁ]—ƒ‰›‰áå—Ï Ì@¬\Ì ,?ÿ£ìkvvv. de€ØËÌÄÄ @Œ  Ëùù¹Bt4äþýÿÇüûóç_ € èÐÏ ú÷¯ÿ ¿ ìÏoF=.]1F1`Âbaàdâb¾píî+€b¤47Ź Àw䪉Å|¶IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/encrypted.png0000644000000000000000000000175211550446572023231 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<|IDATxÚbüÿÿ?ƒ¯o  üû÷——ß×ÄİBMMÙ€……•ñáÃÇ×Ο¿Üûùó÷ÌÌLÿaj—,ég ƒ,2Œ——7ÏÃóïÿ&æ ®ßabbú§««m¬ªª²lË–Ý*Ÿ>}nfdd„[@L ‚…• ‚YXŒMLÌ;Þ¾ýȸvÃæ²Ó®š8wÕtÉòõio^¿ÿéèh[ËÂÂæÄÆÆÎ @`~2ò1üúÏÁÀ/ šÌÉÁÃyúìù ì_wËÿ»û^áßOì_Í>päôR>^^V ñ¤Ÿ~1p  °ZŒþüùÃÀÂÁ+÷îÓw†¿Y÷É0>cP{»›AõÍ.9¦g Ÿþ°oûñ;¿°¸üßL Š¿Žƒ  ph²\“gyÅ÷“…Ø·÷œ †L§y„^+½ùÁÏ ’Wã{ó•ûï1á/oU?>6aÜc&ôûþ3 Ô€bÜÖjÓ;Ú–ZÊ?³0ügbd`þýá?0 ™8˜ÿ0üýö“áÿ¯¿ÿ8þþf`füÉp÷ÊË'® 'eì95)e77†¯Ÿ~½b``*|ÅðâêU†¿2Hò30|æbdøù(ŒE>^ —Ed@zlÀ¿_ßÿ2|xÌÌðãß·ÀxýÈpjÃA†˜ÊG ?ÿ10̯ädpr”b`ø ²¿~°1üû.ñ¤ €X ©çÐæ ¿A¼c``~ÏðáéG†ÿ_@Éæýß ßò? 0³3üÿ+Ö @P€‚Þ ø¤?ÆksN{Á _~30ØMù”ûNm ä d€À@àhüNY@ë>ýÄÿ?2¼;÷™Aü;0|€Žûp¨Œïü@ÌǤ‰ˆ ¬• € .`bF Óÿñ?ýÊ ¢ÂÄÛÎgdàå*fac``Zôh30é³0ƒµ 4  †03ÐÌ@ VfN;AN6hšúá, º€â€ÀÄÔ! ”o@[þCÍé…ç; à‡çWnvFV°¬úÑÕw96‹*ýýÃñ¡‰E?üú†…åþ…÷Ï4‚ ¤ï,Üél™áIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/rebuild.png0000644000000000000000000000165611550446572022665 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<@IDATxÚbÔ ¹yNß@HñûÏÿþüþÇð÷ï†ßÿ€ôŸ þBðß?ÿô_°Ü_Ÿñ?ÓË/ß½»~? €Xô …ÔÜÃD¸_½c`øõˆÿ00ü„áß@ ûù Âÿ dÿbV†? ,ïÎß– –Oýüòð57Ëw êÿL ÌÿØ€Š¸þ30-ÃÀ@E ßÿ°2Üúö Äù @,?€meYdX60‚ÁÊ 4#D*ÎÈÀÍÎÄpûý†€Nz €X@‚ ‚¬ „Á†ÿ0±r2°0=by €XþìÏ¿ÿÄè†Ão†…ç00²è3üú% dù@, PƧÿÕÇ× gïŸcxýí Ãׯß¾ÿýÆÀÊuh0ÌX˜ˆ-ÿ±j¾ñüÆ+«Þ Þgàbf`ägeà`g`}ÀÎË0áÃ>I€bùŒÛÿX\ðã熭×73\ã9Å Á*ÊðûÃ?` 3eaxùñÃýK< ÿži} pücÀ4áÅÇ— ×__gøÌòŸA“Iƒ!Ê,ŠáÝçO ë­:]‘aÛ*1†oϾ p`s'ƒ¥„ ãfAA†GŸï3X©[0|üaËðü#+ƒþM†ç²§SˆYB?³<Ò[”Sˆ“ Åv#A^A†óÏ1ºr‚EA”[†áæÓs Æ÷ä%4ˆ˜xxÎ>ú í?àä Š‹˜™>|¾Çpõí2†¯R$„¤v¾ÜÈL« ŒÊ$ùÎ{p €y´v®åâQýý˜…þÃhÂP†úÉòã<{DÉUÍŸÆy?K0°þâ`øËô‡ù'í­ßníÙy: €ø—q0|ý!Âð˜ÁÉð”àA˜ý/Ç=.)ŸMi¡!Î_1|;vèØRf&®÷Ÿ?3~|úâÕº? ßo#ƒÐ Pœ³Å¸À˜aøÃÎÀ,ø€á¯î!¾\ÆÿbÎoïÝHeøòû9+¯4;ן ‘Öoã<ÍLIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/bookmark_toolbar.png0000644000000000000000000000204511550446572024557 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<·IDATxÚbüÿÿ?% A¾ÿc%%ûüV r)ÿÿìççîÛùù§þú$\ûüãììÜßññ“¢ú¤‘•ýïß–Pkë2‡˜^uuˆÑׯKܘ;·ðïÏŸ š©© Lzz Q¶¯wîèY¶löú#GŒþüY@ŒIòòñ@Í <ÊÊxy¾}ƒÀÁÁÀðéÃ? ~ü€ˆ 30üþÍp°³“aéÖ­…Ä¢ÎÉ™oggÇÀðþ=à °0adÚÇÆðûÏoæÇ˜ØÙþüaø¾a÷˗ ^¾d¸ÄÊš @,Ê \@g2Ü»6¢By÷žáÆÏ? ÜŒÿ,ß¾bܳ—áíµk _€²‚,, ªRRâÄÂòý;#Ó'gB ø4àâËç ‡~31¨F¥3°333¬œ3‘Á¨Yf>ÐuÌÌÌŒÄôäÓ§§?®\a`: †Ÿ_.MM†Oߘ>ýËðýÇ?ñ7Ÿ'žÞ{:öåõ[Õ@+û€ªÿ€´€ŸÓÍ fäeX1ðq±1œ¿úžA˜ã'Ë?†³¯ÿ2HË2p…ú°œØ~´óѱc@ ¬] m1àÇo--ù 9éÖ Ü¬¬ §/½e°RúË ÆÇÆ #mÙ¿ }_0üûÏÉ hfÁðñÅÛ¶·®ïê<@Là0`dÎñö6àåee¸ÿì7/ëo6V&†âEï2f¾eøËÀÈ ¯ÀÊðàÉ'†oŸÞ2h03±°U‚ôØ~QÀW  wŸýcxùúƒ¦43ƒ(?ƒ»ƒŸ7ƒ7 ƒ.7#Ð;/_½gøÃü“ƒ_À¤ €À ð ŸÌÀоèož? ¦jÜ ÷^þbЖccÐWbc¸÷â'ÍÍhÉÃðäÁ †/ß?10rrò€ô8 þ£™é/ÃÓ;Ÿ>›±3»ù¡rÁ!f†/_~3Üzò•aJ® ƒ '0ö¾}fø÷Èøó|6àë‡Oï…þÿc`2©Û¿0psÿgø÷ç7ÃÏ_X™¤þ¤ÿÿ[øûË×o ¥ö0T·1~|ÅÀÁÉTðáçï ÿ^}cøüä Ã×ç_Þ~gøñó0(©–™™ñËO†?ï?é ° ~}ûÙÿüÂåq- –O¿\ôyæ·«ÔBÒׯ Þæ¼ ³¶>g`à`øu÷Á¿¿~´ƒä’XX.=»z·BŠ…«ç¤°Ãä½_8ÿýúõ/ØELLÿfìþͰôè/æ/~=¼ßtÊqV€‚Àt:ÃÄggγ~~ù®íÂ)%ÆßÌ, ýd`øý & Ÿ00<ÄÀøòIÐ#í@=à\@ˆ¤ÌÈøˆ;>ß½·‡åÑãRv~AwFžÿÀÐþ °ßïßïÿÿû{÷Æ#@ÅpmÄHiv0C›L>û"tQIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/filesave.png0000644000000000000000000000160211550446572023024 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?ÔüÕZŽš’\~1100üŠýûÏÀð4@ÿþazôƒ›åþ‰{¾>Œr éþ/øÿÿç_ßÿƒÀ/ þ ÄŸþüÿÿí„ÿ÷?¼ûúñÑæçÿ•/ƒ¸ (ƒ€AU«'ýÿ7[*ÄÄÐxv–ÉçµÜÙåÕkw…Ѱ¶A Ä!ŪDZ«Á?e>,ùq6àÿ¿¿ÿÿþcd``b;ô?#ÄÑ ê7Pà7ÐÀßLß@^>A.°~€ba€FF Œ@ElÌ@Hžªé8L@®† 8Œ@΀Ԗ`db‚2Clg`‚2ô7Pó¨£ÿ32102C¬ ¸ ˜€ªØ˜A¦þó™ 8ºÿ5ýyÿÿ¼÷h.'T@AÈûú›‘áØf†?ÿÿmF#Pçß¿ô†¿ /! ó_†??þ3|úÃÉÀ_€ÀÎòŸáÅw†3WYþ|ûvóŸ¿@Àð÷/$üZðî3‡3;?0FX Øf ¿cóç7† ˯ ââL _¿12üü F†Û~3äLâ`3æe`ægf€@Aèߟ@g²²üeùÇ0wí_S&s}6†ï@—qr22Óƒ¬0XÁ±Âj€bÅ÷_P4ãøÅëï ÓVq2p±ÿbÐPút67;#ÃÇO¿ÄDy^-û 4€j@A¼4õÐ ÉîÓÇï  Xöú ÃçïŒ ßYÿ3|ýò—ATˆ‘áÕ/F°«™ &ÄŒŒÌl| ßÙ˜˜™þ0´eƒã‹áËwë€Ñt30ДU¹î>adø VHLØ€ Û/6åã°üÿñóÿ}¯ž3ðp³]ŒFh"bFÙW Íï€p|afûÇÈxo參 Ê ÄK’ä€C4>Sg¸Œ%IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/2leftarrow.png0000644000000000000000000000202311550446572023313 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<¥IDATxÚbüÿÿ?% €XÍWBXŒP‘ÿŒ Ì,,ù¼¿&¼÷¹æ÷Ÿÿ­ 30ðË20p00üûÇÀðû¯š¨0ûú?,¬ÄÄðïÃ_ þ Tô ˆ?|Ëð·œPSlÆÀÁÌæÊðõ#Ã?NNé@5ÿ$ÅxYO,ÖÔ2Ð’  ?‚@üˆ¿|12˜\[oÁÀÀÉÃðóË?n Í<@‹þ±³³1¯¬ÎT330føø›õ/@1ÝÎÄ¿ÿykjóO­k´g¹ó™“áà©w ˜1ððþg๓é?㺒x%[c †µ'1<{÷ï'@±€ýý홢<×ìÚ{¾Û?l~°wýåkÿ븀6ÿË´}Vvœ²—޹,Ãò“öì{ÉðâõïF€A¾ÿøü)£v€@Ïô¹¼éÜ¿ÉâøùûW á úù]R\)5›ÂÿØÓéæÞô„Žˆ…_myQµƒÚÉ/² ëw¼gø|áøó?þ0°²\a`Üÿ¾î29¦J =;^ÞÁðõÝ×^öZƒ“‰ãÄc†ýO€>ùþ—ƒå÷Gޝ <üÀ(ûÏÀ ¾wÿ8–žfb¸÷œ^¬ß³ð1€¼A¾ÿõ IÈÜÕêH%ýòíHôø· îÿþÍãåûþ/  >éñÿ÷ÿÅA¾ÿPæþþÿÓûòóL î öññ8úµð¶ø÷þ, )ÿþ Bñøæˆ™AʘHØîÿþÃøø÷·oÞB’",ï™ùaË" äó002ma`üÿ—•{Ç× –|¼, ¬¬ Ÿ~±0ýþÃd@L ÿýú”Ê–yû9ÿõÍ» ¢¼Ø€~daWc`fed`bÉüÇÀøìÅßs¬Œÿyþ31rƒˆƒ 4¯0(Pf}xû­ìÕ§ ¢<Àdcgb`dc`:è þÿþïÆð‡/.q…y9˜ˆ…_š‰þCÒúÿÿݯ_~eÿô©ù? ë&–ÿ°L’f`b¼óó7cÂí§ ë€ZXˆ‘Òì `qlH"éãq,IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/filenew.png0000644000000000000000000000144511550446572022664 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<·IDATxÚbüÿÿ?ƒa„͡^Ö6Œ ÿ€\¬à?”`bfbüùç7ãòuû7Þºv+ €X@â^Ž&öUa¦¼ $€OÞzܺÿJ €Àüÿ÷ÿÂjÈEÿ@Nb ƒ™Èa‰ÿÿÉÀÌô €Ààr÷?˜æP6HÍÈ 6l:@±àrâ?(þÿJ#±ñ'›30 ®ƒÙ µˆá/ÿü”`b`ø¤¾‚Lòˆ§³aN‚¿¾ñ/V` ø÷ @IÆÿ Ä‚®æÔÿÐYú‹HûýÆefV†ÿ* ?Xyþ3°ðü Œ‡â¿PÍ_¿~cøtç"¿Óù9 \ _…ê ^žbÓ~´ €À02"ùHüâ_@Ýÿ€6}ý„áÿµå ¿~I2p2¾cøÿ“ã| CÌbÁŸ°Ø€¯¿!üùˆ½ðˆÀ€úÏ.ÄðùŸƒà¯“ ¼¿Ø8ž1üøy‘aÁq/z>pØ€·ß@ Õ   Ìç§¾žZÁÀËù‹ƒ‡AÜOŠ^m¾Â`ëóYDLާ €˜ëÏ?þ Åÿ˜Ùþrp1üøñƒáß÷o@çmúþ“á/PÑç·¿ÿ~ø÷ €À.`eafdg€ø™é/Äù ƒØ¥%Øxb~YÈÀþå)ÃÓõg89¾3p °0¼xÀðáçŠoÅ6àå»ÏL^ý†Á†_@÷ƒ]ò30^0ð>~Àp•ÁŠAEðÐ.†oeL…zø¾²~a °wïnö»zט:þþ‡fŒÿà˜&—@“ÞqýÿÃòõ¿ò-åßLlÌ¥O´nÙ^P_åúçóM€jÜIä©GÚIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/editcopy.png0000644000000000000000000000133211550446572023046 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<lIDATxÚbdÐŽg`øÿŸ‰IßÁÉj›¡–²Øï?ÿ1`ÿa#33Ó‘S—Î Hí_ l||NeñžRžF2 Ä‚Éò"ZÄÂÈÉÁðdÓÿ?¿ÿbUøhë? š?ÿ!ì?@e\ @»ÿÿ –ÿ ç³²1þûùûÇï¿ ÿ£êfaF†ß@á¿ 2ˆƒ ª nÎ:^^KfF&™gn0¼xñœáÔ%`Û€l# Y†_¿ †üƒöáÛ€b‰ p¬ªLrgÿ´ý㧯 @gˆlÃÝ'o¶Ÿ¸Á .'t);Ãß?—¼ùú— €X$ExÉq±ƒuˆòbø_D‡áþó· ?ÿa`aa‡ka& <@±‹âiÿ~}ò3+Ãûï¿~ÿ]ó?H8@êˆE3PðTˆ Rñz_~ýû›ê  ²Í [ÿÀBd<”Ѝ¿ ˆ¨„¹d@Á ø ÕôûÂ0P‚h`˜Âýÿj0@±0Báô„¢liø‡¤ì2 €bùðíÜ0C`®ùl3"¥Fä€bùñ’oþA5üƒ†2Ü6hý‡*HÍÿ¿°@dd Vff.  @Af-@G1A£‘•“™ƒ›Œ spÙ@½IJãèŇI˜Ô@Y˜9 Nc€åp&†w?3<ý‘áÑû?@[™ÁâÿáÆLûgNž»`#×bÆ Y IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/laptop_charge.png0000644000000000000000000000224511550446572024042 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<7IDATxÚbôó‹aÿþ20³ügeø÷Ÿáë·¿¥¥xyø¾yÍ qêƒðýëâz–B§”­ô¤þþfüËÂÉÊüäÂÕ·ÄÒüÿÿ?nw~~…hF¦¿¿}w••åÉçÏŸž}ûüñòQégb/èØfúÉÉÄÎê`ê{Êð4Ôç @±0112üùûOÅÌÌj…ª¢;ƒ€0+Ó†7ožý»}ûúåS7lùÿý¶–„®Pó{n-œúÿ憋ÍÄò÷ï? ˜~Ÿ:}hú¥«§ÅØX9„…„äåe¥UUU£¢‚ô½?~Ñ¿ÍwŽQN¨ùÃ׎ôÍÜÊð‡a'@A¾ÿüüûáððïzøóÿüþâÞÜÊÆùúúø(lXDCV@9ëúèÇ'?GÒˆYLB”è F&vFFnSN^wNÁ~Aq`˜s¾ÿú÷ðÅm+¥ümÿk² ò10²¾cà’fór`~zøòs€A¾ÿüýü}<>A[%'+üþíìôÞáçãÓ,û¥®È5DZ6t-7â±Ãúã¤ÕyˆåßßßÂ"bºóÂs| ôTÀÈÉÉÀðûÃWYqme†Wf–¬Ç¶Z½WÏÀ*ÆÃð÷Û †û‹÷cýþG €€È¨gbêã«m¤ÂððÙ_†+7X˜„€ñ 200130°°03èq\c0uz“å Óÿß SmŽÿø“ A¾ÿêíñèâêýíüùæ0yáýOêþRÞäúÜ þïüüýÔÓ#ï îËæþéÆé”A¾ÿàçïûåšßJî½°æâü'¹(ˆððôèÝýÖ ]Ͻùúéô×{Ȫûïù¨A¾ÿd4ø•‹<®½£ÑN†&ó¬ãþá’(ôVãÄ ù'ý ã’ÔéëÒî„úA¾ÿöñ¤«wÆ–ûÚÎ]ÿ[›4ìŸ Åý8þ7@Ü îÛ´@óøÈýà–Ô“Õè$v¶n ¦†}É ÿ3 >ƒ®ˆ9ƒ—Gz¥ŒÍ®\Y‘«ÿûÿ¿æ«xz3×V æm@ @ œ,ì \Œl  ÂÀÌÈ ÌÏÄPä8s++Ø~ ig=¥·é³ùs…Éc P †ˆdãßÿ ßþÿgÆÃ_ Œ¬œ ú>3LûÿŸAÒXìÜ·?¯¿¿ó1, ÎèÎ\ªXIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/apply.png0000644000000000000000000000156311550446572022361 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?% ƒqp @ðÈ•~µ-“:,Ýׯ\Nf‡Ø6ÔZ:¦ÄxÕ±Õ˜ÒÿÇâ0ìÚü rˆ‰$ë@Žýý;A]YjW¤µ…•+ß?€"Ú WEÿ11Ìv·Ð›_ëé(sñÚóî¼J –ÿ ÿÁð ¨æ% ÿþü3ã㜟좥 ¡Ìбû<ñÓ2¹™6‹ïÕ_¿ÿÝüüøÃS½ÿþ³þøû'UNM°§ÂǘÓF\€¡|çy†]Ô3±³Ìb`üÇ@L|ÌÜŸ} ¸ÙVþþóO¬“Nÿküå`Xææ¨4uj˜§•¸$Cãžk »ö>ïgûÏÒÄÀ‰=€bzvçûL 1†ì@+kF.†uÿþ10þùýÏ•WœeWj°AHƒ«;ƒ8CïÁK Û¶¿\Åþ›¹œ)äA¾ÿ0æîôûdqIJ þÇ×âe"* avW:J"3øþóŸÉЮ­é¸úý]ü÷üúýùÿüA¾ÿ0!ðíî÷3W0<÷S6.*#îüé±ÔÓ±ªìÑòYìýýû ù A¾ÿ/"ÿýôûòï[/'0$ÿïýê¿ÝÖ®¥ñàÿíMàüüù ö ôˆYHC›õÇã/ŸÿYñ«~UâagaøôÿÃé'÷¶.ýþæ÷S–&ŽßWþ3ÿƒxšñ ÌôŒˆ‰ã;ç?¶ŸŒÏø¶ž>ýžá9ㆋ¯î3ì\úë˯Û\1ÌÌ §ñ%0€bbþËÎÂÿؽ>ÃýðÄíç GW1ÿú~Y ¨y'¡ @ÌjFÀ(ef`bdüÎôCìÍm‹×yë˜ÿLûÏö‡áóo†ÿ,À ö#†ÄHiv0P­!3•Žð#IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/power.png0000644000000000000000000000127311550446572022366 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<MIDATxÚbüÿÿ?% €˜(D±ÄcÅ3prqòèºï44áàýó—áÿûŸ>>»þøñ#ÜÛùþý»¿ÿdØ»w=Ìë7àË—w W®Üçzúøña^^±s¢"¢²2²2**ʆ~.üü\ {÷îÛ½jÕÊ òK0}Ä‚p #ógžýú¥èÿÿ+ LLL ¿ÿf`fbâabú¯œ7iÒ„”ÿ~o:xp›PÃ+.€bAö³³/ƒˆµ‚²j˜¸”œ!7ß¿¿ß¿w÷Ö훙Ϟ½Ç ¬¬,ÏÈÈ 3 €à½Ä%,¤Ò‘˜¯«¯À (ÀÀÀÂÊÀðó7ÃÇ /^þe¸qóþ݇¿³°°þé ¸?|Q ‰ÉWÓS`xóò ýÛR@C™ØØxù8Ù™عDÄ%½8 /´µ¸ƒô<¿zóèñ­íߥ2È=qc`düÊðŸ“áï·ó 7/½a8qì;ÿXþð3üýË Ó@pB”_m+Ê—]Ö6çoH£Ú­cG3èÿHgÐûìÃÀÍüŠAH”“áÓ»o 'O/ú{ùòÖf˜>€Ç'‡©³ Wb:ËÀÀêd,Å8ý^%Ãÿ¥ ?ÍTtŽút=/.ÙóßÁ¡ø {<²>€B0 €‰ACˆ¡$Pžá4ï9Ùˆ Ð- FJ3@Qœˆb 7RÜ»°½G§IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/redo.png0000644000000000000000000000130411550446572022156 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<VIDATxÚbf <çûZkNàá:pïùó—èòÄLÈ-)©‚KÚ x"¾¼ýøhÈEdy€Âk€ƒ±±?CDD„£€¾­;‡º¢xÀ×çOø„%<~þü'H @1bÓèblïh¦0ÁÕÅFÀÔÚˆ‘ Š™^?ÆÐÝ1÷ÂÑ›/Ž={ €0 ˆ´3˜ŸŸ``n©ÃÀÀÄÄ@G2Bi(ÿë·ß ‹æoÿ°bç¥`€BñB¤½~[Šl†Žšï ¿?i þó Èþ ¤?ƒÅØØ>3ˆªóq\¼øL €X`ší£Þ(°¿|ÊÀÀÊÃÀÀÂÎÀÀÌÄ ¨ä^)i†ýW™&ö]¼qÿÉB€‚ Äÿk·>ÐÖ?@ÅÒÊ Š ×^p3\;ûœ!DíÃ_†¯ò† ó–>üCŽs¡ÈÉÛW½ß»}è’G ÌÌ þõ113ƒ67Ð)ÿeN bøüŽÃLÃÜpmÓ2¹7âWúî×1ì{½ƒAFXŠ!ß¹ïì[ÞîÞ<ÁÀ4ä/Ä€ôÏÿb ŸßÄXkÛq®iXÆôTø<ÃÄ{ ÿ01#Þ[ÄDŠÝŠx.Ý»pïîõÓ@ €Â €˜4¿30|üîdcì°´|ë]Þ“ Ó´‚5þâ_¿ÿ2ü´ãéV^..† ŸbÎë{ß¹vé00o0 ü½,|'-)^(ø„÷2Ô‡@›ÿ25ÿøý ŒÿýÏð èçíO¶2Hò‰3ÔúVrÝ}õÒçúí[ˆÅZßnæœÜÙâb w?1€5ûùá÷Ÿ@Í¿¾ÿúÅðDÿüÁðïó!>>†Y |~~ŸA¾ÿßîáÎQˆR*;"=`ZSc_üþüýþþþþÿèòèŠÖ‰„–ú²Ç¸èçõøÛA¾ÿæíãJæäáü¶^ýT6,6¸Â¿éòêÿ K=E¡þÿÇÕÉØËÅ»G 鈘X„Xßþcýû‰ñ7 ÃË//ê–×nþâÑ4†ŒÿyxÄ’ôt´‚xXxøþò0|ûÿû3ƒÛ `ô3  3Ã?Þ ï~¾ýñç×?¶ÿ\àÇËÏóèÅ{¦- ÀËÇÇçø(ÈñŸ“õ/+Ãç~20ÿ¥€ÒA À DÑIšR—ÅûŸQ-ˆÁèt;»ù<‹˜T´Q¾áCâçø<[XØåB ÂQŽÎ¨uö®ùÅm G±À’÷¯?¿€|càã`øcbkÀô¨ìƒ›0ÃÏŸ¿>}ÿñßÏ/ ?® Xfbøñçûë¿À¸NQÌfå—eøÇô‡ ˜?Àü²%dªMkØaôí×ÛÏ ÿ~b€¹ì矌?tïêþºûÒ¶×_ß0¾øñê;P÷OV†¾~¯]^ÿGš_òÿåG·þ~ca8ÄÀË ÎÚ N•§ó=âIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/fileopen.png0000644000000000000000000000127611550446572023036 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<PIDATxÚbüÿÿ?>`oguÖÉÉMäë÷ïÅùxùØvïÚZ @Œ .ý˜X6`è|w1“áLÕê¥ËV¼ŽŠ güú— *õˆ¹™LL  Hóÿ^úݦ3hfI?ûëûƒ/ \^ €šðh‚’ Ãï¿ ?ˆ$pâ!¦ÓA† ©yòþ=Ã…[ ß¾200à øä]ðó#@…Þ}…à· úà ½åÄAf>n æÿ/€0 P3?;Е@6@]ðê Ãõ— O`º$C‰AB¨é/ ¿30H -øÿŸ €À¼üÑü¢Ó€É3˜døšmd„ˆý& äÿg` ˆŸ!ûïBmÒ þTÈÅÁÎðûË{ )A ÃÿþþÇ @/@ x÷â/f`ƒ ˜¾t)ÃÌysÀ¾¥˜¯ÿ0ðð±0¼þø›áÁí+olÀë/P¾BâøÈv!À¤X¹Ú ?ÿBøG—=c0‹b˜²hÛe®6à Ôo1²åï?ˆ7@®i¹ä÷_ÿóO„7l(ê`±JÙÿ¡ÞøÕü÷?D3H dÀ$lÀ' ¬lPÿûqÅŸˆðÑàþ‹j@±€Òü»KÀd+éȰè)aðèÃݽO%žò>(ÐÉ„Á Šˆ€ø@ `†jb ø €Ž;ô,U¦ßIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/kgpg.png0000644000000000000000000000154111550446572022160 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<óIDATxÚbüÿÿ?### DEEÉÉ)ÌVRRúóçÏÿ7®?>wîtÌ‘#GÏ¥¿ñ˜Z^€ba@111&&æ«\]]˜EEEþýûÏøä‰©œ€€àîë×o„¾}ûöPÙdCˆ ¡9š hëbwwWæß¿ÿ0ôOœòîü…ÿùøxØõôôg•)1'²¥wÁ_Fö0]C FVn†ÜÌ”O‡ìœÊÄÈðõÕ›•ùÜA¡1û÷pb`ø÷Ù+6`N¸XÎsîÇeüO2ÜÞ{ˆååá/e.üv¼ìŒŸ¾¼>úúÁn9æO ~fâÅ‚ÿ¿þ^xúÓ"¨Wþ#( ÎL¶ù¯ïìÊðûûw†ÿ~0ps}ÆÁÅÀdÿ~wáç÷O ÌÌÌ œ¼¼ Ý“Ï|+[üШùPïg€»€“›“UT‡õ×O ¦÷ þq2,Úñ–‡‡!Ìè5럻 Œ@¥ÿ0°²±²µ¨ñ+ þ @`þýþÁÀðí)Ãïß@…Ÿnßac蘼–áÛ—Ï Î3T„™•þãgøÿïH ?³ Ä@¿ÞmÒ?1(òÿeP’àfçfdd¹ ²@EÀ´Âò÷¼È‘À@`þƒè<†¿€ê~1üxýœáûן ¯?½cøÿà¼ì@ƒ 9X‘RÔ³^€†|dàd½Ê0/ó3Ã_—8™ø€r@5,Ü@µQ  °ŒL@›Ù100ÿ®þŸAY›’f~ƒ¼Jr@«9Éþ+Š6€…H BÂâ?#VJ³ÀØabøŠ¢ €ÀÌZõø¾þe~Ù¿ÿqéZ’ùÿ‘aí‘W/€¬?°”@ŒÐÜ(d± rþÀ@šñÊp¨÷5@Á 3ƒsAâ /…È7 þÔû À­Ë{–IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/ledyellow.png0000644000000000000000000000171711550446572023235 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<aIDATxÚbÜPÃÀÀÌÌÀÀÅÁÀÀÉÉÀþå+ƒÝ§ ©¿„í˜XEù™¿}~ýùëû7'þþe˜ÍÀȰ¨þ;+;Ãÿÿ ÄÂ@ŽÌÿ ]¢r‘jªQ ‚ ž <2@F†ï_žq¼¸µÇ÷Ƒž¯\^÷‘¡”‘‘áÈ€bj–cdbX)kæe!e\ÉÀÌa候ÍÀÆ-ÎÀ/®Í dbÇpeOWЉ ë4~~gðcac¸ @Ìá¶ Œÿ&¨Yéz)Øg10±Šµüâ £ø◠̬?$ÕeØ™‹>¸øD‰‘™a @±ýe#*Î#§rí[ ôèæ¯`/@ |6„á-ƒŽé?†Ç§|î?dð &&æ YUV–·êÎ]n¤™jÀO þÁ¿Î30ý¾Â iÌÎðèéß,€báác·‘ge``:óã`”5²‹B]ÃõÐu¿ÏÕìšùAB…—OàŸ!@±pó1ó±ñþƒXÆü èz !L§le €Ô æ÷rX€Þc)ÿËÔË@,lìL Œì@8ê@qÂö¨àÔÏH.`úÔÑ "&€baúÏðå;'3Çg ­@YF~ Œ s#EåOH˜0 ez•å/ÃÏoì ß¾üû@Lß>}?ñá5Ðj``1‚4 Cý/ ÄRP b‹AÄy12¼zÄÎðéÍÏËÄôåÓïYwOÿaøûf+Ì Hš…€¨™‹áß_†kGþ1üþùs@11³üßûìǵ×ö B±ƒ10@5KB ä‚zIáÆaa†»ç>îcaÿ¿ €˜¾|cøúçïï²#«^\»°ƒ è¨K@¡Êu'Xìß_~†«ûÙŽ,yŸ™ég3+ÀbvÔ,3Ãûß?ïxxéÒ›‡Õ™Yy8¸ù˜YXþÿûÅðãóW†'ן3œX}‹áü¶Û»þþþËÎÉp”™ˆ”•!1Ì]ÿ~EÞ¿pÛóñÕÇY|¢BFÜüÀL Ûo¿ÿüôæí•ß?~LêÙÈÂÂøù?H7uL›WµÊIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/openterm.png0000644000000000000000000000163511550446572023065 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe</IDATxÚbüÿÿ?% €X¦L™òLYIY’‰‰éïÿÿÿ@þû¥ÿþe‰ýû÷BCù!òÌ÷î?x@,\... Ïß¾fþùë'33Ð\FFF ÂÿA®»b;+ ƒˆ  Ãö{Ùˆ¨èßå»7–îßÈ ')ÁRÆÄÈv#È(— l( 3 ÃÛOï|uÍþþþý €X@ >}ÿ (ÁÅ o Äðë×/ BFˆ‘‚è °ÁÌ,L Ç7dø ¨ÁÀ äË ØYÙn¼ºÎðýæk†ÿÿ@¶¢ì°_8¸8NŸ=Íp|ïI†<ç†7@½Äòè7&&†+¯®1\øúŽ™‹‡jû°ÆÿŒ@5À°ùðü3ÃùÝg¹Ez˜€Áò— €X@¡ RøêÃc†d“8†³÷Ï2l¿µ™•‰•é3ãÆOÌ __|gøËø—…“äò¿ÿ1È’/¿?3ë3è2j3<<ÿœÿ»ƒ&³)ßç| ÿ^ 0üÅËðç+;7'+8L@–ËŸ¸Ø8N^>É `ÀÇ «¨ÌðêñO†Bç|†Wï_1´ížÌÀÈ ê?¡þ‡ùïFˆÿ€zˆé?P‚•‘…áýÇï ¯¾¾eH±ˆeáa¸ÿèù[—X¸¸X9¹˜99X8ؘÙ9˜YYANÄòÿï¿?¸y¬å,¦í^Äpçûs†IWV0|gùÃÀÍÍÅðhó`Pýæ/†¿ ßÿþ;ÿ?Ѐbùý烷 ƒ ;?CßÎE ¬@ &ÀPg'"ø÷÷8ÐþÿýÃðƒÿ;ƒ(§; ß?¿ˆåïÿŒrÒÒ [Ëg3üüLÊ@§;Ã?pÚÿ¶Õ Œü‰Ü ¬,ÿα01ËÛ÷~lß¶@AiþßHà€5þƒf  ®ÊÿúlÌW¯ßþ @Œ”fg€ /f2¸«IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/previous.png0000644000000000000000000000141111550446572023100 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<›IDATxÚbüÿÿ?% €X` F£™ ?~30°…X™¾ÙŒ@ vV†ÿÞ÷âåî•äS{øú×Ù_ÇbM@úˆ ¿ù@þþjž §(¸if§«Ze‘=3»6L@á7àï?w¦o¿öúkæÏÈlà¨Àðî?Ã_f6¸€bÁ´hë¿ÿl ¿ÿ¶‰ŠpågY²[8h0ÜûÊÄpûê?†#'ß0üd`ùS@,šü1cøýgº³ƒ’QV¦Ã.a†µ×>½ùÄpbφ›×_Ÿeàd/…i d8¾ýªäâÊÌ)´1uÔeØq‹…áüý ßžÜg¸îæ÷/o¿Ocàçnb`aúÓ@þüÝen¯b“™fÅðèŸ0CþJ`ÀøÎðÿî†Ï¯Þœg`fÉbàd=ÁÀŠvDÔÜ&FFNN>†ƒOØvÞe`xþ(öó??#7ÇO¹>2pp30p1;7Ü€‚ÇÂ?&»;nL\2qëWÎ÷w4dþ1pòs1ðëY1X;èXJ‹s†M-Ðrä` D4þgøtbáïß¿ï;óõ… ÜßÞÿeb8ýM–AÎHW@EC¤‰‰áÿ6`,é´j:ø„,Ì»ÿ³±›¾yòzÎã3ÿóü|Œÿ çžs1üQf”·e`bÚ Ó@Ø#ãg ¢ÔŸ?þF=½ñàö¿·O¹þ0¼úÂÈð™—‘C¦ €ð§DFÆÿ™Ø\Þ½ü<ÿÃÓ— ½ùÄpbφ›×_Ÿeàd/…i d8¾ýªäâÊÌ)´1uÔeØq‹…áüý ßžÜg¸îæ÷/o¿Ocàçnb`aúÓ@þüÝen¯b“™fÅðèŸ0CþJ`ÀøÎðÿî†Ï¯Þœg`fÉbàd=ÁÀŠvDÔÜ&FFNN>†ƒOØvÞe`xþ(öó??#7ÇO¹>2pp30p1;7Ü€‚ÇÂ?&»;nL\2qëWÎ÷w4dþ1pòs1ðëY1X;èXJ‹s†M-Ðrä` D4þgøtbáïß¿ï;óõ… ÜßÞÿeb8ýM–AÎHW@EC¤‰‰áÿ6`,é´j:ø„,Ì»ÿ³±›¾yòzÎã3ÿóü|Œÿ çžs1üQf”·e`bÚ Ó@Ø#ãg ¢ÔŸ?þF=½ñàö¿·O¹þ0¼úÂÈð™—‘C¦ €ð§DFÆÿ™Ø\Þ½ü<ÿÃÓ— †ÆC¬ 'ž1ÎÉ ÈÅpæé?†”yO–Ÿ|Ï $ÍŰrÕ†>å‚ôØ€ÿìÌÛæÍ¾¸fÝÆ[ Zâ '_²0<ùÉÉÀË ÁO¿23ì¾ñ‹ÁRKaÏþç 3¦]Üó…qH/@Abá?ã/Æå?ðýÂoÉÈ🅅“ˆÙ~3q0Ô…H1˜Ès1•ûüóÛïr ž/ ­1}\Wnß|S”“·÷¿»Â†mF†ï@ß9ŒøÒEŠKŽ0\>ÿ¢‰ƒýÃ/HJ H4þLl¬óW­ºæ¨¯+[^cÍðõ7#Ã×ïœ U¶L Ó¦œf˜;ïÒzf– Œÿ!ébÀo þI‰À’Q×xD’››Õ%7Óˆ‰‰‘aɼ E%ûOýÇðáÃ×ÿðô@ŒàÌÄØÇ€…É_v&¦SÃB5CÙÙ™X–¯¸¶é×/ÆL–ðLNE 3ÀÈ—%V¨ÐMÿ€¹æ§'(10°oc``êüÏÆ€HÁ¯€œ ¨(?«A=ËØ@6çW('I3ÄP†‡@l` ;Œ#WIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/ok.png0000644000000000000000000000156311550446572021645 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?% ƒqp @ðÈ•~µ-“:,Ýׯ\Nf‡Ø6ÔZ:¦ÄxÕ±Õ˜ÒÿÇâ0ìÚü rˆ‰$ë@Žýý;A]YjW¤µ…•+ß?€"Ú WEÿ11Ìv·Ð›_ëé(sñÚóî¼J –ÿ ÿÁð ¨æ% ÿþü3ã㜟좥 ¡Ìбû<ñÓ2¹™6‹ïÕ_¿ÿÝüüøÃS½ÿþ³þøû'UNM°§ÂǘÓF\€¡|çy†]Ô3±³Ìb`üÇ@L|ÌÜŸ} ¸ÙVþþóO¬“Nÿküå`Xææ¨4uj˜§•¸$Cãžk »ö>ïgûÏÒÄÀ‰=€bzvçûL 1†ì@+kF.†uÿþ10þùýÏ•WœeWj°AHƒ«;ƒ8CïÁK Û¶¿\Åþ›¹œ)äA¾ÿ0æîôûdqIJ þÇ×âe"* avW:J"3øþóŸÉЮ­é¸úý]ü÷üúýùÿüA¾ÿ0!ðíî÷3W0<÷S6.*#îüé±ÔÓ±ªìÑòYìýýû ù A¾ÿ/"ÿýôûòï[/'0$ÿïýê¿ÝÖ®¥ñàÿíMàüüù ö ôˆYHC›õÇã/ŸÿYñ«~UâagaøôÿÃé'÷¶.ýþæ÷S–&ŽßWþ3ÿƒxšñ ÌôŒˆ‰ã;ç?¶ŸŒÏø¶ž>ýžá9ㆋ¯î3ì\úë˯Û\1ÌÌ §ñ%0€bbþËÎÂÿؽ>ÃýðÄíç GW1ÿú~Y ¨y'¡ @ÌjFÀ(ef`bdüÎôCìÍm‹×yë˜ÿLûÏö‡áóo†ÿ,À ö#†ÄHiv0P­!3•Žð#IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/button_cancel.png0000644000000000000000000000215511550446572024052 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÿIDATxÚb,—”døþû·¼† à¡ÿÿ /û–òÿß¿lÿþ1°þÿÏÀ¤øïß¿ Ì ÞââËþûw÷á½{QœLL׈ق‡G^އgI¤¹¹™¦&Û·;w¼Ÿþû÷€ñÿÿË, @šá?ÿûç£/$´Ì;5•O^__âõ;?|8 @Ì1ŠŠ»bLL,…óóBC”žÏÍý ¨ù“îŸ?+l‚ƒyÙãâÞ½ÈÀ#/Ï $&¦@ÌêÿÿßÿùჇò“'lŒ@732°1H=ÎöëâÅ ¡_¿"Üܸxƒ42|øÀðÿÔ)†3K–ü¼tèP!@1Û°³_~ôéÓ}¦×¯½ä^½beTÈb`À üô)“Œ¸8‹P3#Tó¿3g.lÜøçÄÑ£Eÿÿü™@Ìv<< ÿÿ¾òäÇ^¼ð’{öŒ…YDx \úú L @|û–áïÉ“ g¶oÿsêÂ…‚ÿNeº €˜m~g†6ß?—_üüyõçë×A’oß2³ abb`üó‡áÿÇ ßšÏîßÿ÷ü;Iÿþý›Ã Š! ÄÂÿõ+P€áPñ6¶ÿ¸¸þ}:óË‹ `ïÁ_ Pÿeaù´ìP „Aé €˜]YYþ‚láàð1–•]cõñ#÷W s?¾~Íðöþ}†@üèw&669fAÁ€×¯^=`€¦€b&†ÿìì^jjKí>}âý´ù?HˆùNjdæà`øtáO +ôää8¬­g323G‚Ô #;»Ÿ‰¦æ»·oy¿?zÄð›x€.{ÄÊúï#ã?%ff–?@çþâ_Àt «¢Â ôî웲‹†–Ö÷ïßyÞ¾Íð j3ÃNΟ¿ÏÆÐG–¿«pppÿºèPþ÷³g &&&ÜÀp› @L?¿~}ôèL&  Øà`x($ôçÜ·oÅÿý[tæú«ïß§>úúõ;'0Æ@Q ¿~1|ÿþ@1›}út𹂘˜/33Ãe~þ?g^½*ìTf Åÿ^yýéÓV..O99ÖÿÀ(>~ôè'çÏdz'ÛëoÞþÂÉiù†‹KøòãÇù€)Œ ”€NfE0 A¡þéýû˜˜<=xðàáõëñÌŒŒ' -½¤H^øIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/colorpicker.png0000644000000000000000000000147411550446572023551 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÎIDATxÚbüÿÿ?###!À.í&£"4IRLPúÆ•G{ßWøûʧ'Ä‚Oo¤¬=Óõ?_ÿ>WÐXäî!d*ḭÇ`¿ÿÔÏ›ÙÞ]ù”@8 à “2‘ÑÛ&)!ÄuýÉif†ËÏö2Ü|uŒ‹“›AJIÀáÃ3y€Âí‚O?%¾ýÿÉÅÆÎÊÀÁÀÃpçÙW†?ÿ1p±¼c`ãæaxsëó{ *!€bÂ¥ÿûŽ·;Ÿoý²éÖ»ç â✠쟘î=afxñƒ—áÞÑŸ_^lx² ¨ì@á4€A¶†ÁÞt{£q Ãç?ø¥ØþaøþáÃÛ+î1üù¨ê9@áô‚¦sÂÔµÊî?ÿ›2Üy/ðþQ¯ì†ÿ¿ÿ0°Új9öŽïÿ·¿« D¼/Wli“IýŒÝCùìþ¬W|õzëëç¿>³3¼Üöê*Pó ÒÿÄJÈ€Ýö|ø¡‹Ÿÿþóÿÿúëÿÿ7ÿÿß2xéGæ: t,+c5Žbk]„j€ÑIËùÛ_û Ü|ãÿÿæ“ÿÿ»gý4vP6ˆu€XˆX ˆÙa€î)ùÚÙžùÿ·Ýþÿ¿¨9´åÞffáÅ@Ù0 æbf …Øû1@ã˜`xíÓ Í»ïýÿßÔ7ýýNNµm@5Ñ@l Äü@Œ‘æl€}Æ¥ý_¾ÿùøÑÿÿí@?§.ÿý_XÄMñ@l ÄÂpÑ@™¿ñ?úÁÌpì%ãW ;ëÓn¿}s`>PêßbPˆÿÃf@ÓÁû·¿þœ>õšáíkF†ƒÓ¦=tkþL ð](~Äq¥€byAM¿âÈ“;¯ýúñ˜ÜßÝZv(wˆŸñO|9 ÀÌ0€7(v•IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/filesaveas.png0000644000000000000000000000176111550446572023356 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ƒIDATxÚbüÿÿ?#cˆ200©¿ÿÀ€‘@BL@ÌûÏVz§InØ…ð\?w' €X@Òì‚Be²Ú’~Blÿ€jÿÿÿ4ô?Hãˆ^† ŒÌ< ß_=üÀ¢Zæ+üõÂ&ÅySÿðØ=“êÔ>±? œìì €ºÍº h; ÃûW/Þ^ÝÃ`ng¼ÏÀ­ËÀ ®È$ @`x…¹ÿò²33H ]ÃÁÊðû/ÿúÍÀÀÆÁÀðýÓW†?¦3˜X‹0°ñ>g`ø¹‰a× þW{·0¥Ø€?¿ÿþûùhëŸ ì@þï?@1 fÉ»wßžœÆ ªÁÀÀ)ôD«Se(ètXóóÅó}6€^LŒ LÌLà cв²20|ýú‡áə٠Šê_ÄT€Nù0áìq†)çÚî±¾ÿóóÇE€b‚…7P;3$äYA‘t̓sˤä_2H)°10<šÅðì ù'u Ä­xÙ?U}e &˜ Ä¿?þþùÅðíÇ_†ëÇW1ðñ]g“æe`¸0™áÙþW /þ41È›x2°2þFÌ?°µ‰F–ÿ Ͼ01Ì9ÃÊðá7ß×O¼ø3èÉCñh/ÃÝ‹of|›ÄðÏ,šáï= ^`±0CR@]Àä¼úÎÀpöö?†o~0ð~}Å ¦ëÀðÿþ †—'Þ0\e¯a¸É‘ð~Ù, TŒ^ˆvÈë_20( üa(°úÈpòài†Gw9¾µfø¡áÂàâŸÈðjçG†[;ÙX¸þ]Ï o€‚‡Hð0 ¯ß~Ê0uÎ)†3ç¾2ðè„1(¸g2ü&ˆÿÿ¿1ˆ‹³0üú Q s@A\äâþû÷o ¯ß30¼çÉeÕa`çffxÿò9Ãg†ßÀbc`bxt)ÈÿLLàÈg ° ˜˜þ³3q20|¦_†ºBIÁo ïÞ|føùãÃÏ_?øù¤dY~ƒ¬dcºú?X/@]puß̓º¼\Öÿ¾|úwíßg>^V†g?!NYÃÌð—áÉ—o ?þaüÊÄôíŻ߯î¾9ÅÀÀÁ@Œÿÿÿg :|kã­IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/reload.png0000644000000000000000000000215711550446572022502 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbdHg``øÇÀÀ „ÿ~ÿcøÏøŸ ~ñ_ fgaaf[Çðý×õ?~·20°†™ºô9-ä8•~ÿÿMmÀ¤ÎÂÄðüÿNV6ûïá e5SÞ:wÄ €€.`ù÷ÿ/ÓçO?3üüÂÍðñó/†¿ÿ2üþõ裟@Í@íŒÿ˜þ33(þ1aø|›•!myÛýK×ϧ3ps F†hn`ÚÿËTÝ™j›QàåÁ Ã)ÍÐ3sú¯+OïÞädåadüÇÌôç7ÃËw^?ytwÇŸ¿æ0°s¼a`ef F†(.H^øÅÊÀðös”¹ªcc¸}¸Ê´õÓïݹ}Ù–…ç8Êþ±þe`åþÊðíÇ6¨ ·b(sýFŧŸ ˜Pde­e`äÖþýç—/Ã÷/ÀhfÚ@ X€®ýò H³Ã 0xetòÁñ`IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/mix_recmon.png0000644000000000000000000000114611550446572023371 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<øIDATxÚbüÿÿ?% €˜(ÄRÃÈÈð ÈøÏÌÌðëï_†¿@ö_ +ÿø÷áÿª˜‘‰‰á‰320Øópp” ©6þú÷HÅ;EFv±qr²I^øþïŸ 'ç´èüüésçòIëë ¢\ f 7=T›C L ¢¢89¾úÄ@ † HM…3 K¾JŠˆ˜¯/çO ÂÂà0 |¶Oœ—™y¶/;»ýÿÿŒl|| _¿20°²ügø L€ÂjÀŸÿÿ™€ \Uùø¦†‹‰)+þÌÀðáÃߟ?˜š€1ÿþþý@ý*ÀÂÄTl#/_î%+Ë*rîû÷àèD cn(Eþ``Ðãáiò45 °’’b`|ýšáÝ;¸Ø@ ø‰ß zo''9_=úåD3ƒ±ÇLt`1  `` qqr¶»úúÆÙ»¸ppýÉpÿ>D1 ÜvÉÈÆŽ>nnˆ,,ÌÄXÅÀ°œOX8DÕØøÐÆß?€þýÿý;àAÿ~ü`øÄÿ¾}cør‘à×þ fâáa~pñâ+€b¤47Ź Àl˜[õQÀæIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/save_all.png0000644000000000000000000000203611550446572023016 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<°IDATxÚbäåëgàçfcxóæ+›ˆšäRyg=^V–? <_ÿ+pb`gefø÷ï?°²02üûó‡áÔ#N†ü¬ŽÞ8A¾ÿÿýþþúýûø -#Nç$.$ð6ã ýÿðòûèÓæ =A¾ÿ Š/ FÿþöÕ ùàúØë÷þþþÙèÑå:öÿüõÿùˆEÕÛ$ç»>§4ƒ›èG¾û ì, ?þ²1üùÇÁÀÈøùÐÙß„8Õdž?¾ÆÀòå7·4÷?ÿˆ‰‘ý÷w io_10f°Ml@ rÈ%ŒŒo°‚\dpÕ|ÿñ‹aߖ˾À@¸ÏÈÁó €XÞŸ¿ä´(›eÙ•çXY É÷?ØnÍŠ ÍLÀt|÷+˕ݷÎ|4à0p Iš'å²gEˆIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/signature.png0000644000000000000000000000142611550446572023233 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<¨IDATxÚbüÿÿ?#c~ðˆÙ8xäSÌe&=8¿öÿ¼›þÿ @L\80;3ñ?fVVOI¿ÿ^áüùã‹ H'@±€]±-v²õ]#Ìð‹QèB~-Cw“•?ÿ=ç¼{d¿Ãgé:€  pÃ6†{量ÿæÓ·3_$*Å/¶{Q7Ÿ$Ù ¿>-© °~ÿÂÿñofy-Õ):&fÆÇ×ÌføýÿÐ7ª7¾~kb`ÛÍ@,¸‚íÏ&v~ñz]ˠЫ61¼ÿp h»Æ/†÷Ïsùï3üÿV@,0ÿÂÞÿ€¶‹±deEù×.Zy•áéÃÕ " ŸÞ”3ügÞËÀð° @`ö߇ègÄ4áË/>æÿ‘Ñ¢—ì þ14Ìãc8zúÙ†ÿ¼FC£lPÄ`ˆüúÇÀg¢Ê=½{F“• '7á•ßÒlï¼ø¾íí7v Îo(J5KX)3Ì^¾0ÕGÎ2™añìy ³ĦX>8”nÃð†ñÿC ª‡(a@Èp›©0LT«çó‡W—áãã] í]k¾ÿaXÇÉÁŒN‹á €˜Îù‘²Aº®™ ¢/æOèýwõþ‹ö×@ïí¼ L—¬Øc €à.Ðe ±rO`øù…a÷’Õ ½ó¯N _ü ´õ#0Ƙ±@`˜™ìíM5CÏ_ûÌ0³°îâÑ3Ï—~ùÏ0(õì:FÜÙ €Àr2N½÷àGBþ´®OßM”ågxöå#Q €À|úñÿÝîs¯j€I£”¨þ3 WõçʪçíIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/noatunloopsong.png0000644000000000000000000000163011550446572024314 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<*IDATxÚbüÿÿ?0Îd``fd€ƒÿØ8XòD…¹ÒžÞ}›ÁÀÆr„…‰¤¨ìÿ™4°2€bbÀþþc`øý¤˜«¡ÞC;,Ér'KÃßBèJˆ…´•áïßh!Qnv6v¥§?9Ìü¹U”J÷­=rûÒ½j&æå0-Ä÷‚Á f †9æ>– ŠÊ L,ì`ýúÃÈðþ;+3Ç;Nn:|àížXG>€B¸àÿ¿|M7Û!#u†‡o¾üÂÀ 4A@€‹áû?F†?@%?ücxòðó¿Ÿ¿þ>„i ¸âJ¹¾Aê ïßü`8¼bóÍO/ßdáf7L¯ 7à`¸tò Ãéõ'޽}ø¢œ P@px8™¾>¼ÇpéØc†w^d`ù÷¯Rù“é¾¥§^Þqµùÿ¿ÿÓØÙþ"@!ÂÀhf0ÃÏ?lÀ¨úŒ²­ ÿÿabbôäà` úöö[ ;ëC¤8ƒE#@!€‰q-'+"6~þdâa³ÿþýÏ øCFFv`ˆÚ3üþËÂÀÎò¨j7H)@!ÌüÅ¿ÿ‚4‡X+Ÿªlö)çåã°§‰¯?Õ ­”vfÕ:oUÕ–ÚÓ@H±Ôýë·¯˜`‡Ÿ™¿¹“*ÃÏÏþþùgÏÈø¿“[LÀÎÌÛ’AVá÷–{/`Únk·˜©Aº¢…/³;Ñ« ìŒL ºÁþf¿ÿ3ãàexÉÈÊpaýc†מ̇é ¸œœ,6Ú:’¼üâì ?~ Ðs¼Œ â €Žûÿ÷/ó÷.o9´˜fZaú9%222ü‹U7Pi±4—UTçgøñþ7êi[_|ÿúóÑ_>½xöiÛÿÿŒÓ™~þ?‰€B„3PŽiÑÓ·w<¸ñ¤: Ü(ÃÛM•íÑ£‹¿¼ùVv30-3Ac ˆ#'r°¾úñóWþŠÙGןïe"> ëîïóêêïÈþü›¼÷ÿÿˆnûŽ¿]º²Z‘щ žº ’‚’ Œ /?¼fØsæâ ›θ½Ž…­”‡íÿÿ Ä6ÀWHŽ1’åxÐBïÿÇßùÿýÿ×ÿèà'Pììû“ÿc&dýg1лʠc¨Ì`dÄA¾ÿ%÷7:-JbKdøúùþþþÿÿúþúñúñèöëöþ÷) éùäàÐì"´ˆ¨Æ†…Ÿ%æ7ç/†×_Þ2°ýã`øÃù¬ùë߯ ðóßO†÷?Þ3¼üþ’áùÏw ¿$_2°ÊüòùýŠË €˜Y5ºø´ž1=fâfáaøó÷Øæo¾1|þó™áÝw ¯¿¿fxûó-ÃÙçöÜÙÉÀÅÊÁðÿ¹€(@±pó1Û°È02ü`ùŰåÙ&†ŸŒ?tõDØ„ØY8À.øõçÃÛßo®~¸Ì°ûéN†¯Ü?8•¾3p]g4 &~¾ßü?ØX™þ±üd8úaã?7¤9äxYøÁ|ºâÙÏG ¿ >I€Âî…Ì„…93»J­¢-xÄøS~ýva…2€Â4àß6†ï¿§7š‰0‰ 3\úÂË ãfÅÍÈÀ8(Ç Öøï/@A øÁ€nÿü³Íß]ÉÈ;@—aã5†/˜%UØåTÕþýëcààa`”e`Vë Tüþë.%Æ•S–oÅpì ÃùÛßnßÿÊpç5Ã/ =.Þd&–vnv^°€‚À ¸¿ÿ…˜ÿí¨È³dÿÀ'̰÷Æ?†ƒŽ1Ü=z‚‡éÃ?n&)M BÆ& óåþÿk ˆÎÿ½.È[Í@ÃRƒaïM†óGï0¼|ðâü¯+3}ÿ;(ÿýP €˜´?[þ00èks1ïòÐà6÷rñSRàÚ ´L$@ÌP[øƒÐÔ¯ >3+ÂÂÀeÁÀ°Ö–Iމƒ‰•‹™AU“GéßïÿÁ/Þþ¾@ÌšP[8™=ãËìö‹ÉJ½}ùEð÷o~ñ\a Á’¿ÿ³0 3Æß¿>ýdàyðñ*@1„5‡10ÈoJ–}óÿu0L›ÿ¾ÛòwÄ÷ž‚x üd&Ƶo…xþÿ3Wþÿ?Üàÿÿhƒÿ‹9wU10° ÐìnîBKXX¾ý-Õݲ¡ñÈŸec—7)ÞþÎôµ~ÿû_¨»”— ÿÀþl#Óû'ˆI_›cab ‹ˆò& KIV¾Ë@[€øƒ–$C`˜PõÓ_ \÷>00Üù—áÞ› ÷^ÿexñëïW`ø0 /ƒ*ãŸ/ ¦EL£_ˆ0p|g`ø÷˜á÷÷ ,¹^\ÿðæÁ×ÕÅ5m¬ ÜÀÀf¦œÿ@ú Ï@̼Oþ¬zqý¿©©ý%¦¿ 8¹ð/Ãï×o~½ýÆ *%ÆÃ"äqãÔ׃_ÿýÙ Œÿ;Püi-P)@1ëÓÍ£Çÿ6>8ÿ_KD„A]D( 4‡˜²Øx~20}ýÀ éÊ) g+ñ⠣Ɠ—_N]ð Õ²@ @Ì:@蔟OŸ3¬8¶•á࣠Â×ö3ü¾±‹áÝÇ; üBBÿ˜Ù¾~dàSúÉ`.®ÃýO(òÎ…o/ÿýs ýÄ $þA“.4Õ1ü›ÉÀ¤eyüì²"›äÿ3ƒM\Šáö.~†¾ì;ùï¿~Ÿ@Ì §È@4S#H'PÙ? þd¿ùð‹áèã[ çÎïb`ü|󟈆ÙG>aÙï ÷ΰ =~ô}.@±\¥B ÖÄ•Û †º|ŸáЃû ο¿3¬þÅøùõóû,—™Œ €)ÍΩ,SE0IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/colorize.png0000644000000000000000000000216111550446572023055 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbÌçb`øû“‘‰…áÏ/†ïÿ„\3NöAiaqf^®¯¬¿?ÿüq÷&Ã¥{/zþ20lå``ø@@-ðû'ç¿ÿ ajú²Y–Î fÚ–¢ |òL llß¾}aa¸õF‚ÓøÅgûË[ÚïØú¨üß?†n€‚ðûƒ¾˜‚XG¾»‹¶½î߷n¾xÂõIáü†ŽG) X¤$„¿0Tet1ðñ,i[±üés€ðç/ƒ™†á²°Î(e)é ³¯œb(e¹Ìðýû †[D‚•^¾øÌð]‰áû^†ÏŸÿ3¸E)3;ò± €X~ÿb•3P™Ú«,Îx“áïý¯ ªßØì1æc0æc°ÒyͰY²‚aÅS†wßùÔ¤î2ð ó3(jñÊ {’U°™™˜ò6†/¾0ü}+À`Æ&À°ÚÈ‹áÿ¯? |@ƒþýdVådHbÙÎðÿÓ7NaY†ÿ , ì\ LĤhb£d¨ÌÀÌö˜[‚‘áë»O Ÿþ03°Ëð3pHñ00€<ÉÎÂpgËC†«ç>•\fx¾ü.ÃO†ß Þüú@,²†jR²’ 7þc`ü÷ƒEZALGªÀøü Š^f†ßŒÿ^m¾Ë ~ÿ#(¶.­ºÁÀ#û—áùãŸwˆ……ù¯¬0ûoOf~a&1!Æï@ÍŸ^300ÿ:ÿ+33ƒ\¤&ýwß>ÿøÇÀá"Âpóê†7O¾- –OùÿŸM€MFáÕã7 O÷Ÿa³ `ab`xÿè ýý7ƒŒ­,¿¾а ï?ÿ óþÁ†ós7¾c{÷a ×î(á0O†ÿ ‰è†¯xùØ>}yΰnÒÕï¯î}¯æafx @,ß?¼]°½¥-øïû×w8>}cædøÃÈÄ NÓÿþB0P?3Ãç÷/¶Ì¿Äp÷ØûfF†- a€b†ÊÞûGng|ùÁ•áüç¯ Ì‚Rüà òšI8YÞ¾Űyþy†ë{_L`fbhù Ißœ™ Î ¿¾Ãÿë—ÿ l ¬@ULî߸Ïp`é9†§§ßv1ýg¨e`bøËÏ ÿîùùœ¬^ݾý‰˜î_Å¿Ÿ3\:xáÊ®{ï¿>ù–ÏÂİø#  Æz`”c‰AHí Xû¦ÓØE¹úÿ321}yþu'ã¯ÿMŒlLçþÿþÇð4_¿10|ù €Ï…{iIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/artsaudiomanager.png0000644000000000000000000000177211550446572024564 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ŒIDATxÚbüÿÿ?% €ÍÌÌÀŒS§Na‘ef`õe``g``f```–f›©*+{`Ϧr†gë&^ãùM˜8 ì¿$%YCL~§¥¹rpZXY×20pJÈ ŒŒŒMLì Üò ¼º ,@ ÿýcàÌ)OЫ“þÏÀÅÍÁàm§.ÊÀ©ä@LìììZïÞ½å‡ÒÄ­¤BÿÿA0+GH^iì$1®O L@_ 0hÈó3ðHÈ[“¡‘ÕŠººÖËÒÒR6€6þÿÕ d3±Ú™Æ¥,²0“b|pû*#++ƒ„7ƒ¸˜˜ @1?ª’‰™“/44º¨›á/PóŸ_ ?¿Π£‘¶†I^óæí? O?døõë33 /7;ƒ° ¯@1ýüñek_o£2вû©IÉë™yEíXÅT2„½æÚdTì‘3·½z—‡ù0ÔÞ½ûÂðõëWvvVnfN€baddb`ccz{åÊÙp e‹ eUu/ û0°Kð1ðãèÎ-`˜ò°ÿeà’Qbþ-ÊðäñcyyEF†?ŒÄÂĉ& ßn~å}l©¥§ÏôøÃ÷gÞŠh0ˆØ‡2°ü& †{÷ž2üþûA[[Šáï¿ÿ ?¿ù@L_¾ýkÞ1Ëi3°ÍéaÈçºÊ`ÿõ8ÃßÇþ³20|ûËÂðîÃ;†Go½" ôÆw†ï^½A¾ÿÔ×ÞÕØßÑÉÀ¾ùÙßôêÏÀÒJ_àœð¶³Ýéöúï** ïïòêèâÜA¾ÿÿüøöôíííïêäàÑÌÇ ÝààØÖ.áÔ+DK?%æÇÇß# úÛÝ㨧¢˜ˆ…áÿ_°ó?|x –ïÏïŸÊñ•xÓ†ó\'´Û1ˆ‰~c˜zì1ƒ™,ÃÏŸNž:õí߯ψ5ó0A˜ñ;†#÷Þ~a¿sÁA×LŸáᮀ >33°°±3Ì™3cåÇoç#ŠL,ÀÄóÌLâï@ü ˆÅ2ÃU…›ö}ÿz)“à]^>^•«W.¤¥-F,œ(œòIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/forward.png0000644000000000000000000000163011550446572022673 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<*IDATxÚbüÿÿ?% €X@£þ †Ï¿Y™€& ™R|ÜlÛØýå~ýàsßÿûXJ¿ÿa`ø÷¨¤‘áÿß"€b‚ÅÈøÇð¤èåWaeA™•s}TBÂ4÷1üû?™áç_l. &  A@ _~ÿüûÃÊH‚aõO†yó½sÄ$¹÷2üýë® €À^`bb¬aecÖb`bøÅÀÂð÷?+ÓÏ?B_¾ýbXû„“Á=X›ÁÁBB-={ï†Ý;ï¶ýØÆÀÄø¤ €Ah³öS†3ÈŒ ¿ÿcãgcÐ×aÈØÎÌðâ'Cµƒ±ð/†Ü Ӧž™ÁÀÈ–õÿ_É€{AV”󯫙ÃÓï, W>°2}cø tIãÿ «ï±1LâÊPP`‘ °Z^€{áï¿ÿ O_|eèYó€áþ‡ÿ ‚Ü \\ <œ ‚üœ ÜÜ ÌÌ óϲ#„‘¡£Ý–áøñg@­MÄ Œ?ÿþ2|ûò•áÛÇ ì,Œ ÿ€1òeœ@ÌŒÿX€–|Ò¾q1°²±0p°3³‚ô,„¸Y‚Í„^ûÏÀÃÇÉÀÌÊÊðë3Õ—?Þ½F/ë_†( f†l# µÍ'y4¤ €À¼úð“ù擯 A6bà„ô÷ïAV !v†)OÞ¾ûÁÐ"Å`ÇÉÐØ|Œ¡©ñКÿ˜J@zlÀ‰K¯f¹¦íRed`üÍðèòw?8M ÅÍgöØs¨‰22Ô‡I2èJ²1ÄÄïü·tñ5` 000Õ@Á1ýËp´2ü&D†Ï¿å¿üú{”›‹Iº?IáÀñ— –QGž]»ø¢}60¥0€1<!ôÿŸ@ƒþüçeã`áxýþC[s®®úóéW 0\FO‰Ä‚ÌùÌ' lÀ¤!ÊþéÆãOow3Ý¿þ.‡áÇßÕ \,¿¾ýÅHùÄHiv0¸~#w^£„IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/identity.png0000644000000000000000000000155211550446572023063 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<üIDATxÚbüÿÿ?% €˜(ÄX{ÅÈX]ù/Ð)ÿXþ302üc™Ë dÿc`fa’L ‡þÉ1HÍߌŒÇ/<}@,&¦rUUÑóþ00|~ÂÀðû Ÿ Ãf†×¯ß10111###³²23pqs1Ôöí• –Ÿ¿þüëý÷—áÇ«+ ̬l Ì_2ü}qšá§ÃÞ÷X™ÿ3°³³5²2°°02 ð1XYi3üüóï/@±üüó—Œÿ~¼g`øzŸUZ‹…‡áÛËS@üümþþÚÌÄ `Ìôˆñë×_€bùûç?3±r00ýyËðøØ*†¯_¿2p³¼aøÊðáöÝ«ÀÐøÍÀÆÆ ÖÈÄÄÌÀÏÏÅ ­%Ïðçï€bùõçÐõ¿Øy.~ÔdxqvÃÛ8Ô= Õ-”¹?3üýû¨™ì Pxpqƒ ä¿® ¦?ÿÜ|üá¿´5ƒ ˆçg=×j†7?¸þüûÔ̶™™„™˜†üÝï߈åП¾üa¸ò’AAAAAA€ŸáµÐ?†S—þ1ü¹÷‚AUNŒì@o°€cC@€›‡‹ì€bùûïÃo®¾ffxÂÏÀ`q÷Ï¥« ïýa¸ñžÁ]NžÁL—áÛ/Fh 2‚ÃãÏ¿? ¿~ÿc –o?ÿ1ðóþgPâ­çžsÛ20[+1¼¼ÏÁÀúþÃû÷׎~e&(V`4²€±?/ƒŒ?Ðëÿè–ï?18Ëþbàþò‹á7Ã?%!õ÷4uþ0ˆðÊ1½ ̰ù«$C¤‹68%>þ„ÁÊÜ€áÏï?pnÈIœ\\ ñ‘®@ïüLjýS†žéûî›A|ÿ• l R§älÍpõ#Çï ~20¼ý ô˜(Ã÷ŸÔ¿=ñ‘•õÌ ÄÄðè1þù[“Kˆ¿ÍÀÓŠáñG&†ß¿þ1@¤@ì_¿dl,8DEk€˜4¨ì÷f†Ÿÿ[m¼-%¿q 0|ÙrÕ?(Ùt +/7ƒ”¥0ÃÆ†ÿ¸A® f  >ýH3pÒ/5ô0b¸ÿš‘› ¨˜… ³B"IHZáï¯?JŸî?~ 8@,À8וT“lMI7axòŸ‰AG¢ °D+;ƒj„ÃÆçOš_Þ{q €X˜ØY§F% ¨ò0ð¿üÅð‡èjh°€0Øÿ!fÁÄ9e8㌹öîŸ@Œ,¦³V‰ q™ýô“¤’a;ºþC1#2±0±½|÷ý*@±°±0sðq±3232²üûÿŸMLï?ÿd v~OµofV†¿ˆ3€ EŒŒÿ^.Ü& @,¿ÿ3üõ‹•éÿ? Äð’ìýgd –¿_??xwø $##óßÿÿþé˜~zÿ ÀöÀôY‚Z€sIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/roll.png0000644000000000000000000000204111550446572022174 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<³IDATxÚbüÿÿ?ƒ»»;Ã÷ïßþýûÇÀÁÁÁðþý{V^^^e^^==ýh [kß¾}eÿþÉÌÌÌÀÈÈÈ;wîd dÈïß¿€ „˜˜˜ü555íLLLüôôô„¸¸¸äää$$$¦.Y²„¨y °@A;iiéXCCC[sss5 FF111†³gÏ3•0DD„3¤¦&1³²²NY´h/вN666°6ÀÊÊj[ff&·¨¨(Üyïß`¸téCxx8ƒ§§;Çï|||ÙÙÙ;æÌ™Ã ti#ÈñÄR ô#7 X3È+ ðóçO†ƒ2<þ‚ATT(ÇÄðíÛ7WW7†ôôŒzÎ6:€»€.^¼È¢ªªÊ ##Tøaß¾½ nnN ¾¾>@CÿÉ‘™™Hÿcðõ÷dxûþuPk%@]tÎ_ f¸ÿ>ÃçÏŸÁ1²wï!†“'Î2prr1°³³1#7φŸÞ0|ùþŠ‹“ý?H/@ Fß?ó¹¹¹ž00±|`8sæ CLd6Ãã‡OA^üÒ @LÐXørÁÞ½û^¿~ÅðîÝ{ Æo ÿ?gX¿~ë×O¸9û•ASK&_¾~ýÒ @`˜™™¸¸8:ÁpçÎ} —†~eØ»çC]݆W/>2,]¶†AÏ@…¡wB-Ð5l _¿þ‡6@ øôéó§_¿~3f1èêê2üúõ‹áç¯? jêr 6Î`¸}çCW×,†7o?0,^¼ŽáÍë÷ LŒL?AzlÀ7ª±ðGBBàhüñモ’ƒ˜˜ƒ†–ÊUÓ.œ»Ã0eâ| ÷XÁé¤ €Àüùógþž={ª/_¾ Ì \à¤ÍÉÅ ´› ^^‰ @2¨©)1˜Yè3L˜ÜÎððÁc ~t¤ €Àé”,†tmÚ´IHPP°\OWhÁ†ï@ozx93ˆŠ‰3\¼x“áúµ[ïo^»sæú«™jH/@±À203|ùò¥bùòå‚<¼¼i&"* ZšJ ìlœ ‹¬½rûöý¯_¾ÜŒ±SL@'R.ܳAYõíÛ·«V®¾wÏÐëò¥«{îß´çûø^ó8ËÃò cÀZ€šÿA¼IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/kdevelop_down.png0000644000000000000000000000145011550446572024067 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ºIDATxÚbüÿÿ?% €˜(Ä"ØÍfçb`0øtÌ·¿Ìïþqq‡0°±gø÷_š¨èï? †ÿLÛYØ9$þ³°2ücf»õo™Š>@ P’âµè*µbøÁÌİýøK©ù‹nN``eta`aû Öý÷7óßÓÕt¤þó 3|øÂÈðúõ=^€{áÕ‹¯÷¹™˜B-dÒR  LdÌ>ÿ¯dàêðõOŽ‘ª€ƒ‰‘,Ã/f†¿_‚ôØ€wo¥5g¸õü++Рh~1Þ\†ŸŒþüSá(U7R`¸ôœ‰áÕ›? ï_¾g`øÿ¿¤ € (ijáî½ÏÓj§^aàøùŸARŠÁÜI‡á?ãtf†ÿs´ ¤…ïçfxú–áÓ»O ÿÿý[ÆÀļ¤ € °030r6®ÞýìÊú½O¤!ª¨.à ./jÆ'"`ÿ_P‚áÁk†Ï¿1üùþã3K=Ð `­1àß_ _ÿ¿úÏÎRݽðîŸW/¾1È 12(ê)3Hk(2<}ÏÈðîÆŸŸaÊÌÜÔq5 1€ˆÖ²±mzûñïô©«1Hñýcàábcøò—áí§ÿ ß?~©\ÌÀÈ´ˆ€^k ˆü2 |âÀæe`àe/?qñ㥃§Þ1èË30¼þŒ„OßQùû.PSzB ˆÿ^øÿ² hûÎÀÆ’½z÷Û~ýdЖúËð÷Ó× LL ÍÐ  ¨ÿ”úX˜Ž|ûñææƒ¾}úR1hòvlI €A™‰1ú.º0È%œÀD¾‘•ó?£=Pè#ºæÿs„ˆ‘ÒÜ@çF€^íå⃉Â{IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/kgpg_photo.png0000644000000000000000000000135411550446572023373 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<~IDATxÚbüÿÿ?% €˜(ÄcL™2å¹¾žž0Ãÿÿÿþc¹ì/3ÿÿþýò¡bÿ3nÞ¼éÌŒ3¬@ún€®®®¨„”"ó;OYYz~2°þxÎðŸ‰á'‹#þùõ‹ÁÀP…áòåË’0}Ä‚pÌ¿¿/ßc~ýGƒA÷'ƒ*óy)eN†ÿŸ0Ü¿ÿ„áòçP†g¿1pq=d`f: nÀÿÿ¸x8$x„ôÙ2(ij10°}ô‘AJôË ß~Ù0°²~`ø‡ð„0(ÆÄÄÈÀÉüƒAˆí×_ ŒO~¼bøûç?7ËMf6 °¤ˆ $/}ËÈÈÀÊÁÁðý?'ã# Ï?a¥¬Ôw†· > ,ì¬ Œ @¡º€ä• gØ3ˆ¾¼ÊðüÉc†_¿¾1¼b6gø.ÈÀøçÄH €àéh9HjßÍ ç¿ñ3|1­dþcÎ ÊíÇÀèÖËðŠ—‡áêÛ Lÿ!®…€Bò# Ãë'gDþp0\ýÂÄ há †ÏWÎ2|üÌÀðó÷GNIPÒ€€‚ðýÇ/k+MM•  „ôQÿ€Î'õ¿@.g´eàäzë7Ü€B ƒÿ@M@ ì ÿîddâÿÁÎýÏÌÂð(ÿïï–ßQ €à°''P#DHÿÿàÀ±a˜““˜XÙ`únÀöí[^¹rY”ö‘5 óÞ:zôȘ>€b¤4;»ÞÿÞµßÅIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/bookmark_add.png0000644000000000000000000000201011550446572023635 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<šIDATxÚbüÿÿ?% A¾ÿc%%øÿÿ Y$f!!ýýèëëìØöö®) H öþþúÝîîÐâöö’¸ þþÿˆ1NY™‡—¡7ÈË+Í$(ˆO\œ誟÷ï3Ü[¼˜MX˜A1,Œ $þïÃ+ ø%K~í8s¦š‘…¥ €ÓŠâ=={­²²€¦20üüÉÀÀÈÈÀÀÆÆÀðå 33;;Ãß¿1†§OÖµµýÚzù²7@±èðò¦››™10<{ÆÀðù3ªA€¶201 ÿûð!Ã×sç~i«W¯Ø.22f‹"›$ó§O›ÿüA5ä íÿò¿føÄ_ß¼aø”áäd•’Ò –¿Ÿ?ÿgxð€A@€á×/ˆF¨ °ø{ó&ÃÏC‡~ 3žDpq1üûÿÿ'@±Üÿüùê·‹-¹”•!A¶ñŸ÷ï~]¹Âð„êAø‹Ã?x>31¼cãexüû÷n€A¾ÿßýý‹ÁÜܧHúúÿ ÷÷÷ûëëùââööýòßð^( óþ «ìåýûúæ÷ªˆÙœ›ûÖã?>ýúñÃ^âûwÖ÷@'¿è¿ß¿ÁÎýÌÆÈÀÔÉðK€›‘÷'7Ð0;&n³¿¯En|™ @Ì–ÜÜ@þ=y÷óçkÀH³RçgjþôãØÙß>úøìƒH¢%ƒ /»0¨ø¾ÿ{ØûpïÇß'ˆÙ‚››Xÿÿþ½ñúË—ý¯þüÑSRPåcbfxôå[U(ƒ¤“)'ïw1oyF†7ýã3aTáa  &XŒ1˜l/—Ÿ/® \Ùä7 än†ÿŒ»o®=tèÍ•÷e59´X>ÿ|úîø—Lί rÿÞÿ¾ `õÔŒHëâé‹IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/connect_creating.png0000644000000000000000000000155611550446572024543 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?% €˜(İ„añI&†¼y?>|cБ““_k``¢$&&ôÿѣǟϜ9»áãǯm¢¢bwùøø`.¾uë"˜ †ÿ3YþïàdH2cäãVº±yçÑÿ÷½ýûÖÓÿ °oßþÿ®®^O$­ÔÔôTUõÀdÈ º Ÿÿiñ±ÿ/Ž VW“àeøýã ÃG^¾|ÇàèèÀ°dÉ|i++‹å¿ÿQ†i„€bü¿ˆóƒ©˜â»—?y™ñ²s}ýÈðü›Ã¡dIq1--EvvV†C‡Ž0äæ–öüÿÏXÊÈÈÈpñâQ°Äôçíïm÷7ÿäø|–ý×…w ïÎ~eø±w?ÃÇG7~þþÍðíÛO†÷ï¿2hkë±¶)+ÜÄÂÌôgÑ©u//~ª_ ÿîõ3†ïì¿D~|cûó‹áÝ»O ÿþýgàää`¤ÀÇǘYYYþ  FI®¥¾3ù¾*ÝûÊ/ε–á߇ ç^Z2Ügäk|óæÐÏøøø^½z®ñàÁõ ¾R þ2 €Xþ¼û÷õ÷]Vgýï~ß»ËÀòõ?ƒêÃO /ôŒÀÉäõë· lll@¯|g¸{÷Îk `.â*ÄòìÚœUY}N2²»º•T¸ýÿö…áѧç B Ÿ?cxûö#ÐéB 'Ožüñï³PO4W  `„ÜàøÇpãÿ œß~‹‹ˆàeò˜A\J‘áê•§ LÀˆ>sæ$ÃéÓgê_¿~ J=®È) €XXÿ10ÜååaøÊ#qçèÖíÙÒ\\óŒ ™wí< ôÿ{†?>Ý}ûöMóß¿ÿ>ztG ê‚W0ˆ…è„Wìœ _øxþþ\¼uÛî{´`gcÿËÁÁv›‘‘ù×ó£G·‚Ô;±À  FJs#@Qœ õ¨?»ÇTIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/view_right.png0000644000000000000000000000173211550446572023401 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<lIDATxÚbÔ7ª¿ll£.óõç¿ÿ20üáÿPˆÿc`ø åÿÒ 5™˜˜^ßöûÅùK Äbè` f”ÀöäPPñ/ ‚Ÿþ31ÃÇO@±?qÍÈÉÀÀ|æëKÕˆå͇??.žxËö÷ûo& †ÿ@[˜Y˜^¼üÈ𠈵4eþf%˜‘‘á×o6†§o¿100±ý –Ïßþ1ä03X©ñ20‚1‚Ô01ìßûŒaßÞ[ õ1Ú ¬¬Ì@ƒÿM`büÏðô#ƒï±ß@ƒÙ0AG7@0DO[RÔþÓjðç&x9Û£1#ΊJ…Ü÷CbšT½¢Çã@äƒ L³ýÿ¿‹±±žÇ \¤Uǧ&ƒ<î^ªf_4¯ÌÛƒl6ˆéò7"33Øßšÿƒÿ3Ã_fN0&¬, Äò‡Å›@—1]â0q²10ãðã•Ó ¬~2ü–4gøÂÈÏÀÀÂÊ@, ÿ!™ ,P þù‘••áϯŸ ï/œb`àUdøuu%ÐAú”,~fØÌÂÂ@,^øŠ. Û@zA63²²1üüø‘áËÍ-ÀDÂÍÀôõ3ƒÐƒZ†<³3 §w»ÿ &P,À ø÷ï?Яÿ aÀvÙF†Ÿÿ˜ÝfýÉÀ/û èé3 óy1|¿.@, @df„˜ 3ff›ƒ…áß÷/ ?NÏaæùÅðŸ‹AÌÓ(ñœáŦ/ )”•î$ 3;;˽×ÿ.ÞÿŽ2`Ž``cýÍpãù†Wÿ޾’bøõøƒ¥ì`:þ 4ú ã·? 篨0|}øý-@±üøùãÿìï&mûÅr=(?üe`ºÿÍ(Î°å‰ C‚Ø/KÁw çŸdààúÉÀ%ÂÄðâ·$Ê£ sˆåáÍû9n?RþHZF¤ {ó~|Æçè¶'~Ó´¿EU™ 9E„9¯.zw¨Ød®Ùû6ˆj þÿø ÑÂLÈ©éç¿o /^\òäã+m6ΩÿÞó‹<=%”ôóÃG n†_7 ¤p:x(¦ŽIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/player_rew.png0000644000000000000000000000135011550446572023377 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<zIDATxÚbüÿÿ?% €˜(ÄÂÈȈ[Öx&?œ )ÂÅð|gl"’x¼“©ô„Wï¾ |šë½ w¿¿xïÓˤM òÅìåüVœŸ»íþÿ×_ÿÿwÎ\ €X°hôWWP’b® §%Åð™áË/^»9+ƒ½ ¼²cŒÞ}g`xô‘áÓO€bAÒ¨ÏÉÍ1!.ÂÜÁÎFáÙg†­W2\>y…‹Ÿ—ab›×·ÿì ›oB”+B  ¨?Ìlt <¼Œ^ýbgØpƒáéµ› o<`2f3aØ|Õ¡ÿþC  .‘N¡® œ¼ Û@$;Æ $+ÅàîÎpü-Ãï÷˜A$ÆÅÀðý7@1ýúüþØÙS·žAHrð2¼¼}—áìÝÏ ¿þâF€bþ÷xÓš/_ø/¼ðÜ@@„_D\J€ADJ˜ŸŸ…áÙÉã ??e—fàæbaàdc€cY†+çn< `3üex{ìúŸ¼|#öëËë÷ƪZ2ìrŠâ *úŠ |ÿ?0œÙv˜—›•AIY„“Œ€^¸4 €˜‘\ó‹áÕ¾ƒ_ÞYvíÜ+ÿÿ ¥äU¥®žºÎpe×Öš×/¾kÈÊðòÊËò2°]qãìçÄŒá©/·>2¼Ú³åÅó¿›Î~cÌÉÉ.õôá;†O‡óý?¿û²üò¹·Ì_¿üÕÒÒf¿uéþs€b$ÔÙT þý”a¸;m:ÿn òñ,¦5¼lß^#ùˆ „ˆ‘Òì `ö߆Ù]IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/editshred.png0000644000000000000000000000127711550446572023211 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<QIDATxÚbüÿÿ?ƒZhÇžo{ÆÿÿÿýûÇ€•A#33Ó¶½'Ï\Y\h @  fìÿ÷ŸDP¿ü4ˆb °é ÿ)6\6ÿÚúè²ÿ@ r PЩ@ò6àß¿ÿX iø÷Êþä €Xð°íÈ4” 2ôíwˆ€ÂjÀ°« 6þ…jiütÉo Ãÿ=ûú+D-@1aè„9êF  ¢ÀPúö ( FFˆª €>›ÃÃÍ ¼O@þ÷_ÿ8¸¹˜ª?|üÆðû?+Ð`ˆ6€™‰hÃo†Ï_~0Üyü†…™Õ@k>~ýÅðñûoS=e†s×2üùý—“›•l@agef¸óè%X3P3Èô@ÃÞ}ý t2#˜ÿhÁGωˆ .Œ?@]ð Äz¤ù(Ê@ž¹¨ù/0ô@i¤‰……Ìfü×Ï@`^~ Àß@&Hèÿ…Šè?ÿ Äfú‡HÄÓK(ਃÆÂ_hÌÀLü?"ˆ xAŠÉÿ°$àü0 cd€è@2ã HKÑÿ?×Á¦,È}¸R;! áBð_zÁ «Q©ÓËWËFTûÁé>&>y¼æû³?¿~• êþý†D0ð~ÿùÍ tüÓG¸y_ƒ„˜nݸs!U À³µ8]øñZIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/rotate_ccw.png0000644000000000000000000000151211550446572023360 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÜIDATxÚbüÿÿ?% €X@c4#ÃoAyÞiš:ÒA§ŽÜéøùâO#Ã0*bøË&ÀÂðëó ›™á+Ãÿ5ßlP³¨”šàú´tk Yi†¿¶gß¾ô\’™›‰h4ЕŒ_>þ¼ûåóÓ ¶3° \@Œ /HV îJÍvqdøúý'Ã_¦? ?þb`bb‚+üöí'ÃõkOÜ~uÕ§—ß‹þs¼¹ €ÀfÉ)Š; Šó2¾}õ¼úó°7¿u1^ù~øÿ§_€¡ÏýïÖïå¾þ[Œýñ)çD-öÿœ üÜ ½1àÝ?móÿðço~žÍÀÌ(òÿïÿ` ˜³ý{ó÷;#ã¿o÷üûðý×?&†_¿ÿýé ¤a`:WHÿ`øû6_À±ÃŒÀÈÿÃÄúõÇo†¿ÿ~1üøù¬ €`€x{±$4v æâõ@þòq|ùúCý×`4ÿ+ )• ˆ9^b`1ú•…éË÷_ ,Œ?€€}À@,Ĥw&y ÏdþþüÅüå×/f&V†Ÿ~ƒ¼Æ@„ `ῘþaeøÇøŸáóW Ìï~|äë B|ç”ßÌ ÿ?³3üÿËÜøeh7Ç_Áÿ/¸Wƒ#¥Ù À!B3)Ž^zIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/kmixdocked_error.png0000644000000000000000000000207411550446572024565 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÎIDATxÚbÔÑ1b¸wï.ƒ´´<++ÃÿÿÿÁ˜A@@ˆMZZj²ˆˆhØóç/ºýúÕÆÈÈÈ€ ˆ‰øóçÐþR99¹4}}-IIñâŸ?*‚Ä‘1@1áÒÌÍÍâååV%,ÌËÀÇÇÍ ªª(tÇ?1@ º˜™™‰á÷ïï ?¾c`bb4INŽŸ¦©©ÌõçÏW11 %€jU?}úÀðåó'†O_¿0|øþ €P\ðïß?†¯_¿I{zºÍNJнsçï_?áÁÆ ""t§4ÐŒ?þÿc`ùôŽAøñ€bPˆ0|ÿþCÐÆÆ²¯  ßàãÇÀÀ½ôÎOVV` ³|þö÷ûן²¯3°õËß¿eÅÄÄÔ$$$]””” rÍ>~üÅðåË` Š1<¸áë·o â2 À`ûþû›Éó»?¹€š] @,>>Þ»ÜÜ<4ØØx~dcxõê+ǯÔÕeääT8yøn߹à *!Åð‡……‘ÿÓ»¿<@Íßäú A¾ÿKKK((/ÖÖÝÞÞâëëìùùûêìðêèíλßÄÅêæäôòíöÿs(Z×ì솈éÚ•_Þ½ÿŽP ‚4¾{÷˜ Ÿ¾cø¼C€ ƒ™¹)ƒÍ¹b¢~¶yûú¶-_nd¥­= €˜Ž;tŸƒƒAXXÚ¬àýôäo _¿¼bøÎýáÝã' "ZÚ ¹ñ±¦9•NYYlï¯_gxöêÕU€A¾ÿêëêïïï9ÎÎËóÉÉÂèãáÜ ú #þ ò¦§*1177éÇLjˆ¿ÓîîYˆåõëWó6o^{€ñß÷ï_}ùòYúÚ‹_¿¾µvr²e`ú÷áç_†¯20,] I©oß2|ýóç30ý} fVV¶¿ââ’o€ô[ !¾~ýòøóçk®\9ÇÄÅ/¤'ñç/»Ê‰# @/¾¿y“áÞíÛ * ª**ê¿~U fffAAa°É¿ÿ&¦oÀèdÅ÷=÷ž=¾Ä~ç¶qŠ®Ž Pnî•+g7ýúµY–‹ËD[U•áÙ÷ï „aÀ·o_@YÄæºýéáýƒ"oßè^üø÷ñׯc>20Ì{üó§Ð‹ÕO<}Z `åá¼jöSIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/color_fill.png0000644000000000000000000000174411550446572023361 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<vIDATxÚbü+"ÂÀÄÃ𕉉¡KK‹AHùò…áçÏŸLUÊÊÊOžƒŠÄ;¦¿ L@5l@|óÃã Èzˆ‰0ýc`øùs‹J¬ª´\°ÆM†/_-þþgÀÕ mÿž`|Ìüx^o£ˆ[¦ÍQö_+¾ýbø‡Ý €B3à÷†Ûçîn:öà CMF2Sûòœ0½Õç º~c@Œ(aà¤a|ÿ£¬-~ƒõ?‹“Ü_E)æ/2+?~øÏñ—vÈz 0ÌàªÁŠ Üê—¦€TF1±VIj~’X¬÷ŸAš«Y@¡zù³ÿeøúðیXôbÞýn{1ÿ¾È«Cï3rÇ!k TXÿ@˜¿þÎÿòôÛfG  ƒ0ó¯¯ÿÅ3<û}Y @¡Àõ•ó;п€ôßoßo?øÏ„ƒ5…áþ7†·?÷ikd-Ä„5nþþbbøûé߃_+3üf`0eKGã•O ¿ÿ¡( T@Aöûw8ÿCUoŸ<œ³Àb¶¬šÀ8RdxtÙ—?(Z5B¸ÊÌÛýÛýsÕÿKÿ7üúéõŸá50 ïúÏ ÅÖ…M@± ˜¦ÅR#åÃÍx‹ù(Êwwv½»ôƒ;ƒÚ†g¿0| @¨qp¯¿{•aÃ÷+ ÿÿ]ô(Í" <`8¼þõ[pªw¾^fàãÓÿÏÅÔÌr+Ç/ ›^>f¸ö'›„š”ã™yž0/fæubàafcxõãÃÙ/ü/JA0Ñ gbúòÍIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/kgpg_info.png0000644000000000000000000000140611550446572023173 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<˜IDATxÚbüÿÿ?% €X@D&c|h,à 6IƯžÿÿË+.ð÷ýK‰ï+çÜ ziow†…Ó–?{öìa °2R îNq ¯?±0<ØÆ``vAÑÔDà-›ÍZ¥Àðwÿÿüf€8ô?þÏÈÄÄôÿàÁC§€É6@K“Á‘GŒ™AÇæƒˆ–(£¨,ƒºú') +')6v&†¿ÿ1üÿ÷á/sq±1|ùòU d@ àæfàcøÇÀÀ)÷ƒÁÀô8PÄ ˆEž0Ü¿õ€A\^’á÷¯_ ÛÁýþÍÁðãÇï ½Ä"ž>e¸öÐÿ€Na`⟠¿~³3p 0üýó¬ùÐöÿÿ!øß¿¿`-6àÖ=†“/ÎŒ ?îÍyý‚áùŽ­ ?ÿ 2pñómý ÖŒŒA.€pçCÁú% g–2°=uïè{†'l´}âþýý‰b3È%×@\@LPâË…ó s^]ÁÄÅÀðë ƒŒ¥ƒ œ<ðßa6ÿÇp@1ÁâõÓ/†ÍwÎ2|gøûŸè•ß?¿3üúñ¬ ¤„Q½q@1!¥(1N~ c€ `Tƒ£ ìäÈNÿ÷(\@ €Àp@"àÍ«û ¯þB &œ¿ÐxGv6²+@ €À逈10¼ûýH±#‘‘Ÿ—‡AH€á';3ÐÿQ4òðp2033sô $‚cPðÿon†Œ ×þºùá¤sÛűq*ÈI°ÁÈÈÄpàÀsYYÙ ö[P0ˆãLf»sÞNåd '&'‚ô#¥Ù ÀÚa¤""¸IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/mouse.png0000644000000000000000000000150011550446572022353 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÒIDATxÚbüÿÿ?% €˜(D±Ä2uz:Ù3·ÌÛ⻉I*ä™Û9pqñp~ýòïç×ïÿ¯_8騧›X_1²ò00³q00ÿú²‡ €XþýûëõûÏÏGòJÚ‹££SôÕÔùõt­ž?ûÏÀÏ­È)+Íaôî㣻ö¥,_¾}Ï¥‹wãÿ³²¿cdd» A¾ÿKO‹ðïSef´!-.'ïîèÞØî  ôóöoq’ëž°& ðûõ¼ˆéÀ7¥œ\zœ ͯ_¿jþÃðí³& ÷o Ÿ>10¼}į89¹&öŠº¸Ùøóý;ØÄôõ#7¯¨À±7Þ»É`i%Ä )ÅÈðù3à Ÿ¼{Á/_C•¡«­L_LR¼d@1101ü8sjÏ7/ž3\½ÊÈ0iÚ!>¡ ¼<@'a»âý{†7¯!.yö„AIQ„ÁÕÉ)d@11°0ü{úðnøš5­oÿ3½cxÿ…aæì þ¿a`Fò§ _½òú5Ä ÔEA$°1\»zi¯Ú¢É[¿ÿ8Éðë77ÊE'þý~ÁÀÅ ÔôbûËç ýcØ»ïí»ï™AZ‘ØÞ}|ÿÊg×öº~ƃÿ98y6/¹ÃðïÓ+Ùÿ œ@ƒX8Þúñ–áÚíG ïÞ|k Ô”ÈÊÀðûÏ¿¢íÛ[Cn?mzÊ&váÀ–û W¾`øvê'0&ùøyÿ0^Æâ¯8ºóôÝ{OÂÿý¼û €)ÍDqf0€áû¼¯/IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/view_fullscreen.png0000644000000000000000000000165711550446572024434 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<AIDATxÚbTU¯¼®gª¤òó÷ÿÿþ20üýÄÿ 4ˆÿÊÿó*•ûËÈÄøêÆÝÇÄbãa(ãPÊòð)DÃÏ? ¿Š~Ù¿þ@ðO(þýÂÿÄl< Œ+7ŠË»Oÿþíßý†áËo6N ;~~xÏðhÐ" Ÿáÿg`b`ä``gbe`ÿþ•áóÛ? _¿þý@,¿üeHÐee°ùrŠáõù ¿þ 2ÈFe00ñòµÿc`BþñáëÒI ÿ¿?eà5uaØÁë¾å?@1ýaÚÌÂÁÀze%ïÓé " ² BR" ¼l@ÌÁÀÏËÄl ü¢ü rŠ ÌÏç3ü¹¹„•‘•á? @±üe`Úð›áÏSfv>Ñxøt?È ÿþz‘7(Œáéÿß ïOnbøgü‹á/Ð[ÄòäÇ¿ø³ª˜¥ä Á$ÿÿÁ†€è@Cþýùà äÁÀ cÊpõíO†ŒŒ Äôï?˜Á"/ÏÀÈÊ³î°æÿ€Ñ÷á0 þüúÁÀ¥$Ë👙á?0¶ˆå7#T9Ç=Dó_`lüýûŒÿHì÷_F`º*@LYþ#þç‹—À¨ƒØ ² LÿòŒÿÉ_ Wÿ£ñçãg ÿ~þføÏÄÌ@LÈ9÷§63<Û´œè Í a6ƒ’K€áËÞí ß&ÕS(#P @1BòßV!‰/ ÿ÷g0¼ß¶•‰d(0A.ùqö?V†·{·1°Kcà’þt #@±€LbføÅ fÉð…‰—áÿs ,_lX¸8 N†Ô?vF†Ÿ_>00Ü=ÍÀ ÀÀ¬lËÀÃöVÄÂÉÅÁ´ÿÞ?†[‚6 ?¥b?þnû ¤_àLó€ @檢 ?±1°½þÉp÷00YÙ™ˆåÅ“ç¯6ìøÏñù;Ðç`ÿƒÿƒÐÿ ‰dÐOÀPg‚Ä(‹2{ù €ÿÿLjD’@€÷ ¢½œá|ïIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/16x16/actions/compfile.png0000644000000000000000000000115711550446572023031 0ustar ‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚb œ]VV–ÂÊÊÊðÿÿ0d™ÍÈÈȰdÉ’çS§N5 } ^^^K dÓôïß? š“““áôéÓ@e ÎËÿüùóáïŸ? ÿÿýg`ggeøùûN˜˜˜þþý ²Gˆ¯Ë æ·2më&3üùû‡á÷¯ ê 1Nþ ?ýÄÐ ÃP˜@ €X <”’¬¾1übø„ËVeøûÛ« ½Äò•éÃ}†³ ¯¾cØqãÃ÷ï2 ìLl ¿þþÀi²Ä$¤ö“ùü—à ÇídxõùÑÛb¤2üÿ‹=0aˆéùË7ÿÿ²þeb`æå`ðÓ÷d`fb†+Æç€b¹Óûç¾’“Ò_Ñ× ïo 2̰™Ã`(§ËðáÛG¼Ñ Ĥ'¢õ3_±çŠ%C“ñt=m‚š¡±Äòýï÷òÂr Ží ßÿ|gøüã3^Íè. Pâ |þù ßÄÄ@±1#¶ÀB×€Ív –ß¿3°°°0pqqá5FƒÔôÀ@±>|xyZZZ ÐX®CÎTØø›7o~¤þñ?€b|@¬ Ä*@ÌÃ@i~ Ä ÉQìL‡ª¿IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/readme.txt0000644000000000000000000000471311550446574020301 0ustar ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ This copyright and license notice covers the images in this directory. Note the license notice contains an add-on. ************************************************************************ TITLE: NUVOLA ICON THEME for KDE 3.x AUTHOR: David Vignoni | ICON KING SITE: http://www.icon-king.com MAILING LIST: http://mail.icon-king.com/mailman/listinfo/nuvola_icon-king.com Copyright (c) 2003-2004 David Vignoni. 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, version 2.1 of the License. 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 (see the the license.txt file); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #######**** NOTE THIS ADD-ON ****####### The GNU Lesser General Public License or LGPL is written for software libraries in the first place. The LGPL has to be considered valid for this artwork library too. Nuvola icon theme for KDE 3.x is a special kind of software library, it is an artwork library, it's elements can be used in a Graphical User Interface, or GUI. Source code, for this library means: - raster png image* . The LGPL in some sections obliges you to make the files carry notices. With images this is in some cases impossible or hardly usefull. With this library a notice is placed at a prominent place in the directory containing the elements. You may follow this practice. The exception in section 6 of the GNU Lesser General Public License covers the use of elements of this art library in a GUI. dave [at] icon-king.com Date: 15 october 2004 Version: 1.0 DESCRIPTION: Icon theme for KDE 3.x. Icons where designed using Adobe Illustrator, and then exported to PNG format. Icons shadows and minor corrections were done using Adobe Photoshop. Kiconedit was used to correct some 16x16 and 22x22 icons. LICENSE Released under GNU Lesser General Public License (LGPL) Look at the license.txt file. CONTACT David Vignoni e-mail : david [at] icon-king.com ICQ : 117761009 http: http://www.icon-king.com jets3t-0.8.1+dfsg.orig/resources/images/nuvola/author0000644000000000000000000000010411550446574017516 0ustar David Vignoni (david@icon-king.com) ICON KING - www.icon-king.com jets3t-0.8.1+dfsg.orig/resources/images/nuvola/thanks.to0000644000000000000000000000074211550446574020135 0ustar Thanks to Mark Mahle from Hosted.as for hosting the site, support and for being a true friend. Best wishes for you. Christian Schaller to be a big fan Nuvola SVG and to have made me part of the gnome-themes-extras team. Carlos Woelz for his work at kde-quality and to give me some visibility with the interview at dot.kde.org. Also big thanks to Swell Technology, Kde-look and special thanks to the guys of Nuvola Mailinglist: Marcel Dierkes, Christian Szabo and Virginie Quesnay.jets3t-0.8.1+dfsg.orig/resources/images/nuvola/license.txt0000644000000000000000000006347611550446574020501 0ustar GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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.1 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 Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/0002755000000000000000000000000011550446574017061 5ustar jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/0002755000000000000000000000000011550446574020521 5ustar jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/laptop_power.png0000644000000000000000000000444611550446572023746 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<¸IDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €X9‘‘™(’ÿþebfþŸ*( šÈÊÂ-ÌÈüëû¿ÿ??ÿþõåí·ï_Ÿÿýýëկ߿ÿùóûPíÝÿžsrrüúóç/Xÿïß?$#Ã÷ï_¾|ùÌðçÏ/°ø™3‡àvŠ~ÿþ gÿšÆÃÞêí3ƒá—5àYœ< ì| ¬¬ßÆ~eø÷ç€†¿axûöÙý/=~òäñ•?>æ®-@G}affÁ„" ô û/¯p&;3ÃçŸçعÙ8¸xøxyø889DØÙÀ˜™¬Eñׯ¿ŠoÞ¼°{øðVÖ… î\ºtqíçÏ_ånàr@1"—¾¾QÈr\@lóçïov`dp012ð°²± rqrÉrssKóññKóó HˆŠIÊ(++²)((0ˆˆHCè­oßnÞ¼Á°víú—GmùþýÛ”ÿþ`D@ás###HúçOPÜý‡Ð¯_¿@|&66VN Çß¿„™˜UøùùŒ%$ÄÝõõu5===„ÔÔ”€ÑÈÀðãdž•+×3Ì™3«ýÇïUÌÀà:}ú Ü€Bq€Ÿo4˜þÏcd`ccZü‡¤è†?Àtòçï.`‚`d‚$0PÚù{ÿá=Ðç_uøB32’‹ãââ¸AÉ EÝÝ/Y²È‚……åÜ¥K'ávJ6üþóÿù󓉉 l9+++;;sppÅ€^ggãcdø'ÄÌÄ(ÊÉÁ!ÄÇËÍ/ÀÏÏ!/+Ï ¯g|…‰‰­~Ò¤©[Þ¾}Í󟃃#+0DC~üø†Ê„’A)@Ÿ!¢ôDÿþeÌÉÅmÁ+ aÊÊÎ%ÉÆÁÉÌ£¬@Ÿÿþõóç·ß?¿½ùóëÛíÿÿ~Ÿbgcy -¥¨ÁÃ# µ¿À\ Œ" §”¿~ýŠâ€Â›G€A+øë×ïyÅx-=#5M=fA!NN`ÈS0Š~ýùÏðíû†£à³ã‹çÏÒîß¹úë÷×Wlýf0˜›2èëë1ˆc„Ä€j9 ‰¨– ž}d¸vë1ËÀÜ䋈Z2||7Ù„ê€ß¿€)ö׋¯__ßõâ·¨ +0îþ3ˆ1ÌffYÎðâ­-°8.gPÖáfø´üã`èt€á¾ˆƒ¼• °b rªÀ`ùÛ·Ì ožÿa8sXI}ËÊËÊÀË! ,…€Ñøý3ÃoïÞ¾ÌðáÓ×ÈvŠ>ùÄð‘Cˆ•åÿ»<í'·ØYo‚å®íe¸ñ»’ALÝœáëPh1€ IŽ r¼ýPa`na–FÑ/†[W¿30qr1üüý‘á݇—À¬úáñ““ ïÞÝÛl'@¡8à/³ƒ¢ÀÏÉmÞot\µ€àw {'¬ã`8ö+–ÁÈ;ˆáÇÿ lܬ BO´9êdæS>çÃý O>1HZy0‰p0È*ÿf¸|ö! Ûo†/_?1¼}÷áÆ5÷€…Úd;¥.Д“<·)ú­¡ªüo°åç®224ìâbØóo;Ëù¿9#DD 43|Ô²ìV0psÜçLJw„޽®g`ÓÏb`beGÁ?`¼?|Žá;°Züøù9ÃÙ3Ó~¿}wŇGhǃ·ávJ|úöíãó‡ÿxß10,;ÅÌÐu•ëék6ö6~Î?Ó>ø¤"%ðÏ»ÒâC¢:0jA¡ó„aÎV6†ï#´]Üd_~bàáâÖL ,¬LÀ2ƒáÞýs çÏÏúüæÍ•lnnÁè…@¡„+;·±Ãßy|ŒÿïýdÚÉÌÉZÅÅÆvûûןìül¶濒´ô2°4½,*¶23ì|Á¶†‘õ+»‹ ²²œ¬)»¤¤0ïË3Ü¿†áø‰©¾}}žÎÉÉ»‹Xƒrrr3 ‡@¡„3ãÿ³o~þ³xÃðW”•ñ;°RúùT;þøÿØ0zú˜ß¿30l¼ÈÀPwŒáÑ+†L,¦ÿÿóáë/V`ö5}òø„%Ð(}`(,ÔžÙíìì¬×qÕ7®í`˜Xc±2€ª-&V6.n^`prÀ”ªð13lVãd:ƒa«‚ê `uÍÄÌ®¾±µ¸Aâ@0ð›rbb’ òò*(vã@wÍhÀû4à w@ ¸ ÛÉa™T³ðIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/hwinfo.png0000644000000000000000000000544311550446572022523 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< µIDATxÚbd H00øÎ°ø?ÿþ§ÅÂÁœ $Ìê!ÆÍ¬ÊÄðŸãó¿ß_|þsûùç;þ3.``f¸ÎÊøŸaªñ96¦ wïÜehîèa ’,çb`ðž…àÿýÏËÌÌXç¤Ã›l!Ï)ÈÍÊÀðç÷_†_@ÌÌðŸóÏßÿzO?üÒ;úàGêÍw s„y·²0þÿÒª©¡Æ *!Å@ŒD[.¤ÊÀà1[âí¿ÿåExYÖfÚ Ë °2¼þô‹áǯ üœÌ rÂì ^cøüõ7È‹ÿ2ºù…áÂËÏ—³´ŸD+p}½üdÄßÿ ÄL”å<@Ký€ÁÎ' Ôõd¿° óîb}A.†Çï~3üÆÂÌÈì(É`¦ÊÏ (ÎÅpöÎG†ï¿þ2üý÷ŸAY„•áËÇ¿âëïqúšˆÝÁÍüç 3@±èèè`ØwåÊ$0ìjø~|‹033L 7äÓfú÷áÆ³Ÿ ÌL wýcàå`bæa«áecøþó7×o¿AÑÁðèe#Y6†[Ï¿É,¼-9»Pë¡ÿŸˆÅÚÚ¿äí~}†ðÿÿ·Ö—戒äúÏpíÉ û ±tÌÛ¦mÈ`¡&Àpâú[†Ç/¿2°0A䀡ŒSIF†u·™­/ËòÇò¾Ÿ @Œ‰‰‰XC‹‹ h×HðËÿŸ “žÙ3°°0.ŠÑãˆeüõ‹áõ× LÌS>' #ÃÇ/¿þƒ-üÇÀ ²ü?Är˜Ðûn|ePVa;š«ù  € ¹à?"¸@JJЍ¤ çÿ^5þçan&{–¿¿î½üÌ]Œà)ùÔ×NšÁÙ@lÊ«?*g_`øL Ç1 7ñ3þd¸ýšSó“*›@üçÏ?6#™ÙØXwþùóçîïß¿!€Ä:ÔŒR"œLR?ýe8ùø78Î9Yþ3°}õ˜Ògm»Çl-ÅÀÌì@ï¿ÿü“áû÷?àeÍ?ÿ2|ýö‹á˧@#ùøÞýfW Å9Á ˆb¸yó6Ê “„…EîþûôÙD.ýò×>6&–Ïßþ úÇðõ7#4Ðÿ11p|ùÏðæË°¾þ&Ð×¾yz ”‹~MûóùÇ?€bùüùÃóS§NŠDEE°‚||÷î=-eù#Ìÿþò3ÁCè``„ íç¸þ×\Ø0€ Å-#ØaÀøÇð—á`p ÌàP¥%㨃¡ÍÄø˜AˆåÍ›WÆ+W.©óññÎøõë7ƒ¢’š™š»u|¸)ÐŬˆôÁôŸáí&ï¥ÿþÿüñ 3r©ÈÀJÿÿÃr 8ÎÁ FÃ0МœŒŒŸÞ &&¦çJJʯþƒ÷ ‘‘v,?®3°s 5²C| v#ƒ”3ƒ¼ð†Ÿ!†þ§[ €ü¿L¨Yé/š Å0År0ˆóýaüúêÞo€ë†óX0sþó(Á T t«ÃÏ?| gÎ#8/CñÀHØþ~ÇÀðé0øYøážÈÀÇþŽAýÅ绢 o¥ã¿ß ¦k1In°”$yìt„ŽœyÆðdÈr`NaÕTbhöøÃpwÏ»߀@± ‡ÈbpH€þ@ŠÛß ¬Ìÿ$¤$>åf°þư æ Cülq†?Oßå¿1°«=%q†¢©ç€!ÿ”dÀÒI`:ýûõ'0¹XTåZ=ß1¸+s1ôný r8#@±@Ò#Ü÷ð´rÀPðý†;Ãï_ß|ÈðñÕu†Ï^0Dêr2ˆfˆ0älf¸uí'ÃÏo¬¼†H  gÆ0°f’aPÔâe¨²ºÏà¯ú[À¾ÿÀÊ)þ! Ø ¡ŽrL¾?>̰u׆7ï¾2|úðšA]Z–ÁUé%É”7 ³/H0,½ Épí)ÐþÏ¿ ˜%Y¹™4ä8üµ¾1„ËfáùÌü L0{€ €à!É%ÿ‘ÒÀ_pÞÿ  b.^1†Pi »Yþ}¹ÇÀÇùŽá÷×ÿ ü,?ÊL/3äÛ[3\{ÉÄpóÁ-†O¿88™ÿ2Hq}eQdàbþÇðùÕ'†¿\XÿqûÇŽh`4 z.GÐA¿~|–Ùoþÿ(@m 1^Hîøô‚á÷ç—àÒï÷H=ÀÆÇÄ`(ó›Áó9P?8'}ûÍÆpèá?†'/>0<}ÊÂkó•“ë7$]A@!¥HÜÿÒ¬ÀÆ“‡/¶½É$Ê©ÒýDË? B8êù÷÷“€Ã?V 3ÐÌÿ €σÇ^¿ýÈðñÝ{°’Qd ¼ðùȆ ²€•• Ñ&@®²ai΀b ¯¿V¿¯Ž£Ž \ÿü4ç×O`õËÊõ˜,¸QÊ) ¤4€p(Ž€Õ2777(L£ Òÿµû¸½ÀÆô›áêÓ· •§ÜxÞ0äêcøú‹…˜u£l!eÊÿÿ<ÀP¶ÿüÚ‡¨C- ü‡;€……èP™ÿêqFp»Þpæ&.yfAc`›˜ž°2Üyò•ÁÆÀ€IA‹û/Ø¡ŒðÀƒ˜ÍÈ̬Š?A**  HšcD*Šq,Ãxÿ18Û3üÿºR’þý ¬B£Xœÿbøóã#»¸0'–óGþóp00 ¯—Ž0° 2´Ï~ýûÁÝ7O@^þû÷ØR°å@ƒÿ!ÊxHÅÊÌÂðù'Ëo&†??ˆ^u@ƒÿËçO¹8þ1ÿþòŒáË&qe†ÿî10Š«3¨zFÉçwÀ4'ä¿6Õ?0üg‘exþñÝÇy+öE­ÿ„TIãLÀ\l)ý x0ìì ›6-™/%%¤}h¿†08«[›ÿûÀõŸñ $Ñÿ7HÿÏ>ÁÀðXP±\`xùúË F`éôùubú:Ð4Ï@,¬¬¬ CYß½{ÅðXø¼zõâúáÇÒNR‚e8D/µõŒàÿ“Ú× FPÏÈÜÜÜäÌ™3¶@O‰>|øèàû÷ïw2Ð ãô’Î ÀMkçÅZóV¶IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/start.png0000644000000000000000000000361711550446574022371 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<!IDATxÚbüÿÿ?Ã@€bb`@î€b1û*€Ô ž‚éLFvFÍ åƒœÎ §Yþýeøû/“‡e#дý Xæªåb†Z:“fräq<sc8€þ3h0|úµ‚‹u®¹¹” +#cÃÿÿ"áÌÊq düâ*¡Cœ‘á׿b å§mìeƒNïŽ`¨Ê7eø÷ó/#04Øà>éåd‚8  &´€‚a„å `fÄðµçŸë¹Ù˜zÚ;ìxv¬ dPS`øýûÐnP¶bü7 »  €XˆJ)ÿ‘ôç_8÷ß]掲rÝmö ¶R ÿþýCUSËʈ×r ü`DÑÍÎðãO #Ãÿ¢¬"S¦¶>^V†@_ûùAˆ‡á?X9ã_ K~3°0´ˆ…8Ë•¾ÿœ#.Íç8}º+C ¯ Ø»?üa˜~Ž™ÁYî?ƒ³Ê†?¿ÿ2üÿò‹˜àr!õ ˜x™Qs ÐPPbä`Þ¹ 2 €ˆ‰†_?VëèIj,\äÉ`¤/úËpìÜ‹, ?-—ùN¿" &Æ|ÿX˜ê™Y²,4-Ä^úÅp÷Õ× ˆÈp€bÁëûÿ F ~¬öòQSš=˃AJ’›á'Зk®32¬»ÅÄðçï†ß@÷3ÐÏß Ö& {6Aƒš þÿ3ÿýýÇÀŒ¦å»0ÄWî—„Y@ةԦ®tqUVZ¶Ô—Ÿáã¿ ÓÎ02yÂÄÀÉòŸùßo†Ÿ¿~Ë þýæ‚_@2‚-ñÿ'(Sü²ÎÆôŸ™–åÁ €Xp§ù_í::’* æ{-÷ý/CÿI&†s/xX3}¿ìü†Í—þ2üúù‡áÏ þ ¡ÿþúΚ?þbH²bð1a†jQ@Øð`!\3gº1HKó0¼ýö—¡ãÃõ7@Ë>üë÷o0ýèë{Ÿþ0üøñ ì ß ÊèßÀhù¤|ûÉà«ÇÃÀÈ„™-ÝÿÀÙá·§««:ƒ•0ÿýË0ã,÷Œ ܬ Ë!†ÿ:àÐÆX¡Êø²ÿaô_pbýdÿeø 6\^ Uÿ„%A…6+¤%´O?AúþÁ-ÿý ü€Aûè?¿ Áö90DÀ|0þUÿ›áߟ¿àô€^&ÿ?0 ØöïÙóáúõw llÌ iz¿DXþ0|ø 2ô/ÿŽë_ àÿÍðõëO(²¿ð/ ‚¿|9ô/°˜þÇ€^#¶*LËž?ÿp$'oÃÇO¿”Ū­ÿ0Hqñå'Ø÷¿`¡ ö 2 R|L ÒüŒ 2 ,ÀÄ #ÈÌ ÄrÂ, œlŒ ÿbV‡„-‚ÂþÐ¥ûöÜÝ”—·WtáUñ Õ¶Z÷þc¸ôè'°zÿ òoß3dÛò38kq2|ùþ×ÿÙîßßÿà8aPÂgfÁ¯?þ`”΄¯$<tD¢…sp1 õt90¨Ë°3´¸þe˜zèæ ߀åÀpt° ädfàãb—v tr8ÎÁñþXNýcàãf…åxÈ Û6`z5ýüŠû>‹Î›ãÊ 'ÉÉPáÊÀ ËÌ{ß2|øü\!±²±0œºøž¡kÊy†@G0Á*#&(•ÌÀzàé›o àø³ €×LŒû˜ÙÝwo¿3ßÙí“þŒéÎ Ž¶’ ñ– "L MëŸá_`Ä=~þ…açö{Ÿ€Õðd`‘‡Y1ÁÊÌÄÀÁrf<@×`d8ÏÀÉá~ë껩þ¾‚š­r3´¬4¦Ä1«ã¿ Ÿ%% Èç¼lŸþ13õ3°1¾ÅÚ~D+Œˆ‰¨†¼–ÁŸü­(.8ð%2yýç?4”ø$X~ýùÓ²–•3ÇaÄDtkÂþÃÀÎÜ tˆ×ڥׯxlfX³í1ƒˆ70€XþýCÓ÷I?Ç)!€œ.“½Ãã§_¦Ç%íúŸQv  Àrƒ R°ÿúhœb„œX¡|TG fFlUö[.–¬¿ÿÿ¯_ºèZë‘S/Lõ DXØ™™ýýÿî å?€#Öæ=@!;` ⯪þâèü‡Æn`Qxæá“ÏùŠFÏV ØKŒ*î÷H# ã@wNhÀû†4à0â(÷,‘jZ>IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/artsmidimanager.png0000644000000000000000000000514411550446572024376 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< öIDATxÚbüÿÿ?Ã@€bb`@, ‚‘‘‘:¦‰{00[20üý2ˆÙ˜8§'sï÷ŸŒÿ22f10þ? Rþÿl&@Ñ>þü÷4Røµª6„Y3Ú™[‡éïŸE ÿþJ2üÿ – Ú:à×_- eÎÙ:¿xxØÿ1„Øð3Ør+0üø‘Áð÷'X @!;€ˆy˜‡ÌŒj#R‚þöCP__vA¢·¤ôÏï_¾íû”ö2ÆÎ_' ¤ €`i ˆ››»Ÿ™™™˜+þáöÒP¦ùÿï/3ýùû÷ñÏ_ Áý‰áç+†ß¿™y$g´–{›^Ü»ŠAXD€AHˆáë÷? z*¢ ’l:ž|Rê¸@`ððð.\¸PÎÌÌŒáÛ·o  ¬ùïß?8ÍÄÄÄðçφ¿À`ûÄ}c`ù÷‘aÑ‚ùÂýs¶¥Èf`åc`à’z èÕ_¬u a B?6?yÀ` ¯Î ))4û/7+ƒ‘š Àƒ{otA °þþýËÿðáC>>>°E,,,`K™™A˜˜hÿ1èÊò&ÿf8¸o$©·"ÅÏôfŒ¼KXuIªÃÃÃûfzâ?Ø,N°REY`Lÿÿ €;èë¿………ð€–””dPUUePQQaÐ××c¸zõCÔŸ ö ÿ€¾9€‰í0¤Aa€D7м¯ìD,‚§„'»2óSÇÑG!öœÍAQÇÅÅÁJt2b\ÀìùW¤ €ÀùØÂ‚AXX ììì œœœ`Wß½s—•AJZV8J ¾’çTqœí‘Åÿ 褟ß^¾|/c@ÑÉ4”…88Øþ‰‚Äì^^^†I“&1b&; F°!À| Špùò†Á©þ‡2“ˆÖt»ä5fF†³7€ÔþÉðöíkVHt‚Ìyˆ‘™‘ŸèAæ ød °¾~ýÊÐ××Ç ##¶ ä{P(€0Ãï_?üýýd夎ø q#;;#$kp˵'äxJ)3ì–q*À¤ÀÁô¯êÀ2H  7' ;ó?P6f °~ýúŰdɸ¯EEEÔÔÔ i@Ÿáúõë †@È30±01üüò‘áö•» Gνg`à4ŠÐ‰¯å60Wb8y‘áùK+% ™?@‰™ŸáÍ» û÷aPVV:€ ”çÁQÊÎÎ*wì666†ÈÈHYYY°c@i‚••Lƒøjjª Ÿ?}g˜ÿæ{~6`ÀÎðàÁ†§Oî2øúăKNP:øôùУßß‚Ì Xaƒ¯m( LUÿføôî ów†¯À”Æt¨Œÿñþ —( 0Nþ£òןÿ ¯þ±0|gaxýîÃÃÛg<½ÜDDDÁõ ++0Z>Cáë3ÙvHâüùóà ÿñãÜA šùßß BÀÄù÷=ÃÝkwÙôv]|ÏÀÁ …_kGf>V†??0ü¦Ì§¯Þ)Š2ð ñ3j2ÈÉÉA£ö?Ã_`òúí;†¿ß¿<Ù @ð’0-- ì[P.i%@­®®ÎðäÉ;ks†5;63¼ùu™áñ÷À²èp`EóóǯŒÜü•møÙy€µñ7†?ÿ0<Ñf•Vbøüð%0èëtPì=zô¨ùçU}vHd(1‚€€€¸µ =zÄðåËgM}†f##†Û7®1ðóK3ð03Ì›9‰¡wæÖ @ê>\Ó›ôB9Á›—Iáë³÷ W UEE NÀ[J?þÚõŸáöÍ;·þ~½ °@í€5kÖ`$BP”üºT‰01AR:¨x<ËJ‹„>Sÿ=†¾_¬Îü.ìÖÈðÙXðôN!ÕBUv.pj¥þŸÀû˜ŽÎ]¼t ˜šŸ‚4 Äe?6nÜ.óAe¬É@ ³±±b`À&÷X{àÄ PùÊÈ l2ýšÌðzãQŽs“¿~qˆRxØß¿ghnn†û\LL Þ ÑÓƒ4H–ÿÀÑ\ü -…ØÎ1|{èòóÛì’#ÛŠ}Þ¾9Îðçß1qq†Ý»w¿–K~BÚ1«Œ˜===$$$À T‚#;;Ãëׯ$ÄE”•” ¥´IÆ .ÝP[Öÿ \F–ïÀv\ó­=Ý»>>819ÀÍÞÔRF‘aß¾½ 'Žê*x‰F€b¦ü/111 FÀDʆ°øGn”~üô™áý¥óàF ¨YÆòÿ#ã'/ ®ÚÿR3B‹E†“/ïv_ýîFϹÓjVW¯^XŒ®~`tÁ[rÄ.n™˜Â€Íò6`Üsùq·Ê!U ¨Y,t˜€eúó¿~geN!A+˜ƒ Í~f ¹ÀŒË V˜ã€æü` ÆîЀ÷Ž ^ÍÙkºG8IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/configure.png0000644000000000000000000000356311550446572023213 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?Ã@€bb`@,0†——ŠÄ¿¥þþýÎÂÂnÆÅÅ£ÂÀðÿÿ÷ïßîüúõãøÿÿÿ6²²²=Š10221#ÉoÛ¶ LÜÈQ´€ƒƒg®••«‡ªª ƒ   P”‘áýûw¦·oߊϿyóš…©©)ÐL ll,`,""¤9T>}úÀÆÂÂú‹Ô ä(€ÓÏž½f000…„''ïʯ_¿d‹ŠJåjk003ÿúb9($~ÿþÔóû°Üø Ä Øðÿÿ˜_¿~ºóþý{AAaPdøøñ0 š-c3¼sçÆ]]C`|kÀ´äVP(1¼}û˜;Þ2ð_ãAzøÿÃàƒÄ„pÀç£wîÜû d8(˜ALLŒââLM €¹€ì{vvˆš/_¾30˜™Ùùüüù³–Aøß¿p LÐ` -ô4@HÙðïæ'öß{ûö-8»#ã OÿA}I|œœÀ¬øJ_¤¥EÊÊÊX­¬œ;¿}ûV ,Ä1âTT£c &„"æ‡Ož}ü …n`Ëz1L/@±0P @C¢mÁ‚YŒþükæpi ª?ôtT8Ø9êê&Lèlªk„é ª9æ`m[¼x30‹667w[ÐBà¨hjj`˜4©»¨¦ˆáY €¨ê¨#€ùµiéÒù_A ®ªª‰aòä^å-@éZPâDDu@s¨íлpál¶'ŽÆÞ½{{ P¸Ô‚BÄ8нc€ðÞ1@€@B+êˆXàIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/kalarm_disabled.png0000644000000000000000000000651711550446572024332 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< áIDATxÚbüÿÿ?Ã@€bb`@,0F##\€ˆÿ10pq30úˆH³¸Jÿ7ebü+öñÝÿWן3ìyð…aö_†[ u|@ÌÊÀ "ÀÆ¢"Éà% ΨøŸƒåÛûg ç_<ø{àíŸjŸªaôð FXÀÀ1ÐGË’»ÔÀÉNBå'׆@cž10¼}ÀÀ°ë8ÃíWü€Ž½ÌËÀ a*˰ÆÙ†ÁZR¨YˆÅ˜~ÿafxu“™áò®WŽþ5õ#Ãÿ?±8 €X9@+ØÙó< E{ ýþ³0ýyÇÀð( ÒÉÁüŸ4¤NgFÑçß ÿNg`z3ª×:âÐì7@3>ñv†ãÛþþŸ±å/·•ꀂG8K’e¡˜Ã+`Z. ù÷L ÌǘXÞ-de`—``¸¯Æðç²,Рÿ™9€öÿa`üû†…ó5“öU`xÉÀpì Ãÿ', ¿uÿ1°ñýƒ¤>Æß zLŒÎ3ä^|ʰ— 6 w€¬·µ  0]_ùŽì+û™ÁJ´ì–òÓ¼ïó. åœþkk0üçä:€áÿïß ÿ|b`|óˆíáA¶;=.30Ü{ÅðqÃ&f%³àaF§º4ƒî•§ ’ìL ÷Aöܬ\Œ\ œŒ _>³2lŸÈòù•à_žÄEÿ™xxþì0bø+^ÌðÏË›èôÿAøÃ? þËÌÂðŸ[˜á/8ÃOaMö7v Ü—û˜d÷3ˆÈ½b¸; ë¿8x0óÈËc–• ˜Y™ q@ð‚èɹoÇ—=f˜•ô¼ãðýßÇC§ÿcàÅõn†Wœ™ 48\F`®ø÷ëÃßß@üï@ *5þ<}Àð÷ÝK†o f -šþ½²d`üÅÅ`’L"¬ÿŸÎžý§t󦿯>f¼LO~=ÂwÀLJ¿zwv¿²:þðç"÷"c19`<œaøÎ“à æÊðèÜI†]K–‚Ë &f&°ïÁ ˜‘‰áÏ—¯ ¿>d`fø÷é=Ã7>%†/å ¯iƒ‘Á9žA…ï÷ÿG›ý3¾ñè70•±AÊ€bB*îsýq9i†`«h` Æÿo`pþ7 [jÈpÿʆ Óg}þl AÑÀÌÌðóÂyˆå¬¬ ÿþ£åË;†/¦ ?¥"^³2Hè20Ëk1¤ 00Ýg’•=û_F†áŸ´4à  ¸^ƒBè}oA)Pœp0ü‘ c`áfeøóh!;CP~>ÃísgvΟÇðõý{>AÆ'O?|`àÒÑæˆ`0üÿÇðóÛW†ï À÷K„ ˜s•tX˜yDddÁƒ %Å@ðDø2rú : þÿ—R ÿdt˜þƒÜ_†ß@G³¡_v.êö†»×®2˜Z2èúÄð_Fáñêµ º¦& ¼ü ?¿gøóó;Ã7^æ›$Äþð³{}ÿõûÿãÀø»Ä hI+Á/ÉÀvÀoA`IÌëþ}Áß>eP14d° ‹d8páÃÇw&ìÚËpxb)Ã×ú†uMU ï?~a`†Öÿ@Gÿ–žœ²`ƒ?òr02ŠŠL ú÷o‘èÿÿ›~þÿ¯² €˜+`¢`ecƒ &6°Å”à@ø×ß ŠFÆ ¼òò ¼ÿYôÞžaˆ6à`ˆk¨e0¸¼auu!Ãë·ïXXÙ€ÕÈVN†GÀBiãi†i9Þà’"†T--M©ÿÿ×þþÿß €XÐj¥ßÿ~Àð˜Òãh1(n–ÿÈTøäÊe†_·î1|¸¼ƒ¡ÒÌIó¤uÜÿó3üª(aXSó›!¨©A^I„á!°Lš?ƒ—Áù;/ƒá„|GGe†üÙ³•§^¹2 €à!ÀÁÏ>?døŽî Œ?Þ-f„Z,ÍXX^=zȰwé"k[%`]Ì+. ,xî^g`´`ð.©e0:¼‘a{sÃå3GVôŸf°ÅÇ`[UÀÀ ª TwX¿p1H 300ˆ¢$„PÏ__`è –ŒbϘÞ_cø-¬ PðCÉé[Ô­Ü“ÓÖ¶±3,ßÄù……ɾ”¤ˆÙ般o ¿'ObXwü0ƒÏ_ ö5U ÚÚ@ïÀ¢ûÛúõ û{ëû÷:€‚;€ ’ þ½¼Ì°ùã5K~µß ì–0üüéPúéÝ{CcEm}†_Àlæ•_İX2.YÐÊùú«}Бoج\Ü^Õ._Å ›—ÏÀ¤¬¿Ù•ádž/Û¶1,:sæÏé_¿Ò¹ØÙç¼:®¶þC $ŸR†#–] Ü wx~|_ÈðY6€áÏ÷@þ–‚¬ ¿ýfø,Œ˜€Qòè¸ÍmÍ ÂÛ'2„¸Ø3pZÆAšU@Ãþ¼|ÁÀÌë  ²X|ܵ‹aå¥KNýûWÀÁÊ:õ?P?@¡¤P“áÒÙ ?rT¾0pü.gà|}¨@ˆáÏ?F†Ÿ@_ü– ‡ÿþ lÜÙ^e• ŸËVî:Âð~Ç<`H1|üÄÀ L$À‹áåK†çkÖ0,9}úûÙ߿󸘙§2KÐÿLL h›R(Éè›2ìñÚÄ Î ,þ_7`øÎÙÅðYÀ†á;Ðç|…:X £€“ŸáÙ½ Û“ƒÂ?`PÔµa`W:h6Ð’ŸÀ„wíÞ=†eÿþ]gdd4afbúöj@ÁÐÉÈo§ý‡dKsg†õV3d˜Õ(Ãa`ó+‰á›`$Ãw6%†_ÿ˜å#' ÛGw6çe2ؾ: Èüá+°RùL˜3Ë`ý ¬Ò¹…„.£bë»wýŠeþóç3 Ð3w@’` TI9†-Zæ Þ±À6 3´iõF X.0üeTb`ááexqÿÃÊš} æŸÏ3hÛ耖ÿªûõ¨ö(;s3°óó3°óñ1ð 0œFáæGÖþùý;íïß/Ïß‘,‡6խڬ¹goÃÕM LêQÀ4¨úŒ‘ù¸àzsƒamƒ5­ ¥÷o¡…Ð/?M ûÀZH…‘™”ÀýŒ6K11`KŠ9xã­[Àrí2@¡TF0l„1(h1¤Ë»1žì`øpûCüÍË /N®f(ÖO6òz œ⠜;¶s0XóþaЗüÃðþ ´…à ½ãÀ$ýÚ€‰áÛ=‹¿ñ ƒÝXrpp„m¾|ù'@Á£ ) € ¥}Z.ÅðíÈD†8`ZÞ÷—jƒ<0Çh~f`õ3ÒaÌ qüÅðõ$ØÿÛ³¿ôþ¬ g>0÷hZþ0ùÏÍê ~–ŸÁBL”Ô¼c¥P”ˆˆ0ÌÙ»÷@± ;˜æäfˆº¾áïý# ÀlyZS‚–Àëá_&¦‡˜÷_ðßøÖF3UA`Q ÌРòêà+&†3Ÿ˜ZX™ÿ×Þ?Ê $©ó{Ùöw.ŒoX˜øù€ (&V`¿øÅf%Ë ¯#äýè`¹Ä‡'Èíÿ02î‘Öæ/ÎòÕa+00efgøñ÷Þç/fn}ÈðåÎï6æzPYËÿÑ¢ €à`ÿDzèêÕO™~²2º1ˆ«sûþþó6PŠ-{±í¨bàeÙhl+l\ênÈà+môÃÏ¿?N¾{ΰxφ7~®dcf®ZŽ·º ¸˜X/þzɰ{ïåW f‚† Ù.æ Â*la¿3N¡ì_3h£p9[«¯‡ …%ƒ§÷ŸLÀ‚î Ã¥OOí}ÊðæÊïÍlÌ,éŒLÀ2š x`úÇò—í7ã¢+—?îÓ¹Â.ÈðÝí;Ã<†k1Ÿ®0üeúÏpü?s½²‡d¨…ƒ•ˆ.0 p2|üõ¨ù+Ã5 å ÷=cx~ú÷^6&¦„ÿŒÿˆÊI„pÀ/V`pìüýœñäž×­ìÄm¥ý¾;}gXôùAü¯/Lñ¦Öœ ¡úÚ j\ ?ÿeøþh9ã†ß3¬:òœáù©¿WÙ˜“þ2ÿ{Gl3 €øÃ ¢~±þ`XróÊ/«ZGœD¼¼$]>¹nÆïOE=af†Ï¿¾3üüÿXsþ`xúó!ÃêcÏùw—õ7sÌöH)?á€ÿ&##Úw Þ¼­¦ÎwƒãŸƒŸ¼0%«Õ¬ ï~Æ÷O Â_ Ï?bXsâ)Ãí}ŒY0‡ÿãü}½Bç;FÜá@ˆDª÷˜å?ëk毬Ëo\ýÃpýãm`0døþç÷_>ýþÀðíÏW ~0¼øý˜aëùç w÷²~dýÆ”ÊÈÂt˜¿€vA Æ ÌÌÀjS`Á0@ˆ@°èómæŒ3ŠK¨ 3ü6Hþ}ý÷ÿpH|úûŠaßµ 7v±}aùĘÆÈþw'Óf`#†T@L°Â13#Ó=¦7ì»n\úÃp÷ë=†o?3|¦öo¾0¼ùó”aÏÕ W¶rþayÅV,îWQR{" €¹Ù€Õë´×¹]{úèã7@G|eøð÷%ñۯnlåf`|Ê^ÇÈÊ0—Òê €!ð‡3ÿg>Íð‚cÿ½ëÌ ¯~ñÿ5Ã…'onî``~ÌÕlØtP£þ „þ±¡b–¿¬?Y|¾Ä÷ïáûw WŸ~d¸¾U„á&÷4&†r`B¡J €JBf, JÆ­ ϸ/Þ» høë1Ãÿ+|ë™Ø~kÕÔjÁRAÄŒMþ3ã_¦Žo{$Z¿3íÙ@ËP³ @ŒÝ7 ïЀ; €ÜëŒAt>zIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/player_end.png0000644000000000000000000000343311550446574023352 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<­IDATxÚbd0žYÄðãó,&Æ5 ´Œ 5 ¿þæ1üþÇÂÀÅz €˜þ×y9*ºòs±­føòkÿÿ¦@Eäƒÿÿñão¼B<ÔD[Êlÿþ· ¦ÿ?ÿ2æÄ0ZÈàæ¬âËðë߆￧!O“øó÷·š’ƒ…ÈA¿ˆ (ôïÅû? zÊ k&y0Ìï÷aÓÖ”Èbøôó 0¨J€ò¬¤1àÚøîë?†Çïþ€¢ƒ €˜À¡ÂÀðñ/ß ¡.² ›ç1ØË‹‹ñv3|ùyèÒj—_@G|‡°ˆ äŠ øÁ{†+OA¡ÄÈPªÇ°|Z ƒ_ )ÓÆõ _n¦¢Ò(p…PøÛo†÷ß \€EXà3ÐU?10Ü:âü3†S÷¹z«læL b0¶Vógøý÷ÃÏ?}@- äp¼…†@ðèûO?€ÁòâÀ¨xøèˆG g20h©Š0Lnqg()÷ä•*døöë 0˜ÒHNP ]ÀØg °ÐÒO@Kß}ƒÂï?Ä¥÷¡"ÂÍÀàa¯È`e"ϰzÛ ¹ kOÏüþáS&[50¸·áŒ PÖÃà4dØ?þB|r#²(Tî½c`âcbó×b02”eX½î‚Á©#×·0üþ¹†­háE‚Žr¿þF$B€b%Š? !ÀÌ„3êÀ¡óî%õ×ÀD ÄËeË`i«Á¸nÝÙÐÇ—ïú2°0Nc`cé*|A( >B@àøøð¬LÄÅãÙ' Ï%Eò =»Ç±ǹ¢ÏŸû0°³Ì``fž*cpF ÌE ¸&Å  ¥›¸Ù4•TµåövéÈå¾_>…£¥hù.tGü‡b x€òå{ #ؘHÏVŸyúAˆ›™ÁÂÕˆAÕH•áðöóV/®\ÛÆð÷÷VÖ& .!Å&غÿ! ã701þþG"êùóÖ/?30–Ÿ™xœÃì,b™yƒþþ=Áðû7(4¤€Ê~!; €X`aòû ”†%àçÀÐx ,ÔD¥ÅŒB½žÞ|ÄùüÌÙº¯¯^y£‡@1Á¢ç×_ê•õ,Lè~ tÄO Çx •Lÿ”ÒœÈjÿQÒÆ@õ#ÐT ý÷ÃÃç®,YÅðîúõ]Àœá ”~‚¬ €X` #)ô9H?Ð÷@ß¼¹qŸáé‰S ?_¿¾L„} ll³¡¹€Y@ÀÌ Ì~ÀR„lˆ˜úæ¼½ÿ‚áÑ±Ó Ÿ=úlâõ2ppLJ¿Â¥ €À`’@x€ÁÆÂHZâc7ÐO^|`¸êóóW1üÿ·h((Õß d@±ÀR/ÐlDŒÍL PZüØš¹}ô*ÃÝÃg~ûvhP0(`´Ñ)+4òL±IvP d&"@ÿýûŸáö¹; ×öŸeøòâÍ]Væ6`.AÏçØ;4´A €X`.b²¸€3ánÈ€Ó ÐçÏî½a8¹åÃË›¿5LÝ Ì3œ­d´ÐƒÙ‰P¸a:à?4‘‚ä_>ûÌplÓi†Ûçïügøõk9Ð+ "ö&©¥(ºAõˆ @`€3$ Ðã™Xl|úø‡áØÖ« çö^døööãaN¶n ¯7ÕGÀ,€ü @ð\Ê‚Œÿú88!…Ó™Ã÷l8ÍðþÑ«û@À°›IiI J\Ð °@Y ”@ÁÃÉÓ—Ï¿`ؽî<ýó÷¿ã}*0x¦u<&©‡„# À!ò0 @`°ƒšØæcàb`xôø3ÃŽµ—Žï¼ôXÕmbàd©Æó5†ÿ$vÏð6hã €X@ °€sÂê%ö­»Àðåýç³ œ¬•Àd¿›ê]3`´òp11ˆ€[ƒ Ä,{YÏž|İdöI†‡—߆Ï$`|€âù'ÙSüU%ÛÓGï¸8Y@Õ0+@12ÏZÀðó·Ð9óÁ–ÿgxJãz°“Náì,ç ªhk:¢CÙIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/tab_remove.png0000644000000000000000000000340111550446574023346 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<“IDATxÚbüÿÿ?Ã@€bb`@î€p Œ±’‘™á ³ ߟn&v¹GßùSÿ±±¼ÿÎÆÆð“•…á733ÃFFuu6¶ÉXX6ÜøógÚµwïX™0ýðÿï_Naaa55†þ É02022‚Y[·nÓ„¬›CŒïoŸSq`¡keN°4ëÇ•¿ÿýÔøï÷o-36¶µqee®±ý ™ÿÁFbÇÄ€bA8c¨BOR'«ƒó‹O®?§/^q÷¿x ÐrQF†u¾99ê,ÁÁ ª††l ÏŸO^±uë‰/¿ŸG6ðß¿ ÿ€´›šï±€‚;`߯sŸ?;ž²¶Û’Á2A $—ÁõÝOÇï‹Woååàå÷,,Tg³±a`¸t‰áÛîÝ s¯\9ñéׯ—ÿв1ƒ¢¢"++Q!@p|``x–uëW{÷ìu±IßML£D}¢Ü¿³æ”bರ``¸{—áÛ¾} Å7ž˜ýôi PÛ3d‹UTT$$$899~ýúE”ˆVE221¬Çß鉢 kR‚-8õ=˜!‘úý;ÃÛ#G*÷ï?>ûõë È#˜!ââb ffæàà™‡»pÃL„; Va`bøÇÂòôò[ÆÖËÛ7lÖ~÷EX” ~߿ǰíÚµ_‡ÿ. —ôè gŸ>1ð‹ˆ0¨ãû/0å“SªÜ"@ÌtÀïÿÌžrÿª¥øþ3<;¸ƒáç{ »Ù8lEEÙòóNýüyþÿ_ß³&/0¸™YXþþüIV9@ðlJ¯ß¤ä­ÓRþa’`:… @h 'P,H@ T“›{Ö÷¿Ù@þ%×ç0@p012Jhiþ[iaüÇ’÷vñ 6®ó{98/s-ùä<rrQ®’’3~ýÿÏÍÎË v(n al €àQðóÿ?C U6”èæagX(!÷Y„‹‘åÅ ¿?ÀŽdggð”ˆí½xq†Œì©Ÿ?~$üøñÈ2,@¼æ” ŒŒÌ÷ÕÜ'¥d¯Ý{Âþ(—ÿŽÜ?`ž<(¤Í ”ŸÃÐ!%n÷hÐß.-^Ì`öá=Ãef†úG°óðœR銊J3Œ ¾db`†ˆffF°ÙÙÙ^¿~Ͱ}ûNÇß¿ÙÅ?Àì ¸(°¨kËÜgûÎp÷ÔQµÖ© Q¦F0¯€R"Ãm33†} g†þcçþc¥ªö˜õ¼=<ܬ­m@J€3“ ³ëffxð?xðPçôé3@€Ù @p°üþË&ÀÅΤUÝÀ ÷õƒ˜/Ã`Q ËÛ ZQK‹gÖ,î³çnMŸÍõõë…, Kýúõ93¤8†bfæ¿À`›ÁÎÎRÃÄÌÌ€B8€•ýï¿¿ÿØ€Éd9¶Ôý ˜÷Exx€Y ”lÿ,¹ f1ŒFǰD2”–¹¸øàfÜÌ̬àR äc&ÜÍ„¿ÀPã¿ÿÙ™™ÙÿüùÉþñãg†7oÞÁÀ zÍÌÀ¬ÒÿýûÏðóç/ ‡ Ð. >Ì ¸XYÙ…„„ æi<+ƒ¤¤¤ ЂÛ@.ßÙ³—.\¸J0ÏÿüùX_¨-FÝ} W$@pðòòq{y¹S.>ðû÷oi†ÒÒV ¯€Í‚À´ò" ´K/ÿáu„ %ÊÏŸ¿p/_¾Af@!…Û?..Npê%\¤`‡Â'²ð6ªÜ?xacbb…[@p01á·=@9„xü‡;àÏŸàôÄ„”éÖE¶ €à=i­9rÀha…€B 6FFz…ÂÄ„œh0»Q@ˆ’…œM ˜ 4#R#ĽðjšèÐ!¸pÙ„ä–@eûk`^ÿƒ”}ò2ŒšÚ!–ÿGa£Ê#ðõëPÀí DÖbº»fÍÁ¿ œS n¢þG$ ÌìÈ€’n}³ lüùÃøÆ Æîž G÷J™ä®ÒIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/undo.png0000644000000000000000000000311011550446574022165 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÚIDATxÚbüÿÿ?###±ÀÊØ˜Ÿýû÷ Lÿþ)|çæ8vöìE @1‘¢h¹½àë×¢¹¹ìß¼QøþãG… €ˆv€½ŽN½ôƒ ’—.eàbgg† ¥ b‚œãÛ·z_¾-XÀ ëéÉÀp÷.µ@±°\ŸÿíÛ ^òò IS¦0pÉÉ10|ýÊÀðý;Õ@,x,Ï—xüxBB@ƒoUÄr`¢…9@áýû4 %%µO‚‚€ÜÀù‘T#z.9˯_4_½J(lnfPwv†XŠ?¾váÖÉ“ §öîe8õìÃ;‘ØØ€yH¬Å  çýðaAN_—˜ÂÂÿð²ßܸÁ°˜F¶Þ¼ù᥌ ȉq@Á´<^üÉ“ ‰Îξyy LL‹i|l ¾¹?ÃŒeË. løÁÅ•@(Zì{=½ùj/_&dgd0¸¹A ýû§%„ð·—/º::Ž ^øÆÃã€Ïv€Ÿ¬ìÿŠ„+ ˆÅ¨ad>.9dñŸ?¦LœÈ°‘“óž›7M€výÅæ€DùøŠçãïØéÓËïßg`xñ(ñ’ò¿|AÐ0üù3çO R £¡ú’‚‚¬_¾4°ÑÑY„+žLõõÃ$^¿žddÄ›PQÁÀpõ*Û7UÌÌ4J¬ è€dŸ} Æ 6È?~€ñæõk†Ê+WÎËÈD½|y9º%˜èé)óÿø±ÞŠM7¯­AäÛ7†[·þü`á06.1d>”}ìɆÖ/_>ßgcS¹~çÎ+d#–ÚÙJKkšú§Oiy ††  ¨/²á±±@_2-;öÁ¬Žéºx‘aƒ¨hïñ7J- F\Õ±™¾~šÔ‹=NN¼á lyæ Ĩ½kÖ0œ3?°„Ô×ÔdÐ40`°ôõeàEɦM ÷î¡8àæÛ· ¥¯_¾ðÿ¿îãçÏá@ᬠO]¼8뙄„ãÜ“'¯uåç3|ÓÑÆ01³²ÂÕÜ“’Ú|”›;jÎóç]­›7ßL aX9gÃ7`ñÍIÐP ÎÏÏ`ðý;¯° `0²=„·::âìWAA«_¿®ÌŠb¸ùƒ  4 þ}ŒÓå¯_/ßû¶áYnnóiçÏŸ«åšÄDGxˆˆ0ˆùjCpÂÄT§Ufhf˜ØÿMiiÿÿŸ9ó¿GW÷¿–ÖL,J™AjƒED>­¯ÿÿÓ¦ÿÿ½½ÿÿ·³ûÿÕÜü¨°ð%993˜b€"ºAræÒ¥éÅÅͧíÚõxJYÃ7P–Ãþ‚Ô>”téœ3ç°d` Kp±°0Ó?L1@‘Ô$æãS/¸¸ × ¬Ý¹“á›±1ƒÐ¯_ Àìh’ º8 Ÿ±³Ø»ØrÓÓcPÖ-ÌÌÌÊ 9€¢‹@à+/ï„=€iÖÑ‘XB²03˂Ĉn†ÂÆ»?~|¸lÒË Ã„Ùˆn§~þ @¡¬7Øþþå9 €èê`‹y°Øf@a¾?ÔAbDW€¢á°ñØ„‡€¢«@à ß…ÓÇ3|ge» €Xèí`+9àÀ¿¾O_¼¸äþ0²îýïÑÏ\IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/ledorange.png0000644000000000000000000000411411550446572023163 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÞIDATxÚbüÿÿ?Ã@€bb`@,0F¯\ñßÖŸX~üf`üóá;³1üâæÐúÁÉêü•Qï'Ë_uÆÿÀðcd`d|ÍÄÌ~›•í 3ã†ÿÿ/Á´Ý»o‚i€b!Ê™ÿ<~û™õëÏO+v.^aY-a ]nA!s¾þ¤òêÑMËGwŸ0|úôý3Ûi6v¶éŒŒ k @À(úÿßÿοŸ$J›Ê0hÇ2¨y‡3ðÊk300  9ò Ã×·®ÛÊ{rû6§Û7Ÿ81±p®gaa,Ê>Äe@1Â!–(ÐÿûéÇ>&óêµÔ\Vau ,Ã?F "[þ(öè¨@±_ ?ßg¸¼} ÆÅëÞ¾gxÀÁÉ– T´[ R0#ÀȨóãûŸÒ*Ü^sË,ý~s20|ýÄÀÀ´ˆÈf¥ßP½ èˆ_ßþ|e`fâf0ð‰aPÒV`XÚ;]áê­ï›89YŠv£‡@ÁsÁ_N0þÇÆ,úóÇ¿ÅꜾ³“ôÌÞ¾a`øùhß/ˆOÿÿÒXð¨Ü¯o Ÿ?0ð‰«0$ä‡0èhppÿùoÐetÜÿ˜™þ±01üùÏØÍÍ÷ÇÀ·@‹WM“áýk ä Ï€øïwTößoPü ÿ€à@ö×· œB2 qþ* Rü?d~ÿeœ´Š ÙwÀ&F†ÿ]ˆw°gdøû™áËG AßÀÁÊðï+Ä2û/ÿÁÁrß øç'®ï‚•?“ “0yÅ"; €ÀÀüçCžŒ ƒ¦40(Ÿ?úàРC~ãþ×'( tÔïPúþˆÆþÑûãÓû ê¬_t¤ÿ2C!’’! €JBF5`–³2Ðca`a&¨îžŠƒò7ý „ßCØ??@ðŠ¡ò ć±Az_a`xóèÃÿ VÒ?@¡`”°Ù @ð\ðÿ÷?W!U1`BûñS10 30Hj ý‰Pü2³ÝËÍ Ð\J„10±þâÿÀhxwŸáì~ º¿à £Êö‰A\ˆŸõÍ«?n@]{@Zî€ßëK© 0ðpÝ/hRùdßÂÀ ô¼!Pà7ÄŒ¬@C ™‘ÊßÐÜr$0è_b`¸pè CØ!ZY€!¢$ÉÊðìù˜½„(~ýW.@_°BeÀYÈ¿°—áÕ]`®”g`à† ;’þA²è`ðxÄÀðôз Å;¤ˆƒ?¿Ä8@å³ ÌZ€‚;€ùß1. Ê¿¿!–3ƒ‹y rÈ›À b.^N`QÌÊQôèÈïÀ4ñz_?B,dƒn0Ë!åË?PAdz €à`ùõ— T’‚-üµ”ÉLPC@Áûî3„͈”ŸþA-d…⿈‚µìgd@Ö @p0ýøõú×/vH„äF$ǰ¢9VŒÿ‡ZøÉ×LHrÿ!üï¿YâÏ'˜½φ¬ÿþÞùô h4N|Ï Rv,4ŒÍuŒÍ‚äp›‹áÍn`”ý~³ €àê¹òêÒ+†¿¸ ædƒas YÎäv¤h`A ­ì‚ ÷žÿe`eþf/@!JBvæÝï?ÿrÿ5°‘ÁÃŒˆcV4̆†9ÐB…Í,Þÿ+ÅðüÙ§¿,,L{`öÜ¿¹Ù/ÿæd>yþôw K…!3„ÍpäPàÀa1rnâác8qŸ ˜\fƒ0{î€_œløÙ¦Þ¾÷‰áúE`6cB¤,¡ÀŽ# ;…@5÷þ©1œ¿þ‰™a.Pä3Ì^€‚;à'°Ñù—“mÃö?¶ìÿÉð…K‘Ò‘s Z( = –l ÊŠ ëOs1üþöå,3Ó äl @ð±3üàgÿÏÀÇ™ÿâý‡‹K0|ÔÀï6¤D‡ÍrP%¬À°â’ Ãý;Ï?²±1§E ; €˜0ÀŒØøÙ’®^~ümá!†/|À(#j³ –@Y²rÁM¼¿UVžQg8~ì!CPô<º}„µc¬9÷sr0ú_¹pÿñä5B ׿820pK ¯ ú´àù‡„Aâe¸ûÖaÒ†ãGï¾å`û,~—a³ €ð4Ë÷pq2Û¿|ülƬ…\nÚº: –æ: jÒOX¹^¥?!‚ØšbàäføË(ÌçÒ 'ϰ1\8ûŠá÷ϧ¹8XÓÿcñ9 Þ~0$î³²1{ÿû÷=îÒÙ©—/°›‰K‰1)©©3ˆ }eàâúíoßYÞ|àa¸÷3óG¯þþú~‘•a>ë  å?ñÙ@ÄôŒþ011ÍcggX o›×O»>{ðH‡‰C¬àÿÏðéÿ¿OYY®±²±ìeå`:ÿDL§ €ºw @Þ;0 8à®ÒR-ÜIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/thumbnail.png0000644000000000000000000000351111550446574023210 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÛIDATxÚbüÿÿ?Ã@€bAæ$%%”d2þÈÿÿƒ™ ÿBh˜£AJ òØð? õŸÈdÒŸ€d&óŸ?ÖîÚµ«f'@¡8€……¥&11QXZZšá÷ï_ èóïLà?’‚ sr¨B˜ÿAf3|üø¡¿¿_(w@¡8€™™™I^^žAJJФ`YòFC1’ãÿþ ½¿ ß888þ!ë Tƒ aýíÛo†3g.0¼}ñ€j$>¾³!¿â7@ d3¼zÁð—© (@×2°b8 €X°Ä(8l™€2ÜÜ?ø¸8l. ^6fD€2ÄOPt ÆÓŸÿ Œþ20ãûÿ/`îøñ—á0t>3~:(Óˆˆ›ý ¸cfabàãebæZTÅ s#Ô:‚  ìÀèaJ€ì`øÏNp~#ÃgPb`êcdÀæ€bÁš¬j™˜“A€âvˆ` ¿€Ž`c‚D $›ú7(0£†‘ýPh93î@,¸²(1òã—lЗ‡JÇ °ý?ÄQ ùÅ •ŸÌ ìߥ0·Ò #Ø,D™€ «@êA¾b=ÐrFH:ÐâÿÍ Æò›á0=ÝüÆÎðú38TQÏÀŒªÿ@ ¿Æw`°³r01°‚.;(j ŽÀVè®(`jb=3Ä1Ú‚ÿôþ0±ÿcáüË`ÈýA„÷?¿/ÃÛ»×.oZ L„_€–21°C „™¡ d&¨„„E! ®¸'*Pêjàæ%&†À¬ñˆÿ#UJ„—áÍ¥“ ÛæÍaøýã3Ãã³›.͈aøóý-;0Q㆑|¬œ`ß3¡Û „ÿ ¹”m8¸Ø8¾;´l:Ãõ_o ²ó¸xy í7Ë×ï6.˜Ìpp×e#3.NA†OOn0üçýÃð÷¿ïûKþÝ<ÌÀ`ÀÎ Øj^€bÂú`âßŸß wΟ`¸züÖ,˜ÎðöÓ7`|03³0450Û³ŒAA^€›™\8ì c8ÑÀð T2½ÚËÀôp&0î9 {`fIø¿¿½g¸4?‚aÍ=& Q`±Ê"Äн¾Çð ˜(ÿ‹HFU1@,¸ÒÈÅœœjèÏ?V†ïÞ3ZZÇpëÖ-ßôB†Ÿ_ß3ðC–‰åÃê¦4hSœ-?|d`»³áçÓƒ ìÀdðïû`Yd0üÀ° €°„#´Pa`¸p^ム8f`…pjóR†cW)ÐaÀì(*ü—AJ’…áñÓ?`µÀ™áËGÀBh#¸n€´3˜Á©[9@Ø£Z+ÂÀ›7ÃoÝù ùŽoxýö†¡¾½cԔňÕ„3~UqTÿþÖ˜. ,ià8ø½½}Ø)Ø‚aÀ‘…‰?þd033ƒ·Ñ@aM„Ÿ€ÙÍ×7!88”áß?ÔªÑþc€Ç+ÂàÿРþR¬ÿúõØü Lؘ lå0¨õûþýGHùÖÐD¶Y æ8\b F)fPÎ4€Ër¬­ TcÃÄ„^ b6±qEª<¶P@Õƒ½@X›dø‚[û{ô`s0f(Î $Õâïxà“Ç'† ˆ=æYY-`ù‰ˆ송ˣªý/Qaz€ ¹à"%ˆµëõùÕ«W`üV¹è-eX<¢û[þfDé´ëC`;âÅ‹wÀrኄÂZ:eúôiጌLÿa=HÑEî#âïœþG*|À!Ãì˜2}ÿþ}'²Ä8ÐÝs€`ÿ=©,6h„IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/kaboodleloop.png0000644000000000000000000000427611550446572023706 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<PIDATxÚbüÿÿ? 0šÌb °ñd†o¿-ؘÛX™V2ügø‡WÈ.FF†ÿgÒàBÄÄ@ôï¿:;K`x¼¡Ž˜8ï2†?v0üýçHªQDž Žøõ÷CB¨ÃÚEA Á®lLL»¾ÿZ”U#Ö€"ÏÀ`â?Àÿûôío†/œ Ù%v ­ý!ÌÚfªq ߟ`øù«%B„Œ "¬ãd`dй&ÃßÿR@Ÿ³Å~ù2ŒÿxÞ~ýÏðåÃן üÒB yUî ö© îÞt¶þÍý± ìL- ,Ì«Žù‚Íp€Âï€ ® ?—121Øp °sòq0°±3ƒ“ˆ`fbføú‡…áÃG†@¼ùѦjªÀ «%Ãpùè-¥#ÛNÏûüêS2;K0¡îB· €qä.`‚jfüû·ÈÄJ‘ÁÌIƒ_B”““á?(ø‘Óâo&†ïÁÉ&2‘è5.¦oßÂplç†wo¿­fàbkæ‚+03»þþ›ËÊÄäaÍ oªÍðú Ã'`þýƒ–XŽáå7P¦@8€i”èiQq–Ï »—a8sìÁåÿ3õ`j3 þý+dfbL2sfø§¬Âpæ8*˜™˜Ó’ßø+Ð2L9`ec`¸|ÿ/ñ{/Þ?ú4„ñ6²<@¡;@šá×ï Y+#qm†@ŸI}ÈÊòý_†/>0üùõ ’ À22ðÈ 3üãgûîFˆÅ úÙÇ ·Ÿcøðàñ#&¦6–ÙÈ ZÞdââR3vÔeàe`øÍÁLt ¯¿c8¾ê ÃËG/AÁþ–˜Y˜™4Ê‚äÄ…Àîb€9HϳïNí8ÃðàÂí@µ³ØX»ÃðÕÇ„ꀟ¿mÔÌŒõø€>…öõˆ w2¼yôú,7G3PÕ[ þΖŒL}¼Ü ¢‚ ˜c` ï^ý`Ø·îÃÅC×ÿÿøú})[PýE\ €Pð÷¿¦ªºƒª Ãw`¼rñ00l]û€áÍÃ7–§U\@RýèåŸ@5j²@‹ßýf8´û6ÃÖ•gÿxþþÐâZ ÞO¨ T°³ ž9záÅ£w €‘ÊÌ ï¿zõвÛ(ùïÿffF1†[ç3ÌœxœáÑ­WX™ëŽ]Tõ˜B €PÀÊ4÷ù£w¦Ïï¼þ ORlÀ´ÏÂtÕ@pQüÈø1±ãÃõ Ï_þùýw'ëD ø{RJu€b¤ :Á ?ÿè0p0¯ê¾«n jCªŽˆ…|À Ì{ìÀ"ö$}ƒ\Cˆ…ßBb„ý âqy£÷Ÿ~~üõã¯3Pü,šï€´døý,Œ,À4rÈê‡) B­ähf=c`UÛÌ'ÈåœiÀha­ÀP˜½‰ë׿߼`µLŒˆÒèßÿN}I)>p&X†ï¿3¼zöé%²ˆ…ÈÆ‡Ãß5Œl,Qv~ºœ>a *jü wn}døýûß_ ¥P,g`àcøò“ÇÂW—!%׊áû·? œ\, ÛÖ_eXÔ·ÿ+²ÑDÈ" ¿þ$ ®P1Rv4fÐГ`ø Ô›Þ€6j•ä `4±ƒÛŠ¿þ° p*kš©1<扟?X8zî?ÖhŒÿŸ"[@¸ÀÌð÷o0Ãï?‚²bÞæ & à²ÿÎc¨F`Yÿó °úë7°þ˜ ß°Ò„“›Ë1žUH„áî  Ù÷.}ÌêÌg‘- t+öÿÎ ¿U³óó;¨XƒÚLƒ‹›áá Hq O@š‰›Á,Ô ˜ÖþóÀ* ƒ°´8 'Ãýç=ìÜÀlrìÃÇ'¯¿ µ5ÈzeÔÈÃËVί¢Ï&ª¯ÃÀ/ÂÃðú3Pø#j] ËÿyX8äQÚâ ´ûoŸƒJv^`¥öwÓ  ’£ÈVª~ýõUSeóHÐexü›á)0½38}aË‘\ÀöÁ»ïÆJK(ɬÆ%€•Ô¯Ïv.ÝÃðõýçSÀª¸ =®½$4bøñ§EB‚ÇÓÆC‡AZ_›á°1ðå+J}ÿJÈ-ààÖÏÿ¹õÿŸ ßÞ¾a¸yö.Ãþ-W¾~û}X`¥ÕÜE/ ³(qÿà¯ßÕ²B†öÞ jf* Œ@ß~ýJÄP_CFàÏW†ƒësÅp⥿Àpòì3Ó'Ÿþ|ûsèë©À Ÿ nIc)Š‹ #ƒ °‹aøó¯RJMNÒÙ×ÁÂZlÊg`ˆ°Ä̇59+ÿþþù{PÏCPÕÔ÷X©½¦öË@ö) ‡^à« OIÈðØžŸ l{¯~vëaÝâ¾'1WO©óÆÆ™0è©ð1üºóó ¯yX1°K6&Æ£(‰™Æˆ˜žÑ `Ã" ØÁ°;wèÚúŠ‚Õ ¦gbúÉ (ʲ„ ˜Ü™ÀIþ?q–"€"¡6d¼ÀÀÉôóç/ß KÎTœ9ýÐÊËK ØþgdþÅ ƒÿHÙƒ@¸Ó®J ’ÔÙ~þf"F.Ög@%±@ÑgDW¬Hi À§Òó`HïmûIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/editdelete.png0000644000000000000000000000341511550446572023336 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ŸIDATxÚbüÿÿ?Ã@€bb`@,ÈFýDuA ¹~1i†ÿÿÿPËFfbfyóòùÍ×Oîÿ¿0÷L €PÀ-(ÖÒYŸíéo*Æðë7ÃRl‚ÿ4H/”ËŠeV M'î~-¬êë 9Á´ŠÄÄÕmÔÅÄXVÊ|ýï?Ä ÇüŒl%. Y9Ydu„â€ÿÿþÿýõ÷?ÂK¤XÅ ß‚Œøµü4þ230üø ƒ… %¾ü5î[¨ üÿŒ O!Éañ@Qæ$ÃA˜ÌL@üÄÿ…pXžÂFOWDt6|ûèÃå+>¿ÇP6#0ˆ}ûÊpkÙ*†×/30³CøR ï£[@D9àñ; ‚ƒþ§¥1œNLdøòõ #Ô@K˜€áøó×O† Å% L{^ä1<Þw€‰ ¡䀟Àœõã/ªÙDÐ/–ß d0×ÑaÐ;s†AG>|øÀÀô5(q}ÿÁp&9•AêÎ-í Œc¢¾6Ô3¼Ø”‘JŒ@?ûÂÀðôªùDÐwfÏfо}›'"‚áÕ+¹ÊJwïN3|þò…áÏß? §“¤o\cP),d`xñ‚UE…AKU™áÃ’Å ¿¡ñO h €:@ ä·åä¾åç30œ;ÇÀðä ƒ|j*ƒúËç Ç|ü3HŸ;àôâ3†k×~¯XÎpûæmîð(FÅ‘Ò ‚¹@RCƒáÏÖm §|} ;;øCB89}|þ®^ÅðüšQQËÿfø~ç6ÃÕGOX;{ÄÜì~}„æh‚DÄB(Ÿƒ4ɪª00nÙÊph©Þüù ¢vv ìì *††ÓïßÓޏ tÏä™ â– ¿?!åv >ÛaYí/TQf`Ú³‡á‚ƒÖîÝ Òªª”ÍÜo~|g¸ÊÍà 2wƒˆ©Äçв^*þÇ,ˆ§þ"¹d(Ÿ³²s00òò2|ùõ‹áÙ­[ÀÀÌðXò0£ä;0D„E˜yxÀg=F$3þc¯Üˆ [°3 « Ë™Óë'O®2¨ÜÏÀ ”ÿŒï×?~0¼:æÈ'\\ ªß1|Hˆgx{î2“ Rýðšè €ð:„™aôòñ†»@Ë5fà„† Tí_ +Y€Qñèef^µÿ¿~åe0¼=rZÐÚð?"Ð@afÈ:dË+`{ ,õNŸfà€Z*€…Ãkc3†7–6 ?>~d`:TÑ1¡ÁËÉÀ\]ÊðñÈY†ÿœP‡þÃî€bBoWüG ‰GÓg1hœ>ö?PËñs3KåÍÛ4vì`xçêÅðõÍk`EÄÌðïï_&>5N6†_ ç0üù-ˆp„@¡8àíwDQùZÓ‰……2Ü‘W`Vå ÀdÆTÂðÔÒ–A~ÍZ.a`:ä`]´áµ­÷WÏXYY9âþ;`Êðò…Ôp§€BqÀO Â/¿ià7Ыâ&F ¼@Ë.)(1¼…ˆƒÌºõ Ü2’ ¿¾BÔ°òð3ˆ-XÄðÜÂáÝí› ·Ÿ>cxW\ÃÀãïÅðç+R.ÀÄ‚ÑxdD@ úÏ7  #˜×odx±u'ƒtL'Ðç¿>!Š×ß@KX8x'Max:g›‘1ƒ “ß÷Híi €0ÊÿÿQó.ˆþ¬Åø´uø tþþ€Xø©MfㆉSA¨´˜þ|Bj ¢“{ ®örÞ[ðbÉä6 z“ Ô’þ…ÖDû‡Ö\C„(¢•bÿ‘ F6ƒn9R”¢€B `>bced`&M6f$Ã`éÖ bBÄ+ŠÅŒH!󪪆•Ò7`dbBIø„‿Ÿ_?8vû®’¨Ã÷ŸˆÎÌ' HÍo”èB 9ä ײhÓ…Ç¿~¼ñ ÙN€bDîœ2$³Š©OÕPeüÿ÷Fù̈Æg ŽºÌ,Ÿ_>xúýé•’ÿççî‚ ã@÷ŽhÀ{Ç` ) Å7ÀIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/mail_send.png0000644000000000000000000000502111550446574023156 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< £IDATxÚbüÿÿ?Ã@€bb`@î€p Œ²ˆáß?ûÿ&PÚøÿŸ,öï,03üòÿƒàˆº¿þ102ÕÕ20€ð®_?ÿzüýÏ’ÄÌÌÄøåÓõ´?¿>e`ÀîW€b¡–Oþÿû'øû÷ÿØßþ‡IÈŠZ‡Fè3Ðât6N?c3eiWWeS}11!†_¾ÿd`P’g`ðò²”¹vÑ8÷Ó—‹åÌÌŒæ ‰>fûõûůßÿ’øEøB,Œe¹ÝÝÕô5ø¸9>ûÏðäég–¸ùù8eõ<<ĶnñKûúåâ f†ût‚D”€ ŽùÏŸ¿þ?ýK•r·uRapuV`P–å'­¿ ˜(?~þÇðéæ †?æ0¨I«08 .dÐPaeðö±¸uÕ,õËç£UÌ,Ü áf nßSöß"?¾ÿ þÏÈš ¯"enï¨Ìhg#Ç +Î Î~b‚%BQfn)EŽ¿³j3|:ˆ›‡ÁßWŒaûVäGÏøøþÜ#FFf¸=Ä‚ÝÇÿT~üøÌÈÄ£oª¨cg¯È`i!à ÌŒ_`Ü~ÿt $‚”‰ â'6 ¹_Ŭb—30ój0°±C<«(ÇÀàîa.vù¢nÊçÏê@€U„â€?þ¨ÿúÅÎÎÁal®*éíŒ_=!°Á?~00|ú, ˜!2ÁÀˆÈ 9^>N h9+8êÀQRëí%ΰs{xλ·{çüúýì0G0åÙU|ÂåfæJ|övò J |`C¿ZΈj)zV„‰ß¿ÿ,&'' Œ"&¸<¨ª008:™^½ìQøîͦBNn†_\ˆ ìlé™™ö|))º ’| ?B|Œl Ì" ò-ƒ|ÊôÆÏ?XPQQ(΄á`PôõgÐÔôäáÒ’ÿ#ÉÃðOA– €à!ðóç·éW¯¼j×Ñ`øúb033Š/ùùëÃ_`†ÿé=ý/w¾}ÿÅ ÈÇÏðôÎ &Vf666v`b`gccPQæ`ðô±¿ss[Þ›¿;Šþp1ÜììL ÷í½šbg§ ,$ÈÆðû7Â2°˜!>ýLOŸ>eàáæbøùï;CÅúr† Ï.2üc`cøõXýbd`úÃÄÀd2ÿeÖl ,ÿ9X€4+çÏ Ïù?d0üåÖûY€bAøŒùù§OïænÚt³-=M^1S*PÕçÏŸøÃ/ Ï999ÄD„VŸYǰˆW7.b°S±bøøë3ïß?¾ùíÿÆ_¿þÒ?ŽÿÉðëï/`âcâº|ç¹çò‡mˆ©°a`ccžqæôÍ,?_UII eˆàæ <ƒ€Ó'OX™˜,TÌ…UJçW0ÔV&10KÃÿÿ2üeùÏðX÷üç`d`äåDf¦Œ @i~VI>†û€Yqá¿ ÄË!!‹Á™öÛ·ßyÎΖ³²´ÀiôþüZüˆ••ˆYAe/;/ÃÞ[{â§Ç0¨ÚŠ38…h2¼ÿòß>ýüÁðùÇw†ÏÀÐøøóço_¾üÏ´ŸAKVáí&I†'¸¦ZAt%óÒcG¯åº¹)«(*²ƒÓÈ,,L ||< ï߀ò™8øØÂíB^ýzÃP83—áé•OÀŠX‚B *&`i ,tþýÖP’œ ÌÊoxXÙØÿp2|yÂj^\ ”(€¦…·_¿~œ±eÓõžâ†?a‰…ATTŒ‡‡UÀtÀTËN¤žY fJ¦ O_=Ú J<ž=ùÏpôØg†Ëçï2<þzüÓÏ·ø˜”¹‰á×{V†OÏ™?0°þ? @LȾaP+ˆƒeιó÷nß¼ñ"Ðí(=01ðòrs X¨a¼•º)C¨­?ƒ»V ƒÈ7?†ç§ô^üµ÷ÛÛ{AÿXßìw²´dàà†Ü†¯€uɦ»@ëîÖº€™‰ùã§/z¶l¹5³DKžA`XYñä1þ}¶o;÷íòÕÃ{ž<Ù5‰‹•û𠉫¿¹Ú¥Ø¾ýúÊÀÇÌÎðñ.°ùÇp¨í@!¢ÍÀ´°öìÙÛ¥·nj¨¨ª± *$B&\½ò—áÀþ ûö_x{îüúÕ?>XþíÛãCìŒ Ÿd^1üewàæàQxÉöá°°bþÃËðé1¨”û ¤ €!€æfæ·_¾~œ°qÃÍ)%eºB h1;Ø1Îýaس÷!ÃþýÇîÞº½w9óÿeïß»ÎÌ‹,Lœ ¿Y¾ŠÛ¢ßY´„”9Ù?±½¥I†ÿ_X~¿ÆÃ=Ä‚§ …å'NÝ(½zYYÞИ‹˜“ÿΰs×}†ƒ‡÷_~öìÔ¼//åæ{ÍÆ& n ÇX¾°¼fø&¬Hþ]ûû¯¾¬'Ãõ¿¯8€uÄï7¬ ¿¿1=–F'@öÞ0G¼ûñãS϶í÷'¿~­Ì°mÛ™¿§Ïœ8|ëö†illŒûþþýñ–X01±€0óf†wÂOþÉK¡? v;7ÐUº·ÑýæËG.`ùñã9;Ãÿ_ —€¥Òg„‘ Ñ''Ç‚ÃGÛlÞ²Nàýû[S<ܲ…‹ØF`“¦vDÜìãdaø# d€ZàÀ¢|@×)>¹ÿAð0ZY¾?`¹õÌ|€"Ø3bbbýòñã˜'O¶{³³³oaÖr@1p“ [ÿù…‹'Ä÷ð'K~Ÿfø÷˜˜~¼%@†ƒ0DD×ì?(ˆÿ°°pþ%¨ô´ „ÔÈú¶™áãþÿG$¾_døý•ù9°z¼ S@ôè~b`û—øïû¹»E«Z`|n1@€£ýâq4¿¢IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/ledpurple.png0000644000000000000000000000462311550446572023224 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< %IDATxÚbüÿÿ?Ã@€bb`@,0FhhÂULL lll ¬¬¬ ÌÌÌ ?~ü`øöíˆÖúþý»óÇõ¾|ù®ÎÀÀ(ÁÀ„ ÿ_³03Ýfgg»ÂÌÌ´¨€Æà Ú3gf‚i€b!Æ•ÀhòøýçOÖ÷Ÿ¿¬ØX9„ dädDøøyÖúüUåþ½–7o?`x÷þÃgf&†Ó@ÇLgbdZCÈl€"äÑÿþuþúû/QAF†ÁÖT‡ÁÒRAZžŸ‘Må†>3:t™wý¶ÃN—n\wbeb^ÏÊÂZøŸáÿC\#,b‰ý¿ ÿðñðx™˜28˜©3ðI²10°ƒœ 4’,Œú dÿšóÈÿÍÀðíÕ†m»Î2L^³šáõ›W¸88“Êöa‹€‚'BF`X‚0èüøõs‡˜ ¨A¡“?ƒŸŽ0\}ùÃðçÇ_†@ þ!c ƒ€ôßÿ~}úÃÀtKˆ•9â¼}u]…¯?¾oªrÅwÀ¯_¿Àøßߢ?ÿüZ,.&!‘¡íÁ ÈÌËðåë°Å _ƒú?þÿFCØÿ@ôŸÿàøtÈ—OߤX¸:½ÒŒ´ ¸¿ýþ1h2ºî`\ƒñï?¿»Ù98 ÿZ2È}ãføúõ'ÃÿïÿþýªùÄ?€ñ?Ø7þÿý3@Ä~@ðÿïŒ _>ÿdùÁÆP( !(.óçïŸY@«Ø@èpýÏÁoðEiï†ï?ÿ0üYòõû‡`£àÿbÿ¿ýëýñd'¿2¸þ¶d`âfqú÷ÿ_,²ˆ )«1c8OœS”Aæ4Çç_~¾†çg ã>-øô‚?‚0ЇÿÁÅþBÅÿ#©ù ’ÿüŸáï»? ¯îdP¸*À Á¯ŒÁ?é@ëày €KB5V&+ÍŸ œ¯˜~5¿:÷ü> á÷Pˆÿ|„òøL ˆÿ!ñzß^ùÌðåÕoÖÌ f¿´˜ØX €vÙÀ, ärÀ•›GHúºãß¿@'²3ÐÃ\bǘ‚‚(Æ ø †[涘âÙJƒIŠúèçS—RÔ¨ò·º6ÈÏSÃ,ŽuC0vAôk„S¶xå@ˆ(``zýŸ—A…˜€‰‰‰ P˹j€˜™“\0BÜ w(”ÿƒ +þtÈV`ÂY´‹h%°¬…ÃOÖß ë?Áì ¸€µÿ/?,YY_0@‚$Êô9/Ðr>„@5!$2À+#P"dZÎ,Ù!œå3PÁo6° 50t˜>ðbøÿâÿ3˜½wû•çßß0ü’úÃÀù‚ ìÀ zl)ÂL<@ 8!`„9¿ ¾gøª%ADŽù# Ë_ G€®ü+þ‡áæûÀÊ”ù:Ì^€B”„ÿþï~óñí—§:¯€5ÐÀúä[°ïy Ž`€`! ²E!ĉÁäAŽÖaÌ (n |¤üœáÁÛ'ÙYX÷Àì ¸¾ÿø~ùÇÇŸ'q\``’`:˜*@ù˜°Àiä`úeY"u BÅø¡!t0T/P (W ±0ìã>ÆðçÛßëÀ4pf/@Álïýù÷óïÔËon2\´¼ÊÀ ŒÇÿC€Æ`ƒy!–},ÅÀ`„F4±‚ÍIœÀ{ÃøÃá·§mÖ¹ àÙÀTûgïw¿6,b\ÇðÉê3¨îg…T  ÃÀÁ ò4¸… l9/DìsvhBb6 ôÿ0Ìä^Îðëãï³ÀFî äÚ €àµzXœýË¿÷àñƒñÙ ?Œ¿1püE8æXt€ã^b9È×ðìÉ¡YAeƒæ†~• WÞùÈÉž É+@ý‚ÿÿ?âøÏštìÚùoM<Ó¾é+$Pj¦ôŒÐ”Ï ±€ -ð,É1‘¨–” Ô~1tI,`Øzí WPè<º}„½cÂȸŸ‡…Ëÿ赋3ß·3S¹ÂÀ rÜOh–⿟!øßOŸ Hs-禅óJ72¿µ3l¹tð-#g Ða˰Y@¸›åŒ {xY¹ì>|>£øU¿›Š>Cˆª=ƒ¯ƒ°ÃÈÿ`u`6Ð+_xþ2œþw›aýýC {ožføõù÷i^6ît`9x—5„·_ÔxŸƒ•Íûϯq.ŸM=xã¼™‚¤“‘’ƒ·?'¸%ýùdž'__3\xp›áö“' ~ý½ÈÁÄ:Ÿ“}ÐŒŸøì ‚=#P;˜™‰iÇR gmžýúòÃã§/=zÁðáã'`P‡+ ;7 3°``aaæ–ÿ Ìlü ¾þú ªJ ÀhàdPÕ`àäÒÒÿòåŒЪ·È $ü‹ 0ðÿøž•áÊ•g Ï_¾dxøèÃû÷Ÿ!óœFX>dZÊËË´ ÈfbHÌ L@šh9¸äüÎÆàhÂ`mÉ6— òò| œÜ r_¾0)mº‰D ¸xx9Ë^¾ceظù ÃËO€†ÿcààd);7Ðff¨eLÌŒ`ƒ-gùœÌ~þòƒ™ƒƒ³#/¨àü,¼€Ú4Tyø…äß¾V2ú÷ïÎ.P! ³ €àøþ퓘ŒCZ¦2ÃÙó®^}ÂðñÍ[ á \Üì@ ˜ –‚1ÄBf0:†™…áù› æ6b ¡Ò œ@ËC * _Õyô ”î\—Ðg`¸# ´î)Ì^€‚;àãÇ÷‡¿¼ý ¯o+Â`¨§Ìðø•Ãõ[o®]xÂðèþpà O66V …ÀP¦ZP¨€Þ“WÿäeYâ¢åø%"r±ýTJr02X˜H3¬[!£ ŒIidÜïÞÝ?þìñ›œÏ_U€!Ï  ÆÈ $-Âàî ÂðôɆ³gž3\»ö˜õþ1°‚¢…‹*o>±ÕcHORfàbÖžˆÚî VVäcV‘zó†[˜OÃÒ@ÁðèÑÞs·n¹¼üòù83# Ø& O€¡Ì  ÃࢨÊðöí†7?é{`üÍðí?0‘~e(L—æ .p ùŸañ_h‘ *ªäy45µ„Ô:I à6@Á‹bNNþ{¿ºñüù°!¿C4ƒJBPqûù3/ƒµ•Cb‚:CT”ƒ¼Ô?†ˆ!--!P“ä/’¥0½ èø ¤¹ùØ´4å€&«š ˜½w믗/¯_~Œo%H3ÈpqüR|úJÝL Š  Y)* ö¶Ò`Çý†ª9ÿŠý¥ f9^`ˆ*©—„Ù @p<}zXô>;}ñâ †o?!AÙ†aÂ,Yúá#„;fù/yà'ˆŠ}…&0·hh‰2 ©+00ðëÀ¢ €àÒÆÛσ<{ûåËW†?Œ?‘ªÙ‘cƒ-ƒa¨ž@úÇþ ÄŸ¡'£(Ä ¦&,šd Vrƒì &D6¼ Lˆ>}úèÊ›WŸÁÙçû$ü ”?~¢Yøá[c¸|éÃ¥Kw?|xõíï?7ž00¼~ÄÀðò0BŽMy2 €àPQINÀìøâÉÓW7ߥÄ)#Ëðî¤Bù PuÏ ´¬<@·Ãüéà ç¼d8°ÿ.ÃÅ þ=xtûÓçÏ·¾¼v‡áÍm`8é?7¡Eð(· î€OŸ®C«å¿YX~œ¸rÉÆÓYU–áù{Pg¼@‹ÿSÙ«'î<øôÝK†“'®ÿ½|åÚÇ÷ïï½þÿÿ°óØo|ªrñc 5m¾@kÀÿèM2€‚;àÕ«ÃpAAA#7n|ø™&ÅÀÎ ôé`°^?ûŒá¹' gÏ>b¸~ýÎ7`¡õüû[À`|ôá—[À yjÙkh£TÔþ#Ô7 x¿€™™¿€ -~MÍœƒÎNÚúOŸ¾øáüíïžÜ}ÿõë͇þ<ºô)Зï‚R1ƒÔ{PNŒ…èý€Br;’Äo`°K›ýüÉþŸá;ã—gÿÿ~̦÷¡¾ùð3(PÚ=0Rb»¼¯«³IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/editpaste.png0000644000000000000000000000340711550446572023211 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<™IDATxÚbüÿÿ?Ã@€bÁ1ad¹éÏ?†@üÈfùËÀp•GŒ!Sß“á#K:/Ïÿž,ïÿ}úóêß篾þûÀøãçg–?Ÿ:…þ°5ϸö™A÷Ó?†/@ã€F0ü™¤A^µ}‚êa€b!Æ•?™ ß¿bP{uGðŽIÍôÌ4vV†>2|ûû èPf†_ž0dM,/P=ûy®ÙÇÏÞ3Am$›”~1x2üa`‰!PhügøÍûã“™½‚ÌGñW ¯þüf`C&&Æ J’2 vζBÏmžùûÃæ¿ØzÀ>ÿû—ñ/0`™8ö¹W- üÿÇ0‹ÁRщY^‚ñ׈ŒŒ ?üdxΦÀ`¨õ‹açóݾcafeÖãg8-/èóÞHÖGE‚áÇoÛ YÙ~=ùÈðd÷ó@¥FÈúÃ@W«29k30 }b`º}‰ ¨„é/ÃzFY†÷†¢ Ç>`øñý#ÐQ¨.*åfføjÏϰàüW†©ê~ãá70 ”uþþ2fx¶÷†º}„á`¢ûÅô¨éó'†_ ˜?°0¬abøÀq‹áѹG ̡̌ÁÀq3Ã_ñ_ Þ23$\úÉ`*õ "÷éÐÜß ³£Û@ØBØÿ1Üú%ÄPÿ~ÃWž 7>73|Ùù”áç7`Üÿf†¤Ì?@ú+ÐÕ@60!‚hFfF†ŸYr_v2H¿æg¨‘¯d0T&¢ïHf#€ÂtÈ/L@ƒØ2¬ymÃ`àËk÷áäM%†ßÿ~@ƒ ¨íÿc‚ãÿÿ©ì#8듃‘¾!ÃÂ, óî`˜l{šáÿwH–F„ ”…˜þ}ÃÌ Çû‹…‰ÁQÛ–äBFNð/ÃCPZaü ÷: ìÆ%P†‘ù/0 áÎÌ P6ý‡„Á¹h'0  #;'·ÃÛÿX£ €°F(±52³Óü‡¨[ ³‰ÍLxŒ| b@×<| .Ñ@aOÌ <%t„0¡ÿÃjù?˜åÿ>)…–[ÀrŒáÃw ¯AAÊÈ–À„á€?ŒÐ4À*  þâµæ[Xhü?ÿ@2ÈÇo µ`Y¸ÃÐ@±`‹WPü30²a-©ÿ1 âù’å àýñâTÓÌÛ@£þ2b: €°– lÈ­‰ð9(~Zþû"Qþ…I2À#Ö( Ì\À‰2.ëa‰ð?Zªg@¶ü7¤úWãP±È@#v¶¢˜á?0߃½þÿ?<Àâÿ–ƒè_À`•Ú¡â í‡¿P6, @qÁˆ5 {”ÿ¨QðˆýAdÃ?HA£Q[ŒØ34@á(ˆ€˜ƒXpÁMù m!ýþ©àþüG8 æs¸þAC`¬#þ`q@á(ŠAAÆ …¿!€‚f¬°ù‹Åç0ñ¿ÿÑZDÌØH„£ bDIdÐV <¸amEl>³¡éâ?¸Æ†¸ê?ö4@ØC€…ž @1÷Ö¸üŠÿ¡Å÷ßÿˆ(<ÅÃÈXB €p× Ë™€AÁüç/Â2¸%0š&þ!‹ƒ "¤< *°„@ál€À¯ßÿÁõ<Pã?^$üGX£ÃB-lœ s˜~ÿ‚¶˜@`Ât@a‰FH"F˜¹Ê{†IkÎ3<¸+L„þCãöï?P%Ä@äÓÿ@Bÿ •ˆ™q Ø|˳þ6ë?¨Ý‚%{€ ¢oÿÜôÞ3³/e8ÿ€(ôš R÷ÿ°æ ¢J?@u¥cªÿoKS ‰_ÙÑÊ t¦ []ÀÈÈ'ÄÀ âÌ{_ŒÕÿ3³ýCXʳ‹wÐ…~¾1;7ãý@m˜õ!@aVÇ™Y;ÂÀüçÃP‰ó“^íýGi Ó9PánF@CŒ‘•‰áç³wÀÊŠ… Ý>€ÂpÀWO¾‘ÊÀñÿÿ¿?àè…Ô~ ¸‡¥òÐÔh”üÇ(šiŒ?~00}zýw+º}Ä8нc€bb``ÅrŒï;iIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/mail_new.png0000644000000000000000000000321011550446574023014 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?Ã@€bb`@, ‚Ñ$ÂûóGY@\zµ‚²²ÁÿÿŒŒTó%ЛŸ>}þ|÷Ú¥:†¿¿'ü¿0.@`0üÿËÀð÷/@eKež¡±©1SÿÊþ$Î tÀ› ¼y­KÚNΫ<>Ó@`˜Šh1üÿóáûwK y^êøÙ!rü ÊJŠœ'¿¾3@v@ Ï#Îð·Þùóë7H #Yýû06Ô´¿, @ZÂÄŒ¢ €Àø´ýß?ˆ[IŒz°%ŒÐ(ÑÿP-‡‹ÿGÑÄc€ðûᅩ$æ FXxÁÜ ôà?hiá?Î4@,TÊXÈÅÍæbÁ&g¶rÊ>†ml àúJ—Pú?œr(LüϨø?Pú–KË0bpr”føñ)`Q%pì11®¾¢";1a>†/_£ä?"na¨|T9f`R?røCsÓ>+ëFfVpºb€FÈÈ_1@` r}ò“‰õ?ƒ´,?Y)þõë jjü LŒ>}ùÊ v 0À–FË·˜é €À`eeaPTg¸pá!˜ã)ö CO€,À8¿yó()3ÈÉ‹ƒñ¨o¿ÍEÈ` 1üÅ’œäþU±³³2èëË1\ºôˆáéÓ`—~ýÆÀðí;v ’0/>eøðá ƒºº 8 €¢ãç_HBYþUÿpdn€‚§ùßÀüÏÁÁÆ`a¡ÌpâÄ]†'?€³ìׯØ-ggg`8uê0è?0˜™)3@<òl៿¨eÁ?<¹ €˜` êЉ¿®æææ`pvÖ`Ø·ïó§ïX9¥ ß¿C0ÈA<Ü Ç݆Ô[''- ÅŒÐ¬ µj):Æî€?ê€áÇO^^._]†-›/2¼xö–“ƒáó¦-`j¿ÍðàÁ+ } £Á‡éGÎ!ÈA.–‘@!ðAAÌÏÏËjİbÅ)†W/ÞC†AT„áàþ ׯ?e 3eøó›‰á×OT½p‹‘-gÀwÀo`ÁñëƒØ ß ó3ÄÄš1Ìž}„áÃÛ× ö]g8þC|¢ P 3Ã÷@õhúþc þ¸@,°¸=¨ÞFN,?b¢b )©V ;ä€UZE•Ð"°o‘(Åÿü…(v‘ƒþ#$D°€‚;ät€(ቈŠ1TV{7ÐÇl ¾aæ)Pøñ‹åÿ!Jqå€b¹þÛ7ìPšàá…4R>~ÄQ¦³B²(¬DŽF~Ü?ÁÀÄJvF±òÉFÀVìOÔÂäÿÔ&Š8˜ÍvÈ_`Û Ä9 –P!ZÔ —‘‰‘ÞÌAoPügÀŒ_8f@ÿ‡šñ¥€BuÀH«æï?Fxbú‡¥XEÏfb$䀂ԆÀV1°5JÚLÌÌŒàÃL06Rû ŠPÔ2bQ S6‡‰ #šÁÀRä°,ýñûñ'†÷ ú=;1`/dpÊ!EÈÚW¿À9 Ê?‘@ü– ,À*ïÛ« “§Î2ß°O_˜á?FõõOË—äH£—áóçOÿ•áï·kÈòÄjÁ0²ó@BF7ŠáÂuV^;PK $¶Ý‘ð÷çW†_ï/yv¾Iã@wÏ ጰ Í+ÔIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/fill.png0000644000000000000000000000412511550446572022153 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<çIDATxÚbüÿÿ?Ã@€bb`@î€bŒŒŒrqq18;;ƒÙ°hÑ¿ÿîâVVÖlllI0ó~þüɰ{÷nBQ @D…€¤¤$ƒ½½=º0ß÷ïß—Š‹‹•–– )))%þøñ£ &ÉÁÁÁ`eeEÐl€b¹_¨¨¨0èéé1üýû—áß¿0Ÿ«~ùòe™III ƒ´´4ÃÝ»wjjjÞ½{—ÇÎÎ>¼,, ?f¸téï_¿°š@x²XMM ®¤è ÏyxxHfggƒõ¾ÿlÙ½{÷ÚÛÛÿ£$È_’F ƒºº:ÐÁ >|9¬„ïܹÃ@`”ÚÂ\ÄÛ†]·µe[‹G Á™@jbLL kdd$Ð! _¿~‡ H ???ÃÁƒ&L˜ðh±+Óq#lll€l° µ 4‹áéÓ§ N„]h>wdccˆ+‚&*f`üöòññågdd0899 58q"`È€|Ê=þü5@yP¹Š>X"Ó ØÈ韀¾)€Q O(**z¥¤¤0‚å@>{ûö-ãGÁ|P(0333ØÙÙ1ܼySêÌ™3ëQá4ã ÿ©a™@,¸ß¢ÿôÙi™©©©V`` ƒ²²28J@€âsÚ´i Ÿ>}§¸¡ ‡sƒ0äÎù/€¡ùöÏŸ?Ï€ò€ü+@3Žñ]€‚9@‹AL,hŠË÷yýÚÃþã70"g¹»» êëëƒÓ(‚} ŠP¢%&111e  ¼¼¼à¨– ÀP9Fh± Èáß¾}cøüù38!sÇ_ ˜@ðWKkË´iê  ø¼Ÿaë’%E ËØ ’““l0Èpᔥz`b':e | v†7oÞ0-„çcAq&Ì@½l@þ? CžØ¿äY>~d`xöŒaÁåË »ù:˜Ð>}Ç ô¼¼<8¡Pöù% ߃J¿/^0ÎÎâÞÀA.HªnéVÊ•-[¶09rä 0̀ʾ–îó7?®ýyý:ã«W úŸ>©9ó@âß?ß]ü8tè81Á R0ÈRP‚0(ØAžÑÕÕ•ò×ù¯ ?30Ìxþë(¹2ð£—÷÷ïNû³gO³²°$nݺ•áÂ… `G€‚˜\ Ê ¨ æ.`9a[@L°ÒXè^|¬~A°.’~þ܈ç÷ï¿™™Ë6nÜ®ñ@¾ùŠ€B Didd.¹쀟ÐPxÇÀÐqVÙƒrƒ)(Ö™ÙØº¿ÿü9yÆ ¯€Qs©V„‹h†={ö€Ê’f€;à>,30¹ÁÀ°TqñW©ÿ *P88 €y{ÝæÍ›ÁY” IñýhýJO@3~KÒD`⬠°~@£^30´ÜUñìÀ"Zaý±qÀ*ôøÎ;áe!‹A>Yª¶·oßÎpôèÑÇÀ´äÄ @æØ Õ4G½ÎÀpà $ ƒê?<­~:"ظÌJ`ÃA T/à G‚ £M›61\¿~ý° °FÃ!XA@`“ñ¤PxÎÀ°î8$aÿ´Ä`ÇF`‘ Ï€Ž¼råÊ[PÎ9TG`àxðà(½|ùr1PŸ+(ïƒ ek€—„o€”úŸ1;Äç?Ùò$PòÈQü@ðž<ÉðÇÄÖH¹L@áçÏŸß ô;¨ø…UÓ0ªA•°øYT T×+È@õÐA è` p€Ú4/¡‰‘ ÷,@kj âOx°ºrí¸„ß^ •zîÜ9pà(ù B @9`Ûæз-0‡,…Ê®]»Àé €ÀE1 ÐåÌЖ‘ GCbã?¨‰QjÇAr€Úw àäc e•ÀfY°… /roß¾ ªˆn-ÅpÖðÉ_zâìÙ³ð hÂc€ÕuÐ,ùF 7¦A‰Tõ‚*hÓ»˜Ø¤ ,[NNØœ¸j%íy"¨%Kl Gìß¿\U#€ÂÚ,¯Ò‹ 9€‚ÑÏÏÜêeš³ˆÝ€|PŸJð8E ¨=j¬ €bèÞ1@ xç À|Ë«‘ZDIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/kmixdocked.png0000644000000000000000000000545111550446572023352 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< »IDATxÚbüÿÿ?Ã@€bb`@,RRJ ß11ðrüf`bfbøÇ$Ä`b¨Ëðïß?â|ÀÈÌËÂÊÚÄÂÂÿçÏŸ+ŒŒL© ÿÿßüù÷7Ãö'w€Ì¿ ¿ÿ~c`bbcàdæ”eä”dàdácø„„5ˆ #Ù€†,——-°²2TPµýõë×"  <Ć@± ú†‘áëï ·ïÜbaøû[(0} ) _§²²b;;ƒ©©!ÃÛ·ïÍÞ¾yÌÈĸä†ÿ`=@ Äø ²iÄ„f6Èóÿ ûœäÅ®®Žììì ?þbúœ““AKK•áÿß7>½fþýï70jÅQËÊÀÌÈúƒ‘¹ ¨ÝÙ,€"92CéÇŸ¡aa::š ïß¿e’f`eeeøýûƒ††*'‡™8 —<«3·’ ) ×KFÆÍ@?.£ 3 €°; ¸ÒÁ—/_ utt'GE…1_»vŸŸ•ALŒ—ARReÑÂË (Ä/Éôç¯,/ïå¿ÿÿ¥s³xèˆ92ðqˆì†òI C&ÃÌ €â÷Û×Ï Ož>føôéþüèÛ÷ rròËkjJÄýúÉp˜VXYY€>ÿ´˜‡‹‹5, "¢Â Œ[(rðügbâœþŸá_0ÕËËðiÓË `(Zp°ðq³ 1Î\€ `Ʊ ¸¸ÄÂÆÆju)†gÏž3¼{÷ì`˜ÃA‰‘˜•Eøýç·&+'ÿ`Ö| Ì®u¬Ìœ œ¬¼‡Ê¯121§°³&@áLŒ ÈÁþüfåää™PYYf§¡¡ôñ†—/_0|ÿþl!ıÿÁ!Rr#“8ï üÌ@DZNæPaNN9Ò­L LV@ÇèÛþ ýøù+8èþüÝ”››çèhÁpÿþ3`hüf·7@‡ü†‡È ÌÌ,@>3ƒ°°°p`þý†‘ëÿvfÞK@Ÿ™ÙYx˜™XO5ða @L8ìƒ?2üúù;9;;»"::hùK Ïß3€ì|õê0dþ€S?ÈRP(033‚常ÀQ!ðû÷_VfFf·À¹ÄÌÈìŒ Pœ^ÿ˜Œˆ 5îÁý‰áÇ/Pô˜Ýþ†DFÅôeg'3<~ü ˜èž€}Ì 4ãÛ·ß ÏŸf8pà0„¾ŘÁÁÏÄÄfË .`±02ÈÌôó #59%˜€Aÿ˜0Å6£@±üÝ÷ŸLÿÿ1Èq°ý–àúe¡ ú×JNø§–…B`^ÓÓgo.]º v$° ú´ŒÁÏ/„áÇ— {÷æ x𥠠CXÿþûËøçÇkV9Pùùh)3?ûûï÷c qšÄ"Àý;ÊÓâk¾–²Œ¢¦Š¤°†/“¤·È/†?œz wï~d¸xé>0ÿ'2Pñüïß_pD™š0˜™é1¤¦&3F`L3ü†:€ˆ˧—,on«2¼ù L *@s9„8~|áÖåÀœL”lö—áë×ïà2”Ðþüù ,%¿2¼yó–AOO¨æ8j@â?~üøôëç·ß" î lœÀ ê?(™Óè`$‚jI~ ‘ïˆåÁ_w¾<²`ø(ä²A ©l ÿC|þ˜½@¾å€ÏŸ¿ÊP*)¦‘{@G}fPRR— @U@ùŸ@±¯ïÿýýûÿþCçÿ%&F¦Ï~¾zóýÏ{.f>% â{Ärùê§[÷î>`Pbúü8]ÀJD¿¾0üüÍÂÀ̬ÿþ[úñãgPmÈÀÆÆ ôý{†«WÏã^…ADD¬àB è€×Ÿ¿|zàÇ¿ßÀ|¡ tÜÙï¿?0üúóSŠ“™Q b[ˆéÑëoçïÜyÀÀÀñ¨óÃûo ¯¿20¾þÈÀýã%°¹ö ß| /_@éâÃõë'…€9Áš8ÿƒ£êÙ³ÀrâË#v #3ü`øþç³,PN÷ïÿ_ëþüû ~MPi÷÷ÿß³Äô‡áÏéko^f`ül«|f`¸ó˜€ô­ :¯9âÏW`9ñèëï  ðû÷ŸÀJè3ÐÇB **Ò ÚÚÚF (Ä€Ù”Ÿ? P”úý»£yóã ÄÀ `ø ¬Î¾¹?þßS¼qïf·ŽŽ‰ºº#ãG¬­ €åƒØBå tóíÛ°#<¸÷? Çóß’Š ÿ¼áä|Ì^{À,ý¹˜y%þüý5ñÐáÄ ­Í€!Èø ¨è°Åð*_™²03ýefdzûãÇ·Uß}þêÕ3K`âã•%ZZæØïßßÕ¯(° â¦ƒ ¯^¿dX³rå–_/ý),(ÅÎÄ™ÊÇ.Zñáû‹—Ÿ~¼bgeæ˜lŒìVDsÿüûÅ@ÌÈÕ)¸dd„7B˜ l PŸ}ÿþ͆'OîJ?þDMVVžIJJ–áõëgÀÒPl9°¸eصkûÿ£‡týUVºú‡Y›…oëÛï¼úzhy °¨ÊÊÌ– ´á70:ˆ‰”Æ(°¹u ˜#Bïß¿?mZ÷«ØØ@Åð[`¥ô_µãþ;Àòpç?pVf¼ æ§Ÿ¾¥U`ðKýùãïׯ>gøøó@ŒŒ(ùÄ—ß¾}½êüùÓ²‚‚"Ú||Âàhزe=Ãþý{ Eó©ÿÀæ:3¯ °jÿ,M¿ƒœóôû¸Xù¿²0³BÚ\@ƒˆd@[ ÑÏ>¼[{åÊ`þ©uåÊÅï[·nlŠÏ6Çþ3~ýÂÀ(.ªø€ õ7Ð æ@ü:Ô"‚›@ŒÝ; ï‘{¢ã:1&IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/noatunforward.png0000644000000000000000000000274011550446574024121 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<rIDATxÚbd0ž¹ž!ˆ'qÃÙô ´Æ3ûdœÿû“ @1,¯N1fÐSI<*Êg 0¨J6føz< ÂûxÅ €@`0Ó•d8@ðí04þ10Dy©3_Ém¬>tÄ~ –§ª~30¼úŠàÄ@Á@Güb~v†ò$c†ó#lÍä ÑRÄüÔ dŠÚöáóOi^†i î ½ > b"< P‡ÄSê€/@»^"9 € øu0ý?:âÊ+†k¯!®u7“bX=3Š!>ÊR€‹“mÐç)Iè!@L°xùtÀÛï ï@ðÓÏ ç_@ð`úÈ Óe˜51’ÁÁQÇš>æ““>@¡ýÉ‚?–#cP´œ|ÊÀpö9$}TdX1ÔÔ1((K&µ^ 5}|ù…wß!ŽÀ…£çð#†s@‡èªŠ0´Õú2D$º ð €ÓÇbÓz. Xáß Róà=ƒ87C ½ƒ©¡ÃÊõg.»¼à—ñÌpIw6ý".ý œöñ‚@,°(á÷?ˆKÚoäŸaÌpÍN‡aÝšã®Þ…ƨC°ëÿ‘ØOïà\øâK† 7˜ØØÒS<ã|x$ÁéR~ైV‚²ßÇäçï#ÀôÁÊÌÀ`¡!Å ¬"ŰëÀM§Î6 EËFlúì€ÿÿ!øßò,‡iû ôÈ f¸³s'í-[¾?»±ŒáÖ_†¿Ÿ£ë p0u3ÂDçüùù“áù¥+ ÀxgøûíÃY†g^¦ †Ç ,\ŸÑÕØ¬,˹Ø(³üÙµ› Nžeøõñý3†O×zîNÛ Vm Ïqé °ØYYñ/ÐìäYüá冫{3||òä3×Ë®5Î ¿â' Ì]LHñ@`°IN ï¹þfñï?.ì<ÎðäÊ-†_ï73ÜŸ×ËðåÈ·Ï@™›]<>@AB怿ÄYüX=_Þ–áê1h<¸0‹ááÂcР~‹O/(´ù¸|€;d/±¸}éñÍǾÆó×{³nõmúøzpcuÐF^¤ °þ1BÀý·Æ/>3ì]y€áÅ=hÀð|s/0[Ý…Zü…Ô J¼H °8X1-ÿLGv]f8¼õ,Ã/Ÿo2¼?ÛŒç“Дý–ܬŠ„ÕçÏ=cظðÃû×?3|¹Ó ç—ÐDö—’²‚-l<¶DWÌ?ÆpýÂC`+õÙ,hªæ;¯8‡Ž–++3CJŒ3£°oÙ¦ gUþýûÔ÷] @vÀ¿ÿÌ@·‡° ²e+iŠ©ËÊ ‹ raWú÷ÃO K?¾ùÆÀÄÊÄàïeÂÀÍË´tÁa`üO*ûެ €XðÆçï¿ ¬l,³,œÕ\\µD„yÁéöÿ¿ÿ8µüÊ}ûþ›á篿 ÿ¾ýaøñóƒ­:ÃÇOßö­=÷¨¤Y@ávÀÏ¿:ü‚ÜkÂSÍÕ54¥¾}úËðòéw† ñA02BŒùò‡á÷¿o v. çN? Fw@a:à?P㟿B¼œbr¬”¥¤…ž?üÆð÷7ċ̬À0`&\€¡ð”þAÁÁÎÈððÑ{†Ï¯øó œûOÿøÅ 4JŒóÇ—ÿzw-¼×+(ÉÉqýøëÿÿþIføÄp›á%0Q°`: €0ÀÂÌ*þ—ñÃ÷ÿ€iñ/+ãO†û—?­aœÂpïço†k?•3ƒñµŸ ·€n‘:ʘgÚã+Ÿ.<¾øI9û.|ÿÌð(÷{Î üÿËø÷Ç¯ß Ìþ2ü¦|æßÀ< d3¼ú÷ŠáÚwŒÌ Ä,¸ä> 1ƒŸ ÿðç€ÂtÀ&†ß@›ÿ-ýû‡‘Èþ2üî÷4 ´=Ô×Ð’ŸÁk@, 7ëF9Ê'ÀÔÄ0 T´¡Û@˜¦¥Ÿ¿ÿ00þùÌûL L@6(Ø™IÏXá%?$@Åã fÃS¦þÂU02ü;°\ÿûç#ýûÐ[ªÂ¾þ¹Ëðñ'²òÇ@,Ä÷È­@ˆ [üú ¿~ã¯_À:à?°z3’f`àãÀL„€bÂ?ñþhé`üüŠ‚ÿ Ò˜ÀÐW¢j €°äf`Möœþk´ÿàZþ¨:ÀìHUS0Þ€¾ÿ …¿¿A9¨ìƒã?ê6#[.`üù˜`–ÿ•¿ÙØ&ZÌi×Q7Ó?Y~ë^&îÇÀtÇÊÀÈü‰á÷W1 ï™qÂnXR†iÿ¾°.ú¶GœáÛÍÿ ß%Û·c ¿. ^d`a¼ÈÀÄohP+ –b£ïï%á;/‰hÙ `ÿ¬ÅÖ+’Xô`€¤ ²@1tß €¼g@î€p–h4Ú´iLIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/mail_find.png0000644000000000000000000000522311550446572023147 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< %IDATxÚbüÿÿ?Ã@€bb`@,0FHÈb†?þ10111üûÇÀ ˜ÿÿ~ÿþ TÁÈðŸ ,ÎÆŒ`õÿAâPµ@5¬?~üvaecKã`ã—¿u{QÊÇ+Î13sbµüÏŸo ÄB _üýûõÏŸÿþL̬YÚº’Ž>Z 'N²2 +ÿÈ—/vNûùóîi&&vhB€"èP6Ʊ)' E«ò›-VRædà¦-66v ææb`8æ;ÃO`b”“ã`øý‹—‘ÁÓÇ€ýÔqÏÂû÷'Æþû÷ó/zH ®øý÷ï?˯_Œ˜²ED…|ô UÀ³s00||÷ŽáÝë× ÿ|æœÿ ,,, {öüc°pTgà:ì0'ýúÁÀ`jÌÃ`lêéõøÑ*­Ÿ¿\fbBµ €°9€ýׯß^ ŒÌ™r Ò®Æ&ê ºz² "ÂL üü Ÿ?½e8¼ÿ(ÿßo¾ÿdføñë7ÿ?_Qñ†áØ# Úºv †F† ?à:Æ?À„ÿìé°’;wºâP#@!;€Ú¡ÿ2fÈ)ÈÛ«ãPšAh1++0~–?yzáø‘= ª* ¯Ù2\{ËÍÀÁÎÌðóÏ_†OŸ¿CàM†ó'Ö0¼xz—Áß?\¦p3èx„> Êj’ l¬ ð‰È~ùê)éã{ô -.¾’gàäãbpÒeaæ†ÊG`¡4éî %† Wd8ExÞ;ưe CXh0Ê€iÁÛ„ëÜiŸâ'Of¤#ù/#4) "±1ª½ÿŽa˶ƒ Üû9T•Åde…$$…8ĸÜÅ £gÂp+ƒŠP0I={ý\²³31ÈJ12KÈ2ì9̌ǯ W/`¸©¯Ç ­¥Æ`cËË oöêÕ¶I?>ºÀÄÄ ¶ €˜¥ÙŸ)¼¼ò-í.ÝùͰzó†)ÓO3”—-`âeøÈªÅð˜¿þü`xøô7Ë×>SÛo&†OÀø~÷…áÓWCQ†BÖ ¬| »vm`¥;Y`áêaÀ-!î JˆÌÌì`{¬¬Ì«nÝz’éblæé)ÎF, Üð÷?É+¤d5Ž~dgàüÇðå÷?æßÀš?œ,@5@7ñ/ þt(³Iª)1|øhÂpïò†§O_2(ȉ388ò1ìÙ”ðâå¶ ÿ¾¼ ² €˜YñÛ÷ï_z÷í¼ÊÀÌfÿ~Ó+Ð, ?D9˜¹Åþ±22üc&:V†?ÀÌÿ—‹ "L ¾ÿ ÄŸ~20|:TwI32p‰Ê00213<|p‹Th¨108{êsIˆy—02²€³@¡ÔììÌÏŸ»âÅ£¯ ü<øÿç'#Ч€q&ãb…Xðh(ØáhñO ï±Á Ìz"ÀÒ‘›‡“ Ô?¿›ý¨¨fbàå“Öeg—; €PÊffæŸ_¿}œ²w÷-‹” C†ÀÔ rç_`3 A.H!Ìy ¿€–ý†UÛ Ç3AÄ9@¥"óƒJI–Àäù‡áÙsv†ù ~2¬Zµÿ˃{'6½|µ± X*þÙ @''ËÖS§nvuÕ0•“çdøÆÀ ,×ÿ3üÿù‰‹Kˆå \,üù‡(ÙA¡ªØ€˜ˆY™@iõ#Ã`PMž|îᇛÖ}üt~1++×ù?ÀB V;R6„7’>üúõeúöm7Lsó XØ€ñÇÊðX°pi(0p£€ *ÀtòáP\23AÒ HÍÛï¾¼ºÏðàþ[—nœñúËüã® ¯Pžl9¬)@L¨­3fcc]~áâ‹|W2êÚ wo]gàùýšh/8€C‚‚¹A|VˆÏÙA˜ˆo_¾ÈðúÎ…ÿ§nßœ(ü÷ÕÝД~)i+N^ '˜>|øðýå‹çO}úøéóç;þüùëúý;ƒé‹KYæÖ‰[¼çgarÒaÐ_àXr*õà÷oŸ~ÕÁì ¼M2`¯ÔÒY±koÿýgOOrð/Ã_¦s ü±ò«B¤Ëã*9@¹v€b¡ußäl`q±xÏþì ,§ø?fù³“‘áÉ…×àê €hî¤è˜³sï_Ö×?V¿yw寽;¿J@‚Ä8ÐÝs€€/¶­Žv‡¤IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/mail_reply.png0000644000000000000000000000476211550446574023373 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< „IDATxÚbüÿÿ?Ã@€bb`@î€p Œº˜áï_†?ÿ3€\õŸ‘œ<þ3‚Ù ðû÷? Ÿ‰‘jþýƒÐúþõÿýûOå×o†n¯/ŸŸ/ÿá\7(122"l…pëö€b¡†/@üùóÏàׯ¿©‚Bü~áaÊ2ß¿È3¬ß²Wñô™å«þÿÿö»Î9 D©Xýúãúÿ?c’´Œ¨Ÿ‰™«»‡ƒ 'ÃÉ‹ÿ"ãnßL({øpv6 'Äë¿¡&÷‡á¯ç°D–þýûÇùç÷¿&¦(Ugs UF=I q)q†Ë¿0«p2j0ûǼx¾£÷Ïß×÷˜˜€Ö±õëüG-ñ`µø¯_¿}ÙÙÙò•Udt¬l5tu%˜ GD˜áÊ… ¿˜þ3ˆˆ23°±30xùšñ?ãQôôé‚Üÿÿ™ÿ3mü/L8!Æ 1ñû÷ß?ùß¿ÿ&rppEè*¨[Z©0(«3ðò00°M`úŠ ÂŒ@µgÎ}gÐ4ãe`êýõ‹ÁÂB€AÏÐ/òå‹­“~ý~v‹‰¨øP’b>@át(ÑþþýG÷ß?Æ^>Þ`=eassU99nnn`äu²mac…°¹¸vmÿÊ (Á "ÄÂð÷$±óñ10øú› ]¾Püøþìô@ÛÙþÃC €X0ã÷?(Ž=Ù+KDLØÁØT‹GO_†AR’ƒd!Ðììš… ‡¼~õ‡áþÃï ÖΠÌÿ!âàhÚgeÉÇ` ûæÓÁ©_D.]bøó‘‘œÙ@»3ügΗ”´×7TcÖ7”',…@ËXÙ!>fa&H¼32íaØ»ûƒ0á r3ƒ$ÎN7 ¢BL ¾ÖœçŸÙ4}a½ðœƒ‘ÓíÃϹ@mmw° ™­¡!`Ä ¬*ö¨`bb‚úˆ™A˜"*¬@4ÈöëW0|þü›ÁÖA€áÿ?ˆ#aåÈ‘Àèa•=ÇðDlƒ¼Kƒš¼ CõºZˆ )ÎM@®=sî>Ãþ}ç.¿ËðêÙ+†Ÿß¿×oN`"apÂÄ ±üׯÿ 'O|`0·äF Ó‹¡86œavJ7“ðWPyðd/@ÁCX ´óð/Ô2Qb¸pù=ãWŸ¾}~Íðï÷_v iÂBÜ ¼ ¢¢\ ""œ Ò2œ ¼¼Ì 'Žf`ç``PPä=(m€<²äˆÂÙõ Ó¶õ3Ì,ëfvpaXý{Éû€ŠØÀa@p°±1¯¹|ùQ¶O ‘™‡§8Ão àûÇðûûo†Ÿß¾3|ùüáëÇŸ ·ï|d¸ t 30ü9€ùïÇÿ ž>âàf†=0—¼þü…!µ%‹áðÝ# Û»—2¨i‹3LxÞÂðŽí1ç7 DòœˆLß¾ÿeãú«`߃K<$ËÑ10ú7:ÂÐÓÛÃÐÚ™Ìàì-ü§aõù ÿUïëm¼ ?o3œûûå£åWw‹ß‰ÜÍüŸñ/¤U@Xë`ZX~ùÊÝÜ›74Lõ ø€)Ó°ø^6& Áá ÓfìdØñáö{ B¼œ ~~gà1ùÆÀÿ_Eóñ»'}ßyþ~ÿóâ‹ ¨¸Û@ˆ$ 321þùó÷[Ç–Í7ÿ‚â9È‘ƒäû?ÀÒòåcn[ùb†×WøŸîlûðŸí¾ƒ¼?°>þ+÷Á%]•×L]'‡áíÏu YdþðüføÇ± €˜PÚiH˜ƒeÛ¥«·N^¾ô\û,9TJÄ¿ÀJæÌÉ¿ u—22—ÞšÐ_Zöçíe«ÿ?y .Ïåûõù¨0ƒ‚(ã?†eÏ—0HFþapr7öeùθ‹á7ƒ$ˆWhßÿ~v¬_weƒ¾ÈRP a†3g¾0lÙr‹áøÉÝG_¿¹<ûßßï«þýûôýûÏ× Œl “€5ê­;kyæˆ?e––ñabxÊôžaãí æ¶: v"Šš×Üßñ—ù*К„·AÂÎμõÚ{§.]Ô¶Ð3àeؼñ#ömçÿž¿x`ËÓ§û'21ý=ÁÁ)òÔÞûóJÌdfØÁÀþßñåq®Åß_‹›K…32°}`8yï ƒ„ì#.3^Ñϧ8çU ÜÿþÿÃÖ,ùÇÈô³yÉÒ«[/øùéèñµ›Þ¾½0ÿÏpat $¨ÅÕ„»ÍÀùÏçÓö¿çIK'ö–áÕ‡O ,|@=yØ@ʈ`“ Ø Û~ôøBχ÷¿ýõëýi^^y`Z`fÙÄ´$ß0pý‹úþŠ¥ýÑ"ñ"1_f o€Ú„Ì †@ìƒõÿ·oÏw|ùòð4++jƒ¨N°”bû_üçSÜóÕboÿ’fàý,6ÿ1r¤ˆ¨V1¨9ÍÄÄJaìÿb`–~øv¯P3ïo`³$ @ŒÝ=0“Q`€Sƒ8ÙIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/contents.png0000644000000000000000000000426211550446572023064 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<DIDATxÚbüÿÿ?Ã@€¢ 5Òç*°½Ïf¸ÈcƧ €˜ia¿p„î• U .ýw¿ÿ1Üz}—Z€¢º¸òmû ì´¾2ýd`åføõó¯ÃVö³ wßܦ €˜¨ôö®='3H=føû—AÂZ–C]hƒ¾´ 6-ÄDEËùu|uL·.sz×20Ý2XX¤ÝUx™u%ÖylèÚˆjQÀ¬½bAl…,Ço¿X˜X¬„5ÖÜ:ÌÀ,ÀÆÀ.Á+óù/“ÃÍ—›õUÀ–n_™œV'çÊÀÈÈÀpêî[Vfia¡ {^žg`æaøÏÆdôƒ‘ù0=\„é f*½¼k„ˆ ¦ î‘›¯ôå^~üÁðñÛo/m=†;w_0Üüû”C’Ÿá×÷ßΙ63§rA~†Go¿2ðs²1Ü~ñ™áçŸ üœ`G„èZ3l?}”á ÇO)>öŸ9üã`]tÄW€¢(òÖ¸Ö;eȳË2¼ùò‹áÍç_ w_}eàdgeäfxÿõ8=|ÿõ‹a/0Q>ûÆðŸ™…ßJA‹IFp(ˆìàȳ·÷[#È*Ì/N†¿ÿ‚£@ œ@±Ó÷Þ2¨‰ó3Øë1,¹¾‹E€‡‘‡Uç×ßÿˆ™œìÆ -i¡ídº Ú¨X€•‘•áôÝW R@³±03v¿—áò³@¡/ij”O™?@d©­€;ÐR'a°Ô?`°ýº~ßµW À´ÅÀÁÆÊðH¿ýò›AEœ‡áøŽU ¾¾eÐuˆcàââ‡Äë_d€QÁ4 ±57O2¬|»„áô¼ÃgÖ^Œ}d>@±UØÞ70”WÈÄÅà§ÏÀ`dŒC7Àe0ý0(k6Pû ŒgQ`Pæï?ÿ3Èk0°Ü¿ÉðüÒ>YS†Oß1åß³¥¦Œ ر×ß¼d˜þp9Ãï 7?3\|V 4ò.Ì€bãcx+ÄÌÀøð3Û½ÇÞ|c`¸øè=Ør=9ˆ" O˜ô·Ÿ¿Àôë_DäµdÕ €¾ext„/7Ãc`Tȉ ‚ƒþ30ìk.LgàýðŠáÑ¡» w^Ÿù æ€b~#$ôBZèoÀV5†ÏÊÉ Ÿþˆ0Ø)q2<f'P~•é ,ôñûo`@€óüßÿÀ4¿ûüƒAT\’áóó‡ ß¾``cç`’e`fI|÷™ ¿Yo1œ^yz3Þ›BO‘“@13\{~ñ '—€–¥ˆÅ¥W×TùÞ \cpÓW*Œ d"y9Y~ü‚X®Ì^¯>ý`5)A–± Ê0üÿñ™áÆ•C âRª lÜü Ç_\c8þ}ÕÍçžýÞ;á믫PwÃ@ ¢W_íüÌÁ á$&qÿÙEWõo < ˜~«€Cà'ÐÇ ZNX¸¼Æ=ÈRPè€,…Æ`è¨Èˆ1pò 3|þö‰áíƒ[ Œ¢2 ÓMbxñ&ÃÛ½·Òî½=ÌÉ ( €à%áweɯ^&üÔ”äñÁAæÇUFv1p… #@%܇¯¿Yò0aò1ȱ˜78zXع88øø4L:¯õ3p|}Âpk÷õY Çî/Ŷ¢ €EñµçßIIÜPáý±ý/ƒá;G j"À†+ÃÃ7_`×vZÀÔ *zA!ð *#Ü?ưþíI†_72¨±ÞeØ¿öêY†ÍWʦßÇUÖ#Fã"\»Þ~¿‹áÖ«k@Õ¯H±#Ú0ßÉšwÂßÿÌØ,ïwJ›tDyë˜1hIÚY Ž'µ ÆîÀZ+ õàhøðIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/mix_midi.png0000644000000000000000000000236111550446574023026 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ƒIDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €ÜÄc022©z Vâ?T2”ÅØ€˜ˆÿAí{ ĵÀÜw¤ €@ÙšOçääüŸ6mÚqqqÀggçÿ‹/þïççæsrr‚å;::þ³°°€ÅÂÂÂÀjæÌ™óÁ‚`= q™ÿ3fÌøßÖÖöŸ››,VPP𿾾þ?г7`ö²¾îÙ³ç?hjj‚5”””€ùííí`¾€€˜ÿæÍ›ÿììì`±©S§þG = q0ÿÙ³gÿEDDÀb‡þûöíÿLLL_`ö ¢ÚVˆ" òÿ_‹\6Úå¤ÎNI1ÒÜ?Ì ]™9„»ŸAÄôª"DNU7ßö0³ÑoØ­ÿ‡gõ¯ÂH„ ÅÀ †[M ¬¬¬`Ka.çãã‹c+IAâ09æåå…›ˆ]d)???0¸á)))¸ ߃ì[d5`111HKKƒ=SLS oß¾EŽn8 œòÌGÀDÅðñãG°< ‚n Èrrr À„W+** v¶ Ì(€8@VVEä A´°°08Z°9@^^: y111†>@s%* ,!ðì666 ÏÿCC€"ïß¿;ðïß ‚‚‚Ð`þ‡”åÁ••cxñâ9Ü ø =lQ@XŒ_a6v6†gÏžÂÍVVVfxúô)Ør ˆÿþÂìRÔÔÔ~|ÿÆðE 5 Ðûýû7ÿ#M&9€ Tüÿ{­\¨‘‹$ÜË”~ „®Ošœ&¸ÖR¤­VèêÆšZ¥tŒ$×½˜9­;IË9\™#ÿêÅ@L¨–ÿ­ƒ° ÃçO\\œÀâff¦à ÕÑÖf)n°ï¹89@E­%<í€Ì¶²´`¸wŠ2/0ñ‰õ•¨_›á÷ÏŸ( äxy¿rÅrpéõç÷¯ÿ@ŸY@?üý¤ÿþé B¿Àø÷¯ŸÿýüWÁ?Áüïß¾Õþ†ªý VQûÿÿþ}{@%á{˜½Ä‚êH ÈÌü™8ÿ~Bâöß/v wÿÿG8î@òÀDWƒHD œ@cfÁÔ²²2AR2’0@¨øû—ÿþü¨Òþ¢…Ü?ÜÕ.µL¬,`³‘s@¡8àÏïšøÿoÕþ¿þþù"@¨øõꀿ4r0Wüú†„ì6Æ?Ÿ@u0¨þÐȘþ~F± €ðèÐÁCŒ¿>0|ÿE›(à–®ç¯Üç8˜@1‚X@81124€JNhó‰&mP`fø,<û€ö® ã@÷ŒhÀ[Å4à w@ ¸hÀ`¥žÃÀÈù>IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/ledlightblue.png0000644000000000000000000000410511550446572023667 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<×IDATxÚbüÿÿ?Ã@€bb`@,0£ùZ„(3#'³Ýøë7ÃïŸ@üK‹áÇOg†/ßõ~þRgøÏ Ò Ä¯zn3p°\Ò{€â€bxƒöÿ™40 @,D9óÿ†Ÿ³~üµbãdÖ×aБçcâgZÏÈðéÓ•ë>Xž»ñŠáÛÛ¯Ÿ˜O3°³LÒk @øÀÈ Êðç'ï‰êÊ" Q.2 !¶’ jÒ\ èÿñý—?¶~È»pÝu§ Ÿ91°2®g`e.†ÅC\V#,b‰} ènanƒ‚P†dWIfÆÿ az¢ þùÿþA"ƒc¯¾ýcX¼õC×´ã o_~|ŒÊd ì>lQ@ˆDÈÈÅ`Ž÷ß;d¥y Öš1dùÊÝÃÌðá÷_ A1 ¥À…À÷? ïj˜€0ÖO…aùÌ`]Cy†¯?7¥]±…@!ðýÿþ+ ´e±Š¿D[)ƒ:0¸ß~‚HýýÁþaâ¿ÿò?€iöP„CK;ƒ‰7Ѐy@[”Ñ@ÀLúù§›ƒÃÀ5ÞœAVŒ“áýgˆðo þõJ½û FÿEˆèßHb¾00p³1ø§»1ðI Ë0üù3 h²áˆó]Ùþý‹—qÒc¸ÆÈÍðœ?ýø Á üør#ÿE°Aô(„a9òû†¿Ù„Ým8™€ñ‹ì€bBÊjÌ@çç‰(‰0|V‘cxü‘áíˆAßC¢àÛûÛoHZ€³CÕü†¤˜<ÈqŸ€ô­7ÀДeÔVÍŸt m0k¹$Tcbüo%c©Ì🕙á3Ðò3o!Aúõ7*þöSìë/(FûÔ{ù=°”úIÛ"¦Ú ,ÌŒ@¦ ÌR€BÎή}òÑ ¨mH/@± ¥} a&>NÞ¯ ü@Ml@K½‚Ä·ÐVh”ÅY˜ eÜ ÐDM€ ðÐÿjÉŽè¨ÿÀb]ZMŠáéƒw:0káf5^iA†¿@ƒù™®bN ,˜¥¾ †Ð0  #ªþü‡8¤î0È=Á Ô+ÄI; ì;ÐL ‚Bf-@!ÀÉ,ÆÀÅÁÀ TÈ ô)P† h7 ÄÂß@ñWß!€ÄØÐBä{E_ÿ@rŽ ;$g|…ZKq¬Üì ?ÌZ€B8€…‰èdN e % K¸¡‰qÅΉPð33 ê;fH½v4°Àdøñ’Y +R’ÿÏ­e  €£à5+Ã_ íÿ |sˆJ| ËAÚ™ù(’Ù€˜ý/ÄQLÿ6ü…²¿üúRü f-@!…ëïŸ~X E¾A}ŒìN¯a–3Aƒæ5 ÿ1Bh¥,ÐjEÿÿ@Š".N >}©{³ €àe¿rýñ'ã?¿þ1³‚ÈRïAQÀÍv0š9 Aýš@ŽàøÉ¡ ô;0T8ÿÿcxpë(´¯Ã¬ DAÄôo÷ûWŸ¿|{ùŠAˆß\ÐÈõ5 3Ci(ffFˆCêHPš˜ƒþ½~ÉpïÎÛ¿À„²f-@!ðë÷e†?¿Ož:zXü¦Ih5Ù0Ë™˜¡˜ 3Bi „) þ‹‡¯1üûýäû0ká€ß ªæÿÔ—ž2¼ºó˜ŸZÚ1 â%$˜!Àu(3’:h:‰ñÍúúø9Ù#w€®a 4ò3ÌZ€B Pêü»á÷ï?V-;ÉÀñ÷$^™˜°8€†%&P©ú—aÝ’# _¿ÿ9 ôÕ äÚ €lõþüñ˜‚òŸÝó`þôÝÀ¸û.” Í-Xöc‚¶Ú@qÏÂŒïŒÈÍIH(ñsüeXµàõË/?2p°¦… ; €˜°´€&;òàÛŒI»€­‡ \Ü oh3¢F ¬%Çm£ø\ Œõ‡añ܃ [¶\f'¶, ìytëGÇäÿ~vÿÃGî?®«ZÏðàÆ#~ œ\ˆÖe³ÿÿ0¾ù€~~ÿCsÍz†Í›¯¾eàfJ-Ãf@!ZÅÖ‹`!Jš‘AX¦Î`cft³²T`ðõÑdPц38oÃÊP ±éÀÖðû/¶ï¸Æp`ÿ]`[ôïi`g%›Ïa­b€ÂïXaõ÷°ŽMqfÊò‚LÆz "‚ <ÀF#0¼¿~ýÉðîÕ†ó—_0ܸóŽáÿï¿ØXæ«ÃÀ û‰¯g@Ä8^Xƒ[2¿þº±0%ÊùÐôö  Ok ìÌ{üC`1"ºfÄ8нc€ðÞ1@€¥\ž…t†iIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/newfont.png0000644000000000000000000000370011550446574022705 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<RIDATxÚbüÿÿ?Ã@€bb`@,0†‡‡V â( ‰^^^žÿþý%Á|Pðr1ˆÍÈÈÈúúõëW?~¬Úµk×6€‚;àׯ_XMŠ+»¸¸Ì(--åefff:§C±8Îéceeexüø±dcccP쀂;àçÏŸX þýû·„‚‚7`ŽŒq‰ÃÌÄÄf+))1HKK‹ÂÌ dbÿþýÄ06VK3 Œ0þ0óˆ˜(`€9›Ñit1dqå0À@± ùWà´–&ÐãY,l@Œ86C@¾ùôé 8qŠdýÈv¼E .ŒîP‚9`êÔ© +W®dàââ‚;Ùät.D–@>¾{÷.õk×>ÌÌÛ`1t5œœœ`Çqpp È!G@‘•@`Ïž= wîÜ[rúôiwww†?~ÀÓÈ›7oføþý;ƒ““ƒ‘‘,ñ#›@ðøÿD?ðÏ €–ƒ€ ß?ÎpòäI†èèh°¡«E ;;;Ã7€ÃíÛ·Áé$??ŸáòåË`Ç‚Ì@Ê… wÀ “· /ô?B°ÁG†WŸþüú *ˆPò2éS§Þ¼yÃ`jjÊ $$ö)È2Xb9DFF†!))‰AKK ¬öþýûà´ƒ‚ï’?€Å!0Åø/Æï ¼g9~3ýg‡77ÃÏ?ÁÁrØ„ ÀAüèÑ#†-[¶0ƒ} ,9LLL:;;Þ¾}‹… Ç!'B€bAD6Ðæ¿Àa„ÆÏï¿,¿~j¼“ù®sñÙUÆýW2p0³3ü|ñ™áñ£Ç Ó§Og’’bxùò%ƒŸŸüyó222øùù&Mš–ïééaøöíCBB8j@YT°!; €XP*.&`Ü€Bçß_>)a¹Å)öI~|œü ÿþüg8wçÃó¯6­ÛÄ ò†áÞÝ{ rrr ïß¿ûêÖ­[ ••• µµµà Õ- „¸{÷n0{Û¶m ÆÆÆ ÀZ% áÆücúþK¥o‰O¶{Ãý?÷Á.fB%6e†÷>1ì_¸•aç¶  Ǫ¦¦ÆpýúupÖùøÞ½{ ‹-bðõõeËkBPE„Ä‹ÆT [~ÿƒDÅ÷;«ö-çWãdˆ9 Ì@5Àªb§Û†yË×1üeg(MÌgøÌvÀ<Âð©À9(±r (€‚þ/47R?(§¤¤<Û°aƒ4H@!¥²ì,œÅ\\|ßY~*0313üºdùߟ˜~320ýc&DN†å62\y{—!Å9œAVRšá×ï_ðIJ × >Œ†%@C €àU˜¾[Åm01€‚`ŽðìyGþöúùÿ‡Ïÿ]÷wýçéæùÏÝÂýŸ«žëÿ¥ç—þÿøñëÿã—/þ?zùü׺YÿMÅÊ¡F±‰™@Ž„Ù @ðxÿùmqҬijÌ,¿ý0ØY±'„U…áç·Ÿà2àÿo`ÏÂÌжfÒߦy³˜8…Ÿÿûöý.ƒï2™ï O>ÿ&§c@,Hõâ'`i<eÿ¢X˜YB˜öìÀòà?¸¤fad2ÌÀ‚áÏÄÿ~Ýd&@¥‡ÏŸ?‰VVH¶ûû÷ÐŒç /_¾bxòä 0$0¾}û!0U¿%0¨€>} vÈ2XH€ÈAŒŒÌàÄ ÉAÿÁ‰äx™ ÔïííÇÀÇËv0È¢»wî0üþû›á10Y[›0èëk峤)(·#ãPð/}ñâØpPTpqqÙß¾xŒ!hZøvÈ· ììì@µ¿¡âL`}ÀºXsr1èé0°£ä90=€²&78@!ÂÅËË3èhQ€%B!O8XUUJd((•ƒ\ÿùó`¾G(ÑÀªnA G°°°‚ù ߃¤@€€ 8}üæ"q q&FIqI=~ Ç~3HI‰r„Ø©SUˆ ä; †Ÿ¯^½_òæÍWhPþ»úë×O@þ`¼óÁ   h7ÈbPh€ Pܳ³s03Ã÷¯¿\Ý\œÝÀE(‘ƒ²è÷ï¿¡¥&‡@Km`£áßÿ¯Þ}õŽ˜È@±}Ç ,÷?|ùÌÀ/* ´…Ç ì *@@%DZ#@iT"(8€êy¸yùŽZP‚0(Íž½ˆ¡£cʼOŸ¾ø‹nw(=þæàþòÎÞçõË?öB‚vÖ œ@§ñˆˆ0<<{ŠAìÍ;†W@×óZY1ü!4*@ñªx@ m 2âÇï`qÿþý¶$*öí;̰aÃö+oÞ¼©–¦@i €˜ÿ‚ŠÆ¿Ú*î®Û“ë²ÕEß¿gx¶d)°ûuÿã¾½ Òú ’Ìž/[Ìð˜ò' ,ò5¤d'B»@Á|ÿþ}p n..N†‡1Lš4çÓ¼yËÛ?~üb Å °Æ @1.c`•‹ˆÜoQ[¤ÌÜQÂð?:ƒáâÍ× /_§\£ø(†5 œ® •áí§/”£þÿú¶ `9”MA–JII1ˆˆƒsÑž=€mMÀè©:ø2ÈbPÎ¥%PÉ @,Àà×UÎÊRf>¸‰áóúƒ ¿OdPï_ÈÀ!ïÏ ,ëßUe2¼Ýy–ùêUµõ»Ž—T2ð½yà ¬†ÿÿÿmÊýÇ;(ŽE€ÑÊÆeØ»÷È¥—/_7qrr¬…Tט€bd`xýæÒeMɼ2 Æ· _Ž]bø¼ƒ ™9ÃÇé= ïvœf`R“`P˜µ„áè²Õ O™Ù€QbÄÀÌû\ð’àjùîÝû Ë—¯¿wìØÙ6`4¤³³³^X :@¡kE#0¶€!Ë+ §?Çaá‚P¦%½ŒïV,eøñ X–õ0i¨3HtMa8µûß”ýƒ8@.gÅì@K€9ƒƒáÞ½G ÇŽùx÷î£YÀ41 ¼O@©Ÿ \á3Âs Ĉ( –÷ ÔÌÀðù᥋sïí?ä«“ÅùkÝF†_?>3› ¢ž> ?øEn?Éà9}.Ãïo_> &qq1pÉòñùó×>-^´ Øð¼ ò!±ý €··€e†YqÉ-sÎGÉ! ß_}fø+ÊÏðëçG†{í½ ²l| ®Yi 7¦ô3èfæsÈõë·€m‡[ßž>}µh×L`4œ•Ž‹‰ï쳃º^nÞ6ãpɧñ! ¯zTB>#×HÄÒ79›a{uÝÙ“Ë—¹ßݾã½Ny…£¤™ ƒ\b2ÃÞ)“Ý9z<†]×ô:¸úkrC €˜=Iàã‡ÛìÝ'Àaj­w|âäC×wíŒ`c`xôõû÷ƒ7¶la453<½jÕ¹ëÖ…³òð]eÑ6a``¡Žˆq {Ç4à½c€"ÏùÑMÉGIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/connect_established.png0000644000000000000000000000517311550446572025231 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< IDATxÚbüÿÿ?Ã@€bb`@,pÖdF oýi† ùx\ÌÄÌðÿÿ?ffVNN.†?lì _>0ÈýüÉð $ÏÈà)/Ï0“—›÷ß_†¿Èzv0=zݾüÃÿ$@±PêV c.róðšá/ÌÏÝb,ËeŸÏÀðû7’J`T³ð20¼:İ rªL €Hq€,süû÷”h~þýû÷##ãG`zÄÉÍð‰••û÷o~YiW.S_™X¬†\ž7›áÎ]† €0ð3MŠq‹¤¤¤  7Ãׯ߿¿|ùòñ§OŸöóðð¬eãb<}F@„ÁýõsY}1c –w@ü É~†oç§1쟰g?ó?†y0Q€BuÐrnvNV†ïÐãâEaaÑžAAQ ¿~ýe06Ö`xþü…ä† ÍV¬X•~ïÉÓy_¸¸ÊQ`¢ê¬ÁÀÀ¥Ôöˆÿ@ eà2/0ožðóõ† .†0+ˆ” ÁxPiÏf`p×€KçÛÛ;ÿ?vìÒÿ'Ožý¿råîÿ%Kvþÿôéë¸wïþÿ˜„”ÿ"\¢K&Ë0íý! (z ˆÏñY(¾ñÿùÆøÿÝ, Sš†öœµ €0³!ÐmÕn`–87OVbbû_†?¾1ˆ‰q1Èɉ0ìÛwêxEE†Ù3¦0d&&G‹)381Èj@ƒþ b`Vxw’áPíÊÛ?þ0t±3 j€’10/Yȃy†¦Îj²Šš Ÿüdø ”øòý'ƒ¸87Ó'ož?Í !!ÂðçÏ?vv†k†¯ ‚JHÁ´êÿ†—»–0|}ûƒWA‘y0ÿr~þw#Pœˆ)“Æ0ˆ²ƒüþƒñßÿ¿ësþYˆÈ>fPxRÃÀøç/Ó&†§2 ?ÄÕ¹îß !†ßÀtñ™™áÕ¹= ʪ@s€F|†Ê €· ¢F’ »b$ÙÙ%~~bؾMæ€B8àïU±X`0³|þÅ`L…Ÿ=s ˜éþ€ñ×› ר²8™þ2|†Æ÷ï¿@%Ã×ç~=>È ê` ~Pêÿ f&V5V&pš~¸rë›ßàE@!9€a ÃÅ "Ü ÀÂ…áë_PX%€Ùâ?Ð'üda8÷؇Ὲ ÷o?Ø98þüøÁðýõw†[³10±\`øÏÈÊ e%ÄÀ­t‹ÔQl ?__a8^¾í(ÃïÿSaÖ¼ W_ø¼éæ”?¾¼\ÿ™ÿ3=ÊÈ.þƒË CÞ¿bøîpŽá§…5ƒ ?0aþ'D&~n…Ò¹ Ÿ._fx÷òý9í ñûí–sB£\v1ܘ¸ýÿû‡?yû;ÌZ€bA*þ½ýò¯àÑ÷¯½ Ž3¨ÿQ³^š‘šLp÷¾~ûÎð XÖÿ“ýÍ ,$ ðh¨Ø_`üdøû”¾3phj1ðXZ3°nÙÍ %ÃÀ©©‰°]ì ïÏ^f¸4åâ `°›)Ý Röc×4`x§iËðjû$†ÿy¤L4¾ðþe`õoYXX˜þýùL³ŒÀøtÀ?p~føúƒáÿ§Ÿ ï¶Îb0)U90A ÿÎpsÚ‰ÿ ßþ)qp±´ýýögPð H €áíY¬«tþýûóåË_®—Ÿ¸”Ù™øþ-fûó›áçG6†,± ïY„€UŽŽØLL,ààcââfø¸ëƒàƒV£I.À¨û yì¿ _}a`³¯ö>a8³·X\õƒä¿ÿ¿dP edeàùò‹ìÞ½b`þñ—ñ/0(_|cP»y‰á 0+3ƒñׯ?Žø Î ÿ|eø{z-ƒv›&¤@ù­‰é˜è^e`öüËÈðtýƒg@„䀿+޽Êaæç/°,_€ñþí7°øJC jÏÏ0á0eàà›ü èHFF`aaaøóñïçÇ ?.ó0|¾ó‹AÄ ¨†™^Ç0p02Ü|‘áþÚ»•@K¯Ã¬ „ØΟ_ýiÑÓ_tY˜~üÏ (*-'ÊÂÌÌï_å'#Ã`c„Y€0°ªÿ ªÁ!ñ˜SØ€QðÛ§€¡=¹å««ÜûßÎû½€¡ )¯yX¾œ}Åp£ùì:`^Z„\þ R1üíÎóÿÇ_ýÖî §0qǦDEO ög8¾}0+ƒ•é??77ƒ˜ˆ8ógï€!ð úLÀ„ø—AAXá(ЮÇ"â;¥ þ[2°1 0|F 0z¾þa¸\tìþw?‹™Ñª€B©ŒXžZþî-ÏG. ÑÍgÏŸy%".Ì #/ô!°-t®‚¢"°öôé`.Ö_¾1ðòò2ܽw›áøŽÝûlžÜ\/f$" Š2`=ÁÀÎÌðrêÕß=¯fÁì£6dÆí a1Á‡ïÞ›·qÝFWG'Q!!E%c†7îƒX=ýúÃÀÁÁÎðèá-† »÷^çþñ+Q‡ó“*—‰0‹o†ßÇ^2lê8·˜$—þG „R²üˆ“Ÿá°¨EÉËÜ·té QQG°{/]ºÇpåÊC`âû.hnß~ÁpÿÑã-lÌ,E§<TäðeÖ'à\ðåÞÚS _ÿìüŠæQ˜#£Iöÿ!©˜À^[ÁÁ“&͘©¦¦êÂÂÂö9(áýùóó0î‹ê¥øWh>ºýGùà uv-5=FFp­ÿjÂ%††Ó¯ž+ç5¸šD°Q ´ì##“ïÝ»ííA1vv¶ÿ¬¬¬ŸYXXï03±ÜùËÉùSìý—³G@UŽ¡‚Ž3(1ý=øŒaÒìë §j€Æ<Ãe>@Õ*–x?888v-÷ ˜YDÿÒB_?1ÄÚÎÀÿã;Ã?cAcQ†çß7z:ûÛïr ö¥øÌ ²{F HúÁÊÆ úüƒØ·/ 8åàU°f•åcx7íÊÿG×Þg¿"`9ÙøLzï2x_: n~ƒRO_XïÛ©— Oݘ ‡aDX@d÷Œ~»f6w¯1pý‡·±_|>ôüè§ýOAÍ÷P3¤ˆ×C›š¸@1tï €¼w `РÊvÅvûcIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/irkick.png0000644000000000000000000000546211550446572022506 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ÄIDATxÚba€ÿþ1üÿÿNƒˆ†bE&&&w m¤¥€øT ¿ê{ äž²wå€ä€4õÍ„Ñ @, „PC.k ¹ Ä;€ìG@ñg@ö¨x€l©¿ÿÊÙ G&sˆ'¥/á3 €ñ„€ Т6fff] Ô\–µ\\\ŸØØØ„„„PB æ»·oß2üþý›áÛ·o|@:(žüçÏŸK@uÕ@ö{l!@¸ ´x:++ë ¿QPPðм@_ºÅÌ€J14¾ñ óС»€ø  >|Š5a Ä™@3¯ ; €°9ÀhÈ$ï999WJII4È¥ €êÙê.ùw€øT«PN$”EÃe žÄž>}ÊðãÇp x50Trj"; €Ð ôõ* ‚´èÓû÷ï¾~ýª äOZzH×ñ(tT{õ|é FQQQ˜/fØW  ¥¥¥Aü6`Tè-øŒ& a  Š¿j¹Ê PHåô€XˆA!8ñû÷ïÿ€á:d%Ћ@GTA£cÂÏŸ?9ütF€bѺ@Ëç}모¨øhI0$²€´›²²ò7 ò@ƒgÅÞÅ:싌À g`äâÿÀ”ÿ%@u _—ƒYÈNª{x÷î].P¹›¤—Ý¿Ÿè =¿~ýJšu €˜yyyAñ×ôÕj`ŸúXÈžÄqÂÂÂÏ€>—*\L+€t#ÛK¥¿?fø¼oÃëט¹¸˜˜XY_1þÿ¿èP åÝ@õ;y ´ì= ¨m Я€!ðÈŽâr€PC&Ђ `zø ‰z åW€ƒr+Pã  ÜR Æé ¬¬ ¿îÞeø²};ד'þã„^»ÆðïáCFnnfaa`±x†• è–ÿåÀì»/‰Vh¡-г;ÑrèÀ ün€bæçç:€¨p 0¸ Џ5ÉZ.ôE3;;Ã×Ç>îØÁð˜ÇA^øËÀÀ Ìl aŠC˜Å¸TU€í РŒ@óO€,z&È^tÐW`”XÀ@L@KL w} Jxî@ö c104bêY89~?xÀðéÈPÖøÃÀ ¯ÈÀ°2á¾KÙ 1Pîþ T󨤨·ˆc€ÑÊ 2d6¨¨Ù´wo @L ŠÈyŒo,A ”Ý€bÖ@ü”‘‰é#0½?xTó|g`7dgX[íei¥"ÏÈ šÆÀ&ÃÀ°"âŒ@5je2Pïu ±5ÈLÙ@û,AYd'Ð" > àsP¡d‹ƒ\ -.5ü   Æ)Ã7`¢;Ct+ƒ1¯‰ÃU%P40ð±ƒ10:¢AEÓO ZPh€ô͸´Xd&Èl Ù4ÿ%Í @,@Æ þ *˜ˆßØ@91P± *å@@%¨ôd`0åÿô甹 ÌÀpÿ ´ñ#Ðð÷ < ”…P-È `€ô>:BÌgd™Í uÀW þ @,Èu5Ôb0f‚¸d(ÃFFH-ÄÀâëöý¿ÿäßýgø­ @Ã}rŒ‡@ôÍÕ®0saí ˜ÄdÊÄ Òr+UüÈ—bŠƒøÀ '÷Ï +630¼>dŸâ@|ˆ¿Å€¯—nPÏ@±Pÿ+¨§„@v@ÙÜ@»Xä)PÉ' ,@®Å‹ ¨N²o±Èaì|| r!!  ø:âÚ †ÈÕ ÷¶ùÇø ô}$yí¨\ eààçåpƒdÈL ¥* ¸L q PN žƒDáãÇ Ÿb`= &P%"äkƒ¡¡!Ÿ¼<Ø@ŸîýÁÀ°„ â PÔ,ŠïÉ ¨«3êé10ƒh™PHdÈLÙ ;@l¨ø[€9à4Ð… x–Ñ;‚*@_ËÙ æÖ" n:€Xg°‹Û¿ÐÚ‡˜ðAÕ˜$î•þC²ƒ”‡›€ÈQ ·µñ YŸË̆Ú.s€ø@°ˆu€¥/°%ó(y(‘ñòåKPój60åŸüýçÃ|*˜€M!]AH¶Ù¤ Õ– ÏwîdøŒ6 >N > î™ ³@f•žÙ´ Ô’Òâ*ˆ^ÆW0¨AjÉ]é¤5¿|ù i†v`Büøóõk†oÀrÿÄ¢@Ÿ«@C€ ȉ÷ëÛ7Z`V¥­V ßÓÚ2sÈ`ù×v? h>ï*š”XlË=¶Û€fÍùôé“/Ð1ïX88¾\¼ÈðXá0C ' ´WR,3ðÙÀ*Rœ/??zÄðXgpéë3üùñÔ@5׿íh¦³G@6?ÄI »ˆ šU®ƒûЬÆ7oÞ€šVË€.\jñ}ÀðñÓ'pžgƒ¶ãU¤¬"??#°i.…A9˜¨!éá'(kõ€ô‚Ìzb1ÈÌwïÀMÈ ]çv^Ù @L°‚¨°(aL,a &PÃL û 0+1³Ð¯³g!…( ­­ÍÀlK€"Ô¤f8Yhù T ÒÖËÄthÖ ™@óB¡µ` Ì^€bBê#|º4¨ ¨É äz`0|üþá°þÿóâ8€êAFFq`ÔƒŸA’þAø˜è¾«m°^ ÀªäG Ù &z¤@…€Bé]t¨(Hs2ܾ}›á/Ð@Çð@âìae`[’R‚£(¯ü Ê—nÀöÁÓ[·X Èx.¨Ù×`­i l]³= ì P¾À,¹¡µ *3{H<ÀìJt |L1¼ÏŠ ' oÅÖ5 &¼½B #d¯\aà† $žAXTDPP„TÒkG>hu Œ a¢,ЄÒ£ÔË­Èp€ÂéP È ,ž9€ñ÷·ÿ!DåÅÅ…À-b`ȰA #Pï(SÒà ÔË4ã?GÎÞñ?`%ìÑÀR>”f&ú[¯_ÿ}wâÄ×?ß¾ý‡¦|F`Ç$÷š`@hÆ]]P1‰Õ€Óg.„(IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/krec_record.png0000644000000000000000000000312211550446572023503 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠébKGDÿÿÿ ½§“ pHYsHHFÉk>½IDATxÚÅ— P”UÇϲ»¸¬¢ocR '‡šŠ´AGqFË&i>§1Íå#ÈMdAÔЙÆL3ELB\A¡0QW@ä¡€«$HÆË ÑôôÿØý˜uÁ÷2Ý™»Ü{÷žÿ½÷ÜsÏ%f¦ÿ“Ž?ááá$Â|v‚hð‹{aìnAX!?€}è»CvâsÅ.A˜)*@"ü,Æ–ÈÎÎ6 ÿ1/Nà ¾&R,'¹ÜÆfm°ƒÃÙpw÷Ö(>:>_º”ÿX¶ŒS.ä}Ó§ó÷žžäì|9@¡øi ÑÛoÙÀƒ€Œº­VÛU€3ð«ÀJ"9Œ¯Ð¨Õù{'OnÏ âòýû¹6-òò¸±°‹Š¸!?ŸëOâk œ»q#Ç kœœ*>$Ú>óˆ±lºÑE€=AFã¯*ÉQÞÞ\²m7Á˜¡ªŠÛkk¹­¦†Ûª«¹Õ ±Nlk½~o—•qåœ8k/éÓGïA4S {˜5* ˜‚³¡Q© ùú¶ß<}š åål¨¬dCE®^}<¦¾Í}20W8:Ö¸}2EwfA€/*4FãcCììòsÖ­ã»/òÝÒR¾ó´êõ«±jÀ€º‘DŸv+ LôX£R™”2o^û¨o)(à–ó矛»ÅÅœÆþŽŽU}‰†Ë,ÄB–^ŽÙÄM›ÆÜ”•ÅÍVB«E§ãL8ñ™,¡‘ãö¼¼Z©Ì©Ü½››OœàFxº5iJOçÆcÇxͰaÿº ]VË¿2ÆË«­95•’’z„¦”>¹x1ûÊå:ØW< `­Mfæœ9ÜÏ7cc{†¸8ÖoØÀA†ÞDcÌŒÜdkk(‚º"#ùFDDQ…@µuà@E´d’|®Ppáܹ\¿e ×mÞÜcT†„p¤“¿C¯ÕÚwˆ„°­XŒìI“¸64”«×¯ï1J,à(µšß#ÊMÔj]%?o‡€_]]¹:8˜¯#zõÕ ë&Là(™Œ?"º˜¬Õ¾* ˆŽ€€84”̘ÁUð…k‹Y ??>loÏ{a çPc%;D¢Owqáò™3ù*.kRt¸®E1÷NÉ­ÖC(nÁa2†å+S§r9¢b¹øù¼`œNT*9ãGƒIDºCZíéLÙŒÊ#ØŠ,ˆ(óòâËãdz~ܸgCü-87j'ø8v2Ø<‰â:Iq ÷·D%¡!ÕŒ4•Š †ç’Ñ£¹ÔÝý©(Ånn|ªo_NÅ„¤1›’”• êŒ„kˆöÆ¡!]4lFº\ÎY86ùÎÎ\ßÕe¡Ãi 2Mˆm:¬\[[ÎÃêœ3#·W/> ƒÙ˜­Ôßrœ3àG¢{o¥à.pì ÅûŒ·¡DD ç‚+“k|³îE"1Mì ¦àÈi ²ßuD7ÄŽE ÐŠœpô{nD;`Ê¥KNø.*Æ€q¸$–[ÊÐt ”Y+¦³ÿ>Ñ9u˜RvÐX²%êýÑ•¶4_•ψøÛ?ÁAàC”‡Ä÷c˜P=4-—™òwÈë‡@±g ÑQý Pû”Ôƒj°‡è>â¾÷ÿlÓ›çÑ©@Œ©ôü/‰*½ÚÿF×Fp4ƒ¦nÚêÇù>Þ·°­q˜Ð4 Ùç‰^FEñÑdo¢ªæ$Ó~ÞíˆÆ«Àï ΋yCˆB1ÏîŒ?©©ØÚ…蜔“s‰.av5u3„Õ†•Â_€WPô Ƨåk&·zhy’‹¨ÁܰŸÞÈ«gãé¾Â÷ÅxÖ p`,açÈÈ7 (à?Kzží³‘ªtEXtSoftwareAdobe ImageReadyqÉe<IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/view_remove.png0000644000000000000000000000257611550446574023566 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?Ã@€bb`@, ‚‘19‡‹©Žƒ‰ûßÿÿAbà€a1Àˆ&†^ÿÐäaúå1ô12þýóáÏÏ¿“þÿŸ×@Œ (àãM{ÚØ/Å+/ÅðõÛ†¿ÿ€jþuý:çˆþÅPö¨²Zý™”2Á4H=HŽ…‘áÃÓ× æÎ{õëë q€‡7+—„Ž2Ãq öoCY bù‹0æ˜å‘,ÿ‹„Ajƒèÿ¨jÿmüÍ!ÈÀÄÎÁ ² €Àø÷éï—/Ù?AÂdà˜¯þ£Zþf0L)„`ìÿPõp½PÌÌ4ÿÇo ÙL ð` H`bbøõ‡‘aåš ß?~g``ÂŒ_là?rD#304‚¸L@ñÌl Ò²|`;A €X ˜>|ýËà,õ¡0WèÒÿ 蹓'7@VöÈaÆÿÂÝ/–\ÿ LŠÌ`q€b¸Ž‰á70•‹ð0¨* S9£ýÇå?`<01³0HŠÿdøs ˆ™ ©ôï?ò¬€ˆþŽóPú?T ˜³€fóòþ房À´Á w@A¢€‰ìŒø#«ÅÂh„…0G!ð^0‚æ&H$Á!@Vð2 l929ìß¿ÿPÙ ÁI!‰`pü ²Päs¸åˆ(øåCÙàü ͦL$"€øóŸ£ûšý ²â]€‚†#ÄUÿÉ‹s˜Œás @‰.©ÀúZ°Ó#iÓç’9¾ÿ¡%HD§HK"0 €Ò1¾g@ rEÿÂRû?¸Ü¿ä ˜å`Í`Û wÀŸXÊOœùü?ܗȉ5ÿC‚ÿóÿ_f°ËÀn†fC€bAN„ÿ‰÷9"¾‘ƒš% ÀæƒÔýƒ„8– ¹ €à%!(";à?RMƒÍçÈq K嘉ðÜ06ذ]( H03+ &̇ˆ×ÿXÂç ¡ú¿‹ÿüý_x"d‚F@!ÒÀ䢹8eÀa)~ŸÃÊ”Pø U÷Ÿ^´(ff@®‡Ð-G.Ó‘j¼ÿÇá$Çþûm8"jC€BM„(qŽYà †œµPãäó¿`qP°Ãrà þûï?¼qˆ¨,ƒ€bÿÿ³©Õ‚ QCùAøÆ"Bk7bk•Ü7ܸ€ùœÈ_›&qȨFű\PCdtÊ 7ŒS][ˆ(w@†btñþG•Ä_´\YÚ<Ú:5P¹—Jsáo‚ (>3£„G ž×Àë¶íáŠÊì&шöѻܳ8V0ñò²3œ¿ÇÎÑ{ìp­+jÿ#µA1@äÁ‚ü¯tá}Xzþ‡T~03}cxñŠ|œ !•@ðûãŸwoÞ2pËK0¼ûò¬ Ö*†·‚ Ík¤Ö0Œÿ©eŒÔ‚F7ã?¸_ÀÄÀôã=<ÁØ¿þ1L<¶ñ`>¨Ñöÿÿ?l­ÛÿXª$ þüòPãÿý&¢‚Ĉq ;§4àS€pV™Ä­&æÓvIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/view_sidetree.png0000644000000000000000000000361111550446574024064 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?Ã@€bb`@, ‚‘19‡‹©Žƒ‰ûßÿÿAbà€a1Àˆ&†^ÿÐäaúå1ô12þýóáÏÏ¿“þÿŸ×@Œ (àãM{ÚØ/Å+/ÅðõÛ†¿ÿ€jþuý:çˆþÅPö¨²Zý™”2Á4H=HŽ…‘áÃÓ× æÎ{õëë q€‡7+—„Ž2Ãq öoCY bù‹0æ˜å‘,ÿ‹„Ajƒèÿ¨jÿmüÍ!ÈÀÄÎÁ ² €Àø÷éï—/Ù?AÂdà˜¯þ£ZþŠ™!>üõIJÿ‡ª‡ë…bf †¿f3´2$ 011üúÃȰr͆ï¿300aÆ/FêebdøüùÐÐÿ ü|œ@Kþ#Ô22`hqZþ1³1HËòí€bh`føðõ/ƒ³Ô†Â\Y°¡è¹“ÃÆÊÌPP°‚áùó +Wf}ÊVóûϬzþƒôãáî— K®ÿ&Ef°8@±@\ÇÔøŸAX„‡AUI˜è,$$ÈÁðõ3ƒ’¼ Ãý{w¾ÿÉ ¥­Eå`ý†ƒ¤øO†?WÀA– &ˆë˜ ©úIyøÐ!-Yº’aÒä9à¨øL8¿ à7(}ñO ºŸPÿùûœ6` H01ƒw„ã,Æ€†0Cƒ’…•œ6@øû³ç w&Oeødÿþû…áçÏß FE L,\ÀèúÇ🠢 € QÀÈR‹1ï¡!À2˜áß½û4œ‘áã‰ó ÜßN0Hzÿf`âÆpnÆ]†W'ܘm€ø ÒÖ@}ò˜JHuH8i;ÃÝ»·Š +~‚âúá3†‹g œ¿_20pr3ððq10í28›Bõ ,(AùX‹ÿC=ôýhüþý›ATT„!66Œá3óÉs ÿ®ogø{¨ø05<ÿÊŒhHÚ¹‚b5@AC€âªÿ„-%FX&YML€ÙOHH”ÁÙÅÌÿ*.Éð|û<†O~2üfgdøúIŽAVYšáßë¿à -X€i€‘ˆ4øN2BKLÿÁ¹è/ï_~þúÍðOV†ApÑ^`¥ó›˜ðxYþ3ðÈ 1üÛúèYVxÚ ¤4@Œï‘BðÒê!ˆ<0Ïÿ†3“°NæP½L  Z\3‚< 9€‚;àÏ?,å'ÜòÿpbÀpȃ adFq ¨ÀVé`úïï?@‡üƒ– ÀüÏζR@ôJ"üψßç0Ëá­(FFxj†¶À–ýûûœÐ˜¸¹Á|FP(üþË*šþêe¨>€b•„ lˆìXP#ûüß?ˆ%p€ %ŠA‰úë7†÷{÷1üÖ² Rñ?; »Xý?°]} `¶ù v2–5f9¸ÖûuR6)•õàÒ“áÛ©ó Ÿç42ðèÅÙ^3<8ðŠAw3—Ю?@µ( Dø\#â¯ÿáAsÌÈ%áÇ&Nœ ,û™x¯Übˆ²ádq{ÁÀ ÍÉðÿ+ÃïOÀªž‹-Ð h03 ×Cè–Âæsp‚ÊsFhV È+(0|ýËà,õ¡0WèÒÿ(‰‰‘™™‘…™áÿÏ_ ðe-66°·ÿýùWúÈ`ÆÿÂÝ/–\ÿ LŠÌ`q€b¸Ž‰á70•‹ð0¨* cšøù#ïKجm‰ÊZoŽeà‘W`àP†f‹ÿ@÷üc`bfaÿÉðç È• &ˆë˜ ©ú†a¿ß~d¸Æð|ÁÜQñÿ?ÿû ¶{Û¶3lw÷gøôä%ÃFF†oß~s×oiÀñœ6` (É vFôBñׇo 7Ó’Øw10‹òa±f9 ÀÁÃË «u–áznç»Ï˜¸9€‰ò4]0‚æ&H4Á!€ þ|úÊp);ATu=ƒL²2↓¸’!˜†;ìr&¥ ]‹Ã ÷S‚¾?yÌëœlŠP‚`„¤€‚8ÿ#RÖ×oöFD1üþ¸šÍ@™áé%Q†Ÿ?ÿàô9(èádè¿? oŽò0°‹«0ˆ gxäÍðóÆ-`d»œM™ ö$ÊïìP >Þ¹ÍÀ%+ÎÀ)UÊðø+ãïß ²Q!x|Žˆ‚¿À – òcx±ðÃ`bcÓúÇÀ%ð†áÇÅË ÿµÔ ig†X @\tÍ߈r\ÜÒŒ±Å9ÌRHÊFÄûpäÿøÅÀ©¡Á ØÓÉðï/¤0©øýåÃß_ßÁÙò¤Jë h9ÀLŒ „+fLŸCJÒÿ(9áÿŸ ÿ¾ýGŠž   è+ØpR`„¤€bA¤VÿGލÏAþ÷?ÔAÿàrÿ E1¸Úöï?"´ 5&#ØN ¸þüÃR~býxPâ `ŸÂiýç.ú gH9Ɇ„’ÿã(b!ÑňTP!|„üKXY!)Z£üçÏHƒV @@,°’” aøvú4ÃÛ¹³˜e€ùŸ“á×÷? B^ž B6ÖÀ¸ü‹b9„ýÎgdecø|ñ<ëµëþ²21ügýÎðñÑA'o¡PhÔ0‚퀂ÌLà 8TÕ¾={Íðóh7ƒ´ÖJnÁS OÖ¬r–C8ï 9`EônËîó ^û„¾Mdøvã&·–Ðñ éæ" ^r, 0 ð3(Ëþ¯| oŽÜdàWÈð•œ}þB} J|ŸÿƒÄ5(¥ƒ0Pœh¸äC†Ï{O1<¿bÍ 9c9»´Ã`îGÁx" hQÌÌ€\|Å*ÄÏ >{Ããç! 7ßÖã?Qâ–(!>‡ŠAiV`êý–[ ÷ŽÚ1Ht-c`“eøýùرl€¨Œˆ %2ü‡;à0®™yÙô¦ÏexóÁ™áÓ«×C}J ßÂ|0œͪ7õ',``ç韠-¢ÿðÆ,%ÂZ)LÀ J¤ ŒCˆÁ~Õj†÷Wåêï? À¶ 0?0‚K4FhÄoòôí+‡›;{l"ƒ˜ ÃßO_ ¹¨ØF#¤(„&B€‚gC¾ùÁðåów†ßÿ#ÊP6bádà20cøôñ$è¡¡õžÿ!ŠâÀÖŽ‘)ÃP,~¶ƒ’ Ðf`bÿõ•ÿ9á!@°º€‰Üçï±3DôÞ‡ÔŒÿà¥#8zÁ DH.øÇ‘ÿ.Ù‘jFFhI‹LhÝÍ9ÌLß^|f:>N†¿ŒÒ €ÀøýñÏ»7o¸å%Þ}ù ÖkÃ[Á Ðæ5RkÆÿÇ€Ô2FjA£›ñÜ/`b`úñžàì€_ÿ&Ûx0Ÿ Ôhûÿÿ¶Öí,Uÿ?~y¨qŒÿþËý‚Ĉq ;§4àS€pÑw}ׯԽjIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/kgpg_edit.png0000644000000000000000000000327411550446572023166 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<NIDATxÚbüÿÿ?Ã@€bb`@, ÂÔÔTŒ——gÁ“'OOݾ}»(ô‰–ƒB €À„¹¹åþ Öüßµkïÿ¸¸Øk‚‚‚¹@ynz8 €ÀQð÷ïï·ï¢; €Hn”^ÂL¤/¾ügˆ:ùýÿÏ/÷ï2|¿xŽáûµË ŸOføùé#CØ‚E í‘¾Ö [jÅÐÍ ’°ˆ9 ˜aÈ‘gÿ²ùÃðûÁ=†ï—Î3ü¸~…áë™ ßïÝep™8…¡#%ÚÚŽa3P­²yÄBNºRЪøÄ ¹7~3(ó|þUi÷è>Ãw&PqüŸ™¨òÿ?«ön†ÖÍJæ­XyœÁ¨å;È,€"˧ؑ /ý…Vuêû).–_ñVO0ü9‚é?#30X5·3T?{æT°ãPdž|~€"9b+Éâ eÿHVe:f¥?s• “¬<—އ¦‡¡9 ;+Cs@ð¿Îgo]¿üÿ¿ €(î,]¥¡…(»EmùøwýÑ¿Xž=bøsíÃï—~?L0L ÁLª é õÄÂ@ŠÌ•@uÐW?¡¾áß™@_&ú2>FÁ?†¿Ì@ç1ýc`½s ”ˆAÅ @QÈ@ZPý‚¦‰?Ç•js25вr©K 3¼ÿý¡ûÒ‹Kþ0~øÿ?@QÕ0GØAÃÀjÚèã*6Û7¿^nüϬ'ö€ì ÆîžAh;@Ò4{EIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/tab_duplicate.png0000644000000000000000000000376411550446574024037 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<†IDATxÚbüÿÿ?0f32àÿa  š@üÈüÇbF˜>F†?XŠþ²=døRËÊÀð‡ˆêþ2£¹õ!˜ &JÀ¿ÿóç¿—Hû?ö} ?Ä€K ʲã/Ôß~þp×µc˜ž×¦$Î'±˜áÛ×n ,!#ˆ…$ AÑõ÷¿ÃI†ÿ˜þA£âïßß ?´>þøÀ dú¡O:—aÒÔ-%'ÏVgààMªzËH€"Öœ ?¢&ñ «óñòq03²1"¥…¿¾þ`cxÎðŒá·Ô7†²:7†9“x}·ï<¼‹+ ¨ò)6ƒˆ°þ1¨-Ÿª¥¨æêneË`¤¥ ô#Óhêd„#Ð-O^eøõÿ'Ã{–k Ú ?þþ´Ú¿ïÒB† Ò/èÆ Ë5€©yK”¯—²¿»Ã[æ§ ÷œeøùëÐÆ âPì?0=€ (w½a¿Æà‘)Ãpïñ+ç‡×_Ç1°1OC· €Xð$0^`¼ÎõsT¶óTgØ÷rï?¿˜€™™ ‘ûÐ’Èÿ¿ˆ¬Ë ÌŠßÜeøðá+Ð<–W ÿ15nü`HÓÔ”³0²—cØqó0H3++ÐÜÿ _ÞüføýóÄPCAÂÌñŸGˆ ,ÆÂÁÈðíÑ?†c³ß1||ú{&Ó:lÖÂÿ˜½ÂÊÂÄ”bn§ÂpôÑ%†÷¿2°±23üúñáÞ‘ /n}þÿÓ[`âcFÿ˜þ2|ù%dh¦%Íðáãï ß22\_ù“áËã38™òÁ Î6ÿQ@,˜¥üþo,)%¨þ›û7ÃÝÇ/X€ALˆ ÷}aøtë׿ /ßó?38þ3þ¦•0n¾©?_1Ü=ý…áÅ.†?Ÿ›ù§â½ÿ ŠŒ¢ B \À̃° €Bà$A³7P…6·ãÝÏ^ûÈÀÊÆÂðûõ†Oÿ?gàbÊd`üýR ³BŠcPqËÈøîé—g Ÿ·}ex²ŸùмR6ÆEÂ Ü Ê@‹¹€˜~€ð?’îý†ÀTü—á ÿ5†ÿ,L<ž½cx¸÷Ã÷Ÿ˜€ü÷d!Ó#þ?üo”¾KóÜ]Ög Ÿ~ý:èr6fŽëçß3üÿÁ¸™‰©J‡Eú 0©2È3 ÿCñ_”( ¸”¾*ý—Aü“ÃMÑ»«ß}}û•éûÞÿÌІ‘õ?Ûÿ»æ_u¸ÿKX`ô‹ýûæÖÿ ¯˜>úûç_†,‹ðLuFqF&°?ÿ€²&Z¼#€‚;à7Óoëx~ù ÷HŠWé»ìwä¬ÌÛ¿±ýVüÁü=—ýß)Vfö“, Ç ×ø-n&ó›×øãÿÜ l?2%8„ÌLLLïXYY7Ù(…@!gC`>^éìæì%+- ¬Yÿ€ çíÿÐR˜à~‹ý“'O}~ýúM°ð”S`ŠÀí{lFDŠFN7ȾǓ™ÿüa|ã#1•-@€'ò°²ÓŽ«IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/history.png0000644000000000000000000000636411550446572022735 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< †IDATxÚ<‹Í ‚@…¿ÙÜèÀij‰P°}pµ/”àÁƒ–!¼äKÞOžðxrJ:ƒK`i§Sh]ÊT¿In–õšMz‰©4ÿÌ¿:Ñx£Œ˜¾pÿþóµÁ”ºçÍZ >tÃßÿ< ¿þF013%«Érë›k sj1Hs2p²3•02üøýáõû o¾g8~åíŸO¾\úýõ÷V¦Å@é7ø¬ Fœ!À ôý¯1\<¬.–’J1^ Jr| @?1||ÿ›áí«/ þ­g9Ⴣ ;3Pë“g_VîzȰíàÓ§Þýlgà`š …?ØB €°;€•™èë^c=ÑôÌXmM†û÷1ܽò„áËæß?¸XÞ½}Ìðû×OIi†/?ÿ3üaegøÏÅà §!É ¡ÁÅp÷Þg†™K¯1:ýb-3S.Ãß¿Ïæ¢8 €0ÀÂ,Âðûßʨ`u§¸(m†·ŸÎì¹ÉÀûí-ƒ™.ƒºš7;¿?ÃÞ½;>|xÏÁðéÓg†o_0Ü»ûáäÅO ¯þó1:k0ÈJ²0¬ß|‡aƂ˗þ22„-¿ì€bf …Ä5Ä=< ?þ¬‹ Õp Ôe8sñ3Ãݽ×x?cÐÖøÎàæaÇÀÂÊ fvN†{÷î1|ÿñ‹AGWhæ?NvE%1†¿¿o0<½zŒáõ.†_9lí¥DxYÅÏœzfóÿ?àEßÁv1@13ˆCR9Ðÿ ß~M Ö ñ‹ÐgØð-ÃÿkW2#$LÌUöï? Vm^^nff`âjaPPPd`ggg`bbd`aaeøùó'ÃÖ­[ÂÂ}lD.¼Épæ>+ƒ‹<ƒ ³äù´¡¼˜¸ÿ‚ì f~H6ùö+BW_¼92Í’éÈÙ¯ s1ü>•¡,I†A@D1¬ÀÁË˶Äfe…8äk… äÍ t0'Ã? ïþÛ *š< g=b¸Ç Ê`m!Îpáè=‹ïŸ/jþ @Làlñùg„…•¼£¸ÃõC·¤™N2¼ûôI\\œ@CYÀ¾„ùœõ‘ò2#$;‚ä@j@r`µ`õL ÿ9FEðÃý#Þ3˜ƒ«*ÃןY »ˆ ˜7Ù€¾J5rÑa8vá7ƒ!÷+`p‹2ìØy’aóæ} /^¼`àäde`–  ‡°KPØÙXüÿ K—.cþÇàªò‡áÔÙ Jš <ül ߉йn&rJBåRÎ&¬wÎCrr0 Ê3†KÁÌÿþ2¼ÿ‘áòå[ {öóÿÿÿv<+;0-üfxúø»¸(+£2@±p°3*þåäexq÷ ƒ‚:#/?Ã_V Æ?à`¥dPðò²g01ÑzœaݺýÀ`½Í e ÅÀòàïªU ß²rîì<ÂðüÙ >ƒ-àzà0ý°3ps³+׿ êò< ï|gø*ÃÁÀÃÍ,@,ÀBDøÇ`12|xÿ˜aÏÞçÀìÉÔh napP€˜˜0CT”Ãõëwöî?Åðþà1†‡·n10‰«2ˆ¿Æ¬ž$$„ Ude%„„€`døøñ3ÃñãÇÁó“áÍë¿ ,¥>þæ66€ba`dcüÇÀ®~ÿútÄ/`UÀ þ¿ He4 ÐÔTfàâædX±hƒ¤ë×ï\ ÔÕUP  á>0üûûèQ`QÎ*|±ÏÀÆ@,?ÿ0¿g–ã¼\ÿ¤¥UBBô€mV ¦ßÀtð\è  tƒäŠ% Á¶V ¿¤¥>¼|à¤$År°G@‰0((èÉ? ë7Þd`¾÷‹éÃïßÌ߈åÇoæÿ¾|g“cxÿõ?¸Vc`fç{P!‚€¦þ1ƒá·ª*ƒŠ½ DLEG^øvÄ? üøÆÀøÿÃç_DEØØ~ÿføö“ñ@Ãõλ{o€qÇÊðòÃ÷o?ÀA¾§ÿ ü[½šá;°Äã $˜!úÿÍEÃ/`Íùæ+ƒ”,÷~ýbº@LÀªìÈ“ëï~‰s30¼eà×ç ÚíçÏ_à(ðê†ÿ2|{ü˜#=‰ˆ ¤”•üø ®ª=øÈpï3ƒ”(ã ÏA!} €X89ν|þãÆßwßô„%m€ ß~ï<S€Å)?ÃPCéÆ †ï'N0°çä0°0â/’!qqøïß.œÇ ¬$ lAÉ2kh2üüú‡áÉý/O€ÊC,´Ù¿sÇÂËû1HÈq1<ùÍÇpäÀ?v` jñ½xÉðmæøxVnn‚>%û˜Ab 9Aq¢k;c¸9y¸øm”¬ ^=ýÅpáÀ³ïÀxžjÁ¤ÁÂôöÏÿõ{V=`øÊÀ ¢§Â°vÝ]†ïïÞ3°®YÁðÅÀ„២"Ã`nùê×/ÿ€-U6 6È2ˆÜ†ïßÅþ‹á?¿2lØp‹CV†Ÿ“aû²‡ _ßý™ÈÀÁv›‰ €˜D2À¡ÀÎvéË«_º~0kX:‹0ðËíó›Î0H« 20˜3,ž9ƒAEE X9qB ©ÿ _¿‚ –àvÈBP(€šd Ìc““*afX¿h¹(°TÔ“eX¼ä-Ã…=ÏO1p²¤002ÿb`bf fá,`Ç ª¾€¥Ëg·¿y>ùÄ"ææ-L" ®30\<±X³ë3†ŸÀ¬ôèsvv†C‡2\¹r™AKKœÒAñª²ß½{ɰ{×)†‡uå!*Ë0aÞG†}kž<¦``þx®ñ€ €˜„ÒêP¦¯@Gì~vë»åLRF Nf‚ /Öo†ÏÀ(àæ5½€}66†;w®Cá+ƒ¶¶68$¾}ûtÐ †gÏ€ »ƒ“Ÿ.Ã;.A†öéŸö¯{qé8°4º ¬áV°­tÉÀ¶á€õƒÃ/ÆyBŠ<¾)É" IžÌ Ü@ÃOºÏðþã7`0ÿVTÜ OŸÝ†Èwee=†WÀž+°ÀÇËÉ`n-ÇÀ"Îǰp³Þ0¼¼ñé8ËÿX†¿î2üû ôÍ/X* ì6H€é‚èˆBvÖ2-CnÁ¨† &Iîÿ ïž~–˜?}T&p}ê°[À"R| ïÿ23l9ÅÀ°pÃW† '>ý÷í÷$¶ÿÝÀÔøžáÏOtn0±BÓ‹,Ð!é ìÌ¡üâ¬jº: š*l òŒ B¼@e@¼ÿÊÀðèå†w~1\ºü“áí‹ß¾ÿÙÂÀú ãß›à 6p°9 €;€J30Š[*Ö@lL°Ê@›¥e /¤o ꊿâ»@±cÀœ|hÓ#`>Z,Œð8 À…›Ùûtó)„IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/view_detailed.png0000644000000000000000000000367311550446574024043 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<MIDATxÚbüÿÿ?Ã@€bb`@, ‚‘19‡‹©Žƒ‰ûßÿÿAbà€a1Àˆ&†^ÿÐäaúå1ô12þýóáÏÏ¿“þÿŸ×@Œ (àãM{ÚØ/Å+/ÅðõÛ†¿ÿ€jþuý:çˆþÅPö¨²Zý™”2Á4H=HŽ…‘áÃÓ× æÎ{õëë q€‡7+—„Ž2Ãq öoCY bù‹0æ˜å‘,ÿ‹„Ajƒèÿ¨jÿmüÍ!ÈÀÄÎÁ ² €Àø÷éï—/Ù?AÂdà˜¯þ£Zþf0L)„`ìÿPõp½PÌÌ4ÿÇo ÙL ð` H`bbøõ‡‘aåš ß?~g``ÂŒ_là?rD#304‚¸L@ñÌl Ò²|`;A €X ˜>|ýËà,õ¡0WèÒÿ 4ȈjÄ$ ˆ(º6`ü/Üý’aÉõßÀ¤È  ˆÑL ¿©DX„‡AUI˜Êí?8.ÿ㉙…ARü'ß+ à€„@AÀÈI¥ÿÁµ½Þ¹‹áõÉ3 ÿÙY~~ûÀ ¨gÈ ŠÕ÷ j@o2Ãù8ýü§¡ÿ fþúõ—‡ç?0Gü¦ f¸LÌÀ`g„ñ`¼Ù´‰Oì›ØG†ï¿1<ÚjÉ íâÏÀÆÏ6ôÛ·ïð<ÏÉÉ4 ˜Úÿ2|þü(ÿî(¤žè{.°zPÂüω€‚†#8X`qô /+ƒ˜Ì 6ùß yøÞßâbø÷â›'Ož2W}õ‡¡µµ–AMM…áÑ£ç ••õ ?þ;¾~ýÆÁ P‚`„%@Ar=P)X™}`ø´ˆ‘ƒáצ¯?)¢I@@€!!!賿`‹„……À>åããZÂðTò00‚Å@EÑïßTUUÌßàgS¨Y&p~g‡ÛL±|â O·Ê0023|–(ÌÚŠ ,<å ‹¼½=àŽY²”‡‡‡ÁÇÇ Iœšþ3|ÿŒš?¿áQÀÀ 1 € !ÀqRÞ+ªfø‘N †sH 30³23ÀjOpùþÿ?<¾aìïßÓÂ?püƒJ@ˆü_ ÿ1p±³BÔAª°9-X€i€¥ì`ú’ˆ1S;ÔBh#ðšÝ –£: † QŒO0 €ÒžœŒTäA|ŽÈzÿÂñ.‡zH6„YvØ F° @püù‡¥ü„W  ÐDõÅçÈ4,ÏÃäAE,þìß¿Ì`—Ý Í†„’ÿ#2ß?føxíÃ?&VpãS–aàSU–ÿ|þê[XPÃÒÅ_¤Ð€òAŽƒñ`# ¹ €à%!(";àÁÔi ?îïf`ÿÁðíËc†ûln V}ËÙ™ÁU <¥ƒÞŸ?€!ÅÄÀÎÎìÿØ?€¡ð^ü‡¦€‚˜ÂÌ®€ eÇ`©Äò烆ÏgN•Ï ?U÷Å~ýÍÀÁÅÂðòÕ;†õë7ƒ-eaafpwwe––dxñâ5Ö-ÛÁâ2báÏŸ¿tõtmŒ Qðè( DøÏˆTÛ12°1~c`~,ˆ¸X˜yþ2°ý…„ÈÀ_¿~0ܹs hÑo XììlÀ¾ÿõë'Ãýûw€¨¶c„'Þ?~2ÈÈHãø?´€UÇf¤zL¿1|:ð•Eh!°íòÿ 8øK5QQ1†ÎÎh*‡XðéÓgAA!†ššx°ƒÒ $!þFÓ/`ýñ ©qq@¡&B¤æ¥Pt6Ãç3Ö ?YØ~Ëv)-5 ˜þkµà‚å/Rþ†¥þ¿@ßÿWJ ÄrHäˆß õÿ¡-¤l@(‰, lÇmjÆÈ-š_@Ÿ22ÿg`ü-çl& †5V€üÿŒP>ˆþ f32@ÚhÀ00¹1BZªÐD@ð9àû— _>gø -\`63‚ ÿÐlôÜÞƒóÿ# ¡ÿ¡b PçCFˆ¥@±í`&vPh2ü焇@Áê&^^v†ó÷Ø"zV:þûÔFYÄ‘[ò#´hþMdÈý€H%'3Ó7†Ÿ™Ž“á/#¤x °~ÿcüóîÍ[ny †w_þ‚5ÁZÅðV0´yÔ†ñÿ1 µŒ‘ZÐèfü÷ ˜˜~¼‡G-@ðëÃÄcæ3mÿÿÿÃÖºÅèaãÿÇ/5ŽñßP"ú³$@ŒÝ9 ïœЀ; À…F›Kî[“IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/finish.png0000644000000000000000000000377711550446572022521 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<‘IDATxÚbüÿÿ?Ã@€bb`@î€b1MfA@ü-¿þCØ(à*Ã׿9@ñÕ ÌL“þþÿÄð(ü¨öÿe€Ð Xý”øù›¡@¬ÿÿQ ˆ@˜!ÒÌ´™ ‹øßÿé†bzâÂœÍ Ÿ~îZfÕ[ µìŒØd˜8ˆs`„= @Ê8™ !O£ÿ™¾ýfJ ×d¸¸;ŠÁ×WÕ’éûïÝ ?ÿô102 `5‡ —ó~Á8Ä„Ó Ë9˜C$úïçÏ¿ À`X;Û‹aJ¿ « [!Ç¡aeÌ„S@á—Èʈ’`¹–‰ñ?Cf¬.ÃþÍ¡ >*z Ÿ~mgøõ¯ ¨–î\& FfF¼V~ÀB‚ìPŠ‚§ª/?þ1|ÿù›A_[„aÓ2_†¦V;^`€u2|ý½¨V%=áq@± ùV胆ßÙ€qúàÿ¡)Èûû˜$ÿþ 6ùþ‡ÿ «n²2$êýaPab¨-6cp°‘aHMßxóâ+M>ö Â£`³Yþü…5G0ÂÿþÏát‘`‡ä¤ÿð”Ïtàà/$…8!Tpå冺C, zÜUþ2ØšK1lßʶKãàÎ{›¸Ø¢€Šw‚C€ 9ü €øúG)9Yƒ¡2A‡áë×? Ì ôŸ‘‰ „ŒŒ@÷02°³0R"Ã`@°ƒ´ýbc˜vŽ™áÞû 1ºåø6®öc(*Ù/4oÖ…U ìlÉÀ´°ÿ0‹}€bAŠð?œ¬Ì Ìÿþ2üýù‹lŒ@Ë!‰‰ˆ™þ3üûóáÈ1@ßü+ÐVf6†-w™}d`È3ÿË ÉËÊ0{†;ïßÿø–Ì¿4èˆ@ ö`‹€bANòþýæœÿ ·Ÿgèßñ† ìl@G±±20³°0°°²€Ùì@‡þøÏÂðë3 (uÊ”»ò–‰¡ã3C‰Å_Y~f†i“\Þ¼þηcË­‰ ,ì@¥¯Ð €X0²0¤>}ûÍpâÐÑ,¬ œ¬ ,ll ¬ì °‚Àr;+' ‹p¦zô”@¨Ùð?(±ƒRà? Ïþ2°1üfê¿@ü‡å?³#Ÿõÿo¦¿¿þüúÁ¿AlþÅÀÅüáÕ7†)§™¾ -9Y^†Ð5 á<€¡, b [ @,˜yÏÀ”2èf&X‘ñ%°‚sÉxiõÌùafeøð“‘á°Bã¦TnnPÙôŸjJ$ ªÝ@Ë–þùó˜~10²üóYnfþóô@6ÐqÌ¿4°º`€•1làŸÿ02p%RtDx™¾|ýͰeë=Piv¨è%ØõH €0Bd! 0µK 0+6FPrcf › 茾üþT`þgøt¤#C¡)#ƒ• 3ØaÕ5NŸxòhÈ$p¡†V;Š@ÙîÛÏ? J ‹Kµ€ÙŽ ŠÁ43ÿfA`™{éÉo†Æ-ïàUþ`BZˆ¡Ü†ÁFh C{×I†I΂\Þ´ö:091£{ €À ʼ¼Àef?&Hù* !ŽÚÍðT2þýËÀÃMx@±¯@WX¨°09s0èɱ0ücacèí?ÃPUy˜š™A:“á÷?,ÍO€B8€ƒåÃÒ÷ÎÝxÇðd ¬(†¶p@Eñ¯ïRí{ `F0ü–ÓQÖB 9N¼ R"À†3CYñA†i>ge)æë~HK {e@°2æÜºó1èÖµ·LКÞÜú tÂ`eôùwœµ‰¤xˆ“$°&üà ÊÍÀï%Êà¦Ãà äܼ÷…!3o?Ãþí÷ß3p³åƒl)Xÿ¬¾€bAªzOk- FJ¤@ËqF{66&ñ¯ÀªXV…aB¬4ƒ¦,7Ÿ7úíò‹1<¹ýþ?{2м3p_ÿù‡³: ¢š®0AÚ8À¨øý‡A˜‡™AJ‚‡áý×ÿ Mͧ&O>Ïðûç¿¥ ‚ì¥@?‡·\þüÇé{ Âøƒ| ´À ¬ÅÅyŽ_zÏPT}Œáâ©çoåpËhVC4Ÿþâïø ΦØ?hóü¢EL›Ü\¬ lœl M“.2L˜q‰áÛ»û„8J€>=’Ð@zð$> ìø µü?’å  óÞcÏ–®½ÃpúèÓ×ÀÆA#ÛT¬¾ aö `M6˜@±`õý4ŸCÄÿéæÍ;È-ÜLhÀ„y ìXlà'Ö¸Eè ~  ÆîœЀ÷ hÀ`L¦Öð ;IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/kcmpci.png0000644000000000000000000000375111550446572022477 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<{IDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €XrsóžJKËñüýûáË—OŒ¯^=ÝÀÇÇÇðïß?¬š@â Ä £‘ÙØÄ°Éÿýûl@±ˆˆHH…†F2ˆ‰ 3\¸p‰¡²²HAPHØéóןlÿq9€ l¬ò¬,Œ89ØË£GwgÖÖVØõöök²³³2|úôU‹‡íG·‰.Ëÿ¿Ì@ë³)#P3Р!ÿÀ4ÿh(È’ Pö°OKÖ¿Þ;î *Äfƒÿ.±¶ 0Ø5“—~™l™¡}L£”b¯bANT ?üd`ùõ—2а>þΰ|ã^Q!n†@?GF o_¿ùÀpêüu†ß¿~£îÃß?¿‚Ü89ÙÁú¯Ý~ÎðôùP´2<{ñŠA„ç7C°£Ãÿ?_ÁQh$ƒa(ˆ¾B!öVžÄ³{ £!!&°PUiÚòƒp™7/£w»ÿã°éÚ8“Ño 5ö=2 ©7„é.!žä7Qæ! ØÜ¢T„25nމT mzªö%€ºG§‚ôxÆ=¯bí²ö. ³^7€ñ÷ ÃÏg @…8þ1ädFž-ÿtƒ'#ƒ‘´6$¡ƒ™áãU†Ÿßž1üùùŸ…™‘áÏ×× þFÞ.–/ œÀøÿ TÃʯ KP Ä‚HÝÿáé â„?ÐDôèÚ?ø¦^†ŸÏÿ|'¿ÿ¡Ùìß/f^u†¿,â ÿþ¾GÛïßÿ\Œ8<5Ù€ÚÅéèóSnYˆ}@Sì`€³ ,* ¦þ„Â?`в‹0üøò–á̱« ¯_>bxÿæC€-? ÐB #þþ``då‡$Ø?þ3‚S)ãÿŸÀ¨ø 4ÿ?0~-d†š Ë „‘þ!GÐç #Ÿ>Ãï®_¿ÆðñóO†oŸ?'0D˜ÀêþóPýߟ@ ÐìtÓÿß Ì@GüeüÎðûÐaÀ\Äðÿ4104 iä$ 6„• â£ß߸ùE‚‰“ƒáÿç›À¨xÂðç7$o3-ûìÐò¿_zÙ …#Ãý×l ¾¼gxó˜…Á@þ?'ÃXá y€Âš ™¾|øÈðôÞU¡¿@‚\ü˜€:€‰ë(ÿ4àtr+0›Ó(áýþÍÌpùúW†ç¯Þ3¼xÎÈ &þ›ŸïJá@, ßBBà4€)˜‰‰áåów [Ýa(“€ºš>þ!•lG£‚…W…•˜8™Áéêçן ÷cxóö#ÃÇo€é…,-ÙÀ €àQð^ª‚*Œ¿ ì B‚ˆlÉ+rꀶ‹â?ÿYÞ?¿ÊÀðz?+ÄŠ_Àì(ËûŸAˆù7Ã/þŸÀ”™½ @˜QJÈÀø“@G€ü÷^!ý‡»ÊG°xe`8ûè Cò!†`‘/ õæ§>ÿêgÿÇàoñÒìøÏÎðó×p5ÂÈÄ w@Á³!¬(†T ê’•›C_ÀüÿψÔ~aÇ93&³°)8¥s¼`düóœATLƒAA‹\ÀÂÂ`E3ÐòoÀQÄ F¤l,‚€>àýÁàjgÎðÿã`îúŒ Cþ±€£ëÏÏ/ ¿¿¿gàWbøùæ<ïWD¾ÿgXaÊëL Ï1A²RU Ox tü˜YX™™˜© ‚ɳ30q¿``ü{€óÓE¹§ —ö00)Ë^ þÏËÀrö0'/ƒÈ†§GØÅ¥:'½üyãʳLL 4ôŸV;"cx;XƒþüË ¬6} ”¢X>¼ùÉÁÆÈþíÃ'`èf`ÖˆÀÌð•˜Í~]ú X5ó;‹Pì°²Ö ì ¾2|^¿e"0üÞ3@Ó:~v@ÁCä*66†Í›–ÎÖØ½KEÔÂùÏ,é~K€‚÷9$¡þaÕöÿYŽÙÀ¢šù,û÷__21ýû ɨ­(ü €X@©è{Ö7o^0üüùáíÛ7w;– ”“'£…ý“ÔV1@1jkk3XXX:uÊ¢=>üáÇ]ôj–ã@÷ hÀ;&4à w@€–ûF©°è¹IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/noatunplay.png0000644000000000000000000000252611550446574023424 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<èIDATxÚbüÿÿ?0šÌ’R€Xˆ Φ/d 1Ù @LH|î.°àça[À`<ó<ÛÓÚÄ„.¬Ëpqu$CJ°Ž8DŒg®byZ9 €0ðå7;C[žá%‘ ¦º’@á@GÔ1?µ@Xðãï¿ JR¼ +ú|f´ù0Hˆò4¥/OMNÜyÇÀðô3Ä!.&R ›æF1Ä„+psÓÇ~j¥€Âꀷß^|a`¸ÿžáâ †Û@ǰ020”&3,žÉ`k­æMó)M„á€Ï@|â÷?øÁ†“On¼a`dgh)r`ho bPQ•L€FK=¹ F¤r¤–ÌOó}Ä­IŒ›A˜¿þf`Ø|ðÃÚÕÇ>¼ÿòZ~l$¥ lQ~àÖ’»õ–A’‡ÁßAAO[’aÍ–+ §_ÞðÓxæ¨C.ã€ÂtÀO¨%ß k©¹ tˆ¢;Cz¤1ƒ¥…úgî\ºŠ– @% @‡|Äg@aM„/¿ ¦|ø50ÁžzÆÀ°í6Ÿ /Ca¦ƒ‚¿¨p´üÈÇç€ÂHÅmi`¼üJ^¢âfe`Ðg``æšÕ;o2Ü8xœáï¯_ ô‘ ƒèi €0¢àë/hNøAž@úžË `úðsQgPÑR`8uäŠÂó³gAÙöÔ!aêˆ 3e20üûÄÿÉáTˆíºËÀÀÌÆÎìoÌ`ÉÀ//ï/Ö¡ €˜¨VµB1:xL‚ÇŸ00 ó2¨¸»3(»¹1€'¿¾1ˆ@,Ôr#ÀÀ[`Žyyù20*€Aôó&ÃGH. ¬•ÿä:‚‹C>?{Æðøøq†ïo^}før§—áVß ðK@a8€)ïe"çÇ§Ï cøø˜æ~¾^Æð`Ñ,†/·žƒÓП 5„áv`6âb£Ìâß?2<:w…áñi`pÿùv–áÙ††×@-þ‚¬ €0Àr;ù–?¸x“á0ïÿùþõÃ»Ó ž ¿âçØÔÕðêÁ3†KÎ2|xüä3÷dzn´/ ëO``À™ª{à€/ï?3œÞ}–áñå[ÀX}¿™áþ¼^hœexs¨—áéúËP‹?ë€Âp33°<'—Ï>`8²é÷÷ïŸ1|ºÖËpwÚ^h<¿ÂÜØ@a8àÍ/ÜQðøÁ†]«3<» Œç/—3\kœçç°lE* `³üÓ§Ÿ ›—g¸rÏ/¶Ïf+ ‡áz¶"^ü¶Ž÷l8˰g+4ž?\˜ÍV ”ý–E8@átÀéÓÏ–kÏ/ï€ñüõÞ,hñùŒœxÆÃÏ•ù²Yn\Fë÷g³-_ÌVO ©û•@!·ˆôÁMlpYúùÃóͽÀx¾ µø  Èn€0G0è÷3È„†X Ö7=ºçª#ã*ò/IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/fileexport.png0000644000000000000000000000307411550446572023410 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÎIDATxÚbüÿÿ?Ã@€bb`@,È%%E ff¶&!!Q ÷ߟ?ÿÿÿ÷áßÿ  ‚`ûß_ T‘‡Èýû• ;s133ÿ ý|óæÅ¯_?ÕÅ®#Û @(`gçêNN.ˆ166aøû÷ƒˆ¨#Ð@¡0ÂTÿg`d€ÒŒ@98Ÿ¨Ž¶ÿþaxøà1—ÃÝ»wtÛÚÊÅ€ÒÈvФ¥]íì€Ø}ePÓPa`cceøódÔ! `>8þ€62133AÄ@ñ r 0ü¾|þÀðóçMM-cô( °²²üûýû7PÈÀ¿ ¿ýúè$ËÿÂð_p€²˜b1ÔÌ@þŸ_?Áæ^¼xá÷ï@óYÿ¢; €P!###,S0Mdšö!3ÂØPß‚ø èã¿Pú’ÿºT[[—ÁÈÈ”~0²@¡„ÈdH<3m`Ú¶ œÚ ÎY L‡øEÇ_Hˆü‡&€ÿLqCÿ10‚ÍäææšÇ Ö‹‹ ädÿ‡ZÈøÁá÷êk`Zd`ù$ÿâPf æ¿ @ÍÌ xAÄ‚= ¡Ž8™0`ý…: äcFX$þ‡Xøê8†°DÈöÈŸ?ÿÁæ2b €Âpÿÿv-²P¢‚» ÿ ¾†Šý&NXÈü;æëH!Œ„áD"Ä¢˜ ê˜O™ Qò°€F Ä# Ðb‚;[Ö4*í@.åÀˆŒÿ†ÀÓ7RV9ˆ‰â2X¨¢€Bs#¤rb„&BFìå73$-ÀÀˆÄf€f׿à, KKái ÞøþýRùþŒÿ€̇Ë R) þBË"X p°€£ƒ Ó„‘ `ñõêÕg†7o¾@ƒVmCèÿдòŠrŒPŠ ¿¿C8fº ¬¹äÛ¾€}ñ XœþùóÈ ; †Á3 Š8Èç :[ QÉ>/_>ex÷?<  E€¤X"{ûöý{øùùôõ ÁŽ…6Î’\ëËYkk#55e`0þûç Ç`l Ç_V>W€U;4¤U933f ¬iàRñ÷/DóçÏ_Á%*v,!©ˆ@òòò«tn¤´2ƒk €Ð€(ˆ ®fVÍ¿30¬Zµè»3  vv@ñ_† Â\\œ@Gr@+ŸÿPa€Bq33ÔòÐxýL„€uù†OŸ>3¼~ýšáë×ï`1FÿÁ — œœÀZP°P`dÄ,ˆ# ÀÍ«ÿˆ¢ôçÏ? ß¾ý;¯€þÀâè”[!ÀŽX B€ÂQü‡&H€¢á°u2 ”@|Ü€„''’Y0Oa¦€ÂŒ È}…?~1|üø…A]]ALLœAHḢÔñ¨¤$ÎÅÅŽXY.ÿaφ„, E Å(øNýoß~b—b””§‡7o>b͆ ‚BÔbgç²ÿ!PÌ Ì‚® €P^¾|vùíÛ×N""à2ŸXñ2hh(0€«ø¸B·oC| Š‚OŸ¾ƒ£dùÏŸßÔ­Gèúˆ9¸]\œ ¥¤ä&ÈÉ)ë5þYÊ Ì×ÜðÔŒ^ Ó 9Pnùóç84þBëd`Ô0ß»wûáµkËïß°ÙÄ8Ð}C€ð¾!@ ¸hÀ`;h.÷ÜA=IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/edit.png0000644000000000000000000000256311550446572022156 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?Ã@€bb`@,ÈFýDuA ¹~1i†ÿÿÿPÓ"F&f–·/Ÿß|ýä~ñÿ sOÁÄÅÜ‚b-õÙžþ¦b ¿~309Œêÿ?«ÿ ˆËÆÊÀpüî7ÑÜʾ × ¦ €P &®n£.Æ TÌÀJŸƒÃq£¹ƒ¤Œœ,²<@¡¤ÿÿþÿýõÕßG/Üa8}õAKþñŸ 7¼bØzä*Ã/ ø`dþÑ¿€ê€Y/@L„ ×dXºù^ËAN†9fú‘37zfof`Êp°@B[† Œèd„DèG¯XX™^üÆ $À‹×ò°8‡†Ð[Œ¬, Ÿýb¸zïØLE) a@aˆ°030|ûþ¡¨sõǯþÿüÍàã Ûr͇2âB oŽ)žÊÀÅÎÆ°´3OR–^á €0ðç/''ÃüöT†?@Èõü<œ}Ž߀9ÈÚHáÄÒ`œÿ+ƒÃÏ ?ÿ¢Ú@,˜>ƒ$[a>nüÁŽÅçÿ‘ä™™øy@iä)P¡rïÃÓO¨æ ©Y ŸÏalñˆ¿þ‚ä §9Y°'B€b!Ùr<>‡q@Áü d1’âÿ8r@v’ ùDÿ†õï¨bàrâB?2 "ì'Êçÿ –ÿZ‹ XÖü‡Ã|€b!äóh–üÇ"  þñâKX©÷=´.€…z6 B>Çæ[döoP|ÿEø^"‚ÉØ*7€bÁf1ŸÃ| ²ßH€…Ä_ä4À„=ˆGÍŠR¥"ûd (ÈA–ƒèÿŒHA΀ˆotþ?¹ €0ð=˜añ ÂPÿý‡dÁ?LŸÿc@ •Ðt‚ÍÄ‚î{äøµ¤ù÷?4ß0ö9,ÿû;¥:~ûáÉ'¤ ºæ/#¤.‡'2´|ýæPt>¸fÉüGV ”åãÏ¿`©ûÜGÀvŸ£…È$‡‚,ÿ t,è™f` €Âˆ6F†¯ß0$V.`¸õì5X¼0Þ“!ÜË„áã´àý¼0>°öe8ué>CÓäå`…œÀa[Y‡(†#‚ò5Єä' Áÿzfl`8íC”· $"'6ËAµг =gøùí+CiN$Pƒ °Qóâ f†þMadbbp4WcàZ¶j³ÃÏßà2àñù¿ÿˆ´ðX‹ð38[k«cF†¿ šñ#¦# þCóùçÀ¼l[šë2pr°2|ÿ…ÏÈ¥2”–€ E{s†O_ æ±1c/ 5˜˜˜ÙXØ™ þe<0èAÁúõ'0n™¡–1!R;ŠC …Ò?`4šè(2˜(2|ùÉkÀæ%+¨qÊÄ„’óÅ?¿~pìö;]%Q!†ï?‘*#¨EȵrT ‡ J%묀,Útáñ/†ï_¼B¶ €‘;§Œ ƬbêSd5TÿÿýƒQA0¢ñˆ£„.3Ëç—ž~z¥äÿù¹»`ÂÄ8нc€ðÞ1@€ÁÞì<(Ä‚IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/kgpg_import.png0000644000000000000000000000532711550446572023554 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< iIDATxÚbüÿÿ?Ã@€bb`@Œdébº[CžA€—á0xþþ]ÅÀúÇ‘ä©ÿöüýÿ‡á/ÛL†b†Œ`ùÿÇ.1#®`aƒ²`S ÄÃÀ §ÀÀð÷„ÿ󗿪…ʆæÌtU@7¡ÚÏÂÈÌðæûG†Ò承>ÿ¢ÎÀÂ|ì€CWˆ›ù¾ M@üˆ?ñC ~²a"ÿ†Äÿ×O~yAo } ƒ½æf 9_Dؘ¿¾øÅÏÀÆ — Ø1?ÿbñâ@,ÄŸø?â7Œÿþ³e9?BC€õߦ¯ OùìÀ0ýÊð‹áÓ/`ÐþùÇ ø.@(bu þÄÿPGüƒF 0Ö€Ïðöíw†3?¾3|ã‚ZÄ +Ö ^ðn=0>Ø€¾ÿ4áÚ‡— ?ÿÿ€¨eD8 €àŠ'Ôç à)ýË&ÿ¡Qâó=arâÃ!/a˜þ3°þføtÀ OA hâÏÿ¿οx̰çî-†KÏß2|ùû è“ÿÿ= @`±#Ô¨e†B"ÂK~þeüöòý›5À_tàm˜& L0cþýgb`úËüŸù'0š^£A >½g8òìÃÍׯ¾cb`ç`aøÆö—áóoV 43(_€´ R¼ÿ…ÎÍÉÁº°²×\‹GQ•áèî&‡wܬ¿yö澯ÿ¾/ç``ØŠ…ÿ üÃø¯‰ƒ5ä?Ëþß@\ûñ€áÏï /¿~axøñ=÷?¿Dx9¾0ÿcøò‘áç†?œÿV3°±Óê_‡üˆÅH #ù€= ʺò®À<.ÀÅà§)Ëà#Éy늅÷ÁÝϽí¼öüñýÛ³þÿ¯g`ÿ#$­&¨é©ÃÀÁÍÊðîÛ7†_¿ÿ2üþ÷—A˜“›ùÃç_?¹.ÀX¶aøüETñËÕ· ÿ¾g!€bv‚)$ñ…Ø;Kt…U“/ЋÜì@Zèay.c^wUÞÏï…íož¿ÅÍÀò¿ð>˯ïZ˜™+0rss(0›c…‘œn@åÔ?`´ƒÊžLÌ Ÿ®¼fø}ïÍæÿ U߈YZŸ¼Œ4צ¢.y®ó{î3\zA”ñ 0l€¾a`fFn V`daþ‹áãK1ëw»o0±ýú_qåý·»7^¹ê+0ˆ ð0üùÿœAäß@Ë™~þþÃðhßC†/7_-``eŒføÏôè€bÖ‡æFfÆ5%ýÊ:_^¼bè.{uèÜ埯p:Úzp±1ý„D¨\d†ƒ¹Å†o¥í_ï½ù‡û+CÇM¾Ïw.]z䥩&Í")"Àðã/°ä•”ÀBëó§ï 7Þ`øxïm+0^ò.ú tÈÄ-nËB’Åœ•ݘž>úÈ,&vçÒ¯ŸÙüg¼û@üНCD€QB!§Cœ! Ù·Eé6S!ÓÒ×o?x÷ôoz}åÚ#`iÍÅÀË L€o¿2[qáï‡G²8kàù R ¨lr36åjðÍâ–h Ùì­Ù«T4îGUè 3 _*{Šä€Ç@| ¢Àôñ–ÁÙù3‹5ûW 0'þ¯?8M²ãæñã7ž>xðeþñO_~ f`g˜Ž°ˆOA v€bÌàf|Ó²LJXXèïßÀ¢èj†À"X -z´ŒšW`3°ÌüõŸá÷• =±ï>_¼öÇŒ‰áƆçš@é÷ RÀœ¾’™™IúïÏQÀÊऀa„=»Qs ÀJ €˜¾ýü¿ÿÌ`•ÃtÖ`qó !ÿ€¥>×E`Êx)—¿“è¿—Ðj ï÷3<¾"ÌpõËG ‘9òÚÈÀ Ï€)ÛéïïpËa•ô¦?`Ëa €˜õþ1l¸xî·†×m9; ïßÿ‚ ÿ¡ùó"ŸþgþÁðìØg†¿¿0pJò0J12(éjñÝ>÷;úíÇOo€9/Œ!öOÀŠKŠáß?.`ÁÈ-ç¥0à ~…(†ˆ1b>'0p¶t°9†Y~Bâ ˜û800™ü~ÎÀðõ<0P¤…„ÍE€i ˜%/É0,núÎpdÓù%l ÿŠ8^ª}¨ÄÀðXžñ«Ò»÷€‚ßPk^PØ ZOÕ{J§2¨»½ÿì?¤fâ„b˜#x!.þuX`gà´f%‹Ü û‰0¬è¼xçó§wÙ@ûw!Wµ bï$_Es@1¦Bs8T‘'Ãî°,5«`` ?B£æ`áÈÀ `p¿&•_òâ "ºü ,ßÿ2<9*Ë0¯ùåÿ«§®·ÝÛÈ5žÜ.€4l¶ 9 €µ +¨#˜ ޲ó%Ò<"D¬ü€…!Í¡ßolihúš!€š~\:ä'·‘4?'°º+̰v&ÃæYçŽþûû-›—‘«ß9H pi Ä–Hmh¥$ é<%i†ßAF ËÖ.eøçîÏÀdçlË#y ë™@-`®e¸Œ’gŒ T¤D¸€ˆ‰áÊ.i†ù]w>=¹û¨ %3afŸ€”$`¼Qj uÈo´&Ð!ò@E…@—+åêBŠR ÙÏŸ3 1œ=ùú.Pê ȼ`A@Xûÿ!iŠá«BÓ<€„087¢äÂ}70lù÷€˜a”Ÿ=f˜_«ÀÀÉ lþdøÏõ“AÕü'?—í·oˆ €X/ÃMDkÄ¿­–@@ˆ†ügƒ(¢g®?fPؼš¡Ã˜uß«‘7ÀºîÙ›ÇÀ^Ý? cÙX å@1RÚ¹:BÍá@ƒY-³]ü¼ j?3Üýñá:0=]NÇ€rgA¹à0 ã@wÏ Fó¨I"²žIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/irkickflash.png0000644000000000000000000000565211550446572023525 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ÿýü™áï‡@Ù†ÿþ’ ôÌt6Ø ™TÔÆÈɹ’UJ wrÀP(Z¨ d?ª» äßjyÕ*ô­ Hžñß?y —Ÿ¤ýzú”áÿá@OUC'¨æ ²= hƒx*PA#;û>VYYƒ¢¡Q´xÐÒt&NÎ{LÀ(`øû% €¾cø Š‚?”€–'Ci=Ðç}l²²K?y²(þ¨n*С@×a"þÿç² 콌«Ùdd˜Æ7-·Êæ0qs_Å=/0!Z€ Ô#uÀk ¥×€ü ?~|úýþ=ÿ¯_uü)ÀÐ: tLí¯'Oþþûñ# @ìÔó ¤ €/‹ŠÂ|1 èû¯Ìœœ…,ÒÒ ~0*ô‡3 |Æ?0xAA Ôqá?('€´20H-Ò³¯úÏÄ4ñÿ÷ïÿþ¾ÏtÈJ`H\:¦ þÿüÉ ä§ƒôãeqq­ ´|.з®lŠŠ–DC" H»±++¿<Ðà@±÷@±N û"30ÈÙY 1ø˜òÿ‚¢„‰ äë2`0‹Ùé@uÞ½Ë*€bÓ€ô²_÷ïó´çÿ¯_‰@³®s//Ðâ. ¯V3 dææ–cba™äDZ ?f=y`¯gbg_ÔPÁÁÆöèc†»3,Û·áäõë B\\ ¢‚‚ l¬¬¯þ㞉••hy7PýN`zz ´ì= ¨o Я€!ðhDo Æ+’’ @Ÿ­ZàÌ"%õ…‰ƒ£˜ç¿-®&BV`Ðnebc[Ì~ÓÙ€>¾q÷.ÃîcÇn>{Æð)%«s‹‹¥%ƒ†’Ã/`h=•ñïׯ` ¼~?~üûï·o­À¸çFAÑï§Oyþýü¹È &`Pyße`ƒâ™h¹!?“YX”03û4d:;''ÃΣGúÖ¬a¸÷ õ ÀÌÄÍ Ä ‰õ¯]˰ëøqv`ˆ0¨÷ÐŒlY@þL`¨2rss3ì• @»ˆ h¡)ÐÂ@APÂs²ï G@ÌL±ÀЩçZ~óÁ†µGŽ0ð-–òŠ +î{±$ Lò 9š@µ =@½ @ŒV^™ ³rÛŲÈ7 &PÅtÙC°+-A ˜Ý€bÖÀ´ðèÊk?€AºíàAv ?Ä ÙÖV{‡EZ©ˆÆ32ˆ¦10„ÉíF‰8Ðh†]@µ?€ ¨÷:ÐXY­Af‚Ð>Kf`ÖÙ €b2ø€‚ÏA… -Îr%8|• ËP©õ(w˜è@UЗÑQ¬ Ƽ&F T•À逈•Œ¡ *ãîÕþ…¹@3/=¥6h6Ð|qpÆÄôÌÄdüâÏ`ÅLLÜ@ö;0›™Y H?W§@ ìÀl ASþïÀXŸ2—ùÃW Y†¿‡”¦ ôÀ TË1”Žž="f32¾cÙò,ÓW û7@±0 ×Õ‹ÁÅ*˜Íç`yH¢c_·ïÿýÏ ÿî?Ã/hepäk êºÍqD/ÈXí dƒÌ†·/ v#01ñ‚5€\ÅÈ(ÄQü(. B°FV b6 ¹ŸVlf`x}È> Ä€ø0Š\‰=ˆï¡X¨ÿ#ÄSB ŸCÙÜ@»Xä)PÉ'Éðó'ÈU/ÿ33«€êt û€ÀÍÇÇÂð¨èˆk7"WsÞ ÿ8²FFp TÀ‡†2póóƒrЯÀšòÆH¢TÅ=°`¹Sˆÿ00 èÿ ?~Óq ët€õ8(˜Ž±PLXº1è2hÊË3ü†ñ^`nXÂq(j–ÍÙ ’3PWgÐÒÓcø v&&- ZY`: 6h6È0(4ÿ-@1œF‚¨-,£wU€¾–²¿ ]TØ Ìì"À:CXÜÂJ?N`ÂUc¸WUÌÌÀ ÷ôð`àåÛZþƒ÷çÏg År ³¡v@ÊFÆSŠ‚í@®°öâ¶d¾]{(‘ñûåKPój6°–9 ÔÄÄðFÈoÀ¦® $[‚l5Û˜~=±wçNP‘ ,º9ø,0¸g‚Ìz2¨ô<È ]<@õz@þ€Å–\Á@ `Kh™¡ùïË`H3´3³°||ûú5ë÷ïaú\EÀÂG$Î%ß¾1¼ªfqPÚjšñ˜ 4Ž™9d0Áí¼Lˆ ”€–öe]ÉlË=òÛ€fÍù÷é“°â``xñ‚áâáà —>gE`4Èk .˜xl ä€QÁpåÑ#†Ë@µ = ½@ó@͵9 3éìÐ>~ ;ˆ{Av4ÿ_÷9 þÆ¿oÞ€šVË€.\jñ}Àð÷Ó'/ÁE1ÈVFFYE~~F`Ó\ ƒ =PbÉAB„èx^Œþ,™ù÷Ý;Pn¶˜Ïí¼ ² €@å¤ãðÿ)ÐfÀ° û j`PͲo€²Òw`Úsö,¨åJ€@hkk3ðÛ f±8ÄbYPô€ÔìªýÔÒ ´äЬAÑÇÌúï÷oK ]%0{ˆ ©Aú ÷É@×Õ59\òÛ÷ï K·og¸ RAYM‘QA\AA€ƒü "_+üƒ––W‰nÅŽ`½ Ðûûõ+È!Ž@6ÛIµUÌÈxèÂ|`°pþ¦ú¿·oÓ&+ß/Ðo(æàPf¶%y!% ¸A åWP6È¡à~Á­[ ¿@!i†s´ã¼5 „­k¶Ü?(_ðXr±@}Ô* ,”€=$`vû v`:P¾ ¦Þ‚ÒÉ; ¾/@O°Íø )ÿ·bëš¾~0$æ]¹ÂðÜÐÄ¢"‚‚"  † X;òA«c`4ˆ e&§@= ½LЊ  œ`j¼ ,žã ’÷Á d‰¼¸¸¸ò† ´0RöŽ€V‰þ‡ª‰ƒô‚Ì`Æã€ÂÙ;Õÿ‡ž<½0Eÿ!YQüÖë×ß8ñõÏ·oÿ¡ýÆÀ˜Éý…¦ÿòl††®.÷ÿ°Ú`L2}ýšg¡IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/attach.png0000644000000000000000000000435511550446572022476 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?Ã@€bb`@î€p ŒÁÈØ $ÿA1zº@æ3Bi :&ödF6Vƒÿ?¾•20þýT¦È, Pøÿßßïÿ¾¾ïf`gxÃÀTÆ!4+32ü¿Ý 6 €XÈs÷Ö4—§ *ú’œ k·r|vŠ žÁüüÃO1LkØlùãþ­0–øL 2¢èFޝr߉نœêâ \’‚)¢&&ÇÊ'øþãâaà“bÈï µåTÓØÌðë $±š@$:à;W[@owtŠ6㾋¿º3Ö2prq0Töûs}øÅʰdᆥËï20òp1ä6…™ðjlcøùÛ„áÿ?¬&‘¹þ3'ODKPeD¼:Þs¿Vµnbça(íödxö…‘aÅ¢ ¿ï­^›wgõʆå+î0üádgȪTеXËð矶 "Òô‹“‰OpFBgP¡_<ÃæÃßVT¯a’d(íô`¸÷š‘aåÌ¿¬Ý˜ÅÀÌ4ùÿÏo7./Y¾ìÆ¿·¿XR‹ýåµl61üüëÆðÿ/ŠéD„þðsHʬΞ™âä)ðvÏG†Õõ«ÔMr.=d`X5õàÇÇ[¶†1üû;‡¨…h,óÞç;5­ZxúËÃL ©E¾ââF^ë~3!G@1árø%Ê)#½"j°·‰•0Ú­¯Öׯb0tÖaȬ´d8—aÍÄíožïÙÆÀÄ´‘¨í0‡s _³¤zè§3kæo^vèÙåG Q)NÜâú~Kþ³&Àl &<Á.ϧ¢´>wr˜‡†.?Êu/¶toa°1gHÌ7f8~õ/ÆIÛ¿=t(€‘iP Ðgi…‰¯Ï*( 6§.^›WËÎçû•µ¶¯8øíæS†€([)»f˜MÄ‚Ãr1­UÙÝÞ†2òœ >`80sƒ{’-CHœ&Ã3¿¶LÞtÿã¹óa ,¬g8€z8€–ÿþÍÉÀ.6É1.4ÅËKŽaëá ?¿¼úÇÀ"¢ke$ɬ!ÅÀ°éèO†ß?_?Ù@,˜–ÿ1•27X–ßã©"(ÊÊ0oö†£ 0z0¸ûÉ1ì8òaǤç¿^½ÎÀÎ~› h1'ÿù%ÈÀ-=Ï;%,ÀÖA’aÑ–Ï —×ͽÁðëç7¤T+s+ æ…?1<8ºâ$ß± ±`ˆÕòß6Ênæ«r[%Y8™fL¸Äp~ýi†˜:[G †-À¸kÒº£?ïÞŽb`c{ÄÀ´„þ–`V^˜ê¢o$Ä0wõûÿ··Í½ËÌÊÅœ‘b$§ÂÃ0eñk†·—mgø÷ ‰ãÌV€Bv€“†åê¼V'!`,2Ìè<ÅpmÇ%†¸Ö` kA†uÛÞ3ì›´zûïÇ÷cØØß2p³È÷þÈ1ˆª®,ˆ0ÑÐäa˜¿âÅÿûÛg?`æ•âJ.Œ—âba˜¹è!Ãç«‹30¾Mc`fÿ\·ÜÜ2b‰ÅVBß xvëq†û§ï2¤ö‡2èð3¬Zó’áð¬µþ<šÄÀÊþä ËþÒd•Õ_‘¤#£ÀÅ0gñÓvÍ{Å-¥!—(ð‘…aÑÜ[ ?î.ëg`|WÁÀÈõ =Åܬ<œü, /|`x|õ)CJ«ƒº6ÃòOO[5áã»VÖo œ@²}ð뇲éÊØü@V†ù nü{q`ÙGQm[¾ø,W®GoÖ.=þóï³5 Lß{Y°•„w û?¹À P¶TgPPçcX³ê)Ãá)+&3|ùÏÀ´•ã/¤ZýùÏŽKÓfilއ Ðò9Þ[÷[ÚÜ‹7.Å‚å"°|ؾzÿ·ÿ¯·$20ÿ_ÅÀÀХЇ€B¤ @Žûýç?ÃÿÿŒ _¾30<»ùøÃçó¸™ÿƒ P©ñû¿ŽÝòø|o¡ÿ@Ý‹fŸdøxv;ƒ²K{tœ.á3¬Ûú†áÓ~ åŒ[ šp€B ýû×?pCˆþþÜ,þ20‚0ôXBŒÜæÆe;ñþøÍÀ°|úa†ÏW1èÄ2ø*3l;ø“á̶µ7¾Šb`f9GL5@ˆ '¸äÿûØ:bbø iVN>á2NöçÀNBÌÐ206Ó’û톕3v0|xÁ61•ÁÎ^ŒaÍæ 7ö­8Ìã‘@Ë0ügÄìÈ €`ffµ²@!ÀÀÌÌÀ ,Z¢ 9þ„êDƒäï& q6†;ÀÊgÃì ¿^?epÏHf00ägX¼òãcK60üœÌfo±7ë°€B¤f&£ÿüþÃðøÒ-†#‡Øiç÷_&` Š’ÿ W/ÿe8·ûÃïo_ò””¹,¸Ïðò ` l#þ$Öb ¤4ÀÌ Lj |B‚Àvù£÷ÀY\q£ä€ÿÀx——e°ó0fa¦þë ï¯.me`ýÑl¦ýF¯ë‰wÀŸÿ˜?~c`°²äe06sbø÷”@•0@AQ𒙀¥äS`3sÁô“?¿Ý__ ¬÷ûÀU!y=,€‚;àýík÷±ç #Æß¿~ÿü÷ïÿÿ¿ Úõïßßÿþþÿä3þ¶·AñóÛ‡oÿ?n– Ð ÆîЀ÷ŒhÀ@))±Ò[€ZIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/artsenvironment.png0000644000000000000000000000377111550446572024471 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<‹IDATxÚbüÿÿ?Ã@€bb`@,ØI3…M˜A!™“ˆ™ØÄ™™00²˜ÿÿñi#Ã͆t†?ß~1™1ü{E+@Q,Ü 2aþßÿ|ì¿6d8ýó¨ á”–I`rn˽;…¡ €(s#P»”?Ðç\PËÿ1²³3, 2ýg¡,ò‡AK–•!ÇOIÜ®ˆU@›D™ÄÜXþÿâÿ LÌÿ;³ÂÔýĹ¾2|ýùŸáó÷ F*Ü †Úl šaØŒ ò `ÄÀÀ)´ø/„ÿã{rY¶[©¡ùóƒ  /(‡±°018É¥ä 3tcˆ<pÉ30ðj-ÿ1óçw;Q‹©)– ׯ\b—àg•;âÇÏ¿ ª¼ ,‚š ŒlâèFé`úFÀj9üþ¡È$ª¾¢±*„éë†7ož}ÍÌðïßaaPÌ0Ȉr2Hˆ ‹00òb¤€"ÍÌ ü†8'ºßÜ \â«ü²’$t™îßÀðãÇg`6fZüƒƒ•ƒ‡“…A^ŠŸ‘‰GÝH€b!˜ÊA)œ•âsf`†ÈÁÄ9×*>ËDW‹˜ž<~Àð÷ÏoˆôHyÂÉÉN²â<@.9t+»¸€‰‹…h;ÄÌìÇ@S;ýÿFµÈÌpS+Y†+þ©10<{ú%™”²³³")2‡CÝ*€Â u¬¼€,Å78µC럿¢$\êl¼ŒnšôþÃW†;wŸ2ÚýçÛ[t»«žß»y•ýï/aNp™ ÿÿ@ü÷׆ßß~‚Cá?T ?_ügøù˜ÿYÙÀ>ß·oƒ¾¾0ªØÀúA™ùÝ{`âùÿõº]„Õ_^=|ýÖCI ¾~üÎðóÓw†¾1|æó¯/?ñ‹áÐ!¿¾ü`ø ÄÞgøôèç¯_NŸÚ ¬„XÌÍ-~þü tÀ?0~ñò5ÐäïÐí ìÙðÏ‹=;¶íù¦ÊõùÉ'†ß,@_üôçØ!ÌÌ Bæ0xb@ü èË÷š\ <\Àj˜ŸÁÚÆ l)Ø(`ùðÿ#Ó§O€ñëºU„« º¹vñŒ½JÊ&¾¯½fxùýТ¿ÀÂæïß¹CžA@L‰ýïw°Øëˆ2ˆÊ¨1|{yhéHâÆÕŸß¾ ŽÇ¼š{Ý"€ÂY~|~© &Ýî3+3Ð Ÿø(yù°¢RgV‹O–öbäüŒ¦OŸ.}®¯­Ì,(•È1/_`xöø!Èò'èö¾ê\?þþÀEïþ^ë_ûêùÁ ÌBAZÿ^3ßp‰AרK\jÊÿß@ßÿfÏ·î2üüøì ¨á†n@QÒ(ÝÍðþœõßGmSÿslb¸ÿð2Ãã', B*àÚT }üøÿŽŸ5ÇìÅf@QÚ/øÌ9 o·ûüû>ùÖñÃ+˜$æo†OŸ¾‹â/ ¯Þ¼e8vôÐC ÚƒØ  juͶ2üycuacñ¬Çö1¼ù)ÈðâÙ;`IÈÁ°mû†¯ÎªyM#@S+:¦ªk›½¬©iûŸ•]üŸƒ{?¨zÁe@Ñ  ÍÁÁ5Hw±<>ã@wÏ ¹äG°þ lIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/mail_post_to.png0000644000000000000000000000321011550446574023712 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?Ã@€bb`@, ‚Ñ$ÂûóGY@\zµ‚²²ÁÿÿŒŒTó%ЛŸ>}þ|÷Ú¥:†¿¿'ü¿0.@`0üÿËÀð÷/@eKež¡±©1SÿÊþ$Î tÀ› ¼y­KÚNΫ<>Ó@`˜Šh1üÿóáûwK y^êøÙ!rü ÊJŠœ'¿¾3@v@ Ï#Îð·Þùóë7H #Yýû06Ô´¿, @ZÂÄŒ¢ €Àø´ýß?ˆ[IŒz°%ŒÐ(ÑÿP-‡‹ÿGÑÄc€ðûᅩ$æ FXxÁÜ ôà?hiá?Î4@,TÊXÈÅÍæbÁ&g¶rÊ>†ml àúJ—Pú?œr(LüϨø?Pú–KË0bpr”føñ)`Q%pì11®¾¢";1a>†/_£ä?"na¨|T9f`R?røCsÓ>+ëFfVpºb€FÈÈ_1@` r}ò“‰õ?ƒ´,?Y)þõë jjü LŒ>}ùÊ v 0À–FË·˜é €À`eeaPTg¸pá!˜ã)ö CO€,À8¿yó()3ÈÉ‹ƒñ¨o¿ÍEÈ` 1üÅ’œäþU±³³2èëË1\ºôˆáéÓ`—~ýÆÀðí;v ’0/>eøðá ƒºº 8 €¢ãç_HBYþUÿpdn€‚§ùßÀüÏÁÁÆ`a¡ÌpâÄ]†'?€³ìׯØ-ggg`8uê0è?0˜™)3@<òl៿¨eÁ?<¹ €˜` êЉ¿®æææ`pvÖ`Ø·ïó§ïX9¥ ß¿C0ÈA<Ü Ç݆Ô[''- ÅŒÐ¬ µj):Æî€?ê€áÇO^^._]†-›/2¼xö–“ƒáó¦-`j¿ÍðàÁ+ } £Á‡éGÎ!ÈA.–‘@!ðAAÌÏÏËjİbÅ)†W/ÞC†AT„áàþ ׯ?e 3eøó›‰á×OT½p‹‘-gÀwÀo`ÁñëƒØ ß ó3ÄÄš1Ìž}„áÃÛ× ö]g8þC|¢ P 3Ã÷@õhúþc þ¸@,°¸=¨ÞFN,?b¢b )©V ;ä€UZE•Ð"°o‘(Åÿü…(v‘ƒþ#$D°€‚;ät€(ቈŠ1TV{7ÐÇl ¾aæ)Pøñ‹åÿ!Jqå€b¹þÛ7ìPšàá…4R>~ÄQ¦³B²(¬DŽF~Ü?ÁÀÄJvF±òÉFÀVìOÔÂäÿÔ&Š8˜ÍvÈ_`Û Ä9 –P!ZÔ —‘‰‘ÞÌAoPügÀŒ_8f@ÿ‡šñ¥€BuÀH«æï?Fxbú‡¥XEÏfb$䀂ԆÀV1°5JÚLÌÌŒàÃL06Rû ŠPÔ2bQ S6‡‰ #šÁÀRä°,ýñûñ'†÷ ú=;1`/dpÊ!EÈÚW¿À9 Ê?‘@ü– ,À*ïÛ« “§Î2ß°O_˜á?FõõOË—äH£—áóçOÿ•áï·kÈòÄjÁ0²ó@BF7ŠáÂuV^;PK $¶Ý‘ð÷çW†_ï/yv¾Iã@wÏ ጰ Í+ÔIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/tab_new_raised.png0000644000000000000000000000407711550446574024203 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÑIDATxÚbüÿÿ?Ã@€b1¼¼¼Á4ÈA™™D_½b0<}šá †±1320p‹«rÌáaUyâsÐÈ 9N fb&¨z[ @1á2Œ(ÉH¤Å 0:”ïþ Ò7ªµ¶\`È.Àöâ(†¿ <ÿP &\–ÿäà`øÅÌ VýÊÄ%Àšc“¢ýDX†uöV øfnžŒœ| ,lŒÿAf°°0¦(eH=æ7à] t(;,⫘þýcø$(ÈpÞÌŒá7Ã?ˆ±b …ÌÂê졳ûxV”§‰1Lþ é¿ýÿû—áﯟ™âõúT¦©MWñZ.³ €pFóŸ? ïEE.ñ oŒX00ÔŸýÒ~4¯æ£€µ ƒïÒœt^†þ??þ1ýº‘‘!¸K}Št®ë»ÍïžÌxÞ4ë Ô€b„åäD \FFHTýF…âùó ’`$H fhâS»Dõe¶³[T>ìÚÌÀÄøœ]Y–áÃþã âiú ¯V\ûq9áJãÏÝ@¬@;Lv ¡Š–ß¿á>F¶$¹ù¢y8˜x˜þüsyõÍ;|ù*úò~PJZnËðnÕi†«Eן±p3ÿáä¨e¥ï×ßw ÂÆã{))ÁgÏ@ÁN ÄÇ &ËR¿nJ&¿´,ÿŸ/‘ñ‘áïç Ÿ¾20ˆƒÂ˜P>0pë 3X²PbâüÞÇÈò…áÿ¿¿ ÏÊ¿…hQxtÀccùkר¿}ƒç€ß_ÿ={sýâ ¥, ßßÿù÷óËÖ_¯8¹¥4^d‚¨bdbøûê ÷7?~±òþýÍÄöŸ Ë¿žþ|2 €¦x^æ–¸s‡AøñcÞ/_@i‚˜, Š ¨ä7Cµw¿ƒ—rN 0ôï2ügýËÀÈþ‘áËÅ' çBŽ=ùúäW&7Ë6Ff†ßçià%@1[Ê1Ó0g‹}àX¯mf`ÌÃÏÃÎz÷1C˜ô1†5$™9sÅßß??ü`¾qëêÅ·ŒÿÙ˜˜n\½Š €PBàÏŸ?Ò222Euuul¢Àbø×¯_ 1CþþÑ€ô_°Úk×®ñNš8)ïïÆi¯xùƒ¼=œ­²ÒÓ€ŽÕŒ ÷§Obxpå!CØäJ^i)Pöb…äÌ9s ׬\ÍÍÃÛ2 €Xã¸ùøx999‘Å€®ZÌ¥ÿ‚C‚›‡‡ãóço,lÿx%DÄ@‘’éÓ((æ_`ûè fff0WDPÈfdf‚$?€‚'B..~HHƒbå?šÃ`É–ÿÿE#0²2°±±ý‡DBßPnùõ“áߟ?Hå „faaûÄ`>@ÁC$ÀÊÊñç `A9 @0L\oþ· þ3ao©`¤_`.bbÚ©ÂÉ,ëDE%Ô¾}ûÍÚÝ= L`_þûÇo~ ;”.88x%ØÙNüüùS¨ªŽ@…äÑ&&æ%@îY€‚;€ÃØÏÏMNXX˜ø~‚-*=4ÿ3AZ 6(NÙØXÙ€lSpâáæføùó(:pZJÐÖÖæ gÎ\¹{÷>¨¶b ¸˜™Ù~ 2¨ª*Áã d!¼ðAaC†ge_”4€ Â èhAަpØ’X€.ü Îj„ð«8– £tÙL¼ €Åˆ 9n úiÛOù ”^`¹ €˜!ÀŠ-ÉÒ01±ÀC €P@(©`»` p$wÁ¢ €XÓ(•211!)Äž™™!)["„ñaæÀø°èeeeÛ @È`ùúõ'Ãó篠5#8ÿ£:„ .bÃʘ>ª:ˆÄç 1P.Ú6 €X©“ùîñã·UÝ,ýQFx;V#§jì1‡\‡ÀŠmŸ زûªð¾‚øÄ8ÐÝs€Š®÷d5—ÍÅIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/player_start.png0000644000000000000000000000331511550446574023740 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<_IDATxÚbd0ž9…áÇŸF–@:ˆÿ3ÐüûïÃðóo6'ËA€bZ/\™m.taøÿŸ&–2‚-6`øúk=óOgEV&Æ<€baøóï§¶$ƒ´7PÁ‰ß L´°\ èÑB† ÙvŠœù– ?þþeØyøá?€b¹ìå§¿ ÿÙþÒÂß, ¿ÿf1|ÿ«ª)¡RšnÆî¦ÀÀÇÂÀ°òÐsP<ÿ °>ÿd``ýNe«ÿ3x1|ýY!*%`â§ÍP«Ï %ÌÌðhÏ ô·?„@, µŸ~úO[ü_èãzV–pO_=†¢ce†Ÿ®>…X*/ÌÀðã7$©8>ýr¾SèFi†ŸrAñ¬k¢Ì“oÄàh"b`8ûh0”ÿ-d&1A`ü†h ˆ€’ÿm5ß¿1 ¿þÔ K‹(ÇE›3¹(1°±20\| ÄÏÀÀ ´ç?#$‰ƒìƒ9 €àQð›Œøÿßáû¯Vv>cïpc†H?-a†›¯^7ÈBFFX²â4J @ðøõ“üÿ¯Áðów+k¤‘½KH >ƒ–ŠÃ“·Àà~±ˆ™[ºd`øûbßhØ_€œŸÄEß?Å ¿ÿåH¨+ð‡˜2˜‰3¼úÄÀ°ë:0ކ31A|«(ýÌíïv}…: €X "¢ðýû7ϹܒbšvnÆ ¶J ßþ21ì½ N6"˯ß@¼ûŽ€bÇ n=N ?Ö0rò8êÚë28{0pp±0œf©Ï@ƒ˜!ø+‘±÷ è€7ß!@,XJì_ÐxVcøó»‘%DTG›ÕÆÃ„A\‚áú†·_¡AÍHzµrÀûoÐ\Ô @èø L²ÀxŽ: ’WNžOË΄AI]’áPÓñûPW3AR39…÷/ ¾¯¿ YÝ ÿþíá×’06dQWdàæ`d¸ýwÿ #§h2r.H=(±þ‡@èà=;7Ÿ”ÃO`þÔôÕrJÁßÿP]@èÆ>F®ãû;·7^Y²šáá@Õ¿X8€j™P}ÁHfÉ n …@¡;X€2a`c øóóGì‹“§®][±šáÕå› w3°°Q¡¾ð) ˆ‹vpbdf^ÄÛ~ú”ö`×îÒ7W¯ ÊÙ˜0ˆ*É0ü¦¾¿Èk¸1mgÚÊ á õoŽhFËŠ/ÏžÖ_[ýæbƒ`@–ƒêP’ pÀ‚†Âü½ hóoß“O¬;zs^Ó†s‡n3p» … ƒ¢›…’’X¡‰2æy <Ÿ€écÓÌ]Ÿf·nc¸yé)ƒ°ƒ/’#X!ö8ØÙ Q@­á†àôÁÎböàÒýÕóZ6ý\0áûןD€áç†$D p³ ?3 ºdŒ78YÀÍ%·3».ë.^˰zá9`Iú-‚ €X€ÕûýÛ/Þ¼ä¥ VÚtLÃÝîÛ÷©Ûæ-¼püžš¾™°Hfb F`÷|>°¡æ ~6æ=@2†è¼Ä*l[fK“t–]2$ 'óu)IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/kmixdocked_mute.png0000644000000000000000000000366411550446572024410 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<FIDATxÚbüÿÿ?Ã@€bb`@, BZZáׯ_ ìì ÌÌ, ,,Ì ººf ÿÿÿ#ÎLÌܬll,ÌÌi¿ÿ¹ÍÈȘÄÀðÿ"HnÕªÙxõž .jþý9òÿ,YébKK^£ß¿/Ƭ1úˆ]èz†ïß¿1ܽ{ALL’áïß¿X´1ÕAÜÎÅÅÕ¤¨¨ÅËË A6##=†7oÞé¼|ù: ’„@d§ÏŽ-ôðp­áááeøñãÃÏŸ¿88Ø ´€ÿã ŒBvBæÙøñãGPXX@‡‰‰!ã»wo€éH¿~ýfPRR`†ˆþÏŸ?Õ™@8Êž¸²è·oßtµµu¦FE…³9s L ¢¢ü RRÂ@Ÿÿcàççc‘‘:@ˆ{ªfbøúõ ÃÓ§¸¹yÒÃïßåq¾¬ººD‚‰‰‘áÑ£{@Ÿ3Ó 'P︤¤Ù349 €ðæä%N`Vå—˜ÛÐP¥£¬,Ãðüù `‚{v0H)H 7X½H¿ !Á42„ÿüùÃÆÎÎ5­¢¢ÄYOO Èg`xüø1çOÀe$ÚÀéüü¼@q&qBæ^€BàË—O@K>}ÿ·²¸¸0ÊÙÙšáÁƒç@þ†/žò d\=333¨`FÈ!„@xÀŽ`jÆû老´Ô†ÈH†û÷_-~ • ¯^½Êý–œ,Ðhøv (ĸ¸@é‘«@ ä3`*å툰°ˆþüüt Ï_ ¨§ÐhaX¿ŽøÆpðà °CAÉ¢€••“ˆtÀÆ,\dXYÙexxø,…„D,„µììl•ŠŠÒ î-ÃåËwÀpss€õ02²3x{ò‘aÇŽ] ÙÙJ`yP(€êVVf6B HqÊlhhž¡¤¤(¯¤¤,¤¢¢Ê,"" *fA 0±½Z~”ÁAûçÏ_0E“±±ƒ¥¥!CRR0„‹oq`þ‡…$3!ØvvŽÕÓ§OVdeebøðá;0á}úê;¸h=þ:0¯¿úšìó?~1;°(þÆW¯Þe••Db@‡>b°²²Züæ€?„@`ð³ƒ,?þÃÇ_ ¥ $jÞ¿ÿ MÀå= ˰#@¾÷£GO>|Œo £€ÓHT"£õ'!Ø/^¾üðæíg©‡Ÿ3|þü žAøöí'8¥ƒÚ úoßXÁò ¸Ñ>|axýú5ƒºº<¬’å`H~þBÈvÀ£û÷o¿}õ^ëÍ›ÀTý· ÆÈ v¨ï@U?ÈÒ/_˜Áå¨9òÞ½û@¼dPP;ðß?&p댄@`<¸sëú£ü€eýçÏ_©—\@²Û?p€,ùTЀØ?þ–z,@Ç|`8tè°¥Á,¦áí‡ÏŸ?ýý!¸xñîõ¥[÷ï0ðSüŸ?¿ýûT|ûö…áÇÏïà(€DÅop"¥‡?~0\¿~X rŸ%8ØAqJœ>|…ÀsB &H|ÿ:ºßÞÛBB‚@ß3‚ñÿÿ_0 *`þÓÒ/ #~üø.œ@‰íÝ»OÀ”/Ä //ô½8Ú 9ã8„@¥ä·o_r@ÁªãG»vmXôe5Èw?~ÿõïßßß@ü _8YÙ5Ôõy„Ädþ2ƒBá/°`zô¹<0kòÕÿ€LàJ š;ƒx J„@!µb˜Pša V 33+¨N‡Öíì`š……Œ‘õùÙvvμ¼Þppp601±°«u†µ®qa€bèÞ1@ xï Àp»wû[%5|IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/revert.png0000644000000000000000000000466511550446574022547 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< GIDATxÚ„Œ± €@çîÁìÁÈê{±'»L>ø;W¿'YXf×X+x@‰‘ÞÁR™‹C/áÐ&)u¦ÍµÀ¹Ã=«küS¾G1a•ûÿO—áÇ¿-Ìÿ˜³–Š1üZö¨ôµ@¡:€dÑ¿0†oÿw'٥ع30|ÿ÷›á/ ÄòÿT·Ÿ €ÚÍðãG5ë?Ö¥Ýâsg3ÈÈ-Zû¨ìÿTL%× ÔçŒ ?¾÷òs ÎO]Àhê4þ/Ð=?€qÊ`Ïðÿçi ªcÿ3|âË , ûØÙŽ_“ã€b›öã[«„€TáÚÂõ ¦êÚ Ë~508±E3¸i¹3üJøÏÏÁÊa‚ìcF [¾üúÂpûåM§c7æßyûß_Ý ØoÕS×_"R Ó] I·ˆ‘!’;‚séÚâÕLºº sÞ70<þs“!€+›A™]›…h5fp³3p0p10¼xûžaű ­;ÞŸ–ù¡Ë\ÀÈÉÆÂðã÷/Dš†j‡D#ÃFf¦7_¿üöõW@12ø3Ìñ)²›œÒÃÐþ$›áú¯Ó ¼LBÀ´÷•áÏÿ?àt‰‘I@‰(!Ê,Í`ÏçË`ËçÍpçÁ†° Á º’æ óssð?†àÐú6ƒ™™‘áû—÷ [ϼgxÄ«Éðôð]†ù ëN 3çéC׎ڽûøžÁ‚ËáÄ»c ŸÑiËëÎ Á.Öó#R$|þóáôç# }ïê6°­`hPšÂ°¥`;ƒa©!ôSªC >“ 0å01+(µýbaøúãÃþ+7Äþ¿gàãç f=¾³/Ÿ=´¼òè†|ŽY!ƒ,—þW»„ò,™<˜ß 2ˆÿPdý¡À ÅÂßåtØÍ|ÅÂ8þò2ìx½‘áè›ý *q âÜr +š"lxعþƒáÔ¿¾e¸þäéWL ßßexuþÕ;€ºëÿ[Nèm'¶î ü£¹ª`!C‹üT~A†…‡–0T/©a`ääòšì Â̬ A }1 ÌØ*ng3ôßlc¨²ë`˜°q"êcëJüÓ>‡Xþïÿÿ÷—AIU‹Aà“Ã¥¿çš ÿ?fàôØfÏ|‡:§™©ý †: ‹?­eàäÓbñ™É ÃõœÁX‰™\Àøgf¸öèCùÜj†gož3,ΛɰˆuÃÔ[S’%s|ŒýÖÛÂã™q04@ ¥À’úÿ_HN ¤¤úˆK üê½+SýÚÂæfö1€Š`^n)EYMS`¡d¦Á -ÃÌTuÔ¤”l ]Ž\?ÍP®\ǰüц¯>38jX3l?½—áÝ—Ï ü\| ÿC| @@üßÿ ÖZ]ðÿ 'oô»/_ â'eÿš³w+;ÃÏŸ À"ñÏ/x¶ú 4ÀJÓ˜AGÁ€aáž% oø"™R^<øÄpûÅ]†o_¿2|ûùi Ï‚CT‚03ÁÅ@4@±€k>dü˜÷x&þúÄúàÕCÆü¶ÿ@ÁÇÌĈReÀ\n¢ Ã°d×*† 瀵ƒÒÉßß?Ô%)Ÿ b9ÈÁÿ!2CKõ¿ÐÒ €Xþ°yÌÚTÝ‚ªãkö Ï´ö±ÿfRf/ðT;ÀÈ€ê )U ©©@1Áãú7ÁÃÉ ~A†ß!þÓÀ4Ì“p@±0¬/Ä,fþ‚âš‘•ƒ™YSƘáêoˆÐK%ONDŒQLñ háW`9À ®Ð:Œà–ÖÄÂð—KQýìÿŒ¬ ß à# ,ܱׄÿÁ–ü‡Â_h–cc„.$þq,¥Á• Sˆ…Pµ ªŸÿX^¾û ôÙ e@ÇŠZPÙ´ùˆ$âƒÔ€Ê‹@×@Ô€YÀDÌÌ7"Ä‚ÏrÝþCòÊŽûœ@p@4CƒâX ‡…Èàÿ& þ¬,˜š ¯ ‰ç/0(_K´¿Þ~øö-ÄÇü…ZÉóŒ`ñ¿ÿ@ÙŽ‘ÎÐàfXÄ ¡Šû/Ô"V ¦'÷~2h³¼ccbøÍÇÐÆ ´”†G(ˆæ`ýÏpò:Öì 2, ’†ÜàŒNPýD”@¾a—Ýþ0(+ñ"’(9ä÷ŸÿX«mF-ß¶ah àûËÈ)ˆ . Âià¸D»ç_€Yë0*=ûÎf¢Ì |ì¢ ð0Bô 11ðp3-…Ô ÿ!žY@L„B–x`øçO`#å߆æi?\#YvýÊÀÂø(މ¿ÿ n[òñ21pqAÚðt͆D8 þAò2#8¡ýüë×`EÃÌðþ;×oŸ~õó'fvfzTý ð,˜`ùŸQ4qià/¤ü÷â€`Ÿ%€ ó÷ß? ßÅ~` >P†ÐìLˆ6, € €;à/¤Š›*b¾ÿù è`^f–³ÿþü†(T0S!#¸)ôèfn`ü…ZÌ„p@— ÿ!á÷ï¿Þ¾gc²ÿÂ`cðØ&``xýž ^¶#ƒ_L ‘ ì€ÀÐúûj1¬™ÄÄ‚ÜÔDw?P °UÉÄÍæ,¬ _¾|cxó–‘A]ö?ƒ¶0è13¼~ó«)ÌÀNëÿÿ< â,  –°ÊðÔ—UÌÌ ’ €ð…ÀÇŸ?ݼ´ëŠš’£¸à`ùü…AʈŸÁ@OäÿÐ2,&U`ï€Íð;¯Þ»—L À2 \Z‚ðîü†_ß~=  Ã{ñ•ÀZx† (‡:°÷öï÷ïÿ}<…ÄÅyþüùG°ÛÅÆÆÄpîü[†Óç>[B°¶È ?>~»l!û–´c˜IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/cd.png0000644000000000000000000000442311550446572021614 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<¥IDATxÚbüÿÿ?Ã@€bb`@,0###\ÐÊj%†B`H±üüù×õÏï~¬lÌVœ\¬òllÌüÿþ3üûñýÏÛßßøÿïß^ ÜF øtý'NÄ0üû÷Ù<0 @,è uu›Ñ…˜¿ÿÏÊÊœ©£'nll*Á¨¦.Ì "ÆÅÀÁÎÂðïÿ¦ï~‹>yüYôƵ׶—/>/yøðã.ffÆ> CŽ"<È $ÿ€¬F1 €a.…€ˆˆ ƒ†F Ð¥?ÁbþüÓýýûßTk[Û¨-}}6†¿@-ÿþé¿ }d.++ïöï°háµÿwn¿ŸÌÅÍZ TóíäÉx ž_ ÌÌ\@s¿ÀC €àpaPUÍ*ú4hÐϿޜ\l‹sò˜€©åLjÅÿaþ€zæ÷/ˆ8''0È€j?~úÍ0eÊE†µknegg=y2ú9H‡8×/ÀzžUT2>ùf-wãàXÛÞå ¤ÈðhñçÏ@ñß Pà¿ èóßPþ¿¿`w3üÞ×o@Çp²2TW™0dç˜Xÿúõg;—¼(Èÿþ`4‚G@Áðd(8ÿ+sp°,«¬³e71fx÷âC˜Å KA4Ìâ?@Gýþ P(ü†:ò;Ð/Ÿ¿00$$¨1$&›éËH'/† 8ͽ|¹î€BʆàðdüõëïŒÄ4#aS†,F² þ†ø]í¯_‹ŒRe°wvwt-GÙïp[¥øù󿱩¤‹—Ÿ2×ÏË~ÿÁâ?ĦÿawH·10X8h3¨iDV±°ðË Û @È`dfb, Ób`ÔŸÐàþ‹ˆoX@¢Šá0®¿1 3$7€üÉa ´ðúë7ÀD.ÅÁ`baÊ/(`›†ì€‚;àׯFʪ‚Vz†bàÔþ”½€²ÿA©þ?32@,z|Ÿá䆣»€Ì~† §Þ¾†Æ0#Äò/ß ø*I€ˆ‹ÁÀF–ABÒ&”‰f/@Áðû×_C#qVNnF°¥àT4ì34x@¨úÆ%†ó'À9…AZöƒ¨øO†WÏÿ3ÞËÀðì $ä@ÿ†Æ; G~Ë N~ˆ#$d¹ä”´UYYÅáÙ €à%!°ä²VUf€f8ø V ~öáîuå æÖŸ~S#Ã×Ïì ‡÷ 0œ?ÅÌ`` t8ÐÒ¯ , ´”•’F@æ²Ë)9IfvYc Ñ‡Aæ<Ø9X”DÅëß¿Xj  #~£àá=nÞ fVŸ|ÆäOnÎI ?0›aø LpOžÓÈáÐPC®lAÑ'(ÂÇÀÎ&¦  ¸ØØ˜ø@…ÖÚ¯À,õ˜¯…Eÿ}ô›aþ¼;÷í+ŠÚ»wKÃú oÄ%þ=ñŸáÇgˆÅXÁP(°2°°ò„ˆQýÿýùØêmfþõ‹‘ RR\L®&BB¦JR’ÌÀ¼Í =F&1Œ„ ËE 2âõów ?~=¿ ¤cÜsåòë¿Up>þÌJß¾‚²DVèSq`u"Ä ,31;ÈÇÀÆlƒ¤d¹¬4ÄþaÂ/ŸþËßþxo°ÜÌ;Î{ùêþ­ŸbÿÙÁµ(Gp  H5 âKÉ20¸ú Ÿó@Gþd> `ç…Ô& Ç` {pó=Ããg.ÿý÷é2L €˜Ê—/_}_»o÷}NvH˜‰-–—U­ËAi¼ Šèc% ¼Ð÷’°„Œ#íA‹éÓ‡n1¼zµ=PèL €P’Ó¾mÛoþøöù'ƒ²$ØAš‘ ñß„Ô   Åë¿? ø×À†ÊåÓ¯ÎØuçË×Ë«‘åˆ a0 ÐÓ¿ï\¿¾¿}åÊ« ü¼ˆ€â eŸ€y…©ÇØ€¡ùæåO†m+ýôhQ/йw‘å)¼‡û‹ ÚV¬X½kæô» \\ ¨ARÌ©d~þ‚5-ðV å?¿þaX3û Ãù³Sç}ÿq º€‚;àüù"p(üþýéÏ“'Ó"'L\vbÒÄÛಔ`àã'XšÁo9(ñ~ûðƒaѤS {vMXÿöÝîz ðtu„Tþ†ÂkpóùÏŸÏï<èòêë{³ðî(߬lmu †¯ß!!Š F&ŒR,Æô5#såÌ+†U O2œ<1mþÛw;ê€ÒO±9 €Pšå +¢8™ŒüüN%Qþ–B¶v2 <| ,@Kx„ Î_X{T þÃpïÆ{†ý;ï0Ü¿ûÎÇ‹'~ÿqgPÙ',0 @(€Å ##˜ëÉ03ó*òòÚ¤IKÛi¨k«(+K1É+ñ1pó°Cë?Ãûwßž>~ÏpóÆÃo·n»öâåþÍ_¿ž]Ôzg½µ €°8€êf”®°²J™±±Ë›²±Š*³²póÿ©úõáýŸÏïþúõè¿.Õ½ ”@aöã@÷ŽhÀ{ÇØcª bÝàIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/connect_no.png0000644000000000000000000000536311550446572023357 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< …IDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €Xà¬ÉŒ €4'Cæb†ÇPÔÙq±€¿3022ýþþýûó¯_¿cbb>ÌÏ/¸…ƒƒë ;;;³°°bXôˆ Øø™ ì@Ìøï@±áÈ`QQ±¹yüêêÚ ÜÜ òòb _¾|¿{÷®Áž=û’vìØqîë×/sØØØ¦“„é`@|ù çÉóððLklìâwwwaàaxýú3ƒ¡¡ƒ­­ CBB<Ãñã'ŒZZÚ§}zÏÀÇÇÀðüùk†Ç_µXZZ0¬\¹”!,,4õóçÏ3II[Ä„Q@·»aÀ ÌÀ faëÃðùdž?˜^þÅðáÃ{~~ #Þ1üúõ›áÏŸ@ü—R ½½ ..N1ß¿ÿÈbeå``ee‡cf Ÿ Ó]„Œn Blæ ŒŒ?Xþÿð·ù¯/­Î+eÁºý53Ðÿ˜%ÞH»2°s°-gax÷îƒ?Ãß¿ÿ~ÿþËÀÉÉÉPSSÉ“RýçÏïM,,l@%í`¼rÿÿÃÀÎb£€B8à÷# á&%~†¿~`pˆg`vp``xö ˜Øÿ1üÝ¿Ÿaßøüy@!ð‹áá †Îk¿ÿ3ðSÈ^fvÅwrÇ›R Ä?¿{Ãðþý{ ^P™ö‡A Xì²²²0Ⱥ‡3] T<ƒß›OÀJ! hÁ_îÀX÷¯˜åV¯—ÕO``wwg`xú˜ þ3üÝ»—aáC Û?}jVÝÍÄ‚\ ²0Ó"80€Q.+ÿïÇën]»’id¤ÏðçÛ'`Áó‹“ ˜Ç%Þ¾yäÿeõŠ`8ºéÿµk¼>³’I8Ø,a'S9evuu¸Ï¿-^ü8Ãß¿»9YXªAÖ ¶’éŽ(Ãnnî?zwíØ¢¤ /*/',z?€-•vÏŸ}üXÊq12Èx2lYñŽáǶ]<Þý`0ñׇ쒒À¢ü-0 ýaxwô(ÃÖ ~ùÿ¿••µ T1ýb€bÁV=¾çäšÍÊÀÆÈxØê)X´hå<__vYY) yŸ€Uñ' #þ10müùÆðôû{ÿØyû%¯z|¿¢&°e‘Ö—ú ºà÷Ý» ×.^d8öïß 6&¦f&0ÐQLŒŒ „µEÄüÿ8¾@U °•³ìË—¯ŸÖ¬Ù” l’ÙþýËâøÅÈøÿ°d>Ïø÷ß~±»7ó}~›ë/ðNèg†ç'ö0üùy‚áï G€Å1ƒ’  ƒç¿º»Þ½› ´<“ù÷ïÌ@G QÍ&–-ÀvàŽ/_¾‹K8–¿Œÿÿ2rñ|–¹ã“À½;Àtó{êÏ`Î_ ß1€KÊ?_?3üæàÿ\\ ÌÀÀÄËš°ãéSοŒŒñLLL?ˆ…Ø– ##ãægÀÆßç w®2ð=yÀÿƒca°ÞO=þ_ À"jÌÀ°gšüœ•AX[±`Gý&D{`º`çàßxãÆw X@±Ò€ü ,ßù¾|`P»t‚åûw&^ŽU¦ßÜŒD~ƒ}³Tñœæ¥ l¬WÌu¬ ™ ìˆ_ÀòÄA^žXB&l»zõ@Ývû ô Ðçç30«Ý¯ l†zr¿ÜŒ5€Uòop’&*ˆN|ca¸ð‡¹“ùÿÛÓþÌ?¬X)”èþCa¯­Í *"@D;€|¢/Ÿ1p~ÿÆðhã¿K×ïþ?zí&° †XÌ 4íØ[&†ÓŸ™:YþWƒ÷ë¿YÇ?}šwXs3³!Ék×>{¶ €ˆrÀ&fóK'e÷]†ÀÒŠؼbeüûñË·ÿaËö3ì»,ÞÙ€¶zÌÀpücÐ-Œ&.È×?€R™_¼XtX ±³°0œ¼s‡aý‰+üü™ @D§¯Ñ+Óÿg~ÿ ÝxŠa±?ƒÝý7 þÕÿd•ÿ!ŽøÄéÇž<ùöôë׸G?n¦‡d`.ø`Êø_ëÛ¶µIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/color_line.png0000644000000000000000000000333011550446572023347 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<jIDATxÚbüÿÿ?Ã@€bb`@,0c$?ª (`þ11„þËaÿeF¥‘åàâÌýÿô~0Mb`fxÇÀö¯ (rnü €h@Ûÿ2Z0þeÚ hõÉžYís Ã/¦m ÿ£ÐU MìÿÃd ´pµMä3iF·¯ çŸ12üØûMô÷!±ù Œ ox'L)@Q?þ28ñjÛ„'ÒÖa/$˜¸8¸x\ß3°Ú¼bcøÉ4¨J¦ €¨ë€ßLÎÀ _g÷DÚ2ðÃï¬ Ì?ä93ügdgàrøÀÀ$÷UB…0-D=üaô`þϰÒ9ù± …ÿ+†Ÿ_™~ÿ¥†¿ áR& " Œ|¬ ìæŸ€‰”!¦ €˜¨äs/f¦ÿËž»¿aøõ•áï¿ÿ@{þ0¨ð838‹&1Ô«g0¸ÈH1pCRL+@Qî€? ÁÌÌÿV:'=4uËðó Ðò ÿþÿcÐæwg°Ib`c`¸ûg#ã•O _·ˆþb`ù_Ó@äçFÏÃYXþÍ´ŽzÆ£gû™á;0Øÿb¹ƒ¹P '3/éï³Vl;ȰoºÄÏ_ß™³Øþσ@,ÄyËÿyÆá/Ùµ,?3üýÁ´üÃÿÿŒ Zü Bq \Ìü '¿ÍfX¹kÃÎ)Ò?ÿÿbÍd`ÿ7Ÿ©ô ò|ΔÌÌþw’^ÀkvU“¯ Œ¿@…á ¹L :|¾ f@Ÿs0ó0ÿ6aÙ–C fK}þÿ—%hùZ´ª €XÈðy:ÇßÉj>¯Yeu¿30ÿf``b%lF^O áXvå_f0,Û|ˆaßåÌÀ„ð-0‹b@,$¦ö| Ï'Èz¾eÐü¶œ• (Ì@Ÿ{}ÇÀÆÄÍpü놅ë3Z,ý( ¬v€ë , €ˆÏ¿‹9ÿt‹º¾aVüÁÀúh9°ÎacZÎﱜ…ƒáØ—) ‹×a8²Dâ5ÐrÖÿ;ð @,D{5×ß^» |ò¿Ø€ +0Ø9X˜ …|LcŽag8úi"ÃüÕÇޝ”zÃÀÈÊÀôÿ °Âk4@±ay÷ï:³Ï œ¿Á–3³-gfa0ña0ZÎÌÌÌpøcÂ5§N¬“xÈÀ ô9ãÿ£Øâ žÔδ¼†ûo=ƒñgvÑ? \ÿ ÁÎÁÌÄ`-æ,d€>gac8òqÃ< ÏO­—xÂÀÌ´ü$0O·þ2¶0ðý©d0f3Þ¿ Àìô('+ ƒ³”?ƒ½x 0¼ïf˜»â4ÃÙ­bw8CÁb|„pÓäö„.3ÐrÀRû8ØY˜@–33¸-w’ˆa`ce`8ü¾aÖò vˆß``g j¼Ê@b €€f¿D¥¹> ÿdø LíÀ„ÎÀÍÊÊà-Àà! ²ü/Ã7] ³Wœe¸´Gä C(Ðò¤øˆ %@˜ñŸ 3Ó¿Ð~Ûh.EPeÃÀÃÆÆà'Àà)tÌo†½¯{>?Ãpé€ðYN† ¾ d6®)þA蟿ü-´d£ <Ø_‹0Ä|jfˆR gVŒ``dþΰõyòÕçî>ÉÀþçŒ(hÙÂŒ@üÿÏÉÊÊœ‘néÉð˜ºå}Ú2Üøù„á+Æ=¦2¬XwŽáÉÁ#@ŸG-~Â@a· €PCàï_Wfc&Fv†"ãr†%W0Tnib¸å>Ç»|‡€qÌf/¨Ð§ ¤øÏÂÀÆüúCùÔ} Kº ¿ºÇ°ü؆£WO1\¹ûêÙï_\뀖7+üWÔjÉÂÌÿŒ¾qº3üeØtc/ƒEëi†7?ž¾õòõY`¡´Xël6m3ü£n# € ¢0`jfgP»ó•ãÛÉk¯þoñNö[Àøa—é4èF RáÃÊÀñ£ÈÚ ì^]–ç?Áùú?m,†€bèÞ1@ xï Àºm˜«SÁIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/button_accept.png0000644000000000000000000000330411550446572024055 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<VIDATxÚbüÿÿ?Ã@€bb`@î€p iÜ„a*’’ ˜‚‚)` &õ‡@¡Ó³O'é˹"3@ÄW°õϵ¼NqD:²‚ü½süг•¸˜mæÈ€pØÌˆ·8 ²WÓ[\c÷@´F†ÿþË0üþ?_RB¢ÇÑÄP‰““;& @4wÀß?½˜˜wjiD:Ø0ð1³2üüú÷L €XhfóÁß¿þ5pˆò焚h3Ek¨2̽zƒaÓá+™~ÿ‡‡@ÑÄÿþü3ûÅÄÐ'§&im©Ïà%.É0áÆu†u®}dúñ?…‘é¿øÅf%Ë ¯#äýè`¹Ä‡'Èíÿ02î‘Öæ/ÎòÕa+00efgøñ÷Þç/fn}ÈðåÎï6æzPYËÿÑ¢ €à`ÿDzèêÕO™~²2º1ˆ«sûþþó6PŠ-{±í¨bàeÙhl+l\ênÈà+môÃÏ¿?N¾{ΰxφ7~®dcf®ZŽ·º ¸˜X/þzɰ{ïåW f‚† Ù.æ Â*la¿3N¡ì_3h£p9[«¯‡ …%ƒ§÷ŸLÀ‚î Ã¥OOí}ÊðæÊïÍlÌ,éŒLÀ2š x`úÇò—í7ã¢+—?îÓ¹Â.ÈðÝí;Ã<†k1Ÿ®0üeúÏpü?s½²‡d¨…ƒ•ˆ.0 p2|üõ¨ù+Ã5 å ÷=cx~ú÷^6&¦„ÿŒÿˆÊI„pÀ/V`pìüýœñäž×­ìÄm¥ý¾;}gXôùAü¯/Lñ¦Öœ ¡úÚ j\ ?ÿeøþh9ã†ß3¬:òœáù©¿WÙ˜“þ2ÿ{Gl3 €øÃ ¢~±þ`XróÊ/«ZGœD¼¼$]>¹nÆïOE=af†Ï¿¾3üüÿXsþ`xúó!ÃêcÏùw—õ7sÌöH)?á€ÿ&##Úw Þ¼­¦ÎwƒãŸƒŸ¼0%«Õ¬ ï~Æ÷O Â_ Ï?bXsâ)Ãí}ŒY0‡ÿãü}½Bç;FÜá@ˆDª÷˜å?ëk毬Ëo\ýÃpýãm`0døþç÷_>ýþÀðíÏW ~0¼øý˜aëùç w÷²~dýÆ”ÊÈÂt˜¿€vA Æ ÌÌÀjS`Á0@ˆ@°èómæŒ3ŠK¨ 3ü6Hþ}ý÷ÿpH|úûŠaßµ 7v±}aùĘÆÈþw'Óf`#†T@L°Â13#Ó=¦7ì»n\úÃp÷ë=†o?3|¦öo¾0¼ùó”aÏÕ W¶rþayÅV,îWQR{" €¹Ù€Õë´×¹]{úèã7@G|eøð÷%ñۯnlåf`|Ê^ÇÈÊ0—Òê €!ð‡3ÿg>Íð‚cÿ½ëÌ ¯~ñÿ5Ã…'onî``~ÌÕlØtP£þ „þ±¡b–¿¬?Y|¾Ä÷ïáûw WŸ~d¸¾U„á&÷4&†r`B¡J €JBf, JÆ­ ϸ/Þ» høë1Ãÿ+|ë™Ø~kÕÔjÁRAÄŒMþ3ã_¦Žo{$Z¿3íÙ@ËP³ @ŒÝ7 ïЀ; €ÜëŒAt>zIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/kgpg_key3.png0000644000000000000000000000527211550446572023114 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< LIDATxÚbüÿÿ?Ã@€bb`@,0###öâßPüƒAæƒ-3——¤¢¤ãÏo?ß¿}þþÄÏÿ_OÃí<7Ãuv†ï<$Zº ˆ_BC €aQà uÐ@Ö?Œ,i‚’¢~F²:æ2bšÆb â ü ?¾ý`xñø=óûÝÿöãðª³{ß¿|ïÇÇÀðüâEP{2@ úÆÀ`–d:Å=ËœaÇÉ ŸY1¼cà—ebcà7þÆ Îð…áë!ŽÏW~YïÉÀ 4ð'<$‰ˆoäx dÕõ˜n^âR‘~ÏpìÆG†«oläeÅöÅðm÷.îw ŠŠÿì…Dx¾3ˆ 3ññó næ`øÿfÈÿÿÿþûûï78N‘ ÿ £¯ß>ee`˜‚œìnÁ ÿÄ¥Øn^bºþ„‘áÖ9-iia†;_0Ëj3ðð0ܺùáä©s IO»$˜<ë\AÁ W %ÿÿügø÷ Äg†D Hü?Ã? øîeŸ#6.½#ÏÌð»f/@ÁðOL˜ò~1µ1}¥Î`æ¬ÏpëÖu†Í›ï103sñooWw†#G¤æ¯cgôÝÌ`¦þáço6†ÿÿC¼ ò-ÐR£À>ø˜¢ÿaðIþÇ "'_²jò#PŒG‚¤î†?ÀÔmA5}†»×o2|ýú›AEE“AOOƒáÑ£ç ë×ocHHcpq1dàæádØ´Y€áéé ö¶O ñ $X‘ñ˜*ÿs¹ŸX€Yé¯PŒ (ÇÁÀ Ëöè¦ÿÊ0kˆ9‘üùóG’ÙȪŒ•Oèëàp•àbA†ÿþ1,Z´š!..”ÁÖZ“á0h}Ïà(ÒÇÀÎT ´ðýE^9 e@+¾^g`¸p†AÓ˜[áÆ:† ³þøü“!f'@!; WJJ¢\[[MZHH„áÔ©ó Ÿ>}dx÷î5ƒ¨¨Ð׿ ææº L@_._¾! À‹áÍ»÷ Z‚WÞl†Xôë+á= W±ÉmmË °c3Ãí»/æJò2Øëi1¸ž¿ÂpìÓO† ¥a–ÜBBUŽŽ,,\à ò-È×ÿ22pp°1|ùò•A\œ˜t¾}ûʰuëEUm†—Ïÿ1L_Ïööúý@ÃÞ³3ü¹ñúƒÀå› ~@·®šöþíg†Î]'´€±ð¨æ3r¨Ü?~^õãÇ÷<..N /™Œu^¼xÌ’@‡ô˜&¾!ÌŠr ?bP”``a.dxðÙ„éñ}Q`œíù÷ñ-óµó_Y?¾›Îð÷Ü ¾+„Ø@p|ÿþcõÓ§/²ÕÔø™ÿ…ˆ ƒ¤¤(3'';ï_¿€Y› 2’’"  OŸ>gÐ×Õ`P¾råö²3g/¦½çæ­b—Q:Îôí30úþsñ0°\;ÇÀôä>ØåÇ@LHuÁ©Ç_Üøùó01þeøýû?0ø!¥È¯_¿ü? D dÿdægPPe¸yó ?f»? æ¦Ú ¡AžF:‡Q8ù';—ø_E5pöþåàÃðË ’îŽñu$r©øëíÛû>}ú´øÐÂ@Ëþ‚1ÈAÿE(@Žyûö¸ cgg:†áõëo Ož¼† 7ƒ››-s€¿gŽœ´ä™__¿¥üýù“‘áÏo°C^h1Ü`fF)ž^…„¤‚ 5ÑÒR>¦¢"ËÊÎ. zNN..6 ¥ïÄÄ„@êïÞ}ÂpéÒ ^^V z Í L¤gfàæf:ЇáÇ¿ W¯Þb8}úÂOŸ>W±²²ÿ L[_Þ¿ê=t0$J¥=ôÔ™›7T¾xñ˜&Þ}‰†¿ÿ-f–ŒObòÿ xöêÁƒ[/^¼ÅpãÆ}†W¯3ˆˆp0°²rï ÞßÀ„¬Åáï //{}À`¦-1{{/¸O„,,Ìà4¼÷êÕ{æìì,¡ þ·ol@‰}Ï,¾3¼yó‘A[[™áÊ•›nß¾ýéÓ}†æ""¼ÜÜBüüüÀ\ÄŒ*6`ò˜…™ttÔØ?~â´æÆ_`zA®§ øebbKó|Úo~üø¿¯€ø9(—0ÈÈ3<{öææúRììMÀw¨¥ûãÇo“.]zðöèÑ˯Ο¿Ìðóçk~~n §™!#ô€h0úÀ ¹@ð4 !! ,dì€ñÍ.ˆ€e0Ûù²³³Ù©ypp°0ÈË+ f:à/Ð@^†mÛŽü¼xñª! Ëuff&P.†à_ffÖ4}}•uuy`ð=Ç ¬ÀN}yðà‘2ç+'-š¶ €à 23³0„…¥ ÖŠ@o‚ä€Ñ ),,tXLLPYJJ˜èôž?ÿÄ +ËËðòå[†uëv¯ûþý{0È 3@Ñöïß`ZáX*))æøáç3?~:4k?ÐS€¡ùÿÍ› .œÛ @(ii`"ñG H$̆@:QGG¹OVVè+`jç'ºC‡.€Rº#Ð@%(HÙÌ@}¼LLŒ Q ò+f0 G@a´ŠŸ>}Àp Xr±kDWéÌL€TÿýûÏ×ݽûüÏÛ·OÀÁúë×? yP©Ù4 ”[ ¶¿À¬÷’0ËA%): ¬Íò ŽóðY0†… Ð'Àºà[ðÝ»/ýü ª€‰õ¸ðÑÒR±z(¢Ž Ùà„ ò +8jÑ@±àj@ž;wL«©é5³€‹aPâäââfýòå'ÃÙ³Gu‚¸°’—g¸wO¼éùó—@íZfhi÷ØÂÝ *ýÁƒ[`F@âÀv¢¾¾¸.À„jÂËËÓÄÇÇæ!--Ψ­ ¬ ™¾ë„G Gž«:²R®°KÌkÀvÅA†¿ÐZÀì ‚=£—/Ÿ2ìÞ½Üà¥%°|ðzþüݾÞ[N<à¼ÎÉÉL˜œÞ \³€Ÿ_«åÈ €ˆêš {óæB0žøúë×oÅðy`È0 « Šê"Í01|þü ÙDtßðÝ»Wà ZpÃâïÿ¬¬¿€°Áz˜6øAm†Ó0€hlqŽˆ…Xܹs•áÇ·À§Ê ¤¤ —eÀ‚è ›Ëׯ7½YYYu€‚g`–ƒà«WÏ š @ŒÝ=0RÜ"…‚wIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/stop.png0000644000000000000000000000460511550446574022217 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< IDATxÚbüÿÿ?Ã@€bb`@î€bAæ¬fdD‘üËÀŒ  &VVù_¿º¶óÃy 8È<rþ‡`•ß Ì,,οÿüyä/ê›Tÿ¤¨Ÿ¡ )Úg ©åSS[l½d‰­ÓÞ½r†MMáÿYY·-ufÄ¡(g´d‡Q~~ràÞ½ ¾ëÖŠ›™MüÎÀ0ݳ0@  Dë€ ¼”¡e»žÞÿ×®ýG÷–.ý¿€‹ëõ·Ù@u3€x:Oe`0œÈÌ|÷\_Xí/ þ ÄŸŸ=û¿ÜÉé3ÃÜÖVP(!Ù @XÂÀP·]_ÿÿ—{÷ ¶î]óÿO–ïÿ¿O!ü{Ë—ÿŸËÅõ h¹ÓL úi@<d9#ãý PË?½}õÿ^BÀÿ'3ûþÿò¿¼|ù‰ƒÃÿz ›ÛØí ¬ÆùuõÿŸoÜôïà¦ÿLùÿÿ”`øÿ=Ôüÿ¯—OÀâw–,ù?“ýÐr+ Ö˜ÀÈx æóÏ?ü¿áùÿ+Ãÿó¢ŒÿΛúÿPüãóçÿçZZþod`(C¶ €P°ŒáèÃå+ –ïYýÿ™ÐÿŸ ÿ¿0üÿ$Çðÿc ñÿOîƒåo1…íiýsÝÝË>¿áþÿ"Ãÿ 2 ÿψ2ü?!ÌöÿÎÔ^°#îìÙó¿‰ý ²„’0©[YÌþ·n!ÃßGïþJ0uýã¦ü“g~g†0ü¶†A5:šáÏR?>~d0,*bøòþ-ÃË̆¯Ûv1üê&÷l ¿žýbx¿x1ƒHb¯œ 7·²„‹Ö\niûæÏÃÛÿ¿…šüÿ$ÏðÿƒÃÿ·Ú ÿ_i2ü&Éðÿ¹§Áÿ/ï8¡½{ýÿNˆÓÿ ¼@ŸK3ü?+Åðÿᆀ®Òÿ'ÇýÿTwföìÿÕLLû‘í S¿ÉbŽ ÔNÉ/ŸþÿdþÿÄòçê ÿŸñ`Ð>ò0úÿéé£ÿŸ>ú'Ì ì`ËŽ< ´\Gùÿ“S'À–ßÞ¹ó«Ð·/d;ˆ¹.X,ˆ~S7× »¹sE#"~>½Ïð%3˜á×™ó ÿxAû¼>3¶%7Ãç-»þÃä@eÈGfyy™…+$L,ìÛǰ*2òëçW¯Ò€±²¬ÉN€ÂpÈ #Ü€ŽXj?{¶ˆrTÃ÷§>¦1ü8sŽá?4~A}Ò@ ÿ9‰ú t³‚ƒì¼¥ V víbXùóë»wi¬  Xf`@v@1ᨠvýþö-bObâ«ÛK–0pJË3ðÌXÅÀldö9ȧ` Ùj9Èá??CEIžAvárq å÷wïfXõåË»wI0ËÑ@¡8à?j%±÷ÿ¯_»RR_›?ŸSN™A`ÁVk[†?ß –Â0ÈAÀò–US‹AnÉZaS †;[¶0, ùðýíÛ8P°c³%~FR¥ßüþùó×ÏÀå?//Ã?n.H¶üÁa4PŒ™ƒƒI@¬”=|ûöÈ~ùR·€Céšg€* ¦íöÝÝʆ…… _ß½bx•ÌðeëNpœÿƒúf9(:>Ÿ:Çp'"áík :Àr"tÞ<Ñÿllë!U`è!@XÓÐ\ÃÌÌ«mûú” KJ¾||Ïð*=šá˶ÝÀP€;¨JþL°_¡>y‡áãÉK 7b£^\½Â Ëœ¿Ìp%>舫 :‘‘ ¡3gŠÓÈr Kd;¥$¶*,„T©¯žÿ¿ ­X@Å«4´„ãfø\SXÂÿÿ¨TÉ<½~õÿ>#Ýÿë~ØT¿¨f°$\ âêÿ¿}ö XÝ®ŽŽÿ™ Ûí ”`baqR §Ø×e _Vï„T,ÿ>g–2ó—2ˆ³ÚƒM›®Ë Q -•Å˸Œ€!ñ‘=ùïÕù‹ 22Þ¿{Ç æëËÀ) `€l'@¡8àÏ¿o~¼~ÍÀ d³Y:0üdcøóï`Ë••d,c7–p{ö0¬Žÿ¼*!áÝ #$´tÔ-aà9â;´lø1WÐÊ’››X&0üü r"Jô20d/13ûÿØxµd@‰ÂLÿ32ü?©«¯Xî+–oÕ U 6•ll¯Î,ZÖsÿÊåÿŒþÏ?ï+)þÿêû÷ÿ>~ü?ÉËë C+²„žØ€M¦éˀͧÏÀfÈÀ;S{þŸ²4‡W©wöîýß&&ö¥Øz6±j¸˜ºË98^Ö¢`=gÎþ_mnþw^ÞÿW?~üÿðéóÿ™¡¡ÿÖg10ð!Û @(•Ñ$HeÄ ÌÚ3œœ’ü—.e`“–h_x¸¸î+–UhË?h ®À89—S»ˆ>0ÿ¿ó† Xr2ÿüɰ25•áøªU›€åW4°@ú2ÉN€Âæf:bЬ¥eº}s3¯¤$ãcÇv•—V,Èeû?¤"õÎÀ>Ä2–1 OO†ïÀâxW[ùíÛ×-•ö Ù„Ë Ì,èŠYX"XÄ¿¾ys¨¹˜@·£•šÈz@9Șn«¹„„Œ~ýú ˜è6C« ZÕ0 ; €ºs @Þ7 w@€¨ÛJ1ÿü–IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/queue.png0000644000000000000000000000303211550446574022347 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<¬IDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €X`Œ  E•ì쬅À4Éñ÷ïÿÿþüg€a Œÿüa€ór (|þ÷¢öýûŸ—~ÿþ "Âöö÷oÞ/@µ?Áj@‰ÿ÷ïF€‚;€©¬°ÐJ@YYl HD7ý…c322€QP°Çfýú;¶LLlÿŹ¡ø?\/@ÁÀÃÃÎúÿÿ/–ÿ ÂÂÜí³g/dey@NbGrf` x`bbþ§¬,Åpóæ3†/>Á}C Pè?~è!.>ÈOPh cä² €à!ðïß?``ÐÓ“g8xð&P‘<ƒ¤$Ã÷ Å@æ131Ó Þ òò‚ ||¼À8þ²¢¨?È`DRÿ˜v¶™ÓˆÙ ?þ1ðòr0XZ*3ìÚuÁÊJAD”áËPá·œhÒÎWÁÎÇ ¬,–ûöíCMµ~h¨š>È×ôÁÈðéÓ†øøíž  ºa ÀÇÇÅ`ï Æ°yÓ]^ o>}Æâˆÿ1!!†/CŒ‹AWWœ3@ŽE‡ŠŠ 0TEQ´Ý»÷”AZšÌ #±Æ¿€YFT„ÁÅUaÕÊ3@FÈG ?~ ðÏ_ ü «Wgàæf†˜*(ÔÿþCxèׯ¿póüøL·€‰\€‹‹,@(€äi #€÷r²Â îê óæcøùý+Ø_¿Aä~üd`c`X¾ü,Pço7w]†Ÿ?Àùÿß_„ÀÉjù‘#7Eøù¹ÁÑ Ä„üþ"0È!_¾20¨©K1¸º©2ô÷ïg`büw„¬ ÃâEg>HH¨)8DÀ¾‡ê‡…(0’À)ÇŽ+À´! !!ˆÄ„š†üFÅŸ€9ÒÈH膆ú œì?t´-8ÃðôÙk†„ åŒ`ß#ëûNOŒ ÿÿýaؾd¹0Ð÷âPG!@± ‡È øÿûUÑï 66 oß~gh¨ÛÁ ¬"Æðôés†úF`3Ã}Œ @郑‘lyk«50qÊ‚ÍgDKðÄ‚\FýúÁèI‚ ôð4dxóæÃÑ£·:»B!Æö-¶r"ßñnj*Ë ¯¯æÃŠiä¢ €XP,ù IÝÿbÏó „çícÍàîi J6`ü#•.h€•’Ä%„!¡MŒ 0!•œ„ ÔÍʆÈF˜¥ÄFF6°Cð”Ì,°4õlÞd0!@HQÀÈôŸ GÀ †ùx,D—úÉ2‡‰áÏïÿàtÂÈ€Ù@püþõ‡ñé“ÀR ,‰\õBê÷¿Xªd´*û?¬Žc`ààøÏpÿÞ{k+QpÔþú‰æ¨B€bA”R?KÖ­Ù™òÿ#;rƒX†³³²²ªò p£4NÀ…ˆÿI Ñ@ùõóƒ”4?ƒ½2Ãû µØC €ë‚éÿü™þû÷&X ÈþÏÏÇ ¡¦!q)1Ù…d8®V<6q..&°ƒ>FätJeª©€’ÿþC+fffüÌÏŒ¿ÿ@ Ãf®¤*ÄЕƒÀ N„]Ä‚h°ÿ1@šN m8gdbü,Ç™_¿þÖ®V0MFÂ%õØ_ ÷?þ ¸Þ¿¿,ç JPHpC„™™ùá‹ç¯7,š¿Ù¨Ñ@…Æ9,€Ò º4MÀ¯ÐëÏŸÿ[];@öã@wÍhÀû4à w@ ¸ £ìüo·IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/tab_new.png0000644000000000000000000000402711550446574022647 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<©IDATxÚbüÿÿ?Ã@€b1Ú *fb æ‚°…%58pq2ñ¿<ÿ5Ž•á7T ;2Íêq€b"Ö¥ åøþé LM-|,æ¸Ú²s0¸ÿ…ªÊñ’¦wn ¼"ìeÖéÚOÄY&ÿÚtÀ?fNF~&6fPP²ð±Ô)eË<áRæš t31 ¸X˜qc×â r˜1…×gYa/CûOàß¿ ÿÿaøóƒá;+c®þ\õÕ)J|Bv‚Qÿ!1AÜß~ãÆÀ g¸wì]çɲÚo¢N> ž ãËžoûóûÿßÿ3°q0ä˜ÎÔ "ÏøbÚ‹¿ÏV¼¬ü¨ˆ¹±` FX.¨Ä‘A¢¬ÐÔ 4ÔÎ)CwåôFÅ7k2°raàdø|éƒH¤Ããž3o®—ÞÊac`XÉÔÉL¸£!Ô^€bA¶‡¤¹¢¹Ù™¸™þüsqÙåÛ<¥Šš]9 ?Þ|d`׿gx5û$ÃíÎ{÷8DØÄ8XXê™ÿ0üfxóm Ј[ø¢ €à!Pƒ°T z %¾Ù±k{RxÅ¥þý|ÅÀðë=ÿ//¸)ÈTñ(ö”áç½G l¿˜Ø¿10²~cø÷ãý 7»¾žýâÎÄ‚é=Ãß¿À4@ÁCà'ÜrŽoßÀù”µ~}ýýäÍõ‹?¿ÊÌøýß¿?>ÿcÿûŠ‹[Á‘Ðÿ3ü~þ™áç§ßßY¹ÿ00rþgù÷…áÿŸ¿‚2æ`Þäü÷ÊèY €à¸êâÆð¨ò/#ƒÈ£G ¢Ož0¾~Íðéå÷öQS“4;МŒ u~s<=ø…þ?¿ÊÀÈ)þþcc¸wîÚ¯OK¸XØ€éæ?;ßc ôà ԸG^žá?#<®5¡öÜL ,t㟠oee>Š‹3p}üÈ rúô/Ö?öƒ¢ƒ‡¡ÒoQœlx8ÃõÂRQ±ÿÜ*"ŒçaP›dÇ`ºÃT÷BðùàßÏæ²£ô7 +ÃU!!†Ý ùø€–3 ˆ ò öÖ’ù÷o†À裨(ÃMkk†_À|Æ'ÈT¼<£M6<ƒçjUãÇC®-ûÏ v†+“_¬¹‘qì)¯%›Ñ­yÎYÜÿÿ3­ÖÑa˜caÁ𜗗 h&ׯ_p „á A$Á ÔôAX„რƒ²:¯“\  ÃíÖº÷{;OEƒn:ÐCÌàlÊŰúòÌgžK®>æ6ã`P°åõ<Ç'òן? l øÇ‘͈Ïñýûw»¿ÿrÂÓ 0AžTQùýñɃ;×,SìïÝgÜwÏÆùrÀ±ƒj,Àb’…‰á?¯é2m½WÖKnÑ?ù0íá3ÖSëõ•=8ü`cE-(𙘾qppšøÙB€Bv0KÎ444Š&‰¿ˆl tüoFæ_ï¾þaòbö{yç®áÍ»2ó¿]|òƒåÍkŽ'JZyÎ% Lÿ]øò‡‰‡ÍÛ‹ñ0‹mf`eeexûöÝ¿k×®-— ?0³ÿ*))Ç5773pqq2ü'Êÿ`ü„@š ä&fæÍ;v*Í{ôÈæhÝÜ+ÒR z mÒn.@—þgcfe«aeÒ@ÌÌÌÌÀÁÁÁðõëW¦òòŠØë×oLagg?³ €˜âžGPPˆ ˜@erœÁÙÿ ަlFAaÎíæsNjåÊýe`¥ &¨zXzy‚ XÎ ƒÌæAŽ€BÔ†,@Bƒ¢æ{läfæÿÄ%€–« `h1"YŠâh(¢¡ÿ¹¹árff¶ÿö `\üûÏÌÀ ²ûß`•2ߌÿà–A,‰ýºï¸Œaffö¿@ÏÂÍ ¤¨agçÀRX¢[þh#''—ïq`hhþÚ𢠀u Øw„,ŽA¾F·æp|Ù² ˆ )â,.© @ 9’XˆhÍS@~„Ø„\0Ð>þ#yˆ 9 Ð# v±ÂÙ„T°s T”F.T±ÿK:H1ÎMt h‰d3Ø. $°°|üøH¿¦ÔßHùø?’ÿ Ùí4A!çwt6º<Ä_¿þEÜ^€bA¤N¦»«Wø Ê)0Å (AtžÿcIÑ (éÙ÷x²1óŸ?ŒÏa|€bèî9@€ùøp`—‘IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/2uparrow.png0000644000000000000000000000420611550446572023006 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?Ã@€bb`@,茖‹À¡òJ3`aƒþWdøþ»›áï_nŽ &Ö L@ÿ0db†Ò Ì„Äffø¿ÝÅ>€b!ËÙÿ´>ýXnh%§+,ÂͰg×muv–h Ì1R r Çðéû*cKYõ¶6W†Ûï9._a±5þ«L Ó¶ÝÔÍÅÇÀðî#(t˜ÄÍØ899Ÿ^º:˜H¹˜f2 €ð;€èõßc¾ýœš™iÌ›žeΰï2#Ãúã œlÿ>>¸Åðÿûov)M†7™ÁZ$´ô€‚•åñ…«Sþýã¦ü>|V Þ`ÿù§€ñ×ïþ²2 †„DC†íç\úšó?ýS§Þ^¹ò…áãoþÏ‚¢úf ;®B!©©ÉÀÂÁÆúàôåÞÿÿþг` (±Y@L8}þãO%ÿžÖF[†¸8C†}î׃êrÁŒPƒÿý÷`øþw©§›²'ÚÍw–ügúÏ,zÕƒÔ‚C‚ Cˆ «oa P°²q174Á–‡-_â¯*”—¢Ï c Á ¦£ÁÂøïßl`Ñ› sV ^&6Xˆau @a†Ø§@˜A©œ†…ÄŸÿ‰ ¿ÿM‹SçHŒÔa˜‚‘aíi`ù¯ TÊÌöüúÝ)ÿÿþã†D'¤|`…$X±}ǰ €0À΋”r`.²ÿü+düý¿;?Q›94@ƒaîQ†ÀöÏO`H¿†£„¼"0m²1=¹r»ãß¿ÿB@GTÀÛq (d&PN~ ëˆoƒWJKؘ™:«rõ˜Ü]UŸd`Ø{A˜Q¿3ׇ¯åRRÒ ¬, /ß-ûû÷ Ðåà\ÅðgZ & f`Jïâdeîî¯0eòqWaXy–ØVJl~Ü¿ÊðûÁ%ŽŸ _ €×@OЉ3(›kC6Ö"†¿ÿæMáÆg@ás;÷?S¸YKgÔ™1˜›Ë0¬VÇ?+–_ /^bøøôÉõ_o^œÿt!Xï'Ã/ #ž¼¦?~A5u6¶X`Ô›Ù ‚¸, Õ1ÐòÙÂBœé š,ŒŒ¤¶ à/À‚ŽíÿO†K‡/1|xöú°F aà`÷½~çéG—o0¸jü§‰§Àꘅ—ŸAÝD•›#˜x—MåÃf@a«Ž…¾üY¢"Ç»¾ÇšAI]Œáà=HŽü÷íÃÞ-ç^={{™ƒÍ¨ú0jŸÿcc :vùÓkç®3Ø(}–Mè`äàaÐ6SaàáçôæžM@õòèÖ–êø_—±Žpð¶)ö Šê‚ ÷¾Ë[a`ÃóÝg†Õ+Ï-ÿt‚dùM¤*í)kðíû?¶\?w›Aÿ+ÃG`â|ùXG±r0蘫0ˆòØ+©)èÖf.øËh¥¦*À°çÒ'†[oß1ü枯ßÿ3¬Û|áÝÛ{8Ycªžc Íw ,‘O_ÿšþòóݘÿüR ï¾°0ü6Xù™¸ø¹>|ümˆ® €0«c§MQÀ8«`øÃÈÉÀÂôœõ,+Ëa`eS ¶¹†Ïð®˜æŠµe|4P?H °Feþ lŸÍø¿Ly"²}Ä8нc€ðÞ1@€:¬*ó§8yIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/kgpg_gen.png0000644000000000000000000000557611550446572023021 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< IDATxÚbüÿÿ?Ã@€bb`@î€p ˆcdd¥„?@ü‹ûƒÑ?^v~/Q!o>Üýúãã© ÿN120\`g`¸ Äyê™É°ô%o‡²ˆ”àùÎÀÌÂÀæ"¦ e¦¬'§¤m"É¢i À ,ÆÊðá݆çO¾2<¹û™áñ½Ï?\{ñìñÕ›µ< KÉqHÏS ÞÄ6f–ùA™î!ÆŽr rJì ìâ¬Àpàf``a```àÿ÷™Aþß;†¿þ¿b¶ÿ»b™/“ÿ¥äû_ –â  °¸YÕ=]ÿ0ð»s-‰@¥€Áðèd›…€XèV.Æõ ¬ ÿ´¾00Ø1CÌûƒÃ®?Pû Ä`ÔÝÒß@‚@ @`0130þúýbٻǻy€ÌĆd#$ðþ¼aàbcðL60úôõïÁÿ¿ÿA†*ûQù(þï/Ôf#ÃÏÿÎï¿{æïÿ_a@+îƒ\@P02±±ýaxºþ(Þկ4M4Ìb8€á2É@Ìú‹M‹!lÚO ÈÿÄêþü‡Ø_hÀýf°ÿLñß 9 ûë†Ó›uLæôÝÛ÷åý‡ `hœ °XÙÙ~ýú°¨ëþ¯SçÿÄî^w!¬EÕ=XAâ4Pf9Ð  Á@G½ù±h9ÐwÝ †/оÀÎÄÊäÿ;”‘ლÉ7†ÒIŠ óêÿí{|ï“+@ÁC€‘é7Ãïoÿ@î¾ô“á—Ù÷¯ ‹€ ùÄG ‚<ýZ‚€-Ѭ°d*eªù+ f-–gÀ€Fö?P„c”™áçÍë ?XXÎb Hðþcãdfˆ¬àåä˜õé²²¦"‹šù`ý‹_ gÌbäÜq`ú.0´ù‹U Ȧg`rz DQ`²Öƒ8èɆþY žøãtÏ)€‚%B¦ÿ0¨:ýc(³çea`~t*0Ë}ÆlÐÌ ²ä ”•¡Ÿ€fÞf`ø,YþK°»6oeøÄÀ®¥ËÀ°m Þ §øx¸¬Mt”–­cxûüƒÐÈc »ìV. o|føÿ•áák†kÅn<’cxóYŒAˆç ƒ¬èKyñ÷ ²Â_DØþ20}º «'00ì;Äpˆå?à ÷ÐmófNcHæçfðyù•a"Ђi/?2°®ÝËàdûÝ=äóPË\Vȳ¼óªU¼ù‚‡áñ{`H©2pñÉ3ˆ‰K0ðóq1|ûþ“áÓÇO _>¿aøÿç5ÃßÏ>í?øšñÖƒ{Ÿ0Ü&ü$`,ü'UP™ñ÷/(ØùbRк”¡ÿÕpÕ¼²äœ^ï~ì+($,Í ,Ïà ,ÄÍ $ÈÍ (È ,8~þüÅðãÇ/†_¿~3|Ò÷>cXûe#Ͻõ©Lü øæaø­m 1œ“‹ùñ]†¿¿þÿ4¿vd¹ÐÇÎÙ0°p@Ê š¸ÍK:ÜCìF%­ü¼ü ¦J ÒÒ \\œ@0A³Þ? #8€YŽŒß½ûÀðøÑCô>;û©333ÿÆá_pZbcëùÉ#Àðëë_Ö7çóuce’n/{:ÿ»€X7ËFV¶'ÿA%"ƒ€„,@Að÷Çß¿¿Á½xñ˜‡™DEùÁ4JÝ äÿúõ è@]]-«OŸ?_ú‰ÿÿ2±+­Ë—þ|úÄ lcÇðíígA^6Í7†×ïöä¨pI%ýãfûÿûøÙ#‚_ÞM¾öïÏo€b  ;vexö샂‚,ƒ††ƒ²²$r‹  0ä¦0gg3Ÿé/(¾™˜˜ß]ºÂ ò÷ƒ€ ÙgX½bxvmá/NnNM} .ž½›œBÏ»3<øzâØMk a—ˆ ê¶À‚ûÎÛ¿>¼_xþüùÝïÞ½gxóæÃïß øÿL?¾~ýÊðüùkH‰øñúô˜.þ2|~û‰™ýƒjq;ƒ¹öS–M«€³Cê -{䃓ý ñ\ f%^Þ#Ž[€iÔgL,,LÀÄûç7½ôóç¯'þüùî?~‚ñÏŸ¿øÆpïÞ †Çß3<}ú]Ÿ€ŽüÎðH³k›2\¡Ãp­§”A© œAC7Ïs°Dºw“A]sƒx†&Ë©Ï6î6bø©¥*ý›‘I € %!;;ƒ––6×­[·oKJŠròóó‚}úíÛ/Hêþ‰ 9xt€BíÏß?@ ,å?¼gx§aİv冿_të3ä÷®V?t*58¬¤vœfزQ‹á²Žöç/§¯Ä¹>¹z €`‡€¬¬0þeø™˜@ ›•á°ùýû7RüCó14a¼}÷’áÓ‡ ÿobäÿÈ üÿ³>ësw¾î]ÃÀílrü{´ÜáÇés ïÏf01É`øs9¿â÷ Ö›OšYAÙ˜–XYaÙ‘áû÷ß(¹€Xûü¶~þü ”ÿ¬iÿ1¼¹ù„ÁBî3ƒSÓ Š7P ,Æ?+`ñôþÇÀ¡-Ê`°ÔŠ|*­€ fó×̈Rx1srp°ÚÿÿŒPŒhˆ³-´FúL'_¾|ùÁpùòÀêöÍû7oý?wëÞç+.–,@‹þþÉöû«¡e… ·³PË{pÝüãÚ†[ÍWSäyv6&v&`ˆ~?úq?@ðýûËwïÞ·bÅ=70Û°²²BƒزVð ¨å†¿ÿ1ÓÔ² n5Ô0¼Üö‡íCŽ«-—~ˆ8¼àP¨Ðdcãg˜r-ýÖÿ¿¿ÿNU²ÄM`߀>UÇ@>}ýú-ËË—¯¯^eЄVÀ€éä0·~µ~à ´ÿA¥%(G00è»uxNWËng¸;±˜awãñlÁ` Z“æÅ3•·² 0N“ÌÖº¿§Þ̺shÊy€‚9ž²Al`šøÄÀšžá6Þ^ 0Ͱ½Ï,RÎøöáÁ›OW» y”ïÉ&ßi̬ŒÉà4ÄÊȬª§_̺õïß?Óþ<ý¬ô¾‚B €X Ùê0Û±ÊÛøzÌ œ«˜ö¬_ÈÀôÓï I@Ç›rÚÀ…á¸Ðþ÷Ò¢ünL,šyµðîI àW ¾ °víZ¬|$ÄÅ¥„…ÅØÙ9p:àÝ»WÀÂé ÃË—O^üüŽÞϻà o»`?í¾^´JóÕ™»‘ö`UÜ) 0“,* d/þ5IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/view_left_right.png0000644000000000000000000000310211550446574024402 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÔIDATxÚbüÿÿ?Ã@€bb`@, ‚‘19‡‹©Žƒ‰ûßÿÿAbà€a1Àˆ&†^ÿÐäaúå1ô12þýóáÏÏ¿“þÿŸ×@Œ (àãM{ÚØ/Å+/ÅðõÛ†¿ÿ€jþuý:çˆþÅPö¨²Zý™”2Á4H=HŽ…‘áÃÓ× æÎ{õëë q€‡7+—„Ž2Ãq öoCY bù‹0æ˜å‘,ÿ‹„Ajƒèÿ¨jÿmüÍ!ÈÀÄÎÁ ² €Àø÷éï—/Ù?AÂdà˜¯þ£Zb32B¢èÇ/¨%0‹¡ìÿPõp½PÌÌÔ÷ã7Ðl&Px0$ 011üúÃȰr͆ï¿300aÆ/JʪÿþýÃ7 àçÂH+0>ZzaŠÿcfc–åÛ ÄÑÀÌðáë_g© …¹²@—þg@ÏŒHl6v†E 2L™²—aÛ¾2`hbËÎÈzþ9lÀø_¸û%Ã’ë¿!È  ˆë˜~S‰°ƒª’0QÙGF’™AWS "¸Áp\þÆ3 ƒ¤øO†?WÀÁ– ˆ™ ©ôï?¢ó/80±2ü¦4`ö‡3€-ƒÐÿáâfóòþ房À´Á w@A¢€‰ìŒØ#g4€… žñÿƒ}‰p$Jþ#9 –HÁ ó?$ ˆ Œà 0B‹z˜¥Aû÷ï?Ô±@6(A0BR@A¢hÐ_  I`‡Ì—ÿþ!,GDÁ?(ÊçOh6e‚8 €˜`Áùçið@ügÀô1j(€ØÿÑÀ)˜!Þ h0B\E þC FPð19ÌLŸCõÂÒ†Ï @‰.©Àf´`¦F"Òà”ŠuÿÁ>ú÷å?pÿ%ÀÒ80@¢…@@Hi€ßChFX†E<¨ÿAƒRôÂhƒ`–ƒÕÍ`Û wÀŸXÊO¸åˆ¬öš•þCáx°£çH°ÃBàï?`þÿË vسÐl@,ȉð?#~Ÿƒ Ì0GÓÌBf@I¹‡þƒ„8– ¹ €à%!(";–à}‰Ãÿ°v0‚ °àD jÔDøî„<¸øM `jU@ L˜ ¯ÿበ.Ë) ÿÁãû?J‰ú¿‹ÿüý_x"d‚F@!ÒÀ䢹8eÀHÑ`yp9Àõ#Ü—È!ËzðPø 5ã?¼: hQÌÌ€\¡[Ž\¦ÃC”¾ø÷Ó¨Ñðž(ÿÿûm8"jC€BM„(qþžƒR¦ÿƒgCP ú™%žÿkØ1àZ ê†ÿ‘Úˆÿ!m—ïØ%´¢¦¾úb9´8GîÀjáÿ`ßcxñb|œ !•@ðûãŸwoÞ2pËK0¼ûò¬ Ö*†µ‚A¡n^Cå˜DÄ™|ÿ oýšèÿšêÈfü÷ ˜˜~¼‡'x€;à×?†‰Ç6Ìg5Úþÿÿ‡­u‹µGÄˆÖÆ¢™Uˬ¼€Aög!H €ºs @Þ9 w@€u3Ž2ò›’ÓIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/decrypted.png0000644000000000000000000000375111550446572023214 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<{IDATxÚbüÿÿ?2ˆˆÈ`Àþ1üúõ‹áÏŸß‚ÿþý àwb-FFFæÞßzóæÕþß¿®çà`{úïß úÿXMÙ¶m  €Xˆ ‡à­  ×ìêê`(&&ÅÀÉÉÅÀÂÂÌðû÷/W¯^íÝ»7çܹ“m@±ELLÄ™ @D;àÇŸ‘ææ&s}}½9¿|ùÃðö톟?ß10331ðóó3HI)2dee«oÙ"·pãÆµbŒŒ =ÀÐ!h.@±`ó)2´ÜÀÈHo¦‹‹çÝ»¯^¾|ÎpãÆ•¯>¼9õÿÿß¿üüÂF&&Bjjª ^^~ míëÖ-»ÌÆÆ¶“#ˆ`üýû—YP¿ÇÚÚ–÷ñãw Ýc8sæÈá/_>æ-¿ù÷ï¿/_>“yòä^·»» +« ƒ««'Ëùóg»<¸uŠ••ý=®ô„%¦Q0Ð>::ZΟ>ýbxõê%ÃÙ³ÇNþüù#€••í33Ëw–Ÿìììw¿ÿ±cÇúµ<êa`ðððÑebb ÿû÷70ÑÂ1: üebgøÄLLŒ` F×;wî½Ý±cëóÓ§½&ÄB ¥ïþ3#ÃoV ÿ˜XYY~}ÿþ©ôر¿}ûÁ ¤¤Æ !!ñçϼ! @û{“AæÏM†?Œ¬ÀŒÇLLoÞ¾×~÷îµþׯ_u¾>þ—‘“y* Tï3°þÿÆðçÐÁL÷<¸½áåË— \\Ü òòÊÀà—egbF c™1@i@ó×)†¿ÿþ3ˆÿ¾ÇðM‡á³ÈkvÆ¿ ÿ™€øÿ?†? , *.1ˆý}ÂÀóï8‘J3ð2ý¯´€‰ÇY2^UU™ADDœ˜¨•¿ÿex,ÃòA‹í%†Ã `ýÇøŸïï­‡ÁÁ‹˜ Áú‹‘L 2~e°f¹ÊpôŸï? Ï>}úçàà&#f^)æO Vì÷X˜0#@á,.þ­çH ¯ÑñßÿL` ʲàê? ?Ãg+¦+ÀÐcøðû3Ãfv†ïÿÙ~ª³¾šö—áÏLë[9Àþ÷÷#`Èr‚£WɈr@,Äðî§îÿ[f^^cx~‰áçÓË V÷ ¥Y?}ùö“™‰åÿ ²ÏÈúˆ½à™&Ý«o£•Ç+ÀÁòïï?hvDʞЂå?Š8„I1ÓË? ™ÿþþ§f`NúÏÄÌðã놋‡®.JZö0Ù>€ÂqY‘s_3N`žü´ è·ÿPiPeÃôÿjþðO`0°ifhTý‡ºì\² ï_}ðE· €0tð¿ÿ?10òÊ9߀޸4ô;E8€Hÿ}ÍÀðõPü$d¾-ûL˜‰ è ?’ lŠQ(fQü˜þ-üó–Lÿ:â?Ð’ß Åö·‡ e˜¿ëà‘Ѷ¬ ºR ü 5ô”óXþ F6 ¬%1ÈWiåïOˆÏÿùÀ†á'XüãÙS aßN½„(_}ð7Ã~¶' rFÀøË†™DAy„³b ìÙd1(èÁô h€FůW ûŽ~b¸´\‘‚_ݺù Ð’oŸ zþ ãÏàÐüÅÄ‚µ2‚…8q}ƒðA4ã/0[Œ‰A˜¯y ~U1â Âã;$}üGßèüÏa@aÅ ¾‡ão1fF k^†`IT * ƒT¼,!!÷¨öÏ74ü"‡öê”Ú¾Bâýÿw' Ì2Ü ¶@Kù€<ŸÌ倹LTFS°ÀÄ c±—iÄ„µˆcéøÉãÿBŒІgŸNg¿ ÀÒ‚áâU ÔK v`ä`ƒÐȘh 3fÔ@±`-bÁÎú-` 0(ˆ¿3|¼øáÉ]p¦{î-0A>¼ðŸAAh;Pó?,- Vì/€bÁ.¿ ˜ñ'¤”±™øÅW oÿ0DÚ¹,ü†2ç7 ¥oXXþþi 3V«‡@EéGhÀ¢à¤áfdd0ç@o61'4¨Ñí•’à(À´ €°”„LÐç͉PÑ *ßA^Ú,ˆ«ï‚=øAõ#+V9€bÁZт⋒Áa TfÂ\­ P/TI1b6Jˆk.v68€¾ÿK„¥Äþ°@³7* €úzŒœ@‹y™©èP¬2ZÙ†¾ûöéç;1v&ul& 02ÿgøó•—áÛ—?Ðåï_¾­Þ<ý|%Ïÿÿp4Éñôu°¨¶íÿzøûùÓ×SÐå£IFo`Œ¯â«1xIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/back.png0000644000000000000000000000343511550446572022130 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<¯IDATxÚbüÿÿ?Ã@€bb`@î€bA`dìƒ:ˆ43fFç1#H7˜Öaøñ§š›…•…)(únبy™!jABgÒPì ÒC–dؾýÎdúö{w` Z„²¢@ ïÖ  @øT!73Ä8@‘îGþýWfxÿs­´4ï´…³½$ÖÍñb`g`ø ´ùÔ uÜL -gdøñ7šáß¿ÖØD]¹ºJ ~†¿ÿ1üúõ> (Y΄b8@ïFF†O?;D¹²::ìÓuÁ¦ÿùýÕPZáùœb9 ₜAáÛ·9†¦R¶Ó§»1˜K ÿËðúó¶ÿ ÌÌ`[þ-ÿËÀ v"‹€b!hùᅩ §Ç&*ôtØ1ˆŠp2üúzù5F†ÇŸ˜ŠM3üÿÇÈðýÛ&†¯¿€ÁÎÔÇÏ=ŒP𕉉“å,u Ù €b!`y,Pÿ̶NGβSpè¾ùú‡aú9f†ý,%~30þûËÀÈÌ §)ÂÄÉȘÇÊ͜՘Y±÷›áæó/·jÈÖ NËÿþ‰æàdœ=a¢{zª8„¯¿þÏ0å 3㌠\ÀÐfüû—T’ÿÒ z€9ï?R؃$€™˜#8ÙYŽ\yÚ¿KÝ*€Âî€ÿÿ\YX§OæÁž” 6ìðÃÿ ³.0}ÂÈÀÉü‡áÓ_À¨øËðç/ ªÿ ÿ3 þ÷h 0‘ùŒYؘÿƒbã7ºU„ͲÀ°ŸPWïÀ ±üÃÖ[Œ s.0ƒ£“èóß?ÿ00ýýÃpë冒Íþü:ä×` Ù¿ƒsÆ_ þü僋7C–‡8ØaØê=€Ââ€_™®®*Z¥%f`Þ¾û s.㘸™ñýó×o†¿@ühÙG`¼>ý lño ûTî7ùï?ý`Pa‚g l9 €°8€106V‡ƒƒ™áÚ«¿ ó.2ƒ52³Ý¯_K`øз,ÿÿ X1”ýD3üa`ÒLÿÿ1üEÇÿÿXs&@as;;8ù2|ýõŸá;È\`pÿï¯_H€÷/HƒÙ@_ÿþp ($@¡{,A@Xê‚;Ö­» .^M¥ÿ3„©þbøüí !ðo #¾ÿ Ä¿ ø7ÿ7°ìúÔ÷ž ±@aqë´•+¯=™3÷ ÐŬ ÁêBÔ€ñýõ7ÿÁ‰ äûßÀꂇõ/ÿâÿ ¼lÿxl^¶ÿ`ÌÏÁÀÀ¬†öã„- ®c¼ª´tÿ99>&O†8ƒ¯À¢‰a뱧 ?!Á L_¾þbЗbf¨òæ`ÖÅ1З ƒdÅ`6Èß~ü§F,Q@8 "æÅŸ?ý”ŠßÒ17ƒ·§Ë)2T•ÁXŠrñ1´myÃpüæw†ŸÀDúë7CUßy†;>2°pd:€Ú‚R¬lL ¯>ü`øüûßwtkˆg«\¬,-?ü~‘œ°½÷úõ·|e%† ªÜ }aÿº6ÿcx p©÷ŸaËž‡ÿnŸ¹ ˜Îõ²£TF [X˜YͶSèV ÁæËœïþßm®?2çüù—JúíTeyn<ûÎðë7$…sqS7ëj.–MàZ ÝLØÄDT…q?‡ã– w¶¸ymdØqè%ƒ¤ƒ¾7¸"ú÷ÿĬÿ@«~ãÎóØ@1‘Ð{ÄÀÏzï·º ð-_:Ï2üúÏÌ $È ŽÿüOTkˆx@jÚÀ8nþùÁ£µéäÿè Wn}fá×p+AúþTly¦# ülNçμìó Ûú£¨ù$0¯ëefFHÅÁ)~¿ý#ĈÞ7$ªccƒ:ÿÿ;3üþWÃÈÃÂôŸ‰1(z£cj!³@ô¡wLˆq ;§4à}C€p”öð[G7¤IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/kgpg_key1.png0000644000000000000000000000253511550446572023111 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ïIDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €Ü4à w@ ¸ˆD„122üÒøÇO= Û™‡•׋G€_éÓÛ×~üûr ¨æ PÃ6†ì ¿ù€êɰôßbP!@,P1î þ¬ lÎRr’æÊº2*Z&RìZ†‚ ‚¬ o_}“zúè‹Ë“{žÜÿúñÁ¥G^=zœÔwœ_;1;” @`°³°,Êp 1vcSæ``Jóp%D˜y„ÿ}bPû÷ŽáÏ' êçüççÒmË}lK®@¡m eØܬŒÞxÝxX…@"P©?@ ´˜™HÃ. Œ§¯ |,·AÚ¬¿£‰¢èŽØø ihÊo`ô]€I€@ÀÌÄÀøë× á¯>Üg``šÅËËÀÀÄÕ3›¨ó!ƒ¨"CpЦßïßýþÿš³æ?#(rþüúŽc0dÐ’W¿2\1üùÃðd7@±@¢ï?+·3C|/—äòχÕõädu¯30|ù‹’¢Ø†²À„60Uý&ŸO@7ó‹Bä¾_a`¸q‰AU˜©´€bOÖÏg`X½çÿ`À$´$Cà?P‡ŒÉO†$3.`<Æ)0Q~D²ÿ¡å'¿g`xzŒáõs r N``¸|ƒái|<ƒ4'І•+>Þ}ʰRœÁÄÒ˜Áè/0Ùm;Ì0(•ÌM¶I¬ ¬Ì,ÀÁÃð‡¥ˆ¤ÀðýP)ÐÒï@Îëd`¸ý’¡ hÐk Ôm »MÌPdKM¬çd`¸õîó†ý .@9E`LÍ@U€‚DÁÿ¿¼¿mZLÝ¿€ÄÿõÏlÐøf†èXÙÅÀ°çÃv è §¥ÆdCî-d€jƒZòˆw"Ƀ24#(¯&11¶‰Š1ùÊ©±()é2q)è00H©þaàúËðëë†Ï¯ >~ŒÃ—öma¸÷î ƒ $¬íþaÛÄv؉ÀÄÿèP`)]gt¹•ƒ™¨$ƒÚ÷O Ÿ>¼cxðí7Ã]`4ßv›ƒá"¤>!€É„AM ”ÿB+#€bèf9@ x{ €Ü4à w@ ¸hÀ@î€p«”ƒùäÍÕIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/view_top_bottom.png0000644000000000000000000000303511550446574024446 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<¯IDATxÚbüÿÿ?Ã@€bb`@, ‚‘19‡‹©Žƒ‰ûßÿÿAbà€a1Àˆ&†^ÿÐäaúå1ô12þýóáÏÏ¿“þÿŸ×@Œ (àãM{ÚØ/Å+/ÅðõÛ†¿ÿ€jþuý:çˆþÅPö¨²Zý™”2Á4H=HŽ…‘áÃÓ× æÎ{õëë q€‡7+—„Ž2Ãq öoCY bù‹0æ˜å‘,ÿ‹„Ajƒèÿ¨jÿmüÍ!ÈÀÄÎÁ ² €Àø÷éï—/Ù?AÂdà˜¯þ£Zþf0L)„`ìÿPõp½PÌÌ4ÿÇo ÙL ð` H`bbøõ‡‘aåš ß?~g``ÂŒ_là?rD#304‚¸L@ñÌl Ò²|`;A €X ˜>|ýËà,õ¡0WèÒÿ 蹓'7@VöÈaÆÿÂÝ/–\ÿ LŠÌ`q€b¸Ž‰á70•‹ð0¨* S9£ýÇå?`<01³0HŠÿdøs ˆ™ ©ôï?ò¬€ˆþŽóPú?T ˜³€fóòþ房À´Á w@A¢€‰ìŒø#«ÅÂh„…0G!ð^0‚æ&H$Á!@Vð2 l929ìß¿ÿPÙ ÁI!‰`pü ²Päs¸åˆ(øåCÙàü ͦL$"€øóŸ£ûšÉ÷ ö?xô€ËÅ ñ.@AC€ì*&Fâò#TŒfff@‰ïal`È‚|L_ 4ÇÄÆÌÀÂÂ. `Q@Ðr€Xf31¼ûü“áÑ‹/ þücÀ¨¦¡^Ç"ÐPF°O EÝ?¸o!ú@A Nù -@ö?`€* f†/¾í•~`cœ\¬ ×Üe˜±è3ÈuÿþBË\d û+kÑåA…þ( rä¨Zûçwfñ°4†/Ð ¨˜>}ýÃàa%Ëîi ,–¾ø÷×ÿ¡)=u3 %6ž Á¾þ©ÿPñ¿þ0ðq21l¿ÎİøñO`á ɆÄK„?~ýg“äe°3‘!#+B¢âï?D¡¦ÿA¢ÿ ÌÏÆð„ù=ÃÏ;á@ÁK¿ÀXýƒ”þ#Õ4ˆbÙß¿ÿáÙâëHl„@!ó÷/Dþ÷ï¿ ¬Œÿ~üüÔɶÌL`W20af5X6ƒY£a "«1 ñ‘ hü%Vpc ’ã %!@Á ¢?ÿ‘‹bäâµLGµäšØ?0€ihöùV´(ff@®‡Ð-GÎ㘡À€ÅaÈŽArì¿ð$KÄ‚\þG‰sÌJWœ£øÜÁâþ@Ô‚BâÏ_Hb„5þC€È*Hˆ@“ýÿ—Ù(». ©> Ù|k¡.„/R©$Ó`ú‚5Ήñ5ÄR†³b­žôŽp&`&Ý ¤j^¾ùÁðåów†ßeˆ"Ðò ¡¡õž6 åÁ¨´tùl)°ÐaÚÁ Lì¿~þŠsÂC €`%!//;Ãù{ì ½÷ÁŽ×ZP7üûÔFYÄÀÍú g0"U@Œð¾,=ÿCª¬˜™¾1¼ø E>N†¿ÐŠ €ÀøýñÏ»7o¸å%Þ}ù ÖkÃ[Á Ðæ5RkÆÿÇ€Ô2FjA£›ñÜ/`b`úñžàì€_ÿ&Ûx0Ÿ Ôhûÿÿ¶Öí,•1ÿ?~y¨qŒÿ@Õã¿? AbÄ8ÐS€ðÎ)@ ¸ äè¸ÅÛI°®IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/messagebox_info.png0000644000000000000000000000443011550446574024376 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ªIDATxÚbüÿÿ?Ã@€bb`@î€bAæ0šÌ­SÿÿË2üùãÀðë¯1ÿÿ@11 ý(yhÂfæý@ñ; ÿþ10üùÒÃÀð„ÿ!ŒzY g QÎüÿ_™áçï|†ÿŒ^übÂÊ JR bb‚ œœl ÿ20|ùò“áõË÷NÏA†³ë7Dyþš…•-•¿Ñ- ì¹àÏß6.îÂÔTwS1†߀>ÿ þËðáóoÆJ#UôÕEL´Åªc•FÅ_†_¿A¡ô…áÛëG ¼ ÚÞ œ‚üá ¿×€ä¿(V–§Èðç_‹w€5£³¹(Ã÷o ‹Aqýˆÿ3|þö››“µ¬Àøˆÿ0ðòp2p±3ðè€àtñë×/°#ØyEäl]˜ÊY‚ Lüü]¬¨©$æë¬Âðäë Ëÿ€ñ÷Ÿ¿ؘ™î½f`Øsú90Ç11Ãʽî½úÏÀ4ûûO #ÀŽ…:âÍNi`úQ×bº®˜+˜‘­ Ô4ðï¿4Ã?Fo;;aF†OŸ†üø‚ÿsØaa†yû_1ì»ô˜NiâÙ_^^^†o?~íøÏðè€_@µ?@z~~`øõï#Šû«—]ÿÿý§´é<ÌJ€B ßœø%„ØD¤^¾ÿÏðÿÐòŸ¡Áÿ(ýŸáÝ—_ o?üb`fåa¸ø„…áâc&†o¿AÁÿ œ !jA–ÿ;ì ÏQÁÌÀ-!Áô‘'²•„þ˜È*H3¼ÿÁ̰ðÈ7†s`C e·G/>3p3}fБäÆÔ_vV&6&V¦ÿ N|aøú‹áïï¿àtð Hÿ¥‡?Œ o?¾`faàcørÿ‰²•Ä‚VÜjð 0|ýñŸáè%P†gf2b…:â0þb•dfp7`P—å†0G0 +ákwž?üÃÀÄ€ˆÞãñË—Ï \|¼ Ìœ\ [­ &4ˆ²±±1|&$æ? G¯gX|ä+°”ûÃðèqAn`°³2äÌxÄpåÁg†_@u>ýdøŒûß 9”ÿüþf¿ùø‘áó×ϠĦJf ™ø­ 4ügúÌ&ÿ@•Ç`ÞcþÇpáÞw†?1\zôœÄùÙ~þea¸ôà;;¤²ÙÁ1øç€eó³wï¾|û¶T`ü•ÿÿ3"[ @è¹àÝï?¸!šÀU ë†×Ÿþ0l>÷ƒA‚ˆ™Á>fcašõ\222B|ÿìíg`Zù ÌŠ?€îÿѲȩù ÌÆÀ|ýÙJ€BsÃOo?8Š©32°³€²Ðc˜@†üexñˆ_ÿ‹ÿEÁžÿ-Ù>}ýÅðé-°¸ç`„„È'þ-²™Y~òõ¿¿­ &´àü«‡ÏX€šø9Á.j[6 äFhÈ€Œý Vp,02@ƒêk˜>`ˆ°ãž ˜P½~ RtÙJ€Bu3óÞwÏ^>ÿ샴('Ä' ƒ`4Œ ­äÿƒ r›äÈÿ4Øظxþ~úÂðëùËÀ Ø‰l%@1¡EÁ=`rÞu÷Âu)!vA>` ýù 1 ÿÿ"0#¸ ú …ÿЖÏ?¨š¿Püï¸Î`çfø~ï!ЬŸ€AuÙJ€BÏ À–Lß“+7¿¼¸}ŸAKQˆ•(öû7$x¡>bV:þBÔÃBTòS¡@ËA!Á-"Íð˜6~ܽ ŠÃ @ (€B pÜ^*j»¶ïÃÿ/Ÿ´”E€%Ä ªšƒ–,$‘‚ÚO† [ !)aˆ@ËŽà–a`úËÌðíì9 þ_3؉ÞD L€03s÷÷·ï—]ܲ‡ýÏ-u n.`t|þÎê,Ű­C‡AY‚“á;#7+· ×_, i>R Ú­¸x9É“‘W\‰™‘ƒáËÉS ?¼Ý Ú lM€bDNDŒòý™¿ÿøA:ƒCP BÑÖœS\œáù‹wÀÂ烰¦ü¬|˜à T£ƒ•áÞ“/ÀXäbøóþ÷sçþ¾»X˜ÄU>FÄt#Ü€Â×&üÈÀÆ–ðãÝÇ[76ï)VWfVSføËÌÍððÕ†ŸßAÅëop£äcF`VcdúÃÀŒáï7n0üÆùÿß¿f-¯¸, |!€hÏÿùg ,ä YXÜ@U*§¨07°b. "TÂýþ Ìf¯Þ³Ú‹ÿÿü8”œŒóíØ[ùˆ âúLŒG¡qôÿß¿_>ñürï‘!ÐÓ àŠúÀ,ñZÂ]ÅnF¶ã@[þc4@1tç €¼o@î€ç€=f-,ÚIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/ledblue.png0000644000000000000000000000451311550446572022642 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÝIDATxÚbüÿÿ?Ã@€bŒŒŒ>Mó HøË/†Ï?øýÓ’áÝ7†oß-þ*ðU}ðï=ºÍÀÀtŒe>ݺV ~ç<@Œ`æ&v«å œìÈ`cøô#ŠáýVSE6u!y!Av†ÿÞ¼ýÎpëÖ† gŸ3\»ôâÃß/G˜gñ:T|âªôf00ðKB,a&F{†?{¹¸Mb\ä¢=¤ôÕ88˜±ûïËo†3—>3,Z|“aÅÂó ß?¼ÙËÀÀV ôÉE¨¸ˆÿ‚d7@! ŸÆÀ æ ´Èæ`:ž¨‘½Ã×Z‰¥*\žAO‰‰ñ?$ÀY€æ03Ü1öPì0$þ1PÃ_ ø‰ ?šN0Þtê3P4‹u P%YÄ¢@ü 쀂8@»hª-б@/p²‚‚¾•‰§*?ʈ!Ã[,Pw±1+3Ä €ÝuÀ/ Ç~øÄÿ€rŸ€tOÿ†…Û¯r„¦00”C|Á` Ôw‚ €˜À^à²*øñί߅, U¹‘æ Q΂ ŸÂß~"|Ãþ!Äàì¿ù/߀ŽâÌl†˜š@F‘É "`ÁÏÀ ¶ € øübùßÖ ¿˜º-LŒÜÍyÞ}¹‡á÷_ùð׆ó¡b¿ÿ ªÑ?èã†0-oO¥³5 Ø ¶ € €Ä%ÃßßS™¸T™™ÿò3|û Ο°cP0ÿüªæÇo$q& QEf[^'`H03Â, &xþó'‚“GHŸ‘YŽáÁ«_ Ÿ¾A4tÌwb0Ô 6HÌ1 |4“EI‡ÇÜ…AÉf-@ÁÀÌÈô?“S@‰á/;ÃãO Wþgø ŒË¯?øÛOT>:†ÉƒBïë/û0´ÏÞù ,F€ln>n u¦¹h`` h‰`ÊÁÃcòŸKœþ“ýšsÿäÄ™9!©œØ€ñ ÎÐ\Àˆ” Aòàx‡;È ôóô#Æ‹@|, ýg`’U``½¦kÿû—€ Pë€b–I^ÜBÂ,_Ù¸y h3ÃÃ/Ì O30Ä10sC³Ðp6h6— ¨åÀoh‚üM¸Ï!9ïÃÛ?@ ü@×~ýËð›E€G\óýcyGâVFKA!†÷ “Ù˜˜9™¸€=xËÀ°òƒ£*ƒ‚0ÐP ËoH ;–Aƒ|çÃ^`íðö /#PŒX602üê–cxÿXÚ ¨u6@A*#v%>^`ed`fgdàcc`àbVH0ôð ƒÐ"< ÜÀª‚QþýɆ :ë50Á=:ü)0û1ÅŹ!E4(ÝZþ(Æ&ªÃAzìf>F.vF ëù€†ƒs' Ä·o¹”@%È R‘ Äúšè@ÁJ3<ìµß~#g: c€rÌ I.+Ì Ì¬L Ü@_ñ5ñC2€šà˜¡ÁÎÈÍßQ+"¥,@Ó¸€òÿ  – Hs3 B Z•001Ãx vÀfæwìLDøY!ÁÎ µœÚYÀŒ¨„@aD²„ÁiZƒr#Ô‘œP5ÿC2>ËO`P1|ý’ H°0ßaüÿ]M€è&H°Ã-gFÅ`@³ ,²$ÇôUæˆ_@yV Ç~¼&†·÷Aâ‰EVÖÃß¾}bææsf„oA²²`bPVÄÀ, Sw8„51„Yþ3|~ühé“S «â€ß·½züú'?ËOxa(feFµF³Ã,e…øŒ•‹åHQÇJ˜Ÿß1¼}|÷+°p>² € øñûÒ—§|}ù˜›ŒĮ̀94Ø,fGò=+3–(ƒ%^`tð³ðÛó·YûÒ!`~¸² €•Ñ×?“®» ,1ÿ€,˜Ñ eø= Ð}ÎŒ’`ö×/ ×öK6†Ó`Ö¿þl~uýåÁG§Î1 @%‘ €…³± Æ?ŠåHú@”]„¹þÆÆS Ÿ?ÜÍÀðxÌZ€‚8€™ ’1ýË>¾úÔ×_wî3+.ˆFDÖƒ9ˆ-1Â,‡E’zàý±k ç÷Ö;‹ C0 ˆ’+oaùéêï¿Ò¶MØÆÀôø 7?D%(þ˜ÑÁŒˆ{lÙ“Ú^äZþýÒ]†³vùËÓW 0€‚8àÕ n˜Ø²Onç®iÙÂðãò`Ûh¬Üb€7 Â¡r 2è0`T¾=t•a]×F`ólA>°ŠZŠÞ” D³œÛèX`* ^ñåH&ëéΡöüÆ¡F Ì‚\ ¿ƒ› ðìÇ íüAj+‚ ?P´ü|ñ‘áØ’3 ‡·öšVæ10Ü^‚n9Èn€Bí˜ð›ÌŸ†×@ ìž1k30xtKHXyZû0hÚ)3ðI ‚‹‘‘©,†–„ßÿ3|V›—÷Þa8ºù<Ãû‡€íñÀŽÀ‡KØ:2 »Õ`Ъ³€x2¨¹ ÄÀÌË àÍÀ`˜ÁÅ¡m¯¨®È+«&Î *ÃÇÀÉ˶øÛÇ ¯`xtóÃ[÷>ýüs˜ÏO[À7ã똂ì ,F:C&Ôß õ~BØ4‘v"@ A%H• J߀ñöæ°·lC=: ì’Ü$¦g ² €º{`Û>Nš‹‰wPIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/kgpg_term.png0000644000000000000000000000436711550446572023214 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<‰IDATxÚbüÿÿ?Ã@€b1bXj%$ ™ÿýùËðû߯ L ¿þþaüûû'ã¯þÿûû—éç—¶ýfø_÷¨ˆñq &Å+0 ’“ C@U-ƒ«ø†lŒ LÜÿ¾|gd``aa`eãcøý‡á«<ܶz'œ_”¹{ƒ ¨“‰è?@ÌH$†€‚;àƒœŒ4ƒ2¯£Ä¼ÿîdbXÜÅð•“çKrËvQ/{†ŸÜ ‡³>pÞ¨êî5vvV Ø€˜ˆ™0333 Ã@ÁYÿŒå€!ÊøÍȰuÞ¿_—oü38qæ汵ߊ~20°‰2¨1°3±9€”±ƒ’œ@ü ÿû÷'†€bB ky¤0ùÇÈ a$ËÂÆÀU&Ê#­i«v%#ƒ¬ ?ƒ¨”¸%$2)J„~v;i¨“@f²ücpOÿɤæ`”Ê-ðALè{fA '›8/ƒŠžœÊŽ'|ûþý3+33#"xÁÎ ~d>ˆfF?;ûC AÝ {îaAXbf zÅ ¨ò ÎÂ@ŸBy…GA]G˜9B .Þ!&‚áÏÏïÈÉÉ 6##ÃÌÙs` ¸¾ÿ`xÿãƒ$rø0BU0rB9PÃXyE9ô¼==Ñ,Æ(Žÿ£Óÿ¾ÿþÉðH¯^»® €àøø™áö§ ’|ÿQíÇ;²o€qôçû?ö>¹ÊðlÍ\†¿? e1&0 Jè068Ûâ¢eÈ #$Ê€\øÜ?þ2Üx÷ÁN=M1† ¾fxöä ƒƒW0ƒ¢±.ß?ñ&4v†£×Î3\z|—AAD‚ © &¤ràÆ›7P_3!ìûñáï/˜RVˆâO_Þ~úÃÀ.ÇÍðýÿ{†ŸÌŸpâ_ÌŸ~2}dØ||°G(d` €Xbïîë·  bC¸€˜ ~ËØŸ*ÿø%ï¿'@wóñ§ß ï€eõ?˜=Û)žáìų GïdÈsJ*ýÇÀÈ„€‚;Xþ\<|œáúç/ Q Œ\rqv ŠŸÿÞ¿axwä9ÃÇÇ¿îÝ—cxÁø‰áÕ—; Œ?þà´œ™•™áíË· »7ï:œ”(€éñ?J RT?üø…Áäàq†UÞ Þ\Ðh`'&`Jäd˜?ùúWOþ*~gøb̬…Î10ýeDµ•ñ?432|ó“áá¥Ç ¿ÿ×'\ Dr€bùP߀œ×@ÌM„ÿ %ãW¦ß g™––-`¸÷&Cý¾j`èüf`Ò ¤ÿY¿Æ~baøýXg `æb¦#F¸C €˜0ªI†Ss¦0|{y*Ë «:>~ýÈÐàPÆðûÖW†çמ1p¾bàû*ÁÀòVˆáçS.–×Â@¶0Ó;>Æ_ÀJŠ““…ƒlˆø÷¥6 ¥æÝ}Ê0û݈,# 4ƒ<ÈÄðý×q)q†å×7sÂw+i{†±3<ô=Ø9yX€‰ŽècfN VÕ0ÌÀŠ5 ÅLˆôðìàPeøû÷?8løØùZ–L`X}t Ãêí ¦j¦ {îe8ûø2ê¸é ú‚š ¿Y€…ÔR&feEIÈQ@,X[+ ×Oîeø£êÆÀÂüÔR„ÀŸ?͎̔>=Ëýé ƒ—"Ÿºƒ.· ƒo{<ÃÕ¿¸¹y.fU ZOa¥ Ô&p eC€bÁ‘ƒv_ºÄðþ÷WQ6`yðï/$Ÿÿù÷XV‹3LΞȰçÐ^†÷0p‰ 0<ìbøÏÏÂÀÉÂËðhù`ìý Ú >0舀 ¬`afhM(dåÔ¶K^€rÄÅœl ëÏlbx2áçÞ þaøöã +ãF†ß "óÄ÷`üë7Ãßß¿€9àÃÿŸÀŠˆÒPAN„„ÕÀ4 ÍÍ«ˆ ‘d³2²1TûT10Š›> 8…"WˆªQ+ÿ‡¿Œ êâ2 ?€‰9J9«n€SåÊÙ %– |ÌÀ(ývÌ?NV† ÏH!y)` øŸÿÀAú™FûfƒâDþþ…á?Ð!ÌÌÜïXêi`š½ví.æ'Wb”,À nI0üxêÊ7ÏÁA )`íAh|ÿG¡!ÒP63SãO¤Ú €ààCj·>»´8ƒ±ŒÐAÀ¶Èßß à¦÷—U§gïû.&ü›˜À˜‘›\0Œ­9†$Ì‚Œ@=„Ù @p°"9Xr{غ1h²)-¶¶Àå=0³1üÿ¨ñúyày1¡ˆVÖTŒÒ2þK j¡õ ˆ [‰d+ýÕÀ¶#Ð5À¾Ã`nx÷ò °¥ÏÀÆHB_§nï+¤à†Æô5kV致Ƙ~ó0,¬z l½j:àÓ_PíxÂ,À†€‚³v±#ƒšÀ$òèÎØy³8y%Ø|_ÿåfØ¿ñæD`›¡¤Vâý{†W@Ÿ|b‚µÿm?Blt@Œ°"H”Û<¡NFHŽàagdÚ ŒÍ¿ÿÿ÷aWÊÀ¨â@ü‹‚ Ì^€bèî9@€<_C‰£¹¾IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/kalarm.png0000644000000000000000000000546511550446572022504 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ÇIDATxÚbüÿÿ?Ã@€bb`@,0F##èTŽÁQX”Å]D–Áš•í¯Ì/ÿÞÉpæÆk†¥_6åx˜ ˆlåd%¬Ø…™ù~ýa~þæáÿã/žÿÙ÷‰áÿ®? _z~ño ž y€b„EÌ  a¦bÀUcèÆê"©öƒ‰O¤ý/ÃK†Ÿ._eø»ä0CÓ» M|@õbL ‰n– õõx9å@ç03|}ÏÄðâ3ùÝÿŽœ½ü³è€M¿Ñ@,ÈÁñd9CŠCºH·E“ ë{ j òŸP—U³Ù²Ï˜E…Êÿ}càà:ƒ)WR•…—Ch‚$ó gùÃÀ tŒ²3ƒ¢)›Üóu›~4½þÍÐ4éÌN€‚‡@-0˜XSüê$g‡233<| ´ ¨Žª䈛Œ Ÿoüg¸ô6«&ƒ  ÄÕ_Þ¥ï32ÈüdfàS`d`T†Çˆ£Cõ¾bg¸¶õ?쵿ßÿ`hXµ €à¨ddÔuÈ=àÞ$&Äpú.$¶Äßef`8 TÇ÷á¿£7ÐPa†OÀÈú nV …ÿß1üô™ñ<ÐE߀êMâê 6PÐ €ü'l ¶þý·`×ÏÿÿïÙ @ð(”fM6ÏZþú+P1ÐrY Þ : ôÌ`HØ•jI20>cøsΊáÿ?Y†ÿ10CŽ‘è(†W ,ÿŽ00XCîîk†ã¿þ>ebø«øŸ¨ÿ Ð!ÿÿ1˜ë30¼È´쀂;@Ö€ËB@Þ7¾€}u~3ÃÏï Fn@ß…}|O…á÷{†ß²ž jú Ü‚ ÿY9@ø¨ðÿ÷O Ì/üØïï``ÝÇÀ ƒáÖG†ç˜¾±11¨™þg`*æfMi}˜½w#33(¾?¼fbØÖÏòî•àä¥ÿ™Ø„9þl×føËÍÀàÉÀÂÁ NBÿÿü†À/ º€Ù< ?%~H2p=°bà¼;‘Y탬̆½½ ÿOl`|ïâÍ($+󟉉^þœñøô·C»’|Ÿû¤ôä³ß;§ýgàºï:Þ†+@GüúÁÊûÿ~ƒ÷Ïo þËð÷ï_`Èþeø÷ý;ß'÷þýûÃðEˇá«v Ãÿ§Z Lìl öY Œþþ?5mΟ앫ÿ>¿ü€áÌ^€‚;àËóß½ç¿3¹üâ÷r»T[I5 +¯ñ0üøÃÀíÊÀÏÍʰª¯áñí; ìl@Kÿ-a åÌ, ?ïÜ–# ÉÊðçÓ†Orv ß²€e‡›(ƒuƒç¯ÿ'vŸÿoýø C-Ì^€‚;ªÏ>20\ã`ˆ7&A`öù{׈áŸa<#0”Uôõ4ÍÍ–µ·3ܹx……X^‚ /fV†ßÏŸ3ü~ò˜QVŽá0t€iá÷— ŸÕþr8ã•AÑ‚ XJæÓö}`LßÙ @p¼b«cV3fð•Ñrž æña`eø êŸ?3˜{z0è;80¬íëf8»k;Ã`.àdecø}ø “²*Ã?pB¦ `bûÿç'Ã÷¬ ?‚Á+ÀÀ I-W`‰H ~O„¿!®‘‘ÖePñÿ¿bø'iL™ àìŠë¿@Ãíã^?~°aÊD†m{÷2È 3Ø)(2ˆñ/_@å (j@QôçÇ7†‚Ú Ü åÿa!`žRZúf/@ÁC€‚EùÅ eß>†ÿœ"@Ÿ´dðŸß€ ïƒ_fÃ'n>†_@×Ýxû’aÑ Œÿ ¥+Hí?h(üûó‹á7?0]‚}È/ÊÀÌC¢ÌH!@,h &˜, 8~ÿ‚}óšà€é˜õ889$UT®=¸Ëðçï9YVp(ÔüfKX(€ÂÈÊðŸ…è@ `²2 5Ý?~f€VS¿€®þ¶î %, w.\`ø´œåË7 S † €`õM°Ð‚„0ÃÿùLÄ_À|ýÌðX-|bþ‡p@ÁÀIO>Ýcøªæ^00~{¬kTáYTàüúñƒaÛÜ BÒr í9… |À4ðí+0®â`ÇB}ÿèXfv¶ßÏ€ñòœÀÞjf`þ…\ ý&8XUdøó?Œá«=Ã/6†ßÌÀ6PóŸO ì¿3pþ8ÎÀúa%Páp>Úl…Î`8xçC80—½Dþ6¨½φ¿Ðl5õ€UÒÇ·/¾—“C$ÐLíû ,ß:x>NÊʽl–\ðØxý LéLïÀAø÷ °„Ü l‰MU`øúãÃKfý€bAnÃÀHíh`RÄ«ÅÀ°Ì˜áÑù —t|¼äœ˜øÕ>-ºÉ: ß@õ9Ýæ1`|ŸÝðëƒTî%w'ÜW¸1ø£j##Ü?™ˆA݆!OÁ™oSÃÕ'·â€iíòƒy æ|K¼$$Lø%”Øùø€Àøã×/=yÎpþÕW†Àí#ƒìB_†¡³¬ÔÂòÎ-gØÌ‚Ô‡€‚§ä4ÀÊ`ìXÈpòõ%†s×w0$‹„k,Ðhúõ4°Håš&d3é7À(ÿ­U™¡žb e#†Y†¾ ¾Çz‚~~aX³¥ j/@± ׆ð`abÐ<µ€aÓ·W ©ÀÄó–I Ðgà ¨Á Ä¡½ Vhuú÷B-Pï‹{çÂ?<`˜ÌÎÌ „­ @ŒÝ; ïÝÚD¬ÄÙIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/1rightarrow.png0000644000000000000000000000306711550446572023502 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÉIDATxÚbüÿÿ?Ã@€bb`@î€bÁ%Áh2Ë HÕ1|ûeÈÀÌt‡ƒe2ëf6 F¦ald>šºÿ3y±Ú@¸Càßÿ™¬ÌLÞé‰&RÆz’v Ÿ~­døû"PF€š!@ø ËÊÂĬǰb²7C€¿ïÿy@Gle`dР–_ø´ˆáîÛß ßØúkšJ­xØØ¬¾ýÝ”‹¤†·!Òÿ˜:äCLÃŒV{yyAI†/2ügl*ä¦Ä„ÇÌ,ÿ™Yþ313üøÇÀpÿÙG z:â ËzìœìåX¾ý«bøûo#Pµ¹ Ü`e½õýdž{î3|ùÁŒ~†;ïßc`øÏÆÉÐ_jÄ“ ÉÀÆÌê ”< ±@r@¸ÀÌ’ ÄçV/¿È0iÊI†×ï~Cƒáö†7î}`bÈ Wd˜P¦Ç .Æ- L(k€QÒÔÉNŠˆWQÌh¹˜Yy¿áçÿt!o}I ýæ#P ˜FLäÌ^¾ùÅкø1ñóÀxâbÛÅÀÆ– Ìÿwˆ)ˆPIøž‘1ƒ›£ðÍ«¯_Ö®<ÇpâÔ“_}a`XaÝy6†îl%†(o ff7†?Œ»J¼ˆ €"H%»90WÌbøÇ¨'£*Í ª§Äðó ÃG CÔ%ÂL”EvœþÂзöÃûO ߸ÙÚ˜Y;€úÿà €"Á š]”‘¥—á/C,·ˆƒŒª<ÐûÜ oQ" ,£,lU‰õño†þŸ.ÞûÃÀÀɺhN!бÙ@¸`µ h! jÙv+È!‰ÀxèafaRg`äàaxt/0ù…á§ÌDLÿæïýΰêäo >æ#ÿgòØb³ €pVF bj@W0BJ$0e ' õÏ¿ÿÝþíç† Q&HV¥‹/@;}ôÄ…YÅÉPY‡Ë€ÂíF&hiȈT42rëˆZ`”ê«r3ä”`xò•›áÐBn`-ÅÃÀ Œêë/ÿ1œZù“áÑó ÿ™™O]—‰Ë€"¥=  ôêFæÿŒþvÂÌž þr3üù ´œb±0?Ãß?îÜýÆpïñ¿ÿ˜Yf-÷ê½€ËP€b!Òò`†ßÿûyxXeCœ%>³1LØËÀðh¹/Är~`ðþí†'Ï+LæÀöC PßB!–¡X/ÖJIq±:˜K3ÜøÂÃpâ&0Ι–cVˆ9Ùþ3<}úáõÛ? ô2°“ÔwŒŸ>HñL`|{«ª 1¨kK3ìÄÂðü5$#ðã[hùÿ¿îÝýÎðí;¸þ˜L¬…@ÖGbã €ð$BÆyÀ$ìÆ+%ÂÀ*.ÁpäÃ`¡Ã ̉‚<÷õó†—/2üùÇô‘¥¨i*P'IÍl€Âãfc& m‚¢ ß01|Öˆì ˾æaÿÏðúåW†÷@yœõ*0ÈÓ:ŽBìf$©6 <µáP[à 0h1@,æ•¿ž<þÊðXUãb0»–‚ªrÛ„ÛLÀÆ# Ã?Œ œ\`ÿýý'ÃÛ7_m¦oÀønú¶èë?¤úž6‡€!ÀÍÉÈÀÇõŸáË»/ ?þ…Ìm \ 0´Q`/ž&Ë[P(0ýùÁðXÐü²œu-°`qÊ¢V« €˜ðDAвŸÞ}õýÇ¿KÀ /€¶„S³_@ŒÝ9 ïЀ; ÀÄž,´WX:IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/bookmarks_list_add.png0000644000000000000000000000464411550446572025066 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< 6IDATxÚbüÿÿ?Ã@€bb`@î€p Pluˆ <ÝíÏåÁò$$w‹Ãð.¼ƒG"8^Ñk{»¥ä›/“Œíu&TcP‰ ÌX›ÛÞfàŒ”NaYf§ºëßÂ7ãË=¼Èj…ùP€‹ËùècܳÈF€_òþ³Ó­½¹Zß$¢¤ n˜FÏ_1‚!²þ²°0~ÿ÷/šãë×2ffcFQQv..†¯_~<{Æðøñc†³ŒŒo‹ŠúÅÊúPìÃoÃÏŸEµødeX„…þÍýðáÃå/.}ùòé5'çrV6¶6 £1!9 €à`:h9ÿ÷_¿¦ëþþäáÁ ÆÀ /ÏÀÀÃÃÀÀ ,¦OŸ=bø¿z5Ã%KžûÆ`jhÈÀ›•ÅÀ`jÊÀ $ÄÀÀÎÎÀÊ]?~00¼~ÍðýØ1†ý‹1l}öìù/^ÞTöÿ¶Â@pücbbúöë×gvöÀȲ2fgg†_¿ ª’j€É†““aûv†«W’’øø€Ž«…em §€QÊÀÍÍÀðü9ÃÞ^†YGŽ|øÂË tÄ€; O[›áÛ¿UV ­ñ•• ÌV@0øþþ…‚@€rÈOAÅ¥„A¡ך›¦Ÿ>}û/— óÿÿ¯œñ¥!üí[npH³–ÃØ C èÀ›Ç€Žde…DßÛ· ÿ¡£åïÏàrýºêÖ? Ù˜™+ì€?ÿú[rqIðëë30ØçäoA¡ÂÁÁÀðý;ï;w¾£é˹s ߀f‹£Êhþ66¯_ÿþõØœ?~ØjKIA =%Å3(-ø}ø0×;¾Ý¸ÁðÈÿÊÂ@üîý{`.‘aaѽÍ̬ @`püý«Ìrõ—/¨ Ž_ƒ&¨Zømˆ@_ÿz„ ŠA‘ú$´Kôß?Æ[ÿÿËØÌŒŒÀÌÿè:p¼‘ ´òõó ÷ïcøuö,ÿ߿XДýƒ:à?ÔÌ þ¿ÌV÷›‘ññ÷U€…??ñiäk`ˆý;zœá;ý ?¿[² ä‘0(øE0QþêûÔÇòïßs€‚8àß¿£~ýrT¨P9_(€B e÷0|>uš¡æ÷†Sn2À€`cøÔÃFüZ*Åóø3ÔŒ ’À\ñâÛ·;Àüq €Àºdóéÿÿ ­ž<áfùJBµ@¥ x8?®\a`»r•aÛ¿¿ ûZ<æ—T3°þczæXÌ ræ/ÐrN†ÖƒKÖÔmbàûáãŸ?ûØŸØlÿÿŸzõ÷ï’ƒ?¦»Ëù_?20ËfP†e+ ƒþ€,Ê¿}›á0ÍË>†ìŒ ÊRü jì@_-Z‡\‚0!Ð @Õ6Šr ‡™~0ìùÊø†é/(aØ ÊýÿÿêýŸ?›ò23Y}ù Xñü¦F`"û d¦ŸoÞ€-f†&(P¼22âøÃ+†g@òbd üÎð˜Ö>3<þùóÿÏoŒ5ÜÌ·@Î hy 2ô-ÝüîݪOÿÿ;+•Ÿ@KŸÜ»Ç𘪙¡®e¥d¨þ]òŸå/ÃW†wÀ,ö«˜€ºY€r¬L? 0/:/Ê4“‘™EŒ „’[€Ùñ°~÷Ù÷úuÇóïßãU«²®.Û7¾CÉrXü‡ã†Ï oQðì[ˆü fãO¿Þ3¼ýöŒáÁ»k ï„Yß,åc†Z¿ˆ#[30¼àdbJ¸ýéÓÅ9·nu()±©3<æ·¯^C€ )Àþ:à †~üùÆðòóc†—Ÿž3üøý™áãï äÄò÷'P'0Ô@ €°6É@¾ãdfîÿôógÀò›7ïV$2zz ’ÊÊ ¿€iXï1°BÕ‹;`(@Bà#0%|bx d¿fxùû!Ãã¯7>ý~ÇÀ Ìvܼ ìlœ ÿÿübøÿâ|` Þr†‰iûß¿6ß¾=÷ÙçÏÎ^Àš’Øê¹påC—3Ã'>†»?¾2h2qc™ \ü€ÒÀPj¦v6` ÉL¥¿˜~Ë&6`ÎúëÇÈÅ ÎÌÁÂõóïÿ+nÔ‰‰ÁZ'àìn·Ø  ÂæúõëW—¼€@v ¾ÃO¦ 2·´3Ü\åux8˜ø8ÿúëüÄŸ~þÒÀv¯_¿MËŸ ß¾~gxùâ¨d¸rñ ÃéC¯÷Q­b`PãdaÉôî]ÚÂÇ¿üüò“aÛ{†O‹Ž0<|õŽAGÀè!Na ²Ø™¸Í6`s€X~13pr±1(« 1¼zñáâéW[ÿÿû @¤4Ëÿ²³°ÌþòãGÀÒSÇ|¸ù”aÑcU†+}ËfÚÄ Î ÈÀÏ ´\b9Ç,|X™Ù`fààdbv†][î2l]}cáÏo¿C>{@$÷ X÷2ýûï°íÆ•M×/Ý`(9ÁÆp°¬÷}ßæ9?xÄ€VK-çb`¢càæN.`âûÿ—‘aÝÊóÿì¼ÙôŸ•1…™é;È<€"Ùÿ!åÅC`.ˆ8ñð^í•›7g8¾ûâ!ÃÕ÷ê{æ\½ã•#0A¬Ç¦ €X¨ 8<|ôȯhrÍü_¿}zÿîS<0&0üÁ® ÀupÛ´v©ùsIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/noatunplaylist.png0000644000000000000000000000227711550446574024323 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<QIDATxÚbøÿÿ?“ Œgæñ ^Ï@€Ù @LähZ*$'”&3ðñ°0hÖ”2 ˆ‰L}Lu%R#ât8¥jDíÕÈ1 €˜Èð½= (H±døô“Á×C‡ABŒŸ—AÌ9(ÎLªqDN,p´UcP’axú™á#;CBŒ‡xƒL¨©†© ““M!+Á’áá†7ß XUKAMM’Aȼ ¨Š“#ˆ‰Ëùdƒ—·1Ã?v†@¼þŠÀîþ– ¬¼ *¹¤8 €H ^@/]†Ë/–~CÅl‚" Z†ÀtÈ£ZTËO¬¡ÄDB¶+ð s`xþ…áÑ'L€°ž³%+¯:ƒV}±  €ˆ ‚Ò’ &ºR Gãý+vüé/;ƒ¼¡.(Aæ³¥21¾÷’.A ·ß20¼¦ü·ßpca}c6^`¶”ð¨êc#d<@dôu •x.ãþïÜø+88­ŠfKcB†ß×3³±)¸y3\~ÅÀðó/° gÀa€WJŠG˜-…­&¹<ø¬ &Ù®@ÓÁ’AK’áÖ[Ò p(°p³¥/>u„/&p »©3œ}NzqÉÎ ,ut€Á¡Þä ãR@L8|¯$ÌÝ,ø€É”øHÇRÆÆ ÌÜR ÚMM¸²%@á ÂJò ÖR —^Ó y˜‹›AÎ ˜ÙEbqeK€bÁâûxP¶‹ˆ´bà–êï30ˆð1 DltÞݾÅûñ·gÃëƒ!@¡_ÈòÄk 122ÂÞ 7c…ÒDc†ûn¼g ¼¸ÿŒaˬ- ïNy1ÜŸ»Ö"€B~a…”p. S…ŽåÓ—b¸­/Ïpóì·f ÷0É"LfÊû ‰™öiþêpÍÿUÿAöé7vK¾ýF(bbï^fh*\ÎÀðõ~ÃŽv˜½„"b<22¼ û/<£ÈÇ K¿ÿÅ’¹ÌåÎý dÎbpÉ@è!°ˆ hþý~ÆðéZ/ÃÝi[€öÞ j"4œ’Äðí¡9Ãÿ¿´qÀÿ¿Ÿ^í[Åðñò5 ½àt@È!ÏËÍ6A]I˜fðìåg†g/Þmc8Ÿ´÷;H €Ó€€¸”0Cl†/Ͱ}ëY†g›‹™²@ Ž€BɆ ¶Ýê«4³ŸáÑkL1€bÁH½hç€ßÿ0ň‰a€@¡„°î`Д¦ac½f d¥‡ÏŸ?‰VVH¶ûû÷ÐŒç /_¾bxòä 0$0¾}û!0U¿%0¨€>} vÈ2XH€ÈAŒŒÌàÄ ÉAÿÁ‰äx™ ÔïííÇÀÇËv0È¢»wî0üþû›á10Y[›0èëk峤)(·#ãPð/}ñâØpPTpqqÙß¾xŒ!hZøvÈ· ììì@µ¿¡âL`}ÀºXsr1èé0°£ä90=€²&78@!ÂÅËË3èhQ€%B!Ov«ªJŠþ Jå ×þüXú‰ó÷;p…UÝ ƒ@Ž`aaóA¾I ApúøÌEââ LŒ, ’â’ :z ü@ýf’å±S§.ªÈw@õ?_½z»äõë¯@Óÿ1ð°s1H‹J00}ÅÉÊÁ &,N´ þP4€‚$ ã@!Š{vv`f`øþõƒ«³;ƒ‹³¸È%rPýþý7´ÔäP °/~üú¹ýÁýUŒìBÜëÏìÇü{`¿çî9e19-IU†¿€³'(±ãXæƒ,ebâ§PB¥Pp°sÅF Ð2P%à7oÞ0¬_¿•áÀcó€Ži –Ë.½öA€Mðë]æÝ[nsòcP‘:ÐÒï K­& Ç :V@×ÿd€Uë ø9” AÑ*#~üøùðïßÿà¨Éʇ}û3lذý еÀÒt(Móu‘ ×ß_`¸òêǯ__ºÚØÄ{¹[1Î}8ƒáúï‹ | áúÁ kvob°V3e`&¸?€ƒd¨89èÿhŽøÌMŸÀÑ -`£„áÁƒG ¬ü´sç>`c'•õÌñÄÂÀÂÅ S¥ßœ¶M$’ÅëÏÍ·7YûOO& &†H[}g†û1¬:³™A˜WÁNÂá0-üE4š”ŸÄÅÅùT°ÄÂÀüòÀxù*Q -„Ìÿ€1 *ñÁÉÿß@—£ûÿHÉ L;@K2 0ܾ}Øh¹þhñ`wžw!‰’¸þ@±00ýùöøÃc† £™yFv†]wv1L89œŒ%ÊlÊÀÍp!n!†o¾2üøûáÎí{ ww?þöøñË%@ËfØ9PÙ±˜øÎ@13è²¾:õàŒÔŸ_xÞ½|ûÅHÚ˜O„O˜qÑ™E €^¶–³f¨¶«fØ~l7ÃÃGO¦ošÇðùúï—ß^ý_öéË×T`:™¬ žc³TdCÊ Fp»@b°–4@C€åË“W›–ÕI1ü6NYè«ë°2|†÷`!óìó †ÙK1(ýÕzÄË!¹LETb0Šn2þƒ´Iñ1: h¥ÌÀ¬Øþþ~÷óÃ?{e;†eIKÁ.PUexûõ5?ÿ~ýõ˜ýþQ§O @Ì @Ï2«d O€Õü­W·ø¿ýú¡ ¬Ì~}6iï¼¼÷§g{ïÙó/OfK±)¾åeàg6+Áur Inã@÷ŽhÀ{Çß $¥X”IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/kgpg_show.png0000644000000000000000000000337211550446572023220 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ŒIDATxÚbüÿÿ?Ã@€bb`@î€p ˆX¶l# ˆæbcFFF7 ”'+ñ > L/§€Iæâ¿ÿoÙ_Þ¿ÿN–¥sæô2œ:uˆ”þˆ*Æd‡ýýûÏùï_FS _-tL 8ˆA¶>e`øŸ¤“ã€ôôrNNn0 €ÀøõëïB kü‰ÔÏ Ä*@lE®þþýÃ’R fØ¿ÿU&Ã[ ¾Ä@fâPó ˆaùœÊ? â|ÿþ,@,H’¤o(&,â4¿A€b€ÜÄë€XÄ ˜ÅlP.Ž@¼–ÆŽðâ} @ÁÀŒ$ùŠi žƒ€‚¥V( Ê'`*€e˜¦A}±ˆãA €ÂFF&`ÄÂÀÊÊÆ,p~üøvˆÏÊÊÊÀÌÌ Vƒ¼FbâÅ@|IlGñO €X –ídæÏ¿ _¾|ax÷î Ãû÷o~þ%‰`÷±²r0psó2ðòò1ðó 0ððð2üùófèT #ßéë@zÿ¿ÿš€l »èàK@>;0½€b ìÞÿÓ@Ðràó;w–úh ƒ²²,ƒ˜˜Ð"n`žýÆðéÓ' þÈðíÛW†Û·Õˆ\TW×¾ ,T޽0åׯ ³~3pqñ¤AØ?^½zÁÀÇÇÿzëa–‚ÔÀ@pöìñç** ‚êêÊ@ßñ3 ò1ó‹Lv`4ü†Æ/`‰ù›áë×o —.]eزe×>>)ÿþý†Ö[†×¯_À ³?þTÿ• }èÈÉ c °€¾úÎÄÄÍ`d¤É ))ÔÀÊJwþü'@..v`Hp€ÓÆó篠i„ÝëèÑý€Ñ÷¨æ33°6–g ôòåËXzúÅÄÄôïû÷ïŒß¾}Éýê=KÜ @`011s02þõ†sçn}ÍÆ ## t 8!Â(þüùƒA@€—ÁÑÑÚóçÏŸžÀø;ƒÄ@é Y Rüþb¸ÿÑ ?è0p" ˆÁLàd½cÇa†gÏž1¨ª*ƒN•AEE \Jà j;JBBˆAIIšäE úóç7˜U4 æ`úâ?`ñ/^1°³+ÄܹóD¨>h䀂†(.?~øõÇîß¾}É—‘‘}÷î#0è9Á†²Þ?ž>}v#ãg¸ã@|P\ƒJu (Æ Y`d;zLL¼@5oDDÄ<Ξ½´¨X €`3ÈgÀ„Ât5#0Øÿ€rH#(Øþÿ‡8àÛ·@þp™ò=¤à A ÁÌ oÞ¼‹KIIƒÓÂÓ§O>~|Ï //LÐâÀDù ˜¿3|øðµ÷A¼$äà`c044äzøðÑaIIQ`Âãûäxû‰h˜¼”eÏŸ?¿ƒ}JíïÞ½Zø (ö(÷áåËW@þW†«WÏs†Ðo€æŠò»¥¿~ýL™@Ђˆ‘TII‰1¨zgffù_xuŽ(–ÿãóÿÿ¿@_-ú LõßÁñýýû_†{÷ž¿xñ⨠ùôéÿ—W¯¾­†¦ñ§O¯ôÅÄ$€Žz¿èׯ_‰ Ü2 € i€‘Ô&„l@÷€ZI`‡Àª éà0j¾ƒËP¸sç0í<4ð-Ð7€ê¾{÷¯áãÇçÀP¨zìÚß¿ÿYzÝ?~ l_þŸ ´ žµ–yØÙY¾ø MX ÔͦAg«e·?@µ9å°0º¬NSù  š™ ¥FI6È,P¨B,yþo"#4KCb €À$°t›qêÔY_aaA9aaPIÈÃÃÌ2  é/¸B%@P)øãÇo†»w>–ž@ ~!*È&²eÈ”söïß dMf F'22T±pS¦:0xL€ÙÉ’ÇTP_Xü~þüùë# …wì;@ÃnCì,_!¦Þ}öì0]É¡ˆíÚµ˜`_ƒ@ŒÝ7 ïЀ; €ÜœVÚ—!Íù:IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/edit_add.png0000644000000000000000000000337611550446572022771 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?Ã@€bb`@,0c,”#Dþ3Z0|ÿZÆðçŸ ÿŸá#HˆþiûÏÄÄðé*;ÏDF–•A4ð¨öÃÿ]wÁ\€‚;€ýBÁ?fTMÿþ›1üþ¹5Ð*L(Ô"„•…•u ËÁŽƒº‘‰áØÕ“–Ó·Ì3ÿñû3ó\B!@0ÿEˆêf†Ÿßª‚¬Ã…Öæ/'¤!> ¢ü¢LU³jê8xw…ž |´î3J( j0C ¦?G02JC@?ÀÄÌýñçÃãOªþ30!12üýÿ—AœKœA€C€!Å-š¡eåéoß¿)101?F!3"… Vo€1‚B„¢†‘™•™,uãÍ ·%n ¿ÿÿf`eee`dbãÏ>3ô;ö3¤é§1p²q‚£ žÈÿC£K’ œa ¦ øÒþïß?¨Yÿ~ÿý vÈxF o@$öÁ1øï/4{ÿûœX±[@ØÀÄ*à¸kû/ ¤ÙPò.0±!fddc0›-ç0¨ø `} ¤ß!+ 4ü·`øñ»hŽ0«ýcúô3ÃX@žýóç7Ãß?S€®û`bøýýç ;W;0‹.ƒ© dè2üú³.Â6Z2Æ"š›ƒ›áÿ?H¸ýÿûA[V›hp³s2loXÎð÷/0+‚C‡ .è^>uÉOˆ¹`GÂ?ÿä8h;I.NYÀÀÂŒ;ip°pàðõv&vˆ¯€úít,0Ô8ØÓÊ_ÆÎ}…0¦¿ FþFþ`͉èÔãSÀPû‰chvcÆ (@r'j|ƒän}¸ÅpúÅip–„(‚¢ÿ´…´øXù|,\º–NU…é t_€À—__|æû0|úõ X˜1302C30áK[fff&Dar  ÃÜKsæ^™ qÐdp²3þfØè¹‘ÁZÜX¤Ë&D@È•ÑXÍöñ„áà¬û£®€9LA 'dˆd RáÍÀ@8#äC†60á¬ZA ªÿcü‡™E¡ €¼: Üy1 IF|úˆƒ€bA7¦áóÏÏ ¿~ýbøÅü R&2A0 – dbøñ÷°¬ù ‰fD´!PQ,À-Ë2@úƒ8Ÿ8è¿ÿùGO >ÈÚðã7O õ$'üüýT3´-žÀÀÀÉ9 ¦ €¢€ñè显Í= vNQeeaçæP Æð÷ë7–ÅyK",CˆJÙ_~|e0-ò`øôåó_FFV` 12þýó÷÷Ÿ¯_10³Ï¶.&ÃÔj"ddÜÌÀÁ¶ÿßß?*?ÿã62;“$ïŸSų8)ÙëÇïŸÿýþYÀÀøï,0‰°Ëõ \€æ½D΄-ëoÆ ŒL°¤/¤¾ã+€pJÀxb< ħ!){u@,+v`¦›u(þqµˆ`m¤Æ 7Øâÿ¸Ë;€ÂáP3Š Úˆ·Ë€MˆájBj [£·2€ø Š VSþù÷‡AURÉýùû”M¡m: ‹€+¸ÆÅhš F9nñ Õ¥ Ïäí}WÈG[…3ð°ó0ØÊÙâ ¸•G72|ùðæ5;÷³Á-bTµ„ê¯A­WÔ,ö˜xº\dÃÅÆÍdÀÀ bx—ò?¢ý™[çš—÷‹L¶ @á{¨¶ý¶Žæ#¼ Ngw™ Àš|¾»fLìÚLL¬Ìàâ¥kÆŒ' üµûæ30²Nņ9?Ù jwBÜ@ŒÝ; ¯Ž ¤EKíbèP6IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/viewmag+.png0000644000000000000000000000552511550446574022746 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< çIDATxÚbüÿÿ?Ã@€b~~~p&&&†¿ÿ2°²²‚ha íÊËËg/,,l À¯ÀÀðŸùÝ»÷/ž>{véÕËW'>~ü°¨îî¯_¿¾|ùÂðýûw†ß¿eùLj›ÈŒŒŒÉ**ʹ6Öæú òr@±1|ÿõhø†ÿˆþþù]÷å«WÑ|òÔ™•¿~}éj}Cj#( CàÏŸ?‚¼||}~>^ ¶Öf ÷_°1\¼÷áÍGF†ÏߘþüûÇÀÌðõÿG¡ Zr¿ž={°dÙê³—/_Nê?KJŠ€…ÅÄÄÖf¤%ÚKʨ2¬>ÄÀðî?ƒ™.7ƒ²4#?7(Ž€¿20ÿâ_ Ÿ¾ùŸ¡ÄÂü ¡ÁŠ ï.ÜüÈœ£ÄÇÇ_ûãÇ&`t0àà @`S0¿²’R±›‹=Ûœ ,BÜ ¢ o|Fç?úÐò¯ d†Ä þ tÌ_ ¼¹­,Ãíߺ@°0ØÛÛ&ýüùSªø0ØŒLLÎöÖ?„nâbÆÏwˆÅßAÿà¯P‡€Å 4Ø@G¢\ÙÔŒáò& S#`ÖMùò0Ñâ @`ðóñ;i©«3<ÿÊÅÀÈÅÄðû/Är°`¾GÆP‡}ÿäH ƒe$™þ ë0°sp2())8-á$ä€;@DTÄ@DD„áÃ/nN`”üAXÆ¿–‡: Ùq¿f±“³ P¯°”,Pƒ¢‚œ4ÐhMB p.àçWdbagøf58@A t"0x™¡¹ê?8ÑBrÈ 87+ó°=#ÌÁðñ!ƒÐ9 b„r@ÀÌÌÌþ÷0ùmáôhÐg?Qñ ˆR` s(ØX˜!˜ˆÙ˜!à:€—‹‘áÝÿ Dr23!Øß¾ó÷Ï/a`þþ 2¨õP+;ÐrPz…È?¤: ",L°ÁÀ ‰¿À afü¬@a,2 €;àÍ›7Wß¿{«Î/¦Àðù'Ð vfˆïAñûÜÈE +Èr¨C`úöùó߯ OŸ=ÿTz‹ì€÷ïÞ~ôèqŠ˜ÃÛü ‚ÌK@Á ²ø?ÔŒÐøÈ0‡01AÊÙ¯\b`ÿõáÞý‡—ܧ„Šd€ç`¡±íü¥Ë™¿½#ÿÀi·üÀdÄÊô˜Ð€•3170^¹ AÏ’‡`.`q}ÿñ{†oî0<{þ‚áù«—+XX€•73N –K.\\ojl” §ÅËðæ—ƒ°ˆ]}|ù;Ç€ÑÁ ô98$~þüÍbÃ`¬jÎ% ߃Bêï —ï`¦ÞuÇO^bÿÿyÐ’ï R•0üEà @°\Àðõë×–Ý{x… ЉËò2l½xšáʽ= µ~@yp¸3óäëoz7ÏdP’hcæd`:àPîè¾C Üß3Üyô”áÑÅ‹Ógþgøæ¬ä@ á$z~BÙ úÔvë?V`ð2ß½{åNÚ^¾ƒ+|¼x8îÞÚÇlÌðõCÏ‘&`˜ópp3Ìp›Î {d'ÇO/%î=ÿÎpòà~†/.1èjk1蘙3<;x0GéÊÑW »!pâ'Ô¿ ø…䀷Dã%Àœÿ3p½ç. Óë¾Åz—9=0á#Û†˜U± ŒœŒÀBJázúU††ySä-xÿ±0¼¾qAˆéÇo_5¨ƒ±‘1ÃÏçÏxïïeø>gñÇgûoƃ{#6$í H6äx -aC-ÍlÒØ…¸˜µutd´N¿9ÉÀ Œd.v.~v`¦C;†×Î3¼ùó›áæÛ› _n¾~ôìæãýަ&¡ÿ¹µÌx¤ìîðÿŠý¼äÙgÉ@ÓWaËiþf•ßÿY-Ô-Û6e¯Wùòç3°ú ¬³ÿ2<úø÷úÇpýõ +#C!A†s÷n28å†ìÓýô>ÑnÅrqÕD?Î3p<ÛÎÀÂ÷ŽAs¥+ÏŸÐ=sŸz lG1lEw@AÊÜÿX„yEøA–9Nwb¸÷á0ÿaàbå·–¿ÿùΰ3ž Ø@ýøï#C’nC‘Z9ƒ¨¨0ŸÛû› R?ÿå;¹ÚCËÀg¯+cíe޼‹aýƒã ¶Ü[†Àôué ;ïóµÎÂ&â+€áã ³ €ûÿþþÿ¶©Ý³•áÝwÀ¸ga8þìö»Û€å>+;;C¾A>ƒ¬€ Ã/Æ_ æâæ`gý¥&&Æ­œÿµ?þÈÿă;þ0ÿgúî§hõR†Ëm6=«ÕN?ƒö,rþuPt@Aò8ëÿ_gîœ^2uÿŒ"5`;ï/ƒž¼6ƒÌui†õ·Ö30S?3C±IÓw6†Gož1ü{û¡y÷„ß_¿XËÀ+ôÿ¼ Ãû;_øÿþýl¬„ïÙúg‰3Ã÷`%Ë7\¬R9å×¹‰îðÙ>(¢@P0ƒjîÿ�«É™›y•‰EÁf{j÷ýcÖ ÿþÀ1HiÅÒ–_³VOÌÀÁÿGX¹·½ùÒV`€4~|û˶}Û^OænJæï µ°@ãÔ—eà–å© Ô®#Ów`JšÇðŸd^ + [;3;ƒ0§0°/ÀÉ À!,z™•ëo M]@E¯€9ÑTaDÏbï€MºÐM›/ðfø¨jTÃÏÂpÊ[†ëŸovª ,}ÃÿšâÃÏ‹O.1äºe0ØçÙ8 ¬ÈËÄÇðøí³¿àZˆùįÿpW·@ÙO@G$oÜò›Ûá ƒÛO¦§ '~ßñûÇ¿Z<@±`(ÿmE±3ïh^×¶ðú³;Þ¼¬6NP»ÁÀÍ^üèñ—ßÅ.1|þñA(Å4ø#0$íT„e„€%Åÿ†¿Œ ø…¹™ ŒåÎ=bdøŒæ@ËAô×÷þÿþò}ÐôCØ "€BKÿ˜a90=t:þ’aÒªû \@w) }4ø0u›Z(3°²±]Á$.«.Çp÷=Ã{ ã~î7ïñþï'0õ±°,:½WI@¨åoe!fæ6`Hì[°á>Ãæ£o$PZùî30Qòó0èš«2¨(1°ñð1¼FϯßPŸýÅðçÛ'PH^Æy)0šþ@+Z¹ÁÀ@hÙÙ¹@|ú õÏ?ÆÇ½‹o3\{ø“AY”A(ýh>¯¿ˆ8»ýø Itß~þcøýù(A}d`bJ2^á« w ZJ÷€ÅaþÛ7¿ÿMZyŸá÷ÿ zÀ4È,pA¾þü ä`ŸóüÏO@ÁAñ*rªŒ¿x=7KË¥«æo~¬›Œ %ñ§ïPñÏ/_€™ÿ(¿ÏJM…f-,- ø°``x³p€ÒE0$ví?ñ–aÏ™ âÀBÑ@RÒJÊŸ RîçÏ/-å÷ÿðŠ #€B« Ø018A‚Ê|ÆŸ ,ÌÙÿ˜™¬Ùõ’áÊý_ šÀ¨Ð ?€AJtŒL8d‰mqQÀOw€áŸýíûÿïö¿¦‡ æÀ’’õ3(¿kZæ šc¤4Hˆ#ŒŒÛ€µfÛ“§?›wŸøÄ $Ĭ°€ÁÏÊ:½sñN T0ÙBcdê``g5:ã{ 30ï1²ž``¶ÈÄBfSØÌ&4&f`ÈÌdg’ïÈ €ºg@Þ* w@ ¸hÀ@î€Ðháø`BõÃIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/irkickoff.png0000644000000000000000000000145211550446572023174 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<¼IDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €Ü4à w@ ¸hÀ@î€p ©â~10èÉ30ë00¸ýa``¾ÎÀ°ÿ)àaÇ’X·¨2"G20èNãf~þÑYçÿ}©ÿÿ™þßg`øßÉÀð1†Á‘Tóˆä(Pd`èLâe’àótcø£¯Áðh/P\—(GªyDrˆ10X±¿ûÃð¯g*ÓÏ ?þ20|Š¿â ª¤š@$;à-Ããç¿þós¿øÉŒ†@|ˆ¯10m¼'Õ<€"Ùú¶30ÌS…XÈðˆ¯ñ H–Z@ªyD²€Á<ÿ×Y†F‰¯@1`H¼Ôd6“j@‘œ!xêw†­ì@6;ħɱˆ,s:#ƒ¦-q€PŒ™¹%¡0Ëi ü@ dË HNó €HvÀ_–fGAhÁ´\‡Y!ŒY) ÅÇ)„ø bZŒd˜@d9€ƒ‰ICMLŒ—‰ l¹$‘c@‘|LLzJzz ¼ll`AÒâH% É>\"ììZBŠŠ ‚,,àD( q„èHš$ 9! .ÊÇ'ÎÈÇÇÀ PB”Æ$6HD²X–( ŠëR `YQè0 aò¤š@$;Xò‰Ë r0üûÇÀü÷/<ˆ«6`V$Õ<€"¹.úVWZYÀÈøõ "`¬ Iˆ¤š@,d”ê'ž>ýÅrëÖ·?ß¿Ã‹çŸ Ü Ò@€ñ»k™ IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/wizard.png0000644000000000000000000000334411550446574022531 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<vIDATxÚbüÿÿ?Ã@€bb`@,0ÆFF0ýˆñ þ Ä¿ N@Ú(×÷‰áÏï ¹@þ r,ކ<@¡‡3P8èˆd -ˆ® (®´|­~žºƒ¼‡´ Ðÿ Ž&Ã@ÁrÏ_ Ã¸õŗЏ*Íúð(в\ °0#DΈWÕØ(ªv‡2üaù © ¡E*†€bBòÈ@>VAFÕÍ“t–äkŠXNZºèÓB ½Ô ÄTM©±‰áß§ oo½9êÌGÿIÄ0@ð4ðbЊç[o‹n?&/9AÐË—AzÍÃÛÓÖŠÛë3¨´·200}þä&ÃçW¿^µ<:‚ábF2Ò@Áð B½þñ‡aÚ½Þú®~ ŒüÎ âÉæ âî <â ,@%g¾?ÁðéÃ} ž‡_¡‰õ™¹ €˜ð â‹…O¿»ñvà ˆ¿þcLȘÀàdf„úž wÀw(þÁÀðòÛ_†9·'­†í& ê×Àø¹L9w€Þ¼TtA›Á·CBJQƒeÐч€8¨•‹œ ”DMˆ@*QÔF›U˜ü%žñ= è€_/˜YTÓUÂ0„‹[É+3­êÝ -R@Lèù” JÌ´U:Û8¸.º ´„åÍ¿çàüÈð‡ì ,R¢ ºé† )}Z †,®ÀÈ'ÕÄ‚TèÍ^kTe£¬ÔÚ s@GÜg`ø rÈr`ì½g`ø|åÃÛÛŸ^^ýÆðéÙ†/_3<º÷÷;à le;¾Ü@püad˜mP ©¬TçÄð÷í†?Ïn0üxù’áÇ“w âÎ@óáN†ž1,H»Ëð_HƒKÖáðés—8¿|ègøå'ÛpåÄÿ Eí¿ÿðUxwÀ?&FæÀLu"f.Ãë믾¼þýöãëÿüg š(%"§Ìo, Ÿîý`8ý sÎaس[º·³“Yúɓ˥¤~ýøÁðû×/†¯_¿2üþý›áË—/ ß¿gø÷÷/ŠÅ¡4@!ð÷ÂåuByú30ðo3ß= »Ÿ3¢ÿñÙ¯çÊØË00 ó2|¼÷‹á-PýŽu+¸¸XfÏœ)ÌøçÏÜæÎNNæ_¿f3Èvè €XØ—™˜©Pù I‹®_ù{õ=õ!†wcƒï$;Û_Õ%K–ýùó‡aΜ9lÿü™ÑÒÒŒ+†IŒŒÄ—‰Ä€#Ñü‡¯À€û,&]óržªÕ†Ÿ~2H0°u¨««3Þº~}éŠ+8A.X°€ äÝõõõ?€ô,&&âšÄ‚Kâ7¤P;*kîÞü›´©ã†ÍÃ{þ þþuÃàÅ‹¿µ´Rï^¾¢ÖZŸÉ:vøO.PÃq`ép‹ ˜º…EE—þUP`{ðàÁT #@ÁÏ0þ|f`´ô—••13…PtN0bò/³30¤ÁÚÿƒR633ó|))©?OŸ> t;Ï0{ölPRš““ó ³ñ9 €X(mÓò8Ð’Å¢¢¢L/_¾œL˜œ@Ÿƒ¢ƒ˜§ƒì˜ŽK?@QìPƒôùB!!!æwïÞM¥ Pü&+(:JKKA ¬!@;à°Ðù„–ÎãããûùáÇYK—.å9 ˜EÙ988¦pÕLF×@,”?¨¤Ñ°ÄÆÆÆ¶”“““XúM_¶l8aΛ7XFýêFÇôè ªDº£€b Q,›þÌ: Â (>è ’ÿ3`êˆbàK EÃTXÂeQ`å4©ªª $v@ÑÄH¡2JÏ%LPt°îÞ½»怢º@QªAÕ0’#@ë¬Å‹s~ûöáÑ£G¯a’ÄBmŸƒðóçOlÑ –ªµkׂ Ùj˜@1tï €¼w `¯ÆÁ'ÿK¢bIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/reload_page.png0000644000000000000000000000470711550446574023477 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< YIDATxÚl‹Á €@“ÓníÄÕX?‹Ðä¢{Á!ÃÂÒ6¸ÿ䮌[d©Ñ_6ˆ'î¶B“#Ò¥fàúó~¼Û%à#fÒgøó¯ƒáû×µ@㕈5 €(s4d@!ôãǯ8ÛX†8‡¤@†/Ÿ0üýKŒv€¢Ü  ý âßÿþ*‹(2,ÌšË01u–$#ˆ_ûÙðé "maøÿO“áÏU†¿ Ü@ÿcøp0þføÁ øóûo†OŒ¢¼íÌ•÷3ÅML*¸õàª6§0(4^b3 €ð;àƒ"ïÿù@Ú•‡›_]VX–™›•ä°4ð’~|ûÉ $¤Êð–á9ÃêßÝ ~ù [w2„¶Çº¹xh#§`PÇ t+ˆk.`d`cøÍPôm¥›¶W–m6ƒ‰Š;'#Ã_ g±& dbdb¸òçÃÞŸ‹Á†¸ñE0è÷enŠgØwfï N!/†ÿÿß#ç€ÂæN`pÎ’’™5ƒÁNÏŠáÔ ¾eøðç5Ãïÿ¿ÁÖáJÿÿºû/XÍ÷ÿ_ìx|b¼+cÎݾÒÄÀÊ^vÀ¶`„Ì@ŸÏWWß™³“áÿC†ò‡Ñ ~¿føtè Äi7°1q0p2q‚óåï7†£?2*§3hÉé0œ»zA…™E=@± ¤æ?ÿ#E8EÂ×&¯c¸Îr’aÊVf&†ÿþ2Èq*1èñš2ˆ±J0 jføûç?ÃÕÏ.~9Åðóïwi9†jÅI 3W®bX¶sùNžéèÚ9„¾¯k lf`üËÐ~¥– h*ã_†,ùR;N/†‹÷®1<ÿð$ h´âï?¿,,¸øV=]Âà äÎС8añú- 3+}žTÝ„pÀŸÿž*Þ:^ Õ7óÞ~ý ¶ AµƒAã‹)CÀô†ÓwO¾`øó÷¤(fbdøÏ ŒŒÿ¾üÐ)Ѝ4õTdðg(•nbh_0“¡gõÄ/ lÜé LÌ«áñ÷QüÂ?œu]ïþ¾Å°ñá6pb ‘a0øgÍà<Ñ™áùë' 8x‹˜þ¿…ÄRÙ¢Ù™·ÿaüãá+È ùÔ!¹«„aljm÷8Ò€–ï[þªöÂÄ‚”t-­~þùÁ`Íg zf†lù†•‡V€,? Û eÀTLá,@ƒ~1BbdØ?V# # Ãæ£û fÕ2¼|õ|3p60Û=´¼@„p#£ÌãO”ß©0äðARñ‹_ »nìz–u0Èÿ00}ÁúbÐÐß@Ë¿pB“?ÃÒƒ›ú×Ï}÷T)qóu30ÿFXü{m @ˆr …ýó?&¦À¼)^ÁÅ쟿LÀ"¦ hù Öß°ÿÇ$ ¤ŸÝøŸą́= ¿þò10±d00ÿ?ÇÀgNh†<íüù¿ïæ.€BŠFë¿ÿþ³ü•òÿþCÒ ˆ g`þ q†¿ÿúnrlÁj>Ëb`fy¤¿-©õª]Èðýç Åÿà`daa`ãF ƒ1H@!gÃï À¢ùöJ3ÿf·_ž@ÃzyxÄ4¿þøy^‚ÔàøÏt ¦õ¿~‹È‹É OÊjL\  €fdùÏpîÎU†êé½ðT@,8"‚Yþ€€‹áû÷:6f޲֨~FF&V†’Ù…À´À̺ÀR ä[`ò3#¬ÕÌž_?Ú:jZ3øYÚ2ìú¿˜«~0X2¹2ð°[2üýñû=Ì*€Âî&xI'ËðåÛuI-·i³´­fîY´7@‡€Ó –j‰áÛ—l.Nþè,ÿ†?70¬~3 XGücP’6`8~ñ0Ëÿ~S @`´óþ›2|þ±ÄÛ,@maæ|†Ë¬ûÎÿÙÏðïPêó_-Ž/+`‚&,XBû¬.•¥…¥'ô3Hk°3´>™Çðï/ƒ°—ü§Î°jï$`´±…Ù@ȉÉîÿº ß~lŒuL–œ–:aíÇ™ +Îd(“ïfpRw`¨Žoeaáƒ7R¡ø0+J*2Ø™1üyÍÐ|/Xƒ~døñï;CœTÃÉã·N_<÷ X¯¯‡Y@,X*`±º6Í-G²?±ƒ¡÷q%Ãáw»µ'éWÇl„x|CmÁsÀ4ðæ×s†…[.\=ÍÊÑ?ÿþdð“ˆ`0úãÁ`=5X±1̪¼Ó@ˆr šz¿O6S²ÎÙQµ¡ñ~>ÃɇøYÀr?>ùùï¢ÂÚ,ù®¬@X“FÈ$0D æ1Ä×–3¬ß»ã7 (ÿ‡¸ €PÓDèý篟¾~úÎ À ŒïÀ¢œ˜€A LH PF|L`âäeæe04eˆ–Nføóœ—Á½6•áøi ¼ü@÷}FV@˜i€™£ûúƒËö Ó3ì–eÌc`ùÇÉ0÷ÑTp» B,žÁ[$á7°Yƈžò" G²1²3ðüãcøôúÃôÛ–n[Ëðþ0Áò Õa´ 3 üÿÿ™“?|ï¹[z"Œ¦Ïb–e¨ºQÊ Á*ÅðöæO† [¦2°±r#õ”!æ†ï?33ÔΪxÌÀλ‘ ™a=$& ûÛC`9q˜Ø® ×ž€¤€ÂÝ,ÿÿÿ0$¼n<¾ÕçÖ”ÙZÍîÉ0…u °îç½ËÀÁ]±¹`D°ÁÿÇ“`! €tL€å';OÖ÷_ÿ.”ίi=ÿðŠˆ ÐLV&pÃ\îÿGËŽ„-EDDÏh 3Ë,–ÃËv¯ÈÈÊåÊÀÊÅŠa/™ €ˆìšlbºÎÀÁåýÿ/s%°Y¥õ&ÅN0^pñŽÆWÉIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/klipper_dock.png0000644000000000000000000000514211550446572023673 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ôIDATxÚbüÿÿ?Ã@€bb`@, âŒ#Ð),@ r3#Ï?»X†/¿_³pˆ~϶¶ÔIT’‘Uxñéɇm»n¸¿þ^Ã#Ö¯dù€€jÿÿ…z‡a8ÇY†_x,…>@±`—úçÿQ%}îeAaž.RR ¶(ÿ—ãW2TÊŸõg…ùËçvÊ2þÿÏÉ*ÆÈÃ%öÿÛ÷ o¿¯e`gXÊÈÂðd”¿ÞO _ÿaw@Àôñÿ? ‚~2x2³0È3s0H°p³Š¿»ª»BQH‹E‰áÐË# Œ@ÿþÿ›DFEj%ì¿,6:†0ð+‰0ügec`üûaç!ßÿK7&¼ûú3 hôë3_)20$?``øðÓvÀß_ b,’b»$S£õ¹dþsq1<þÅÍ óáæ©^†Jû˜ø9ž~y …ÿ ÿýcøÇü‡á‚Ê=†àm_ŒµÝþüüà Æû…!=BŠA@^ÔaOöÔN }IO30?f`ø‰#­Øß?3ÄÊ•Gꋦg2|ûôŒ!o/ƒŸƒ0;C°ü†é[ÒTõå>0ü`øüõÃïŸ?~~xÏÀpŽÁÜD™!/Ú”ƒaÿÅ_ Ý‹÷0´&0xØ©D*.»Ó~—áö<  €À`âbHø} ˜b>3|{ñœáÍ{>†™2 Í ¿é;C÷á†÷ÿ^ÎoîïB šíÍ‚ ãÂx ñЇfl Oj0œ»ú‚Á(ÂŽ#{ׂÂ7 Ù tù‡œ¨0üù[Èýÿÿãmÿÿ\û?»ëÿ}×~ýG¯^¿ùñÆåÿ—n^þÿðá£ÿß>ý‹ÿâŸÀxùñûÿ õÿÄí¿ÿ ›ÖÍjýÿ2@æ³ ƒ,3Žü² €Àâo?2ìúô˜Zîžd``çepP|ϰóÜkÅ¢" zê: ºj: rr² œ¼ìÀôÌ) ,ø’q€É€ÁX…‰á#»>ÃÑ+ì bá¦<‰| ¹ñdE€;àëw†9Ož×öMaepRûÁpçþc†¯8âÜ ËÿAñ(ýè€oÀDà®À0c'ÐïFò ñæ"É¢ â¸J=€‹ýedØõè9ýÿ·€©êÍ+!q&`¶xÊpìæO,Á-& Ã}ôæo þÔb­ÃÈð_Äœaï.åp¡HN†tP1ÀˆÅq#×Wï¶¾½ÿáÞVngå· ;O¿ÄV>Á-þµü7ÔrXÈü†\T€ì}ê †’ ‰F|™Àt*Ȁŕï¿ÖÜEíƒ@ï°18ªf¸s÷×_ËQ,†Zþè¢_ÑÂ߀zŒTE±¼#ÃæóB aŠl IØB €˜`®úÇÈpòÞ3†»]f`x÷ŽAHŒAŠýÑk?àAÿÍrôþ£¥  M?Ú"eæ1eø§/Ê¨Í‘Ë ¬bÐÓ@Ù þ|ñ†aÃóÇÀhxt 7ƒ‹ÊK†'ž!B- €R=,üCsÄ`bÔ’†»¦ÃêsR vÁbòîÌ 1ÿÑB € ÙšÖ¾ÿfX}Xt1<=4ÁQíÃÛÞÿ€Ô°8ÿMñ¿ÿ!,Eö=Œÿ¨/$@’aéY'†?z ª,…¬À˜AŽ€;à×?ˆ«€zÎÞºÃpõ÷“ë _¾0ŠýafÀpøò7p°ýƒÆ7ÌçpÿÃÌš 1P((I20Hy1,½ ÊàÈ£fÇÀŠ vÈ'?!ÕåŸoÖ=¼ó‘áã-`ÝÎÅà®þ”aÃ'àºäPÚ¿ÿPÝ?,QðMßd€Ÿ(Ãêk tEâ™J@MX¤ª~ÿ"Œµ—.õ¿– ¿¹¹áã»÷¼GDÃ?AþK¨üº\Z˜AÑÒ‹aá__=#_Xå@4e0BèK·®1žÿñ¿3ÿ`PâºÇpèü`[»oÑø°„Êò*+„í$İᦃ¾C´$c #4쀋ЖÔˆ#þ¿ÿüÍÝ+€Î®*½40ì?úTbbø–0™€r¬@ËØ€IŒˆùO€>;rîü¥/&u\cxþÌ â îÎ|Vú Þ »ÀŠ˜ÁˆY%Þú˧þ5iG]fe`sdpÔ¸Å0ù؆gï´9¡M?h”#>s.0 3Ü{øáÖí ÷n½axõø ÿOo„ØÞ3(‹fTüÊàÐöŸA@”ŸÃCˆ!hÛ× 1[ˆ@¿2hBC7ï^þwêëã»ÖÜ¢. üBŸ4yo2,ßö–!5L˜áÑËÿÀVÆW†·>2ܹõ–áÕ“× ¿¼af{à"úŽÁOî#ƒŽé%™ BÂÀ`âšÈ tù_n ëmÅÕß vÝOÀŒÇ  PõùñËÿU·Ï¼·60{àe¨ ¾Â³`5Cüv†?ßß1³ÿ¿êÖ‰ß.&& €q£t¨³4õ7ТÀæÓ†oÿ1|zöáõƒ /îÿaxôà÷ÏGOþ¼xøæÏƒ'ßÿßFà5`ú¼ ,Úîu€*–¯Èv< @¨ i æT0‹É¨°_ $%Î-üŸáËã_ oîýexqûÓ»¿ùòï0 ®½†XtjÑgBÝ2Ý„â¨åÀâœIA r;ƒ™Cµ0/³äãï?e`¸ ìëÀ‚ñБÀfxOn¿d7@1tï €¼w `ôŒ Q3ƒIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/folder_new.png0000644000000000000000000000375211550446572023356 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<|IDATxÚbüÿÿ?Ã@€bb`@î€bŒ!ûÒ~þidøñ—‡á0N@ÑòŠÿþC°Aø?ÐÍÿ_ße¸ÙÈðõÁÕ@q$5ÿa˜áói†çÓâ_q: €À`øñ§ÎÝLLÂÛX˜áç/hš¥Á| C@nûÏ0aõ ƒ§OôJÈ&Ú«ÜZ ßïóE € øõ‡SAF˜ÁÏ^–áûOˆ½Ø##ƒ4?Ãê½ož2òk1° j…_ãRD?þÿùæIg00<ÍÀðõ2Š"€bzïß‹®?g`øóáit ü÷/Ÿø]¬DœŽ1üÆJÁ¢î›ö7^‹2†O—2üûÅ€ÍkÄ î¿ÿ3|êù u P†‰U10¦¾ýf`¨Ï6aøðIŸ•‘‰•áÿ_„ëQÆÃÅÀ0gñ=k knJ|À怂8èâï@~úñ!<{þáë·_dø×{Èåbgb`bb‡Š±¢4Xx2ì í\< šþ ì×€¾ ò²?ÿ3|¦6 ·Ÿ|b˜´æ4+,Rùpð"õ?´\‚„™®áÑ0’þÿÏdÁ¯_Œ ¿ymW3|¹4ñÌ„ 0sÙE ï¹.ÙÙdÎÀÏÍÌð÷ïÌÄ€ÂÇ.ÿ÷$G p12tͽË0­ï„P˜.Á”<¾³ß`|zèý? ?q}û'ƒ*'Ãï¿$”,ŒÌ ôÈP4ÍŠ°çcàe¥p`càDV@,° þM?ÿþeøûë7P톧ïÿ2ðrð‡ôŽ™™áåû? _¾ÿaxóhúÏ$>AÕJ|FÁ ~½ŠëÀä ’´‡˜6?ÿçaøÌ%_€žûõš6 ÉÉ4ðê€ÀxÿrÀwP9EBðÊ ï¿D7w3üøÍðѰX\0ÁC9Å<‚ŠàÏ@ß2Ëp@ð™˜e  ·~c˜˜õ˜€¦²Üǯ¹ ˜•ŽmÖ`øÁ LY@v#ˆ æ`œðõ0@^&1|+fÐèζ3Þ+…¯ \¦¼ ÏÛ2ljzþC•ƒ•µ—™©èÞ÷¿¯üû³ €àø†ßÿþƒ¼ Œ‚ß Òñnü¦|ås³z#O1ySâs†¿L‘ ¿¿½ƒ ü¢…ßß2…Ê0”Å‹r3°|Ëf`ûÂàx‘á¨ëc5€‚E¨zøûTW*| ­ÿY~ýb&& ø_ìyèf†7¬² ÷oïaøÁ ¬è~}`øùã'/ã+.9C¤&'0t¯bxô(Zþ2|½ñáåïlm0#X8Þ|ôÅ3H¤s°1|xø˜áó3`•ªñþ3 ªe¤fÚ-·ã~ œß0üú)Îðe>Cód9`‰ÏÃðÿå-F6 øAeï†Y1÷Þ/døÒÁÅÀøà ÃÿŸ@Û#¨Ç(ÉÀïXÏð‘Øêø¬ìm86Hëä/Rµû{µËÀÄŠ?.¿7ó-œ#È(Êp3³ˆAÔO……‡“áíÚÓ Š¬>m¹ý//üʤ…ßþ € 5öYUX¥¤dDmŒà) ¿;p3F¯Y)ìÍxº$ûßÄÞ ç§î 0fåaa(±Xs<£L^O¯SûϾç IA7küÝ Ò @àV.0œ(nß·È0Íùÿ¸÷ÿ…jëÿ* Î ?÷üÿ{*ä?ÐWÙ@ìz¿VîÇÿWfÿ{T¸OÁôÕ ÎÀ ÂÃ0S™¡ÄŸÌÀàýãxÈÿÿW"ÿÛ30TÄ@ŽÈæc[$”ƒé ¨X©Þã b`0¹Y®þ÷a½Öu†d\6­:§¬¶—/™¸@ŒÝ; ïœäÃÀ=p+IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/mail_delete.png0000644000000000000000000000523111550446572023470 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< +IDATxÚbüÿÿ?Ã@€bb`@,0FHÈb†?þÁÝ ™ÿÿAlF†ß¿ÿ‚i†Hîß?¤æ###ï÷ïü999â˜þ¿|y$êïßïo€X-¿ys@±PÃÿþãùõëO{²½ƒ‚™“½ÖmŸîÜY›ûêÕözff.:g0 eÿ•ûýë_ W’‰™º²µ­2ƒ›“ ÃÞÝ|CEî> Žß¿ûØ”ÿ¿½fdÄn@‘ìPüû÷OèãP~þD-9kk%eeAY†;7~1<~÷‡ÁÉŒ…ÁÝÓVþÜ)³ÈNbbbÅj@‘ä€ß¿ÿã=MHD0ÜÈX™ßÒJ…AZšƒ‹“ƒ˜z€®;vê;ƒ–7÷o V6¢ zaeG] ¯7ŒXÒ@±öñ`âükLh©bbBa†Æª&fJ 22ì ì@O±1+ƒ ñC?Ä™ùYþüŠ 1188[J_¾hšüîݶNffn‰(æNƒ™ ˜ú]þÊ”“—´36SçÕÕ‘b”dg`ZÈ ÔÉ¢`úþÃÛ¿ W®~g0sàg`ÚÁÄ 4ホ« ÃÎm^±§OŸËÀðë zZ ,>µ +[ŽŒ’¤‰™ƒ®® ƒ°0#ØÇ Ù ³u33C³ußgE6~^f†ß@ß3ƒr00›‚Ò…··›ö«c>9>Ý„Ìãù÷ï 3 k–º²‚®©…0a 1ƒd!;Ô§ ˘Y €| ¢Ÿ<þÍðáÓo3>`TÕÅAÑ Šq&`hØØŠ2lÝZ|úÔ¹ELLÌï@,Ÿÿ[bd(åï`Ì  ( ö(Ń0È0fˆoA˜‰ j8DþÐþ ê\ œìLÀ¬ µ–Þ€òªª,À´`+sõŠVاOg03sÂ@,ˆ8g”üó˜ŠOÜb8}Š™A\”—ATŒ‡AV–ŸAT”› è-åèàò¥o .QÓäføû5 €ì6 -n2 »v†¦_ºp{õ?†?oÿ3@$ˆQ¨ü™ðëçbuUæ[w?1Ü~ö™áÒ­g Œÿž `aàãaF0txDD¸xyYXX™Î_þÅ §ñ ˜þÈNxàBËqú† 66wîE°ü:;•— w++óÆ{wžæ6³±µaøùì üû“áç·_ _?ÿdøöé'°xýÈpýú 8ÃŽ ~Mìb¸báÌ Õ9˜3€u022!B‚‡áêÞC –‡š¾ ²^ûúo®…8Û<@ÁkC`!ñíû/Ý;¶^càòqÉÔÌ,a$Äx4ÔD,,¤\Ý•<<•<”tîgÐÙ“Æ`è£Ä pdÃùÜ & ^VH(€0Ðòkû1ÜËLa²Öfh2áW¶âaŸüñ÷6½„R³³³l;wöö¥Çw>3ðqCêEP*¥ìÿÀ ì?0k±ó21üuëú[_Á‰– `y䈿ßDUeÔgo`¸û–ƒáã¢&†@G0?âÛÓwV ;eEÞß8Ïðæò]`‚ h=#ÐÑÌ ÜÜÜ Ž<<†[~ÿNÆÜd{ˆ_Ó X.,8wþfîÕ+*jœœì ë×ÝaسçÀÍkO,}óúØUÆ?Ï-¿<w”fߥ®øËøß×ÿ _ÿõåÃïÏÀèbae``øô±!÷Nο|aùöÿÿ ˜=Ä‚l!F§‰ùËŸß›&M:¹äÁƒ gŸ=»9ëþ‹ý«u¿¿| ,oÍ~—”aݤ«ÿËðïçÿ ¿ 5!0ª>°ëf6PbýØ–³àãcfá䜼äÍ›Ïÿÿ_ ² €ð6ÉÁú¯å{öuÞFü= î·ŒœÂ 6n2ø00Èüc^cjþÛ X.ü‚ö€uÃSfV†cBk¥þþ3¶d`P`‚6Ä@ް`ùÉÎ>gÃë× D² €˜ˆhþûóûýi–·¿X8b~¼e°Š¿âdŒ´uþkÎlòÿ¦(V ‘¯ÿ±0œdâŸö•‰%ä{øi6¶·ÌHÙ äII+‘F €ˆêš1223üdfg°|~‚ÁïÃm`AÈÌŒ§ïÞ`ú«ñ@Áþþ73Éï|s¿ýg.`úhø©‹LLq'ÿÿÿÀ µŒ¨øÑçÏ 7>}ÚÒ @D÷ ÿ£Cèûÿ!a ¬œœ>ÎuéógN`y÷‰áè îŸÿ0¥33þÿ¨a¶ü÷/òà¯_8…È3`~ž~ÿþ¼G_¿æƒäˆ¤~Á_`HüG òù†‹WY’?~bnzú‘õàç_L…,lÿÿþÅìýî8þógì÷Ûüý{þåïßÙ¬,,àö@1t÷ ÀÕŒD]!pIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/laptop_nobattery.png0000644000000000000000000000424511550446572024616 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<7IDATxÚbüÿÿ?Ã@€bb`@,è³~é¯@ü‘Aù3 9 kjÚ³ +ýdbæøøíû·'Ï_ܼuïö¡—ß¾îyËÀðàÃÃDXˆâĈ.0耟 V¬¼ Ùêböœ†ÎÒÖÙ• Bjê ?ÿgøüå;çŸÞ¿yÇpõ܆ëf1¼¹}îáÑç?ö<úÏ0hÄR@˜ÅÂ/í¨2K.+“UÝ‘áÖ£Ÿ fÆÚ ÿþþfxÿî×Ï_>}úÎðåëw†÷¿1|ýøA†õ+Ã÷“;–ïØþuËË/‘@c6ë€ÂˆY®RÉŠF6ç(¦ï?NœÚÉpó'//ÐòoÀøÊðHúô•áõëw llL ìÚF ŸL’X¹¹¯Ï[Pp÷Ã]Ĥ€Âp¯”·ãG†'§Î0*(1H+J3¼þ´ðÛo†_?0|ûö â C~2þg’`øýó7σs ÿ1°p0°2|c`$Ö„á€ÿ??þU’;Ãðîím†7'•Ty”>0ýaxúê+ÐþþùÅÀþûƒËqþo—¯]dà½{Žáú™Ç o¿1ü#% f$sæ+ Bz÷„~ 0üº®Ê öšAñPêㆎøñ‹áÏï ¿¿}gøüî#Ë/®=F ÐϬ$fC€bÁ.ÌÆÀÌWÿÝaøñˆŸ00|?Ït Ã÷›@ú÷?†þ2|†òw°Rp˜ã0ŒÁP\œA’‹‹áÿïßrÄ‚×y@S¡˜”zÿüF dP ÆÌññ¨#°hg0””d°––f`ü󇋈…è°b„”›Œ Ld,3311KHC hùß¿ Ìÿ05FQülÓ²ŠU6´¤o-+ v>@²ÿI0|ø§ô昧Á4#š&EsñY`\½…ªæà`Pâçgø ô5¾ Œ(ø4òúÏ|z ŒëÅò] ¯^3°ýÿËD ÿóûw…¸ÿsÅ·_ Ï€‰á3Ã^`Pÿùõ ìX AAvVV¶ß¿Ó~32ÞjÝÄŒÅÄ‚$‰XæÿHVHq wþexÊtˆá×e†_rŸ>3ýbàÿò”Á“áËÛ Í·™ëˆ__?ƒ(°€ÁþÏ@\œOèË—ÅIªª~O~üø³ìéÓŒ¿ÿÿÏE· €p$Âÿ LŒŸÀeÂ/!† ª ×Ù€á øžAå÷e†$K>¹¢% Ïž1T•¦0ü}ÍͰètP9ôýw99!¥ÏŸW…hj:Ëõ÷3(ܼÉÂ9mÚœÕq Ÿ„l@hüe91Œ¿¸Þ`ˆe¿Ä YŒtu`EmÎ`QÚÉÐÆ÷Á™ù?8éòrpˆYýø±.ë``¸¼ÏÔÍô‹[Z˜ü¸¹€«Aœ²²›LE0>Æ?ªÙµ‹áÚÖ­ÿϽ{7Ý\€"¾E ^f g h3ôœþËðzVã@G¼d`VaÐÉ*e¨š–­¨È ÍÀðXb½yÔp˜á¬Y K/]*ûøëWº±ÄBJ>…Ë?†ÂZ ßn^cÈŸßÀ ç›ÏÀ ¢ÂÀ".Å Ÿ_ÄÀ, IŒ/_2ü»váäŽ?·~ø÷ƒ‰i3##†™ÄBjalÁ0p0ÿe8 $ÏðíÙ}†¼¥} *N± ¬2j ¬@Ë@¥Ýë× _Οg8}ìØ×Ã?~dýcbZÄ ´ü–0@±Sâ1‚ÌaúÏp‘M˜áöÛ× ‚»1ðh»%Ø€Y˜‰áϧO o._f¸ý÷ïS`Tl: Tc«)ˆ,ü:B_~0¤ÿ{È`)ò“áËÇŸ ïw¬gøõTW°0°ñð0p‹ˆ0xps«xÿ~ý³C%å;F,!@˜‰ h:(õâè/üfff¶ Ëþß`ðü¯5€ºXA¨˜õ@ÁÍTë.+ë¤ °ñ÷ß¿’ØÌ üyûöõÿïßÁñÉÄ‚R‚,}õ–¡˜á<ƒƒÒ†Ÿ@7Ó%XŽhÒ6v†ç¬,àvÁPóô@ÇxikÛ(‹‹oþó÷¯2º}„á€_ÖÜ++{øüÀp‚båãc`âädøÄ\¿3dý?É`­óáÇ?H -ZvæCö¯¿×üÿ×ýñÿÿŸ¬Ð¬û÷@‡{YZ«ÈÊÎG· €X°Tû»Þ;f¿'00™K_ßQEEç#÷_`c”ñéK`:ûi‰-g*e­sYžW}ü;ùéÿ¿s™X_]ûöíÎovö™ŠÀÚÔšù A¶ÿ0< @X!Ðü‡þü©{zölÝ÷³g%½#}`\+{JìK™81ç¨*ýù4õúæ[Þ3…¾aøs Uÿý›uõÕ«_À´0UC@€ë/0Ž:táÁÓ§IÎhv ¾ Ä1Ïìç01Pœ_8ÇtøëÇÿó¿cxóô5c ëÿû,H•>Ð׿ÿý[pýÑ£/@á©¿~½þäõë6¶èöã@÷ŽhÀ{Ç—¾˜¿óIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/help.png0000644000000000000000000000515711550446572022163 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< IDATxÚbüÿÿ?Ã@€bb`@,0£É,LÙÿ€Œš‰á÷_3†¿ÿÜXX ÙYÙt˜YYDþ3þùùû㯟?oüÿñëPþ3ó! žÏ ÿ¡~üûbÆ?„Ñÿ_–‚i€b!èDPýúã´´DLVÊB×@•S^^ŒAT(ÄÌðç/÷ïù_¿ý!÷ìé[·;—n”¼xðô¿/_§301-âŸøŒ FXÀÿJ3üú7E^K9À×טAOU”‡(üè¦ß ¿ÿüÒÿ~ü¹‘‰áÇ?F†Ï?žÿ ÿÀgÇÔŸ¾ÿdbøÃÄÍðí? Ãí«÷ÎnÚñáLJY Ì,˱9 €°GÐr6®MQ±.Ò¾2 ÿ~ƒ ‡D癋Ož=~Î 'Ê `Càöó ￳2((I30Õüøò•áÏe%–ˆPs·,üüä9 +ëb´L@À$þýg`dYà.ík+Éð ¤ÿþC,ß±ïƒÿw†´8%uE!¸ÖŸ¿3ì=õœaÊÆ ÂRò Üœ¬ ¿¾bøùå;7¿ƒŽ—ë¹Kgüüôõ> Ëdj6Yôûo—“‡….ÌrPÔ1ƒ÷4ÐçÊ‚?êS Á–ï8ùŒ¡vÖe†¹›ï‚£ ÈY‰aF±.˧>}ý4†‘á÷Ïo ?Þ=f`åfPröàbbfš L4\à” Ä„bûïßfb ²±!>:à`F/8Ž¿ÿøÏðøé[†pyHJúÏpðük†3OØVûÅиàXLM^!7@†á΃àDúó7Ð?¾0üxû”KZATGO½ÙÈ~ &$û™€¸ÄÓÓ˜Q’Ÿ lÀp*ÿ LíÑÀÄðåû¨F`šbbàçå`ÐV“d¸ôð/ÇO Dò—ÁV_œ‡ý/×o¿Ázýadøõí-Ã÷O_x5̘99ÓþüY @üþ£Â#"ì(+/ LXŸÿðó×?†_¿þ2ÈËŠ1L\ÿˆaãá' =+n2œ¸ó—A˜Ÿ˜83üøËÌðêÃO°/Ä…ØÄ9 ø4¤H|ÁÀÈÎÅÀ+#¥ t•'ÌZ€B8àÏ_GE9‘GŸ®>ýÃÀøb1Èß~ü<Ü |"Ò 3v}b8|›˜¤Ár?jþþùÇÀÉÁÄðRL@™˜™~€,þ 5 ?¾}`ø÷ýœ,P£#ÌZ€B8€‰IOZA†áõÇÿ Ó÷}exùäˆÿ×ñW`žçáfcÐS“bP’Zð˜çÿ1\»ÿžA^œ‰AJ„Xnýcx÷é7ý?þƒBìH(¼þðáÓÇ ,<¼ Lllš0kîVVeN.`!ó—áå‹_ Swaxóù/8aüúñÍ ¸ýÅðèåG†;Þ2|ùL¿ Yüÿ_`1þìHÉÄ‚¨wþ«Ô_ ìÌì€\ÄüœÝøÅpõƒ¼03ƒ33Øw,L¬ Ço~eØyæÚCoÞjê»ÿê#0ȹâ?¤Ì€TÅF2£ ˜¥üþ³ €àøóó×Ý/¿8s ñ102ý:ø/´ÐùvÈÇ/.}þ *¬´d™¸Ø™î<ÿÉàX~h P +#0 ÊC,þ¡ÿÿ…cV6v†??~0üûúí Ì^€Bä‚_®¾~ü‚XÁp2C#ÿ †€h&Hˆ€øŒ@_2³ÕÕ2ƒjVpAΆàþÐÅ ÅÂÎÉð˜~þýüy f-@!ÀÌ´ïÉ­ûXþÿf`a—×È>Æ5(T€¡óâý/†¶µ/z7¿LݨZT_Ãô²°°Ëv†ž‚¢c?ÌZ€B*˜¯~ùæø›g¯äÄ•?ã?ˆ…ÿ`¿ÿ0ð°‚£@RARˆ-ßþA¨Gãàúüï§ÏžãxÌZ€B8à°èøó·÷ú±s ¼ÀRMQŒ“\&ÿƒúŠá¨vaägcX]¥ÊPàÉÃPÈϰ°Blµðá?>Pœ‹ è€ïwîKÃo €¾} ³ €˜PÚ~,Ì{ßܾ¿ùþÅ ª ‚ ‚|¬ ´õ¸¶dP–ábБaaxûîÃÇw_ôäÙå?’ºõ–‰KXl¿}Ïðýæ-`âcêa@j• ü r8#cþ­C'~|þŠA[Y„˜íà!dÞyø…áà­? ÂÂÜ ü‚< ¯ÿ`xöú 8m ¤¿¿@…ˆ0Y1|;sö° LÁ‘«c€B´ åû¢?;pðpoÖtwâáb¸¬ß_¾ú®n€¥¡˜$?Cˆ£ÃO`1»v熯_COØØ¹¸„¤À1ñõÄI†?¯^ä³ËdXôÿ_#˜ ìø.iÜYØÙ*;Z‹ ÈË2¼}û‰áÅ«· ߀í½àf04¯3m`þÏ ,,, œúÿýË`ðôñ[D¢Ãt@v¸@b5V¹À ˜‡]™YYµ™89äŽà;0ÿ÷íû`ÔÜÆÿA ¥;êBJEä&7¦ˆq {Ç4à½c€õwÛIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/down.png0000644000000000000000000000332411550446572022174 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<fIDATxÚbüÿÿ?Ã@€bb`@î€p 2‡Ñd.uª ÿV2üþ«dÿ‹€’#3Y˜Þ101&Ù°)ø& Î ¢œùóƒ¢ ¿ag±%3Ðÿ!`øE„Ìt 3CÛ¼ üÇO=ó`à`>@Èh€"Îþ3 ñ°2:*-@ööT ÊQŒ, K¶Ýa8þûßvfL³Qƒ €ˆs#Ãÿ@ó¾|ÿÅ ÀÅÊpìɆ÷ßÿ30-üûç/Ão faøÇ`&ÍÀ ÆÏÆðë÷?°Ì‡gÄBRŠêÿ´tíM&†«¯XþýføýëÃ÷ïx˜þ0hù²2H0þÇ­  ’ áÿþ1°½Çüÿ/3Ðÿÿýb`ùÿÈÿt8=`x‡å @D;à?Ü `ÿÍð÷ç_ k~1üùõˆ|æ? ÿÿ°ôÕz<–ƒ@ë€?°<J ~ÿZ Ìÿ –ƒ1ó_` ¤›¿„,€Bw/Ãߺ ÿ³ yú;ï¿ê KAqŒ @q þ?`ú÷O fýËð÷ï_pýùTôë¯,õs¡„ ÓM ëL €Ðð† {+õ÷¢¤ùÃÆÌ ÈËÆÀÄôÀ@Ç€ñÿ ÿþþ»Z›•_€3ž•‡5Åt qo¿þ• Ž01€BuÀ÷¿¢fâ S*l€YëØ2‰ÿ€†³³23°ð÷ÿ@‚䀿¿@˜€>©ûþý7CU².Cf˜:0Ë ¸¿@‡‰‹p2t/¹Î0{ù5d+ÕÌÍû>²ºóð#·‡µ,Ðüßà g,€–ÿf`%Âß g€E-;¿€j€Eƒ€(Ã÷háåæ`xùéæÝ÷ÿ}Ñ‹l%@± e—ÿ~üíÏo;T³w¾?ƒ´0Ããw¿æýÃðë×_F…@˽ùÅÀô÷7$*@†ÈW`H4­}ÊÀÊøJ_¿þbHug0VáeøÏÄÂ×s’áå«oëxX—"[ @Ly“¥ãÖ­·'gœ:ˆ…A‚ç??0m»úƒaïM ¾þáý§Ÿ ÿ¡¡Ê ÿ€ià;°”ÜwéÃÖÓoÖ|ôùui.!A.†y[î18ôø)KÐŽßÈV¶êø+{ö¼•Wß,Ýz›“‡ƒ!Þ™ÁBÿ@KØ9òÿßßP˃Ëß¿!¡ÁÎøÌW–`g¨ —gÆû¹;Ÿ:g_ü´<˜( [@L8ŠÍsÿ{Jº1\»ÿ‰AT!ÛšAˆãÃç¯Ð–ú¡ ß¾ýd`FS5Ðr n†o™ {O3|üøk!0î×a³ €˜p{,_¾üº>¥îû/Ô%XÊœ¹Åï E¿À¾‡%@ûÇß`ñ² Yg}!V.†ª)ç.\xuïU 8ª€Â×"úÁÀÞuüø“K5SÏ2° ´Så`ÈuâÇ÷`vû -†A¹ãÝÇï )®’ Ñ ‚Ü ³7ÝcX²îÖ åIÈ: M²ÿ/€é!~ú’+o&®¸ÎÀÅËÉhÄËí"ÄðåëO°C@¥à»÷ßbìÅr}e€‰Ž›aÏ¹× “Ïÿ&è `¼_Àg@1Q_``c.,ï>Á°|Ï#A!n†;!†_ pÜæˆd7I†ª0 Qn†‹>3¤7eøþëO+°Ø]KÈx€"®2bcZòçç_á´šC}¿ë­™"]dâD„YÀ‰ÒQ_AL„›áä ɵGÞ¼û1 ˜ê›ˆèr Ñu1;óÄo?þ²e5íúüÍ”!ÖCÁÛŒR\³03ì=ÿ†!«õë—_g㽄á?Q=€bDîáiêX†ßÿB~ý›äj+#‘¤ÊÀ ¬¨VízÀ°lÛݯÀVY-СýýƒÔ* Ò€Z ß~çãØ‘‘‰‘õÿÏ¿§€A>˜à H ÆîЀ÷ŒhÀ@AîEÄ›ù†IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/edittrash.png0000644000000000000000000000351211550446572023213 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÜIDATxÚbüÿÿ?Ã@€bb`@î€bÁ%Á(ðÂÅøùW„áû_s ÛŒåŸ*+û?yf–ÿB ÿÿ2üýó÷ãï_¿2üús›áÏiÖ'øÿß@Í€füaøÿë=ÄBЉÿD¾þÏg`ôÓµçÔS2`cgb`ád:Œáï? Û~ücøöåŸù‡×ž\ýÌp÷ÜÛk?ß}ÝÁÀÆ0¨æ>ãˆW"d†À/SÆÿó‚8´B9xÿ2Ü}ü•áé“/ ß|cøþé;ßï¿ÿüe`gadàâfP’`øÇÄÃpëè{†+›<øýëg04vÿÿŽ=·xßjp²1îÍlç•Õa`Øsò#ÃÃûŸ¾~øÎðÿû þÅðïÇO†?ß~0üýúƒáçg c¾|g`úý‡ADŠ—A×׌‘CœáФóï¾þáõÿ·ËIlöîDøó¶_§”#Â-onÞþ ö-ë¿?À$ð—ñ/0nÿüf`ZÈð÷/Ëÿ l@ÓþýúÍðüÚC†ÝÝ«>½|È ®.T[†Ë€Âé^!F;}6†-‡>0üúö‹”˜€†ÿûñ‹á/†‰ý±ƒÃÿŒ ç–`à–äf``1Âe@áL„¼ÿ˜…x8€9à÷ן ¬3üý ´àço(þLÙ01¨8Ðÿÿ…šð‡ƒ›á÷_F`ýcÃe@á Næ¿ÿlõ¹˜¾¼ÿÆðû 0Îññ9Är0 Âß‚Œ þÎÀ%"Ì åÁðâ5#Ãïïþá² €Xpç¾ \,ÿ YؼŽœäb¸yñ ÃÇ÷_~úNp‰ñï7 Å_¿5üd`bffàd³Ð`73dx÷“›áñý/ Ì8íg <åÀ_»eúå˜T%%®‹2ܾû‰áÉÝw †(㘓¸„ùøåÄ8%$þ²±3<{ÊÀðêÜ,œ¶>°1ËšÀ´Ç ŒA[}I†:B ¯¿ 1\xÈÀðì ¤ 9ô'P0>‹@‹¿}:œ˜ñ; €ð8Q@°€J< h 8× Ÿ> Z L›  ¨& `Òó™˜ Q–㎀ÂSýkf„:äQÀ(g8uèÛ_³Á΄:ä[ˆ1S.@¸¬dÀf f¨¡Ì@ÕÏ>00¼ýqñ·ˆ Ÿ&FpY ñà¨A€ù–8ðì\ €Xð;à?Ü"Šë—!iTÞÓ?H|ãwî |¹€§ xEÃw Gþ€ÒмoŸÿS=(õÿ»˜–øÑÓ2î |!ð›ïÿªX€øå› ›7þdxûö/°f¹ (Î LÌÀꘃ›‘…™áßf´ ÁÄ„;æþþfÖ¿€Áþü9°¦ce`xüô/Ã…³?¾|ùÎûÿAAÏi˜€ªõïÀPùôæ7Ã÷Àê4 „ "€ÂéF`&çà`d¸yó7á#?µ!¸Öe`åfb`ç`b`cƒ`vv(Šqå8€õ +PîÿoV ÏÿƒÈøg  œQðç÷?–ÏŸ¾ö\Á²$0t™YA V E,l ààgB õ 4L¥\@Å!žl@8CàÙÓ¯öìzË .ÉÆðéóp6dZÌ ²Œ ”€‰è0Ø8¬ˆ9Xþ¾{ L©_®ã² €˜p—ƒÿ'Ìî¹ýãõÓ *à¥& Á©Ìfc ãØØ€aF +ÐL\l Ÿ¾eøui?0AüŸ€Ë€Â]±3í|ñä[J{á©÷ÎÝexþöƒ˜( ¯#++³€«_F6f6nf.`Zàabø L€gx½uŧÿŸßfÃk.kw£”s?¸=Ïðë§>0IÊÈq¹™;KH¾b`øÅÊ ´*À‰‘=À< jŽ}ÿ‰áíƒç ï®ß}óëýË]Àpúœù4(ñüÿ_„Õ€"쀿 ôŸ_ê@×8Œ8¸™YØÄ™þsÿûÿ—éïï?_ÿüøõêϯ€eä î½@˯Âk)< ÆîœЀ÷ hÀ`žÁÂJþôšIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/spellcheck.png0000644000000000000000000000337711550446574023354 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<‘IDATxÚbüÿÿ?Ã@€bb`@  @ 5 ¾ Äû€˜ÖJ ~Ä—€x9Ëâñd.ßâ@<Ù^€Âæ€B ~ ÄÏØæñV ¶…ªOᮈ¿q*«C=· €°9`?×ñN ž„Ç3€ø5_â§@¬ŒE 3⃸B €ÐÓ€*ëq(±5 áp+_â|¨°¨ù Ä?XˆY°@èˆâ?@œ5ä+<¡ ĺ@,ÄŸq¨éb1 Þ Äm@‡, @论M\§€ø2WA}‡ l…$@Ùjäp‡yv±+#C,K]|ÚÉ€b„Å?###Ur•!'CÃ})48±=$‘r30øƒëXäÿÿ»@ꈅšYé@üˆÙ8j0D8Chq‰8}’Í5@zî=h‚ø Ä·É°Ü š Aã…bˆr:¦C‰Á”ßño†70}w@ÔŸ¡ù ñ« †¡Ç-T¤9*n Ä?R60„€jêqž®ÅÄÄ.õïÃ# ø9`áõ bÜ_¡†‚4›Ci~h¡ÀMPÁP±H¾äAJpÿì †NeFF-QQÎ?n½{²ü6ÐòHV°; €0ÒÀ¨O@jAÕ_¤ ˜Å€“RíRÀì¬Éʨ¤oÀðÿÛ7†ëׯ3œ…XTw9TÙ@´h Ð÷¡–~…úø/4T°Õ^@Ù€©=Xq´ãYB]JŠAÔÚŠáûÃG —¯_c8÷ŸáС¬lŽîVF†I𬠦þ2¤¾üË”XGLâ:Lè«Ny?Mv6Y++#†/ÇŽ0\9u ÖW–GÍ»óù?$ýw0x>½ >¾À,üâ/C&Ðà8kQ. A"L êÿxUÕT„Ý=˜ÅÄ>®_ÇpãÜ9†ÓŒ —þgdc`¸‹ÅÈQ@pθ÷ŸÁÕœ““Á’‘•ãćOsŸ22p²üg˜ŽžF€¾6&Ìv`ÖrÒæãawvgàúœá÷†kV1\¿´œ‰áÆÏ a,H–cR`œo}ø“aÏk&Fñ [Y&…ÿ Sþ22Ô"ÏF†& F†Ã6¬LNVæÆ ¥U <`Ë?¬_ÃpýÂY†ÿ.}ÿÇà ´ü¡( $üüÎÀ°äÞûo.²¯_0HÖ61˜ÕU11?{Þ,˜˜€–åfdhÑdd0×”aõ fà´°d`ü м 6®c¸yþ4Èò ?þ1Dƒý,§à¯ º€uÐf†Ž ÖZÓ10rp2<«,b8ýàñÿo@“tٙ嬂#˜ø€iþÓG†ÿ_¿1¼_³œáÆ™S 'þÜ_? ¯îÁr #Žœ“µ €˜ã¨øÏ—¿ óî=õ~Á,‰Ú35EF{eFÕÌb¡´,&6 ?óø å+n]:ÅpüÃùïüY M/¢@ÁC ZCA€…a§;«™ja=‡¹Ãÿ×À¢ûï?FÅŸ…õß¿ ÿ¾ÿûüÖ…“ G-ÿà JíLH‰‹˜ &ôìÔðáˆY~þførp;Ãÿ7ïÿþf`ü,Å)Ãïߟ¯úüÊI†C?.-&”Úq€bBn;Á0Ð+nýd¸ü´?.‹ c¾|[þïÓW†·«1ܺ|‚áÐ7†Ó@Ë€åÅ}r«p€BΆp 4ðëÇ¿ s-ü|Ø’ú ,ÿþaø÷ùÃÛËnß9²ü·ßà|þ’6@Áð £hÁÍŸ WÞ=¹ÄðëÁ=†_~0¼Û²’áöÝó {?2œøò‹!èД6bˆ9  I||ý X.ðýí:¶™…‰á û>0œùñ›!X±<£F+ €p†À?Ht,ºú‘áÆ·—n=½È°ó Ãɯ¿ÀqþŒZ=J€Âë äóߺ·¿føº÷%ÞoÀ`gtB¨ˆq {Ç4à½c€ÞNõéŠNoIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/fileclose.png0000644000000000000000000000433111550446572023171 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<kIDATxÚbüÿÿ?Ã@€bb`@î€bAæxyyáT‰ªÿ²¿ÿvøùó§ñïß4þýû'ÄLÿþ}ËÈÈpƒ‰‰é##Ó~ Ø ß?@4P˜†E÷ƒàæ 1®jTþùóG>ÐR/AAQeUY^^ e ?~bxøð¡ÓÝ»7ž={üäÿÿ¿{XXX&µ^ d6@tÐå)?~ülQVÖ÷ðð`077c”g`eeZÎô݆_¿þ2|ýúáÅ‹× çÏŸ“Ù±ckÂÅ‹§B€¡ÒÆÄÄÜ 4æ.óˆ9 Eóïß¿:Y‹ƒƒÃBB‚„…yÁ¿~,ý¦AÁ r(¸AF±²²Cä ÃÖ­[–/Ÿd¿]ÊÌÌ’ ôÈGlQ@¸B€hy;;wQvvƒ§§#Xä[&&F†Ÿ?Ù߃è¿`1P<ÿøñ¤!00ˆA\\ŠaòäÎèW¯c„=™¿Ñ- ¬¹àß¿¿)ŒŒl…ÙÙ…`Ë¿ÿΰeË ÞËðáÃgh(ücˆ#~ƒÓÂ÷ï?®\¹ÆpæÌ9†›7ï00dfÓŠPøïß?j@j@ŽDÄ„%Á)~ÿþ£%((œÑÓÓ賟 ;vd““dPSS`عó Ãû÷_Â2øÛ·Àø¿Ì ¯¯ÆàáaÍðèÑC†7n3èêê1„†Æ£è_90º,Ñ@L¨–3€,,VUÕ‹Œ Çï¾}ÇTU¤¥Å$$„Œµ>ÅðîÝG ÅÿAàw†‹¯¨.ƒ¢¢477'ƒ¿¿0þß1Ü¿ÿˆÁÊÊÁÐÐ’ýÇÅ@2#Û @hø'ýçÏooGG~~°/A.feeÆ=Зßñ*Ä`jª æ Ÿ>}Çý¥K×ÌÌtÀ–þü•Xõ0iFp”BÉÊʉ™™Ù˜Xõí ž“  ¸Âÿÿ\@ÿ-¶´4Zp›áíÛ ||¼à –”hÀpùò p°ƒ,WR’eøòå+78T6lØt<3;;Ãóç/@—’’çûõë‡'²„â ëL$%倾ø ú`Ë88Øè3œ;wîPKHˆ0X[¨Ï ¬,·ü÷ï ›7ZÎÔË΢wî\¦›7@=² 5@¶ €Ð£@ƒ‡‡TŒ W¯Þbسç88esqq2èèh2œ|xV äã ¤˜;…|}–Kƒ³( ~üø Ì-?Àñ ò½¨¨ C\\ƒ––>Xîï_þ?`G01±õäØGÈvZ"d<ÿâÅC°ï€lp(€ŠaåqqÁÀ¬&æƒåÏŸ/^Ç0gÎr`Pƒ& ""üÀâ7X ›s(îA–322kË' k.#Û @(ÆëÞ—/Ÿ>õê '¸–dˆ d•×€àÔ¾té`PŸ–ù—æÏ‡8ä0PúäeÈÊJfQ{°vv`4¾&È;?€if'²„^ܺx×ç@¹äj¡‚‚`y66V`€,ßÈpêÔ1p›€èÓÀX âo@>¸åʪBBB@3X¡#¬.‚þ¼ïÿÿ‡™™Y®°°°|Ò ›6­fy €Xð¹¤f9ÄQ, ¿~ý6pttšäææÂÀËËÍÀÃÃÍÀÍÍͰxñrÑ++ƒRûãÇg''禀_Ö{÷î{Þ¸që×½{÷¼zõê·o_•l© ¸´µdd”à–-Nûû÷Ÿ9''w×÷ï_oBôÕ?yy9m4Ç2‚|üâó¢²² óSSYùÔÔ”<<œÙ€âj·nÝW+**Ö*Û² €À06¶eÐÔ4ôû÷/†Ÿ?eš™™M366` ܱcMÍÓ§÷§ýû÷—|_€¡ bHè033ÙAŽ~ 566Ž™©² ËA!JfLLL`u»wïc8sæx'Èr^€;@CCŸáÏŸ?`5$MËÌŒZÎÍ ªª ¨¥¥5uÅŠEî_¿~žÁÆÆ K¸È øß¿ÿ ::fQ¬¬œ_ýýýuÁ©¥'P’Ú´i7äIýÓß¼yµ¦ €X ‰n 33kŒ‡‡ØrH“`HK‹d÷{ÿþŸ€0ü‚EÔfVVggçZ.`B‡Ä ìì¬ —.Ýbèíí9u÷îõ2ä¨ &hò‚§üß¿víÚu€áóçïpEïÞ½e02RgÈÎŽe0ÖW:âà?À(ÿ‰v†ïß0¼ÿž!55옟?ÿåþ2°°03¼~ýhù„wÇH*ý‚ì€;àׯp`<íºpáâŠC‡Î€ù<:ê0š”N^zÉP4û<‹B|ùüß¾ýdðóóePV–eøúõ;Xä1gÌX þU¹Àôu¤ODD”–Àfج¬lh)úoåîÝÞh_¹r=êÔ©Ò@««ìNN.­ØØ  å"`ß}úô˜u޳ↇYÄ€n=þ€ÁF˜cþ2‚ó6È÷À\Àðð02ìܹŸÁÁÁXœKõ}§+PTÓÁ`BÿÌÊ@} õБ,ü »ˆ ZŠý“0Š_& _¿ó20+É00<ûÄÀ°ã:÷ß:á70èþü v$'|aX¾l8¢$þ˜~ÄÄ„%¤üyËÀŽÉA‹pp" XÏ+`ó¿áñËÊÂÄÀÃò‹T(Šó10<|ÏÀpõ%(w*P¤„A–±qò0<þÎÁ°sÇ^...pÖ劷o?0˜›ùÙq%0g\bxùò5ÈÛàÒ €ÀQ,ã[»ºú¢•5”””˜DD„¤¥„”¤$8¾3ü0G|}ªõþƒ$ Áì¿ÀJLÆ:„áØ…m ŠòwEDæ~F \áææÌ°dÉ †;¶_}òäÞŽ'Oî/Ù @Ðpÿß¶gÏzýÅ‹§ôõµ¦MžÒÿ€õ‰ ƒ°EÖíûÀ ”HAò  Šb`] ‰o/Ÿ?\,/ƒl &Dcƒéϯ_ß/?{ö`6_ð•+×®¾xþŠ!ØV‚áïË{ ìÀÄ .VHÍ bPbûüùØ! „ÉÁøƒALM‘á­€.ÃÁý‡QÁ ̆ß!ñ˜¨ß1ÈÊJ1F;)*jÔÁì ”’è`õ«ÔÈ ÔðæÂÞ}'T”Ä|T~2ܼúØòa`& °e –(II‰³Ý7`p³132€ üÆ©ÎpëÞC†gÏ^‚Õ›m@3yž?.¾ùø\` pøùó¸r01±añMU‚xyyNž¼Ä¦ÇðrÖ)†#Gô$¹½xÎpæÔY†gÏ_ƒ÷0·|g`:š‘[„áÔÞ« qF, b6~ ón`°µµcxòä1Ãýûw?ß»wóü£Gw¶=þp5ÌÄÉ«Ià„,@mVö£¡¦®®@\W¦Fš 6^e8rë ×g¤„Y”T帄ž3ð0Ü{õŸáã‹w ÖB º*‚ 6Jo€¾~ŪÙ³ïܹ#ÎèÅ>@C€˜Ø@ÑjÝQdllbja¡,™klŒ~üøv=²#ˆæHíôŸWy66f ¢¢üà²àû÷_ Â@_îØq€áüù+ F úÒàFÈgÀæ6Ðð?À2äÃÎ]GN£FZZXœ à7p=¡¨( lıœ;g\rìØ®­ &Ìv°­ö=0~[À½Û¶íé••k>qâ 0øŽ1ìÝ»y0 ¹zÕ6FUUMKVVÞ,Õ†wîÜ66^xüøî33§oß¾{µ::J /€QsåÊ%†‡oï…5Fa €À¸ÿƒ’’¸eÄÄÄØwùò޹sÙZvíÚúäøñÝoÞ¼˜ËËËÿCGÇäÌŸ?ÿw™›Û<àbõúõ‡ gÏ^øvôèÎL q'ŒŒ¬{oß¾–÷êÕËæW¯Lùnݺ¬šçv[Ö- ŠÙvÀ±c» æ-°×cÊiV³µmÙ²êûwo4îÞ½2èË›bEÓÍ÷ïßýæm1`-*nß¿ÿLé÷ÕÃ]H£† ”~&½ÿzïªU‹jnß¾t(߈ô0@ð4põêY`»O¨‘,qòä¾ièŠA•0­>f½ûÀÒMTçýú“áÍ›wÀ<ÿðPÉ[är…W÷î]‰¯÷@(-¢­[W2à묊‰âñïÏŸß®=|ø X×ߦð‡À8~ ,¸ž…Å/¬/@  ”¾á߀=—uÀŠ#‹åRÀ.–.4ÿþ›µví %`‘ÌLÀÿYë-°Ï°¦vÿþÍ ..ð–/>@ŒÝ=0 x¼wµÄbIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/history_clear.png0000644000000000000000000000677211550446572024106 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ŒIDATxÚ<‹Í ‚@…¿ÙÜèÀij‰P°}pµ/”àÁƒ–!¼äKÞOžðxrJ:ƒK`i§Sh]ÊT¿In–õšMz‰©4ÿÌ¿:Ñx£Œ˜¾pÿþóµÁ”ºçÍZ >tÃßÿ< ¿þF013%«Érë›k sj1Hs2p²3•02üøýáõû o¾g8~åíŸO¾\úýõ÷V¦Å@é7ø¬ Fœ!À ôý¯1\<¬.–’J1^ Jr| @?1||ÿ›áí«/ þ­g9Ⴣ ;3Pë“g_VîzȰíàÓ§Þýlgà`š …?ØB €°;€•™èë^c=ÑôÌXmM†û÷1ܽò„áËæß?¸XÞ½}Ìðû×OIi†/?ÿ3üaegøÏÅà §!É ¡ÁÅp÷Þg†™K¯1:ýb-3S.Ãß¿Ïæ¢8 €0ÀÂ,Âðûßʨ`u§¸(m†·ŸÎì¹ÉÀûí-ƒ™.ƒºš7;¿?ÃÞ½;>|xÏÁðéÓg†o_0Ü»ûáäÅO ¯þó1:k0ÈJ²0¬ß|‡aƂ˗þ22„-¿ì€bf …Ä5Ä=< ?þ¬‹ Õp Ôe8sñ3Ãݽ×x?cÐÖøÎàæaÇÀÂÊ fvN†{÷î1|ÿñ‹AGWhæ?NvE%1†¿¿o0<½zŒáõ.†_9lí¥DxYÅÏœzfóÿ?àEßÁv1@13ˆCR9Ðÿ ß~M Ö ñ‹ÐgØð-ÃÿkW2#$LÌUöï? Vm^^nff`âjaPPPd`ggg`bbd`aaeøùó'ÃÖ­[ÂÂ}lD.¼Épæ>+ƒ‹<ƒ ³äù´¡¼˜¸ÿ‚ì f~H6ùö+BW_¼92Í’éÈÙ¯ s1ü>•¡,I†A@D1¬ÀÁË˶Äfe…8äk… äÍ t0'Ã? ïþÛ *š< g=b¸Ç Ê`m!Îpáè=‹ïŸ/jþ @Làlñùg„…•¼£¸ÃõC·¤™N2¼ûôI\\œ@CYÀ¾„ùœõ‘ò2#$;‚ä@j@r`µ`õL ÿ9FEðÃý#Þ3˜ƒ«*ÃןY »ˆ ˜7Ù€¾J5rÑa8vá7ƒ!÷+`p‹2ìØy’aóæ} /^¼`àäde`–  ‡°KPØÙXüÿ K—.cþÇàªò‡áÔÙ Jš <ül ߉йn&rJBåRÎ&¬wÎCrr0 Ê3°ýÜÌÀÜÓËà9oË´2†K¯}ˆƒ{Î>Ïö·ÿ²Þýï›têÿ¯ï?þûö÷ÿׯ?þÿüù}ÿþcO““ÿßóôøÿÿÔÉÿÿ>üÿÿñãÿÿwïþÿLIéÿAÿßü«»wüøÿ=""ÿÿøûÿÿýúÿÿ1PmSíÿRr—ˆùc ½²©œ!³° ƒüŸç †ZÜÀòá¼tƒ±H!LÿæÍcø.(Œë BŒ@5üüÀÂì3°üeà52bàš;—áò‰ Ÿ€Åô«  +]]Ö–PÊf`øú•áî]†×[70Ì»Éy €€åi¨¶$³¨žëÛ· VÚ¬ ¬ÀÊ”Õ`Y ¹ú·z5Ã7`›@('‡QF†áΤI Bß¾1°HJ2ëd`ÂaàÖ×g`:ò[˜š2°•—ã÷7°Iö“áÖm†w3û*Îr2Ìý•¶ €˜¸"ÿÿcŒÖsRdþ¬#Ôx¿0ÈÊ‹Õþ‚¯L`G€áÿÁƒ ßnÜ`àÈÍ6 •‘¬,³ŽÃÍ)SÄÞ¿g`øP@€WNŽA˜Ž˜32 >ÿþáöm†çSúfó2,­bøüäÛD€Ö†qo¿}ýç¯m.-Î/ÆËðëþC ÚÀ*u ƒ¶¶.'°•*Óß»—-+‹˜à`€GZšÕؘáÆÔ© b?20‹ŠB¢À2â ïïßgx96ÃlQK†‰³ÎoºûXÖÔ°Ðfÿòï'ÃÂËû1HÈq1<ùÍÇpäÀ?v` jñ½xÉðmæøxVnnŒ\!t€ü¢E §Ïcø³iÃ`9t °D‚8èø3§2,—5cøØº„áá™· ßß|ßÈÀÆñ €X˜Y8Y^?õ¦ÜÀñ›˜™•Ã÷Ó?>`ø ªn?}aø½bÿÀ`. péI¨5âP[‘XW¼|Él½€ªCˆÏeÃë× ÌÀÒ“ùëÛïNï{ÿ•Kp"¨Ù@À(HVèŒßÿýdüòúÕ/#GqQn†³ûo0h(r2ðlZÇðY×YO‡áß÷Ÿà²hþ.²AŽyräóœlcqq`éÈpí°Íq0-p‹I0¨|ÀplË~†ËßUÛÿžY'üû@13ˆd2€CíÒ—W¿t?ü`Ö°taàÆýùMg¤ÕLÏœÁ ¢¢¬œ8!…ТÀvƒ;ÞÔ×2›f¬ ËAñÿë$Ń0¨Å `[’]@„Áœÿ3÷Óe¯µ?lܨýmß_€bf΂WŒŒÀ*€åÀ³Ûß<Ÿ|bsó¦ †×.žØ,~Ù€u8wü6¥Xù¸Î-ZÈ𡹠ØÊ±``0À©ˆ½yËpE² ¸¤E '°©¦''¢}åÅ+½·¿ï f¡4¤:”é+лŸÝúnyã“”‘…0ƒ“™ ËÇÀPü-ÂðùËw`}l’q±3|¼z•qÎ,3GG&Pœ€Ê€?Àø90èïGE3°´v1ÜÛ¿—AáçgF.> #€!Í !UEE{/_ŠÐéÈ%šw@Eë_Üù¡¹ÿôou!†Àmea†»À®×µëï.^ÿÀpïQå·wD54 ©äs`è¼¹w“á®§'ƒÐ”ù ›^(2t_1eྻù‡?°aÆ `tpËŒ»OŸ2¦˜˜AŽø¬C×}ÿ÷ëÑ?Œ÷]üÏù—‹ÁÞAŒÁÜT’AZ”›AVG™ùóc¦‹§8E$€øÉðùþU†Ê– W“g1´ÏùͰbÎû¯¯¿È·³|>T'úù¼‡¼°#°F&$†­gϾ=u÷n@[‹g‘À "`‹ˆ‰š6Xd~1¦3°3‡ò‹³ªéêp0hª°2ÈK11pÍúÖSÍòï0ƒÃO†êÛ ôg1¼ùãÃÇ[€ÍŠ) ,\7#ïF1è~Øb %"¼ÎN[GñÄãÇïwÝ»ç ´å8@v3”f`¶T¬Ø˜`•YW˜¨x™Ù™žÌøÂóÿÓ‹Í"Ùwÿýç<ÆÀøë(ã¿Gà<ËÈÉt€ñ‡- À$ªËÉÆñþׯmÀÂù(¨¥`ï†ãÇTãfIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/2rightarrow.png0000644000000000000000000000427711550446572023507 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<QIDATxÚbüÿÿ?Ã@€bb`@î€p ŒÁè¸Þáç¿nFÆ» œlù ŒÌY”220|ÏÀðç;„þg3|ù^ÈÀü#s5Pß&f,êtÓ„ÿj\dõœMľüYÔÌ¢ƒ˜XÙ¸€øÉÀð÷72–gøó+?"BSY]N ˆáóï‰xìÅ„pÀ_~muQ†¥- FZBŽ _ÿ.†/#P ³20°pÂtÈâ?0ÌÉðë—›*ÃäW!qž4†ï{€z™¡~", áf¦¿?üex ºYµÆ jJ¼ž ßÿÌg`aæa`aúh9¯0‹20üûƒlØ? î÷žÿbPSf˜ÜåÌÀÇÃVÌðão#3Ð Ì@³q17'C@!ÀÈÄÈÈÂÈpãÍËÍ0«Ú€AR”+hÐT -L`Ë@>ç—ÆÓÖ ¡?.¿``00•fèh±cà`g©føý¿œ˜X y†¡ €Àôýç  Ç10° ñ1L¯Ôeæc‹¦nˆZhÐ ÊÕ3B£†é?(±}ûù—á0}½ÊÀ`g§ÀÐTeÁÀðû_ßÉàôÃðkœ¬Ûví{Ìpôô{†o@µ;®30ˆÊ2L(Òfàád)Ô¶¤™KŒG<:þÜÊnßÿÂðêîó îž* 5f,LþOcøó?¬  ¤4À\ÿé㯕ó^f¸}ï3ÃG`P¬$§,ÄБ«ÎÀÉÌ^¿þU‚C¤¼âà” 4ø'KöÓoÏÌ~˜á͇_ w_10l=ÍÀ¬Î•¦ÇÆðíïL†ÿ½°9 € ¢ÿ?ØY2?ùµuíÚk Ož~cxüa)Ð }=†’xE Æf`H¦ãž_ ŠÉÀð˜‹#ìñÝ—7Ö-9Êðñó†SwÖŸd`HˆÕbˆÓäFã`è9ÂszIøžƒ5öýûÇöì¼ÉðþÃO†+Ofb`p²g(‰’cføÃ0蛆ÿ@ß )@0Øÿï3psD=ºóìѾ­'¾~ÿð‚[Î00ä¦ë0øy+ˆ2|þ³d¦à, „­(~ ‰ð￞ƒ½´ÐÝ0‹QØs £—ÖŸ–|ýõû?Ãg`öú tÄöK ’"À À ÌÇÌŒ b‘¡YØ … #ØOùñíÇ ¾õÏ:žŸ‡‰AD”äo˜6€bÁüÀ¿DS‘×ö3¿<Ó/ |Àj@Daó¡÷ /î¿üÌ55@u—ÁÍ×7 Ÿ3€ÙÿT~ÿZ¯«+£ð˜_ƒáÓ`,s-÷†Þ™·^Þ}ü†µf@aF#ÃÏ¿óu¹|ÌÍ”Þÿâ¦- `ýýüd90ú™Ê€Ùo&8o~…°œAT+Ì¥5ÕL>ýbaúU¨÷óƒ; /ï<úÂÀ ´c/Ì:€Bw3°Jž&/èn Ì°ú;8DeÄ~}þÄðøÎ †ŒLµÀàï…JÀ8ÿòf¹Ã?KõtÅŒ¸ÔŒ6^feà†8üãƒû@Ÿ?ü LW) LŒ»- Tüýß',Ä–¨¦¯È°ë6'È9 Ò ºçûW†' Ëÿ³ c Üò÷ ¥!#£Ãï¿K•…,EtvÝbVH R@½_ž–õßA–31üý7™ŸÇ‹SÈáØ#~NˆÃ¿½xÆðä*°Dbf­ê‡-±rIÉÀ+Æpû¸•ZÎü÷Ã] å¿ý_ æ|p*ÒS埰¯ û?âš w>ò2ðÓ‹ Pï7/Œ2Æj |® @± WÇL,¬ÀÔ Œ7`jgeøÅpX þúþg+°Mtà7¸Úoo!Å)ÄÀªè<`6»˜0½¼{´ü&°äfêªkÇ×" ¤`úÏ ÌÕ@8˜3ÜZþãÛŸƒ ¬Ì‰@ɯGƒæÛ;HS Ü^dë5x9ÿÛ ÒãÃÓ×þüù;ØÈ©d€×áØ@!;€‰‡ÿî\}ÆðùÓïS@Ëc€¯ÁÁ®z‘¨ŒLÈ FaA6F`b½yê*0Êþ-f·Ì,ΈÀP@ˆ(`bþñççO†[—Ÿ1||÷ã2+K(ÐñOP4ÿ6H¿%*dcãøç··ož]{ÇðóëÏõ ¬¬é(Q†"XX&¾|öéÁ›×_-Š0é1|cTgøÏ Ò Ä¯˜Xo3p°]a`aÞÃðÿÿ Þ ýæ ˜ ¢œùŸÁƒá×÷,†ï?­Ø¸D„õµÕt¥µ„€¶32|úøIåÚƒ{–ç®ÝgøöêógF–Ó@ÇLg`f\Ã@ †¿Dþüïdøõ-QCC‹!Ö.’!Ø…aˆØ/4ñ¿@'|fàc(kq`Ta“aøùÐ&”Ä@üñ_W ïè­ÄÀÌý™áЀ¿pÃ!ø/ÐwÀøPæ'ÿ†Ä!?‘Ôþ‹}†ÜO¶7 ÎIÜÀÊŒËÿ±È „þ323üþ—'§$Ä ¬ÅÉðüÓS†¯ÿ?‚ ú4†-ûÆß¡4.þ°ã¾ÿÿÂðèí}iÝ_ ê|ÀfHÚÆ³ €JBF5`bej-ÍÀ,w>þüÀpïÓ`ðƒŒù2 JCð þÅ0þO4 Òûøû-†·ß_003ýg0ñä¦cf`Z°Ù @HåÀ_W.!.!9u†Ë†kN1rŠ0ˆ³)€(:X€V²ó#03CsÁ?¨,,º~CƒÿÝŸ ßa`feaøÿ—‘ARヤëóGoÝ€Úö€ôÂè«*Ë1ð ²0|ýÉÂÀÆÆÎÀÈøáÜ»ý šf ²jpGü[Í tr6ü uİ#žÿ¼ËpõÃqpúàdãdøõû;÷?5=†çwÞèÀ¬ „ÿª‰Kó20³ýc`ýÇÊÀÂÂÆŒÌÿn|;Éðþßs vE&QvFn Õ¬@ÌuÀ°Å?ÿcøôÿ-럞}¿ÏðX ±CòÏŸ?à²ãã~I Ff˜µ„pÛ?16nä Å€030G¼bøòç-3/³ÐÌ@cÀÅÎo°å_þ½gøöç 0¡ÿaà&$Å ÌÈq(Ðn>~˜µˆ*ƒ€a†JÒ±ÿÿÔÁz .Úuì „¾ë‡?þþfÚ°dÒy†„ÁÉÒòabDH€,cƒ:ôì(é„Á^øl\‰2,íºÅðíç÷³À8™\Â_¹@-_`jâÉ~ç݃™å·X>K…´„¡˜ \ ³B£ÿðÜÁÎÌ`= dÊûK‚aIÃS†ëîdàbM…5²³_ðáw҉׾M)½ÂÀô^l¼Ð9æV¨ÃáyX\Ã…ë‡Ãü†» ÛÖ›_¼¬Y@áóèÖ®ŽÉ~^vÿ£û/=®ŒßÍpóè`Ló€Óùh…¡! H%ô,Š^ |t–¡6þ Öµ'ß-:l6‹Ñ(uЀ†¤#j!12(2üø=ƒ•‘ÕÍÊ^›!8Ä”AËB‚X ü·€Y ¨Éúáëßï 7Ͻdؼö<þ]@q~š‹-›ÏaR€ÂïH¨³0üùtH*‹™¢¢4“™‘ƒ„‚°ê†”Ÿ?~gxõø#ùsw®ß~ÄÀðû×E`^ŸÏÀÊ<hùO|=#€"ì`·d~þvb`Í$ Ô%)ò€•%Ãß§ l,×€õï^ Ø! þDL× €ºw @Þ;0Êi04h‹žKIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/view_choose.png0000644000000000000000000000400011550446574023531 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<’IDATxÚbüÿÿ?Ã@€bb`@, ‚‘19‡‹©Žƒ‰ûßÿÿAbà€a1Àˆ&†^ÿÐäaúå1ô12þýóáÏÏ¿“þÿŸ×@Œ (àãM{ÚØ/Å+/ÅðõÛ†¿ÿ€jþuý:çˆþÅPö¨²Zý™”2Á4H=HŽ…‘áÃÓ× æÎ{õëë q€‡7+—„Ž2Ãq öoCY bù‹0æ˜å‘,ÿ‹„Ajƒèÿ¨jÿmüÍ!ÈÀÄÎÁ ² €Àø÷éï—/Ù?AÂdà˜¯þ£Zb32B¢èÇ/¨%0‹¡ìÿPõp½PÌÌÔ÷ã7Ðl&Px0$ 011üúÃȰr͆ï¿300aÆ/JʪÿþýÃ7 àçÂH+0>ZzaŠÿcfc–åÛ ÄÑÀÌðáë_g© …¹²@—þg€¤AFT# †²±³0,Zx”aÊ”½ Ûö•1pCWv†™ðÈ`ÆÿÂÝ/–\ÿ Af°8@±@Œfbø L%Â"< ªJÂDeI>v6f]M1pˆÿ!ñ&)þ“áÏp0‚…âF&H*ýû®þõÎ] ¯OžeøôÝÏouõƒBá^§&V†_À”̾àøŒìŸ?Á³"H œ¡||ìÀñ˜6˜á H01ƒÄÿQðfÓ&> lÂ/¾3¿ex´É–AÚ5€–€Ùƒ žñ¾{þü%CGG?ï_¿€ÒŒp‡|ÿþ!0Ј½Áb „ùŸ  Fp°Àâ a¼¬ b’OØ€éâ/;Ãû‡ìÀú¹LLPK >åââd°°0bøýû7Üàìøû'ƒ„„$@¹” !A @ ú dAŠ2æ_þ¿ü n6 ]ßÿÀô@À9ˆå@K>>~†˜˜HD´ÿGàïß0üÿó ìnp6e‚@,°àÅ);Üv`ŠågxºU†A€™áûÏ ÌzÊ ,ÜÌHy‚ìHñû,òhòŸ?€¾þOÿÀå 0Þ¡ÇÅÆ «ŒW!…°XQ5Ãψ4`ôÓ0ápH 10³2ƒ Å7P13Ä2pÉøB¬¬,`6$B,t€ôo°ƒÀƒ$°=-X€i€¥ì`âãeàb”œ„’×™ÀQ÷ì£`ó~þüÉððák°¥0õ 6È<<¼ üÜ‚`q°4#$RÀ“…ÿ#ê6›–a˜˜á>eaafxòä-C}}38+233Áç·oßBCCTâCŽ…¤™ÿÐl@püù‡¥ü„W d Bû?4þ‡Æ÷ÏŸ¿ÊË Á>†åPÒ?¿ÃÏïß!‰ð?430J"ü”Ê¿?~ÄðñÚ=pÙ NáJR |ªJ`G0âžÕþƒÕ°°°2¨«k@ãý?4-üÓ?€Ñóû÷H”ýƒV @@ð’” ‘ð`Út†w¶10‹|eøöåÃ}.O« ËÙ˜Á *Àþ!·?à9æÿÿc‡DЀ‚„0¾@´HÿÔÄòç'ƒ†Û+N™ ?¹çâº× ¿¿ýe`ec‚D¬4Y àà`[ É‚ÿà9âï_ Ãþý…'B&h" ügD©OÙ¾10¿{,€îlÿ yäPVæÿÐr€ j°ÞúèãÇ Gž€ø^üÍ¿•Ì5ÀiäVXu @Ð(`f@ª‡À!Á,>?ùÇÀ"ÂÀð ä¶_Ì ŒìŒðÂäPyiñü׈_¾|aعs;ØB&&D|þøñÁÝÝ›ÁÊTQ­C@¨‰©y)ÍðùŒ5ÃO6†_Àl%¥­ Œ º_À`de„gCP ,g~˜ Cmm 8 ÀJCH9ðœïAÙ\‰ eC€BI„°`¥/nS0FnÑüúñØvù6ƒ ظ`Ö† ìL‹` ~~¤\𞾃Ún@1fp³Q<@øþå×Ïß~ÿý(@ö ü¡A–ýüñ‡Ô¼þlß1üc‚ZŠ_`Vƒ¹ Ð†²AÖ §_ÀìÈ🫠˜xyÙÎßcgˆè½v ÈbXéøï?Rñ?¤Møò£„6CÔÔ7়„Cëüƒ×ˆ ßcxñè>N†¿Œâ €ÀøýñÏ»7o¸å%Þ}ù ÖkÃZÁ P7¯¡rL¢Œ âL ¾ÿ…·~aMôHMud3À•&0Ú˜~¼‡G-@ðëÃÄcæó& ¨ÔÀÖºÅÚ#bDkcQ‹Ì‡ªeV^À û³$@ŒÝ9 ïœЀ; À)‡<õµ:+IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/kgpg_identity.png0000644000000000000000000000605611550446572024073 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ÀIDATxÚbüÿÿ?Ã@€DÏ1 Â@EÑû&RØEˆ Ȳ7‘Fpa.(`i'úgþ'ˆ¯xÕ…ÓÿÎIbËtä’zEqJT9"GÈó[æ…ˆÀž¯ºZøù0ïã<‘éÈ¥Eê¶/H­—Ti)†Î’q½Ý1ÿƒ7üG± 9†‘‡›!¸¼’AˆSh ;##׆ï¿~ýcfàäæaøõŸá?Ãñ=’†s»¶GõLiüû÷óÏo?˜YX¬YXY%®üöûןKÌ,L{™Ù™ŸÀ,¨säe¨Ùó % RÒR ª‚Ò@Žóýgxu•‰a~#ÃÏÏß~ÿ‰*üÆ­•`ÉÀÀ¢Ì`öï âNw _¦þýõÕ^@P´ÛÎ7ØTEOŸ‡‡áÏ÷ ÏîÝb¸|üäû7ïNþÇÈÜÌÀÄðGŠ—‰ÁKK˜a÷Í÷ ¿ÿþÛ @È0RcfàD¸nßÊÿ ÇÏýfb`x²}îÏsZŸ˜D%ÄåŸ2H)Ië01ÝÏ4´ràšÑÀÆ'­ÊÀðï+ÃÏ ¿?0Èk+1X: žÙ³·nߺíúÿÿý ÿóá§—:7ƒ¼üSoÀvÜÌ 6J @+(2€ôªºÒ |¬Ÿ’þþý÷ÝÐU‘‰(ÁÅÀ$ÌÍ ¬#¦ÀÁ%6-¨ª—‘Sh9Єß@§‚ÒÂ/`Øüú ŒdFw{¶ÿþV®ïÊ2ýÿÁ`& L3F|`{î^VYY h(t˜þ3|ah×ÕúËÀ gô™[ â:.u=QÆwßd€–ó} ô93Ðqÿ¶ÿÿ5è`Šý÷õƒ¦… ëÛ×s\¸0—ƒñ È>&°½Äs€° ƒž  Ô÷ÿ¡2¤3Èyg`ä€Xò"›ƒ–±$ÃÝ«·þz:îç;`é¿?€ÿâß`² 0”Mô™ù9þEñ°üba.æ_`{ß¿3¼ûñAŠã?Ô P‡€T0r ) 2ó0‹ó2|ÿò•á×»ç ì"ààfø÷â€?ßÀôÿ¿¿þýæç?¿8øø„ØÍ~ýÂÀÈ÷7@Áðé ÃͤÀ MÀNl¯Ÿfà¦xvn †ï ALÊBðç+Ðç¿þ ~ýùÁÀÉÁ Àö¨† a(@Áòó?÷F³áFHrù“ûŸ$$¸ò_!Áÿ ˆ¾ÒÀQñ÷ÏO°þCå×/ ß>½cøùëßgV&Pec ¸ñÀÀ»þæ ,"ìûõˆ¿ÃÒÄTüáÙÃO ÒŠÀDóóÃÿ_ø˜þ÷û ÐÇ?€%ãO†?@üüùáëç· Ÿ_?gøòå﹆» Ìð›áÛ_V°½„\Þ~ù”…€Dƒ¢ ¢×¾°üc5íÏgÀ¿ÿ3¼}õAÃHá?0ñüþýžzÿsÁPÂúüç¯ _>¾aøüé%ûûþÿúókùöI ÂÌ‚¤- ¸€ö]>y†áò—&èTF~ˆ8 Èh`|ûÀðåØ;†×wÏ2|ý)ÊpçìË/ŠJ¿™5Í9ÿå¾ÿÐò˜è~ÿZþèó÷À„ú†áõý; ÷n›õü·íæÏ K”3ˆþ[ËT@,HQýôó7óCgæ¹û3Dð#E#ˆæá`Ø¿ƒ“aÙÄÛ[ï3*ï»-‘ïöýå7Žk4ÍõX8¸ƒ,ÿ Œóo@|føñhù½; W_è1Lÿ´@ùöqyÖAŽ˜tCÐX€bAKoß¿1Ã[PéUñ* LÙô»Nj¯2o­wýñíÓ½¢ ï-dàçüÈÀ#!ÈðŸXyýüÎðíù3†7¯þ2|ˆd¸*›Âë)ë2gÑë}—Îýõ¦ãÛ%Áv z&¦ñÓ ç1|ÊàgàSVú(ðÿ7$oþýýçÿe或‰ "¶F®?øË ¦ Ìyî Öíd_ÞÆ ðçÃﯿîãÑ!ŽC^ƒÁó×?ÆOÏ6M‘PrŒþ¶îþ½ÿÖÀ„®ˆ K._ûà%CÇ«çPY ÁåÐ _02úû+Úy13Üyò‹ÁßQ˜A†ó?÷| ©¡ ª ž ²^2Þçf°Ž«dW×`PbùÏàoÎÄ ¥&ÀðùÛ7†¾IF†?u0ûÅŒˆPxûV¤3‚ê{pJ þ^ Wîÿg–çgøÌ"Œ ¦ÀÒæH^Y>†¿rò _å¤8_3x©008k£¨_\Š›áî‹? zú\ ¶vÜ™ ?ÿ(ƒì &lÍ$ nŸ>ÄðãûU ïå3(Ë‹Zf&F†×Ÿþ0|æ:6n6†7À2„ÿMùôý?Ã×OŸDxxôD„~¾|.2>³õ;`9ò èXAn†;Ï1xy s Œ]Oÿ\¤\½ÆðèË[5N`1ÿ÷Tè€ïÿ0Hp32|ù R èZ6 æ_¾1È›X¢l¬ Ïþýexþø9Ã_`bV ¿½ú†’l _¾ý`PàfàbôÙ@,ØâÝÕ±™ j¢V@6ÐŒïm¸ÏÀ2û/P×[ áì,°5ü|ó‘áíÓ§ @6 ÿbøñü%X ¨­xðÙVž. Ì@=À¶0Q 3«€Ì äøÿ`Këx€9ñ÷O`:`e+ëO¨˜ 9õÿë \ R?‚KÂ{ÀrýˈÇäxcž«ˆW_ÿ3H °0|üñŸ•õ?7ÈT€Bn’ÁCèú•ó¼U­$yUAÑÿRÝ]óŸ•á=0NÙ@éàÄÌ ¨xù Xîÿ&´ ?ü÷bê ÿ€!Ç´XKÅÿ ŒÀñ`»ð#Ð#ß¿üW‰ùÇÄ‹ŽgÞ0,¸vâ&ˆ³@Mí/Àð9†ß}ù"_nÞ``ºpšAXŠ ~z÷îu†7‹W`m l¢ p S`ñ bxõö7û§ï_‚L xˆ"Uý ¨æd°T32€õTMCËúoÿ™ÁÙí$þY@! ¾† n]gø{ýÃ&E†W^ùÀÖ#P¨yðTKH`Í»vô!0—|Ø2 €ààFJÀµ´°c°Ô…Ô¾LÀâ,Ì,Œ ×ßcP–cÜ ê$þY€–gX˜;Å-‹á§¨,‡('ÃG`zõCþ€š‡ v 0;?<öŠáÌ’“/˜ÿuì äV1ÃD"Tø÷H½‡ÄÇÿ_ÀHü¬¥cxxðÈñ‡Ÿ-µ}ÕDÕ%8ùØ€  ÀN£†0®>£ç/¨ûJÿ>Sὃ·nn¹xûï÷ß± ìì@vÜ÷Xê`3`Õ® < y!m Š…a{ÿ†“{ï­Rd‹:}î†íÁs×â9…y¬y$¤¹Dx¸Øx8X€Ù‚\}-ÖŒ¿¿³ã‡¯¿¼øøæó³Wÿÿù¹húb ‹?Àì ¸ö10d4!mP{%ífV!¦LI+ †]×ÍM†Ç_`‰t¦¾¿ýÀöýí[`§à?0 ýçƒ6c`iãÀH`¦ ¦ÀˆúÀÀÄ ­Û Þ€b„õŽA)$åIJH‰‘‰q “Á÷?±ñòƒ=Ãi¦h‚5½‰é]C`ÌÉVŒ7þÿœÈ@ŒÝ=0¦€F_{XIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/messagebox_warning.png0000644000000000000000000000411511550446574025110 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ßIDATxÚbüÿÿ?Ã@€bb`@, b5##Éáæõ¡Èä²;ôR͈†>@±ãj …ŠŒLŒ‹ ã"„Xy¸ÎÌ]4ã×÷_7Þ8NªYD–~30T*é ©×520°°2¼¹y›ýò ž@鿤˜@LdøÞ”…9J39 ÈZùá ƒVx877—ý/Ÿ?@Qb1Éj¬Rr±ãtpa`x÷–áý;M-g6 \ Ðûœ¤8 €HrÐp/NnŽõøx` døú•áûw ýAÝÅ…A@DÐ ÿ!!Eƒ@11¯˜è€jWn- Ïß30|ùÂÀðù3ÃÇ ì|" :öÖ G±0±!@L$$¼~QA+õ¸8†¿Àÿcø!'äÿ¦… f– RrRj@^î_"@D…À?H¼h†2°É(10¼}Íð—““á·ŽÃo†?@‡€Ò #+ƒ¡¥HOP½ä?ˆ^œˆ( K‘דõðúì߀ñ®¢ÂÀÃÁÁÀËÄÄÀtÄÿ@#?|`P•gS‘üÉÀPür811â ­Ð 6 †7¯þKI1üaX¼x1ÃÔ©S>òð00˜›ƒÓó¯? &zz LLLiÀh0 ”ˆ…‰ƒ#îs%Uþrvf;`Âûû—ÑØ˜áÌ™3 q ô‚¢¢ QÁÁ »w30<{Ê À'È ª$Ç{é΃R6†h|æÞª*3S‚nX(#'/$ßËÊ20°±1üûó‡…ZÙ ÌÌ 66 Ÿ>30~þÊ`© ÈÀÁÁ ô€Í_hñˆŽA €˜¤üjy#]Q k`Â{,v 2ðññÙ’’’ nn 22à)ÉÀÈ +#Å L-M@°àJ„„3€.´ccgÔ ``dfƒø^[›—¬Q\\œAè...aaaˆiÀœÁ,–ÁeÃÛ V‚ ‚ÜœŽÀ‚+«€€ èû"e3C6v ïù3 Å| ÿTUá¡#L„ Gðóó#ÒoiÉÀ «ËÀðú5Ûϯ ú 2 ,F/°ô`@Æ @L8‚Þ–KPÀ_Õ@áÃÜv†wsZ~ÊsзðÄÌ~ bÀ2ä`dggøÉpõÓ3†sÏo3Èóq3ˆóó™ §@l!@` Å ;P²^Õˆíé5†_Ï?1üä`cø­©ÉëHd¹0KÂ#H?PÍ{†oŽö _ßýcøüò1ƒ¾´8ÈÅÕ@ÝÂèÙ €˜°Ôv±’â¶ÊŠÂ ?®]fø LÜÌyµ@­â ÿ[ Ä§  €~` ç/(G°q0H—Ö10ó²1¼}ñ–Aè>Y>>5`Z(ü‡„^ð% UMÉÃk ¿_-tu``pôføÌ^À, cF°AQÍðû÷o¸Ïÿˈ?@üûçg þÀ`†g –3¼}õœAXVÜýø1ù÷ÿÿ³-§‡0 %JS”Ó’çaøvãÃ_†?a) ¿ÿ31üùõ“á7Ðw Aýúõ‹áüùóàé+°Z9àP„å~ýøÉ ŸÌÀ"ÄËðîÍÁ¿Ôù%@¡ð©( ¸€>W&UÚVÆ ÿîœgøóù/Ã/†Ÿ¦ ¿ùd! ³²²2lݺ•ÁÕÕ•Á××—aÑ¢EàPɃùë°XÖÒeà‹‰—S/ß¼b0äça`cbÊZn‹H€‚;”U$U•ED¿2ü¸ÿ€áÐ÷_‚’~þüÅðóÐÇÿþC‚¿-8ÀJH]K›ANQ‰á'(T€¡€Àÿ~C†;4’EL€áý'`ÆûþA‹— TQÁ@°4 ÍÌ¡eªÍðëÖ1†ßÿ@ ê/óý› ¿e†ƒòÆŸ_ ÿ~±}úhš’"úU+Á‰NPHáíË4&pHK÷o1üùþ œÃž¿ÿÄ ',Äpõ3³ß׿€Bûˆ”r§32ÎS77L4çcøtâ Ã?`¸=Íð‡…áŒÿÿŒ  Ô_&HäÿÎÌÌ d30üüL yP.â? 60þÕÿxpá70ƒÌü 4Sž—›á)#ÞŸ·.ýÿß €X ¥Š“´”Ãÿg×XøxÀ®ý $ÿ€Bá:Øð?ÿÀ.²ùü/ØA ÁÂÿ ø?„6à?D 3С,`±0þgøøý'ƒ''#£Èj€;èÚKnÞ—gV×`ø#ôhÐõ@ËAÏ ‰ÿ€A JåÿþþË1ÙLA¶CØŒ@1fž ½õÿ‘ÔƒõBÍcâ;ÀtLK÷@v 4%VÞ¼v‡õÖ½'†ÿÿƒñ?¤Tü„ÀàzR€ü‡F¬ºþñ5´‚•¦ uÿþÃØPµðNðf`½, ÊA<€bèÞ1@ xï ÀïÒ¤|vߨIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/filequickprint.png0000644000000000000000000000613211550446572024256 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ìIDATxÚb IeÀþýû§¨¥¥¶ZIIŽÈþÇ@`bbb|þüÕ¯ ®$122žÂ§ €X~þü‰×°?þ [[›zx811λÌpúôyq c𪠠 ñ*Êÿýýûïo “üúõZ© ¨5@üŸ(ƒÿýùÃp{ÏA†¯Ÿ201#û¨ÿÿ?†¿ŒÌ Š–V ,l¬L‚x €€ø`bbeøÿÿ/z0 ‡ÒÕõžÍŒeP0“ªeEq#Pÿ÷Ïö¯1`àÏm:‚áÿß¿h郙áïß?À´õˆ¿2ËŸ?oýbF66VV>0nì„/ÿÍz¾oƒ ƒxÁh¨ÁB¤ŽáN·'Ã×O| ‚ì ,@Ëþ321 ‡òÏŸ~üxÏò 3@±€$@œ¿Àhþþý ÐU¿89%Áb0‡133ƒøúî3ëûs ü^P?Áƒ’AˆáËùY ûV]fpZ¸—áë_Hì‚ô22²€Cöóç'@Ë?C”…… ¬ €˜ã„‰‰˜x>ƒ²°°C„¬ê‹O÷ï2 >cà0pòÞBðˆ00ü<Ëp¢«A*®”AEK›á÷Ïß@½ì@3¸€žûÎðáÃ#°å ;Žf` Ì<Ì ¦]ÏÎÀÎ.ø ¨ ÎOw­gUe`àòÞ!%òÿ ÷µ2>XYc5aQQ 6)†{wïó;#ÃÛ“‡Ä ¹8AÁÿˆAe0 ÿÿÊ lïÈàââLñ¬ ïvoe8µôƒ€ó')iO÷ÏgÏž{¾yóêÏÝ»w>>zôàâû÷oWí[L ¿ê€eþþÁíΠ¢ ìà`feab8uö<Ãï§?~œ?Í kÌF·Ž1ücfe`ádf`æpAÉøõÞÉþGtsÃë·ï44Ô´µõAv°üþý[øýûwN'NuZ³f¹&P¬ €˜Uµµuçfgçsñó €³!0 ÀQòãû†«w1ª3ðp1ÜÛ|›áæÁ× ×çc“{ÉÀ£¥Lm,ÐùÉpwÖ †Ûßäã³~þebøðöƒÃç/?>}úÂð÷×?v5uM†gÏž™=zt?@1±°0y9::‰€|ýë×wPü€ò. 0~g`eÐTeà÷ñcž²«x1Ÿœ4ƒ¨½0 p@³áw†¯N0lÛÄÁð3·ƒá+7‹„8«” 0$¾30+¤Ÿ¿~3ìxvšaÿ½ ?>ÿd062gbgçð nnnYYYPK&`–ó?þ`øÅ/ÍpíÓßÿ L|Œ V/gpðûËÀ,"µR^z’á÷'Y†ß2l7 fø.(ÆÀúW„Ášå '+Ã×_ß~¹”€0‡00HHJ2ðññk //Ÿª°°0¸äcW.ŒÀ‚ãïï?¾üøÍð’IáÓg`± Lˆ¯O¼dð|³‰AÚOœúÁe3P=0ÿ0è5›3˜p11a`”…Ôc@‡3C‚áñk†Í'D™Û2|}tô'N†ûïÿ0˜¨ËP†jüà(agçbà &`YÏýéÓw¨@¾ÿ Œ  `xóå7û/œ [Î30\º Ìù?XÎ-yÍp¶à0Ãïçß qõó$€:Tv‘¡‘·šá«„>ÃK`õ˜pßÊ}`fVÏl \\`ú÷oPÈÈ @L?eö¹s·Ξ½Åðô)¨2úΆÜÜÌ ÷>p0l9ÁÍðì:Ð`1²]1—ÁíÆÃ;XX™]´ä5`?î:ÇPyÚ›áj0Ã#ˆz†çl wß }Ë ¶ôß¿ÿÀ:á ÃíÛO.^¼ÇðåË€b;¨Daxõê#¿VǬ << â¢Ü jü )_>ýecøð"À¬õƒAŽAO˜úy€eÅ7`]ÀÇÊðs÷m†Ù«d^„×1X« !¶ 쀎4“æa¸ûèë7_À‚< Êâ z˜îþ °Âx,¶9€ùó°µ’üþýÃS`JsüdÈÔþnX0ƒE@˜áãò- âÒÀàÿ W`Âdxò‘áTïk£²j†P³ñû3†¿@sþþùÅðØÞüL2OŸÿeø,[@€“R»‚*=`Ñÿ €€ÒO™˜þqrrãT…² ÷ ìóÿþ…Ö@ÍE­éé½ Zå‚’XÇŸ©:Á0÷•ÿõ G/3´F¶˜€¹‡œ¶LL,$$dÀf‚ÊPa,wÞ°Eôûáÿÿ F°ÃÂŒ/`Tpþ422“À¢”•™AZZì`¾cx,ǹ­ÙN¾ÂðÑ-‹Á>)†åÇO†?ü –‚Û`Ç;4@3¸]îÝ{Á`l¬Áðõë7°A ðÆ+À¨g8@Ì&&&¿>þô\öÀ6'°CÁRxãÆ=`ÂÑÇÿ_ éYð뺹 ¿.žg¸þÛŠA½¡h(1| ²Bÿƒc Y ¢¢ü ׮ݦ‡¯Àôõêïñã‡ß={ª 蘽îË‚5{÷î<Ôeee“úû—EÏÏ/ Ž——›T,ƒ|ÄL \iU wvìa 6»Ù~ë XÐÃ0¤%ýLÿü ÌŽÀÀ“•û?{öœ5LLßë™oß¾¹ÁÆÆv d7@Á›d¬¬,w!p÷Ý»÷À¸‹ÐÐPJ†tN!†þ5›‘)ƒº©9Ó7`úìXüg€úªæß?(lÊËÉI2²²òÜyñâé4QQpaëì „þt);Ãë×€®fã23ÓÎSP;Ž››³%Éã€Æ7$ÎaíJ,ÇÁÁL isçÞŸûäÉ×» ÜÀÎÉ5,ˆXÁ ÿýµ@£Ð÷ï_ø6oÞõè/¨^f`ÄÑie ªï+“?~Æ Ìò@#ïþùÃÊë„%ÿ©òTõIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/view_bottom.png0000644000000000000000000000424311550446574023566 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<5IDATxÚbüÿÿ?Ã@€bb`@, ‚‘1)‹‡‹¹’ƒ‰"ÿÀa$þ31Rý‡Š1@ÅàêBu ˜j L¦ßßþ\ªIÚ| €AQ ÀŸþ¦eB¢0¿¼$÷oÿþüc`ø Ä€ªÿþb ‹ƒØ!Ä©û UÎÿƒ¬jÖV†««w2<;y¤‘½ €À!ÀÍÅÆÆ¯ªÌðK\”áßw Há?¨óal fò|&7€üÿ!¾eŠäÀj `‚:€Èfâ ÌÎÀÀ.. }&&€;àß?¦¿_¾þfxø”áˈ… ÿ >ÂFÿƒZv#Ô"° HjÿBi˜ææ9¤ è,&f€‚¤&F†¿–ozÈðçó`<3¢$xü2bdÀ® ø ŒA%iFffˆa@ØÿY>|ùËà¯òž!ÃGìblvR@~úúõCÖ²W ÏÿÀÄ@Ä L ¿€©DL„—AKU„Š™ š? YéÛ×_ ̬¯@É ì{P ˆó˜€‚Œ ¿ÿü%Ϩ ú0¢A42D3òõû/†àà…?0*@—üýKŽÅ_Âhˆ…q”ø ü“ 03=@ÆÅßÿäY jˆE°PøÇÉ]ÿà|FX.”Áv‚0@AC€˜u!¥E>ÿ„QqÔ1ÿa!‰€B¤ÿ¤ûÙBHÀ|þ ÿþ£ª;€ œAö< €ÒQÙ –9™™±¦|C øuÄ÷¬¬ü®l@iˆZ@\ôèņc_@+ÿˆšîõÿH9 ’œþýƒ™Kÿ#,âÿX~ 86¦ß Ì ¢ÿ ?òB‚ŸN†Å»î1¬\qœá#´Ì—ÉÐ\Þ‚ÊÓ¿àòöÿ¿?Ðò&uPÝÿ¿€õ#ƒãmCöG [¾j3¼cäŠÿdàÌg`aeD0í403|üú—!ÐE‘!ÕÃ’á÷_„ïÿ£øü?HbÙ„Ü?`u.^Ù€¡ •?¿>Þ|Ä u8‹Á,ž—Áwþg†ßÑ5À ëCæ6†çC ‡ÀO`ð¨Kð2XH’PÊA¢‚”_ž¿`¸6£‘G˜A½ …á߆÷˜õµTT¾1ˆ¸h2üºr“¡úv)ÃÑ< KYä@i € ©Ž ’ þüù‡Ú¨€g£@¹¿ ¿ÿÆá†Àšëû÷ßÀ²ý'j;?oƒ¤É/!ùç §Ëâ>¼ÿ f†ÿ¿~1üfãfx~èÃë)1 ™sO1LßÊ ÷ñ+7@1ÁsÁ?ìù½xEIl01`ÚàW7axyúƒlXƒŠåo†;-¹ ~C‡““áóÅ; ?¥1¨×Cêã}û…^q‹€=@0BKÂÿÈY ‘` ¢Àù‡pÈ_HP b`TJ`¸ØXÉ Ë ÆÍÀúë)P '?ûEÝ&v6a†Uùr ño:þqsüÒÿù €PKBx¼"J8dKQ‹WHÔ0³q0¼¼táÓà l¢â ·×‰0üÊ(d0íËaø÷ÏÀ´©ÙïÆðëÓ†sþ׿<+eáÿÌ`ýp›B럜Ïþ#7&#‡jQûŸ…ƒ“áñ‘# Ï÷41ˆ©(30¿ûÉ ëlò|’eøûø³º!Pï3°þ?7ž0ˆ0,âÅÀÆøX°D¾ž!Ì @,ðDô ¬`cVŒ(–2€ùàB‡Výæ$f†O÷¯3H¨r2¨xEÜ+ Á_ê¾10r|ªú 1XN°) 2H*³1°°¼Z*vX¾ã2 Xø¬‰>}úÁðú-Ѐ¿ÿàCò>¤2@H邨Žs `¸ºàÃÍúI Ì| ?î=ezŒÁqi:P04~ÿ¦vF†¯ç^2\.½Ï°GÈè€? Roo\¶½s® €`i€‰—Ÿƒá솈É/áU+¸1ü¹e;ôÿ?X¹ôœÕ˜Ø ¾‹ƒæÉ3†Ü™ ÞS‹€M_~†wK–1¸›0|=x”?D‹AãÍW†©“•Vˆ…10¼=±ÑGüЀ;àçßß<ÃÀ!&Ã𠘿1ZÁÿPùa-^ˆÜï_Àüþå#Cæã †„~wvm5†-Ny ‚  VA, {›_0è?ùàX Ï0‡m{Æ…ýßð´ë5°žì»Zõ`#°wö–á3H;@±P³§ ,s‚ŠV †/ ÀÊúŃm73|YåöâþßíR oø ¡wÙ› Ô§²}Å#-IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/bookmark_folder.png0000644000000000000000000000443211550446572024366 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<¬IDATxÚbüÿÿ?Ã@€bb`@Œ !{s~ü­døù—‹áß¿¿  ù÷ÿþc`…Ò? ý‘¤€e Îò¾3üúËÆÿàjêAfÁôƒ Tá€bdðÞõÊÇBLÔÍH˜áÇÏ¿M ðjL3ÐvV&†{Ͼ2Ì\y‡áÇïæ@¹S þ"9˜t Ã↓* " !NÒ ß¿CígÄ'°>A†gO¾2,^s÷çï%€âB@ÌVŒf€Œ{‡/ ˆ…ñßßÇïþ2\yÊÀðû"Ðȃ"| _>þføþñ'ÃçŸ} ,LŸþþg‚ø ÿaQ÷Ÿ‘‰ñ/'ój ö.PX`3 €X@Â?ÿgøú¨â$t˜!Ù1 ö§o ¼œ ùÉ:ŒßþQfd‚ <ºàÁÍÆÂÈpÿág†u[îþýóo=ë °¡P½@ Haø´ø3(øCò3ÿùûŸ‘ÙŒ _Ó;ƒ‡¯&®$ Q ´C˜Ÿáε· [·ÜaøÆÈ$L¸Œ þa0@±€‚ëÐ_€` ü&ªu‡î0Ü~ð’VþAÍHû tØä çš(j@âÀô ôÐO†oAü) Ÿ~~aà`ùtdPÏu˜ˆ¤éû¯ÿÀ(æ. ¦[Ͼ1ì?~ŸÁ×JŒAQŒƒá×ïhA µ„æ0DÜ#EàC™€AÎí. r°Ño¼Çðéý­À †; €À!Š‚o@| Üù I+ÎÊ –üà`gÀ‘3À–!ÓÈ%#(m10¼þð‡AF”…—aÇÁ' Ÿ^~ýÇÀŽP@, ×ó4Ãg E¿ìŸ?ÿ€}pøî1ü9¥£_~3\ºý–ÁJW˜ÁH˜Yþ‚Cé?Rñ@übdøÊÀÐøýó¸ðøöã?Ø÷~ãw#33@ õÿ ÷‘ ÈÿþXÌ0p1übbeø LîÿþþaþÏÀÌ×@(øùœ @:R$ÐQ ù‚ÇL@X¾¾ýÈðõÉm†Ÿï^00±²3pH«0ðJÈ1°³33¼~ý’áíµs 7^ ‘çcøùýƒ×­?f|§ÀÙ‘ op6ZÆL`¿~Blñ?}¹š½Âzˆá°Ø|º}Ó R¬ÿÄ99þ~ùÂðúí{†›š D¥Omg°dF¹Ã Ùñß¾2ÜabˆægþužƒáÏePÀØ¿¡Ë?þ€³Õ—PøæF å¿>½cx7#Áä÷—Ô 3KF~`ÆZðóÔ)†›K1¼;~’Á0,œßÓA\”¾Ý¾Ápië·õûïzÍÄÇÉ̼ €ÀQ ˜À‰(ò=3"Õ%à:áφÏóª‚ÙÞ08¶õ+!`rºô³°2°;82èãæ+ƒ”0Cô$Z¹Ôµ,ôŒäµ6HLœ:uÁGo€bäY`Yðâ€ß¿!ŠAúŽ$pí9wˆA÷ÞaÇÆ& ‚/À|öš¥ÈÇß¹ÍÀÀf潟?~¿yà ÉÉÉ ..µàñã €‚†Ð@3é_¿þ€ ›Ïß!QÀ s#¤Àc>»ÁNL"ðèîìÒrвÿÀÐù}æ Ãçýû>ƒ EM€‚8à7ØŒ@!d‹ÏŸ ø‰ê€?À´"ùþƒ;óêØG8-gaã¿gÏ2|ß±ƒáÛõë ¿ …'H—80j$þý X±ùíÄ?ý‡À`áôå¤~€;ÈùÅ ,žAÁþü98aaæO`гóùû÷ ¿Oœ`øyú4°8ÿR«‚"ì/0J~þÿÿ €À€E°(dø ÎøÿþÙ_~¡†À_6F†7¢ 7n®eúˆAL âX"aeÇÓï»w~<Éð÷ðAÎü¥A¡Àtà'..†g?~\ hãT‚À͆ÿ9ãç?¤ø±ë¥F Ãñ 3,.ŸaàQÔšÆIdÀxýùîÃ÷7þ<{÷ñ_$€ª Zii†Í õ¿¯ PËI`[ôжÀ¬óþ;ØÆ¿ÀÚëéS`+EHeá6i†5š "'™n3r 2¼xýŠá0È>}‚52-)¨@–s¤˜‚ÃA`¶<ûþýVÖtó3†¯ùÀ7ˆRV†?¯o0<{uÞÜ‚#Ã+†~Ž$†·¯–2Ĉ}d¦ö÷@Ë!¥3¼íõÊ¥nYY†Moß2\üøq. K!(ùȱ© ¿?Æ2ü{Çt.0ì‰è'0H™Þ@Z´Èí=$|›Õ”a+ËÿŸOgùH jëé1<f±/ß¾1°!?(+J+*2|dØðäÉ—‡Ÿ?Wq°±M¥€9à#ÓpžeDjX€ª8PІ·:ñ?p¬þaácøðGb×Ý[Ýod”bìôõ^ܼÉðî¤!ÌLéÊZZ ÷€æm»qãÆ×?2¹ØØ ç€b¡¨WÌ®À–Þ vFÆÄS÷ï=úðõK©»Ž+ËÇ ß>fÑÐ`8 ò£wîlz&ìÑÍ *uÍÿp°°Tßù2|Õ¹s/þë)CC†÷îý;|ófЗ!ÌLL±UëÄBÍ~°v[ÿùË—‡[ÏœéúVæÃ÷ï-ÀD9Ÿ ½qè ÆîЀ÷Ž ¾7XÎñ-ïIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/kgpg_sign.png0000644000000000000000000000473511550446572023204 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< oIDATxÚbüÿÿ?Ã@€b¤±Š@œÄLP>³&£„È>–ßý~»²‘áæ6F†ÿÿÿ1 ÀÄ9@,Ä ÐýÇ¢ ¯ºK2ÞÒñæÓŸ lWïÿ|¹«­éÿ¿ým Ð &ê;Àˆ% ìÿ ¬\|5ñ‘2 º  \.ìÒAÝ­ŒL… Ä‚Í[ f¹ˆßñ# þ@”åz@lÄ¡±Ëdï[èRàÈÇð‘ÃÕ—ßž³¨0¼Ø¢l Ò@! ÄÊ@,Ä¢@¬ÄNPG)@†q Ôrø+ íj07#Sƒ™óÃÉ' þ32˜«p3¼Û±åÁŸëÊAª%8¡Ëðj,ˆ@±¿âë@ü%-‡14Üþ3ðIILÊkvPVãg`8 Â÷?€Nd`8¸ìúÿ3;ª2¾?é ”¹ÿ”ýÉòÿPÇübV –AŠ&°‡:í„ËÄ›Ôàë¢ËÎp‡€ñÇÇÃÀðìúw†Ë{‘º¦ €˜`犼2¬,«ÿ10φ†ë_$©ÿÐÐ9Ğ弡¢`§+»$ÚLŠ“bøú…áêk`¾`ƒH/kšxêÇ×͵Ȟ ¨oÄ¡>ZÀÄÄÈ´  ÝÞ™UBža߯;Ég^¿þòõóµ@¹5@õa9B“Pþ1Ëé«Î-¬2ÆÊQ`\ý*äÆíª®Ÿï_îH*úì€b±ÂPË ²•aQ ÎF!| Bü º ïjkž>ú¾æÀö»•—_;òõçljÀ Yr8@"Œ‡¯º°ÓÍ^_Š‘áê3`Z†À`Øø’aïâ’2†WГ.@±(#e å¶B ÁEr@ËÆóEù¤Eþ2¸i 0¸…‹1ß¿ea?±ú°ý…Óg‎Xü^Ú1ÙÆT¸Ô8ð3<{ËÀpé)0áðôцM} «ÎÎÀ–wˆ –i€(($À6?½^Žåî¹ ;Ž0|;°˜X¯10p}( ÄÀ kÁ h!ÈÐ4ÜÁÈÔd>0}„Cœþ—ßÔÛpnv–ËÏ {ZnSþ=`:ß5}éïïæäâʼφ@+¦¤UË+ÿx÷Š¡+çÙ•W?ö»_àÊȘñ˜•A¤âГÀ”«ËÀ§ö¡q–!s{æ¿ÅÛNÜý&$+êYÒâ * Œug€~½ÅÀð˜nî¹öïùÅêt ÷^âr@±€Üÿ!Ñ7D$Ê Œƒa_Ï#†×?fؤÇ÷˜c~3sï]h®ÿ)%xTxU0ÔÏÕf½­±Ñ*ΙÑPaÏ Ïc¨äåÝo v•u³ÜN|e'@±5RWgï +&ºô}Xt·ý­zõI83 [OAð<4·þ…:às«1¼þr‹Í*›1Ô_šáÊm`6;ðŸáÉ+F†€¥Ý„ ¶Ö*¼ˆ1‹ñ^Ý|IEi ³S4ß ¿~Ê0pÉ=Àˆdç€ÌâÐZN˜¼1¬ê½ÏðKn>ƒ¸Ž Cër`þÔO`búqnß§ÿwìÓU|–ƒjC€búý‡áÉ“ Àä *¾}úé ÷s.©S@±ÇÿÿùŠá´jzÈÀðb0µ+28™²0pý~ÆpïÑO†ÀúùèÃÿ»%%„,‡€búýë¿ïôŽOû/mZ",/¿SÅ'`º‰á3ƒØßÿ2üÿ÷†áÙé{ _^ßaøÏ mQ&kùÛ ‡Šw1xòïûõï|Å,†ó³Ù •š> 30ÍK«°É5_ö– rè©Ø“ßÓ_‚ õHXùÃ}n‰‹3¸©Âà~ÿ÷—ïfϺÉðd͂㖠7²xJ…€˜Z¾€"îR=ƒ ˆ1Q¾Ë ð2쯜Ǭ(c Ì”ÏþC$8¡˜JóAL:³BœÁ½}ƒ¨Ø7†Ÿ –—îldaØ<ó꾿ÿ~ä=vZ5‹lP@#•áZ fXóÀ¼»÷òÞÿA"| C}ÒG†;×ëÓ¸št@1£j†ß„¦7PŽãAj»±"Z} Hmºß@CÞ|ûÊ vë2ƒÕµ£ ŒWC¨QИ{9¾2¼{ñƒñów†/®^~shÎÞ`. &¾·z×ñaHE Æç¡¹…ŠY‘úv@ºæâMýý'¬×`È\4[ÀÆ+P¡ówNî÷ ÚÖÿ8˜Yí‘{£ÄB xÁ¹…Ä¿ mÂ1@óµ¢iýØBº ÍjÇN]gÐØ¿–!ßXm¼¶ ߃ôÑóG lÌÿUÿýEôˆâ¾!¨¯`‰ä(D4ñ±±0àåfýø™áöà’ñ*0;¶Ø®~„æ€bèî9@€N (è?×IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/editcut.png0000644000000000000000000000347111550446572022671 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ËIDATxÚbüÿÿ?Ã@€b¤…¡ÆÆÆò²²²JJJ\pöìÙ‡¸ÔÕQuuuý¾}ûþ¿ÿþOOÏS '>õDU4yòäù_¾|ùÿýû÷ÿ>ü9(̆O@Q uvvÂ-ù~õêÕÿ544lé ª ´´´üׯ_ƒ-ÑgΜù_^^¾(ÅOH/@1Qj¹|xxx0ž>}ÊðèÑ#†£G®J$¤ €¨á€+++ ï€¾gÑ·nÝzväÈ‘µÄè & -··°°HøñãÃÇ~ýú… .lJ¿%Æ €¢ÈÎÎÎ òòò`_ƒ0È·oß9`1Pú1f %qokkë³ü÷ïß _¿~e¸wïÞ7n\ÆQ@ésss¸¹¹9 9ÌŸ?¿ €Èv€¦¦f°´cøöíØçþüaxõêÉ'à‰ÏÚÚÚ^\\ÜÁÆÆÆ@@@ÀADDD@AA¬X:~¾sçÎM€bÁâJ~ 788~üØpöýû‹ØÔxyy€ Y  öÕ«Wää䌧M›¶Ÿ““ÓAQQ‘–;þþý Ö J¨ ô,'fË‹»Ä‚l¨à½{ ll>11 R {Oœh˜|þü‚}oÞ$"«ú<÷ÿþý ~¡ììì ÙÙÙ Ÿ?«%NF PÚ²eËæLr¿ØÆÀCýÁƒÝééb@þ÷7x?}bgàÕÕMx{îÜñ‹?Î2æá±w¿|yƒ²ƒƒ¨aïþüÉp÷î]AAA†wïÞጶ‹/~Þ¶m[ñcÇ–€Ü °ÔÅÅÌ.,4`~ñ‚¡qÞ¼Ïû¾}Ûœ$ •ìèÈ`ÏËË`ÍÆVÏÄÇÇ“«­Ýk ê÷žž <`صkƒªª*(ØÁ>ÓÓÓ§dâë…χ^,fCêÈ0y€b1Œ¯°µ5àbffXvð Ã.®‚Ÿ>-ùù÷ï«°—/ xq$))'-Ý«ÎÆÆpüÊ %%`q 6 l@qPt€B r °D¼yùòååÀ´±2@AŽ*Ä¢ùãG€¦0ž}÷àÅ‹]à<ÌÁñžß••þ¿}Ëðúñc[[°EZZZà %2`¾ÇÿéÓ§?¿xñâìõë×÷éÏž=»Ô2ç/®h ®ïßX€¾I>> ãoÞ{œ™¹„\ËA €fCP[A–‹k²¾„D,/(€ 7ŒŒÏ6ýþ½åÚÇÍ•€@@¤ôŽAL^hÖý ­å~QšÓ Ÿ0>ªv: IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/endturn.png0000644000000000000000000000330411550446572022702 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<VIDATxÚbüÿÿ?Ã@€bb`@î€p iÜ„a*’’ ˜‚‚)` &õ‡@¡Ó³O'é˹"3@ÄW°õϵ¼NqD:²‚ü½süг•¸˜mæÈ€pØÌˆ·8 ²WÓ[\c÷@´F†ÿþË0üþ?_RB¢ÇÑÄP‰““;& @4wÀß?½˜˜wjiD:Ø0ð1³2üüú÷L €XhfóÁß¿þ5pˆò焚h3Ek¨2̽zƒaÓá+™~ÿ‡‡@ÑÄÿþü3ûÅÄÐ'§&im©Ïà%.É0áÆu†u®}dúñ?…‘é¿øÅf%Ë ¯#äýè`¹Ä‡'Èíÿ02î‘Öæ/ÎòÕa+00efgøñ÷Þç/fn}ÈðåÎï6æzPYËÿÑ¢ €à`ÿDzèêÕO™~²2º1ˆ«sûþþó6PŠ-{±í¨bàeÙhl+l\ênÈà+môÃÏ¿?N¾{ΰxφ7~®dcf®ZŽ·º ¸˜X/þzɰ{ïåW f‚† Ù.æ Â*la¿3N¡ì_3h£p9[«¯‡ …%ƒ§÷ŸLÀ‚î Ã¥OOí}ÊðæÊïÍlÌ,éŒLÀ2š x`úÇò—í7ã¢+—?îÓ¹Â.ÈðÝí;Ã<†k1Ÿ®0üeúÏpü?s½²‡d¨…ƒ•ˆ.0 p2|üõ¨ù+Ã5 å ÷=cx~ú÷^6&¦„ÿŒÿˆÊI„pÀ/V`pìüýœñäž×­ìÄm¥ý¾;}gXôùAü¯/Lñ¦Öœ ¡úÚ j\ ?ÿeøþh9ã†ß3¬:òœáù©¿WÙ˜“þ2ÿ{Gl3 €øÃ ¢~±þ`XróÊ/«ZGœD¼¼$]>¹nÆïOE=af†Ï¿¾3üüÿXsþ`xúó!ÃêcÏùw—õ7sÌöH)?á€ÿ&##Úw Þ¼­¦ÎwƒãŸƒŸ¼0%«Õ¬ ï~Æ÷O Â_ Ï?bXsâ)Ãí}ŒY0‡ÿãü}½Bç;FÜá@ˆDª÷˜å?ëk毬Ëo\ýÃpýãm`0døþç÷_>ýþÀðíÏW ~0¼øý˜aëùç w÷²~dýÆ”ÊÈÂt˜¿€vA Æ ÌÌÀjS`Á0@ˆ@°èómæŒ3ŠK¨ 3ü6Hþ}ý÷ÿpH|úûŠaßµ 7v±}aùĘÆÈþw'Óf`#†T@L°Â13#Ó=¦7ì»n\úÃp÷ë=†o?3|¦öo¾0¼ùó”aÏÕ W¶rþayÅV,îWQR{" €¹Ù€Õë´×¹]{úèã7@G|eøð÷%ñۯnlåf`|Ê^ÇÈÊ0—Òê €!ð‡3ÿg>Íð‚cÿ½ëÌ ¯~ñÿ5Ã…'onî``~ÌÕlØtP£þ „þ±¡b–¿¬?Y|¾Ä÷ïáûw WŸ~d¸¾U„á&÷4&†r`B¡J €JBf, JÆ­ ϸ/Þ» høë1Ãÿ+|ë™Ø~kÕÔjÁRAÄŒMþ3ã_¦Žo{$Z¿3íÙ@ËP³ @ŒÝ7 ïЀ; €ÜëŒAt>zIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/messagebox_critical.png0000644000000000000000000000460511550446574025241 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< IDATxÚbüÿÿ?Ã@€bb`@î€bAæ¬fdD‘üËÀŒ  &VVù_¿º¶óÃy 8È<rþ‡`•ß Ì,,οÿüyä/ê›Tÿ¤¨Ÿ¡ )Úg ©åSS[l½d‰­ÓÞ½r†MMáÿYY·-ufÄ¡(g´d‡Q~~ràÞ½ ¾ëÖŠ›™MüÎÀ0ݳ0@  Dë€ ¼”¡e»žÞÿ×®ýG÷–.ý¿€‹ëõ·Ù@u3€x:Oe`0œÈÌ|÷\_Xí/ þ ÄŸŸ=û¿ÜÉé3ÃÜÖVP(!Ù @XÂÀP·]_ÿÿ—{÷ ¶î]óÿO–ïÿ¿O!ü{Ë—ÿŸËÅõ h¹ÓL úi@<d9#ãý PË?½}õÿ^BÀÿ'3ûþÿò¿¼|ù‰ƒÃÿz ›ÛØí ¬ÆùuõÿŸoÜôïà¦ÿLùÿÿ”`øÿ=Ôüÿ¯—OÀâw–,ù?“ýÐr+ Ö˜ÀÈx æóÏ?ü¿áùÿ+Ãÿó¢ŒÿΛúÿPüãóçÿçZZþod`(C¶ €P°ŒáèÃå+ –ïYýÿ™ÐÿŸ ÿ¿0üÿ$Çðÿc ñÿOîƒåo1…íiýsÝÝË>¿áþÿ"Ãÿ 2 ÿψ2ü?!ÌöÿÎÔ^°#îìÙó¿‰ý ²„’0©[YÌþ·n!ÃßGïþJ0uýã¦ü“g~g†0ü¶†A5:šáÏR?>~d0,*bøòþ-ÃË̆¯Ûv1üê&÷l ¿žýbx¿x1ƒHb¯œ 7·²„‹Ö\niûæÏÃÛÿ¿…šüÿ$ÏðÿƒÃÿ·Ú ÿ_i2ü&Éðÿ¹§Áÿ/ï8¡½{ýÿNˆÓÿ ¼@ŸK3ü?+Åðÿᆀ®Òÿ'ÇýÿTwföìÿÕLLû‘í S¿ÉbŽ ÔNÉ/ŸþÿdþÿÄòçê ÿŸñ`Ð>ò0úÿéé£ÿŸ>ú'Ì ì`ËŽ< ´\Gùÿ“S'À–ßÞ¹ó«Ð·/d;ˆ¹.X,ˆ~S7× »¹sE#"~>½Ïð%3˜á×™ó ÿxAû¼>3¶%7Ãç-»þÃä@eÈGfyy™…+$L,ìÛǰ*2òëçW¯Ò€±²¬ÉN€ÂpÈ #Ü€ŽXj?{¶ˆrTÃ÷§>¦1ü8sŽá?4~A}Ò@ ÿ9‰ú t³‚ƒì¼¥ V víbXùóë»wi¬  Xf`@v@1ᨠvýþö-bObâ«ÛK–0pJË3ðÌXÅÀldö9ȧ` Ùj9Èá??CEIžAvárq å÷wïfXõåË»wI0ËÑ@¡8à?j%±÷ÿ¯_»RR_›?ŸSN™A`ÁVk[†?ß –Â0ÈAÀò–US‹AnÉZaS †;[¶0, ùðýíÛ8P°c³%~FR¥ßüþùó×ÏÀå?//Ã?n.H¶üÁa4PŒ™ƒƒI@¬”=|ûöÈ~ùR·€Céšg€* ¦íöÝÝʆ…… _ß½bx•ÌðeëNpœÿƒúf9(:>Ÿ:Çp'"áík :Àr"tÞ<Ñÿllë!U`è!@XÓÐ\ÃÌÌ«mûú” KJ¾||Ïð*=šá˶ÝÀP€;¨JþL°_¡>y‡áãÉK 7b£^\½Â Ëœ¿Ìp%>舫 :‘‘ ¡3gŠÓÈr Kd;¥$¶*,„T©¯žÿ¿ ­X@Å«4´„ãfø\SXÂÿÿ¨TÉ<½~õÿ>#Ýÿë~ØT¿¨f°$\ âêÿ¿}ö XÝ®ŽŽÿ™ Ûí ”`baqR §Ø×e _Vï„T,ÿ>g–2ó—2ˆ³ÚƒM›®Ë Q -•Å˸Œ€!ñ‘=ùïÕù‹ 22Þ¿{Ç æëËÀ) `€l'@¡8àÏ¿o~¼~ÍÀ d³Y:0üdcøóï`Ë••d,c7–p{ö0¬Žÿ¼*!áÝ #$´tÔ-aà9â;´lø1WÐÊ’››X&0üü r"Jô20d/13ûÿØxµd@‰ÂLÿ32ü?©«¯Xî+–oÕ U 6•ll¯Î,ZÖsÿÊåÿŒþÏ?ï+)þÿêû÷ÿ>~ü?ÉËë C+²„žØ€M¦éˀͧÏÀfÈÀ;S{þŸ²4‡W©wöîýß&&ö¥Øz6±j¸˜ºË98^Ö¢`=gÎþ_mnþw^ÞÿW?~üÿðéóÿ™¡¡ÿÖg10ð!Û @(•Ñ$HeÄ ÌÚ3œœ’ü—.e`“–h_x¸¸î+–UhË?h ®À89—S»ˆ>0ÿ¿ó† Xr2ÿüɰ25•áøªU›€åW4°@ú2ÉN€Âæf:bЬ¥eº}s3¯¤$ãcÇv•—V,Èeû?¤"õÎÀ>Ä2–1 OO†ïÀâxW[ùíÛ×-•ö Ù„Ë Ì,èŠYX"XÄ¿¾ys¨¹˜@·£•šÈz@9Șn«¹„„Œ~ýú ˜è6C« ZÕ0 ; €ºs @Þ7 w@€¨ÛJ1ÿü–IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/mail_get.png0000644000000000000000000000565611550446574023022 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< @IDATxÚtŒ± €0 ßaFËhLÀLBÉéqdlDAÃU¯ÓéÉÝÑIiÁ—¦§x®ÕöœÏÕ Û8ÆCDADh¾7Põg1JQ03D.Ä8ÀÌñÞÿr ã÷ïH–ÿgøû÷¿id¤A¸¹¹Ã÷‹NŸ~zñÁƒ÷?þ»ñìŸ?ÿ¾211-f ÜLL“€–3ðð°[Y)0() 1¨ªŠpÅÇY>~üÑòÂ…gÅGŽt÷îÇÀ ?ËÂÂpôÿˆu@ÁÀˆ–À077—•†²!Œëß ‡âèX _€_€ÁÓ]€ÁÅIKæËןQ7o¾ˆûÈpêô†Ûw£æ''/0:þ1hj+2h¨13°030¸9J3ìߥb}x×åXNNöùØÊ$€bA~`dej*'ý·ß¾AR?Èçÿ¡?{öžáâ¥; W®ÝføTÄÍÅÅ ÈÏÀÆÊ N?Ì,\ ÖÒ |¼œ¢$ÅÊàâ¡Æpüà­ìßþmªyî€Bʆ BBœJŠÒ¬oßB#ÔaÏžÇñ•«·~þúÉÀÉÁÁ $ ÀÀ ,nY–ƒðãÇ_eymmHYt8;+#ƒ—³4ÃUã›.…ñðrÌD/šî`9.©£#aÅÆÊ NÑ =Z|ñòm†«WoÓÄ7N.ˆY€–³°@ÀÌ d³³28-ä†DÈ"Pé..ÄÊ®ÅpöäýŒ7¯¿¯hïaiî7#;@Á³! 0õ›™)ê0ügbxûö;î=ç–­ÜÆpòÔ†¿ÀðÏ< \\œ À8çää:ˆ“›‡ UÌ šB ÆZà(E(Ê@•ðfF övŠ@OFƒ+?`Aù…‡Áåû€‚‡€ˆ—7Ãò•ç®\¹É𘀠Çll`ß²@ƒâsffaZ Ìzî2 ßüú‹H3 r '+Ch¨Þ=w Þ¿ÿ¹ž…í©Øÿg Ú.3"2¹Üzô›áí`ªæf‘d`ãäg`dZð¨ŒÔ,ì@KÙ8ØÙÁÑÁ tðŸßŒ † 2R\ Àä·†a%§º¦8ƒ·šò¯_¿"~ýgaÐú}™Aöß+€‚‡Àûwß.°KÔ²J †ß@ƒÞ}þÇðþów†¿ß¿2|zÿáé“Ï ß¾þÆ+0î8þ0tÓO+ ¸Å0–…ý†fé$$ΔaÏ¡ÙÏï<]éΰh"@± ªà¿SN¼âig.Ï).ÊÌ *Èô=70عY bðŸÿ¾}þÁðüôU†Gwß1¼y󗇛‘—Mˆáç.HüC€\oü•˜ÿÿ0p|xÈà¢þSqÿ[EÌ f¥ž "²î¿w÷Õš çïÇÚ9¨00CT˜€,6v€mV.&†¿Óf2ü©)eF´à6`Iù—áðJ•¥+$åä~}F„Èç¿@¹“án}=ã¹Ý Ú@C•~übøŸ ´v@¡Õ†Œvî¸h`$L¬`ƒ˜¡Žáßo?2<]²œÏß•_‡—áßé üf¸qø8Ãå¬\æ…KxØy€eÔrP”ð00<œ3›áÕün;©ß \¬¿Af1~db`Ùó€Á €˜[AÀªóÜ­Û/×;z›äž_¿0°`úÃÂÌØR ¿¾üb«¬fHób6c`0ô:}ß&†sµÕ AA*W@4°D|±{ÃŽ|Gf#uF q5e y@›¿üfx@LHõ¤8f`ìÛ»ûú‡¯_~0 7°oÀU1°rú VáÆ†—2\Ïîfð,i !1'†¯ &1\œ6‰á30Ô~ ÄwÀÒóFyƒ¹½0ƒPh° ºøŠaë-`aÏÐ @(av6– ·ï¼Ytòø`®`ø ´üÐ7߀–ýt š ƒHÏt†;3W0<\r€! O†A^†ÁH“áeW í»Xµ×í²9V+I.†{ŸžCróu }ÿª–¯ &ä4ÃÀ¦õœ ®¼þòéÐ^°åߎø ‘O¯òή ‚3Ζõ2r€ÁYøÇéãÀ¦ `NX´üÅg†]À€-Ù @pÀZ9 e9#ó„íÛo>û,ˆ€Í>†¯0€¢ã¨àß} vî ‡Ó[~H10øû3p£ÙO‡!Þà/ƒèS Ï¥þ†mÀ`¿úŠá:;CX k€0ËÃÛwÞÍ>¸ç:ƒ(ЃÀ„vÄ—Ÿ‚EQØ2fþÍpR+‰áÈåÏOýÿÏÖ‹ÁÅš˜¼ø€ ”àDÞe`8yŸá0€~¹\Ö4 Z‹eÙš5Wÿûò‰ TK y`c]Mü'áÍR–¾kŸõ¨áŸ¹Óõm'ïßÁÀÊÀ`©ÊÎÇÀÜq];.3üj–~ §Ð$Ä‚èØ7¼õôÙ×Y‡÷ÝhŽI3cxùü;ÃA`X®YuýÍù ¯f³²1Ïãææ¿2è“ì#“V¯â–à6ÈŠ¶Ff1<¾ôŒaÃYpíØJØšd„×ËôuënD11þ×ܹóþ‡sç_-æ’ \ܬ·ÿÿ6ã™x~¿`&›mþWìlY6YH.“AÒÓ‹aí¢9 ¾3,&ºv\­b€BibwÓÛׯ¿‡·wœpFÉnn¶Û ñï ÉéM1ÿû q`Oùüù‹ÂšŠ…Å’B /Þ1ìZž‡¯c@,Äôߘ™]sffùú?šk‘yÀò®ñÍÃWb/¾R²s@5=>³ 1Aä±QBÈIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/no.png0000644000000000000000000000371611550446574021650 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<`IDATxÚbd ¤10ð) 6b(P|ˆÌb`øH¬™ÄH¤Åþ@*“‹+@M[›AVK‹AXNŽAXX˜áß?†·¯_3¼½qƒáñÝ» ·nßføþýû ú@‡l$d6@1°XHMPÓÕu°ôña°Šg`e`àà``øÿ‚AFù ‡ ÇæÍc8¾oí{÷E €¹ˆË€bÄcy='7wCX^ƒURƒ  Ãïß‹Ñ10$Puÿ>ñ9sVmØÀðýÇ#&b³ €qX>_FE%¡xþ|.EE†_¿–àÂØäþdøvð CïŒ O^¼EI"º]ÄŒÕrUÕ„âE‹¸$$¾}ƒ8hÃúûw RÂ_¿"0(:€b¬À(3áæf¸úè‘ê—/ gÑÒ@1£Yž´¼¢xî\.!!ˆá ad!²å Kñ9„?f`š¥”¿þù³Ú—/Î"¥ €bD²\ž‹‡çBõ¢E"ÀÎðç$A4ƒâÆFÆØÄÑÄþýýËðèЧ[¶0ôß¼ùèt`t<Ù @,HÐà" ÊZoß2002BÔüíãG†Ó¦1|gff°TWg°²°€X‚Œ-X³†á-//ƒ 0=„›˜ ä€füF£04€:ö104í‹Y @Œ0ßSüƒ ëÖ10\¾ IñÀx9âPÓôÉ“Â,`50`8¤víb°ÒׇJ@zÁÖ­ jEE V /\`8–’®¬ÌÀðîÃ_`ÙðãÙ3†Ÿ@u@ùˆ_00¨¯f`¸@à4` ô½Gx¸…:ëW Ÿ>10¼yÃÀðþ=ÃÒÕ«|gÏ[ ú1ÐQwì`©Æó‚mÛÔJKÁ–ƒ?0ñò›™1ì:H˜ÿÍù Í?Рþ įø<Ãv€‚EA€¹980¨aQð ȆY ‹Žéc½½ ·€Uko‡[ ßeeþ?|ÈðTV1ŒÖâ Á@ª €XÀÁÏÅ¥ ËÆIµ,@711ÁK8_II†•éé á3gbu„” ¾}øÀ0ÝÑ‘!ìɰÿ,Ñ"@ÌÉÀ L’²IATØ€‚9«A±,ƒÕóç +ÓÒ0 ,Å8-¿y“Ad9’±((:¹ €@0e;`"Áæ˜,0AZ£gej*ÞŠl¹“CØ; Ãþ£ð/FÆ0ð1Ðre€9@€‹“{Aƒ@5Vׯ3,@ó12[~ïØrP¶ÄææbV` ¼6e'tߣá½@ÃÕp:ÀXq=™²Tø`±9@ €@8pëÚ5ìÁ €åƒZ[Fœ£§ `u èˆÐl÷Í0>0€©î,@ðá¨&6\ŽXpõ*Ö¬Šs¬ŽÖ%G¡–!cdGü‚°ß¨±ðäñc†o ì‡l14¬&(µÎNì©ç+Am,Ž`Vå'Ð,‡Ñ@“Þñn` € žaÃ…/°úþ-0‡à²< ˜3¬€åÿÊÄD¬Ž¸ÊÏ  G #@­¥ÏwÀq`03ˆˆ`8ÀÔÄ•ÿè–Û²Àx–&6«%KV¢9”[t•°¶€c˜î@Šã] w¸.ÕÏ ïÞ%¨éé ˆ£T{ÁªRY`QüxÓ&†[Àv „†¤V. BT ýb^ zî‹vË* À°¥¡AtáBu$‹aŽx©ž-g`ȵ"¹=¯¦¤´ ˜¨ê ¢± Å€ ô0u;Ó Ør ¥à¬dÃ|öˆB‹ge¨…¿hÞ Ä7j710´ƒ’@¡´ Sù©¨Øú‹^pe„ÞðY mïýƒZü)hÑ}‹î ÏÎ|!ƒ/ùd'@¡4É;|÷.Uøß?Yh4ü‡µl@ $ÿÆc)6| ˆOƒØ‰þá‚@¡8˜8¾*CáúÿÿaBÿþ±K-YøKJþM¢åÀšóóu†ô+Xú³ €0ZÅÀ2ñ 0þ{‹'^ih³ —ð9ä$ÈAø&0ÞsŽØ 8 flE*ÈÀ¤¸XX\b`PbƒÖḀÍò›@|ˆï=ÌðPŸÿB· €õ ™½- åeÀôa ÊV*@, ­LÐËø§ ¤¹ tüY`®˜¶âëç¸, F";±<ÀÖ‹.°šM¶ÙÁÍHˆC€ÅÃ[¨"`Mrìg¾_ 9`ë–áÔ}8@ëä(Uå\ ìÁÀ`Ü.Ë@öƒ‹ùÏPš(`sáÿ­‚FIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/laptop_nocharge.png0000644000000000000000000000206511550446572024373 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÇIDATxÚbüÿÿ?Ã@€bb`@,ø$ëêf1üþý›áçÏï ?~àüñã»ò¯_ßݸ¹Ùløø¸•ÿýûÃõéÓ§_=ºÿäÉÃãŸ>}ØñùóÇÛ ÿ>ýøñ l¡ B.ü÷ïŸ<ÐtQQ+!!^mY&&f†?~ö•áÅ‹×Z/^ö>þlÙ½{7¯^¿~áô ³Ú¯2 €ñ¹°¶v–×QEEEI†·o?1ØÙ™€œÅðúõ°å_¿~gøöíçOßž?ÅÀÁÁÄpóæ5†½{·¼¾xñT>ÐËñ9 €ð†''{·‰‰º¢¡¡*;;+æMG.^¼Í À´ð+×/ß>þ¶üýûOÀùÁ   Â ,, /¯":uj[#м ¼‰PHˆO–••hÉWP@|÷êÕ;°Ï¿|ùÿvÄׯ G|``fþvèïß?ŽäcPQQ"„7˜™™þHJŠ3Ü¿ÿÏïdd¤———Æù†?þ€1È!àÄÄÈdÿó¿~ýÉp÷î3p(„× Ëÿüùô' Ê–€Áüˆÿ€å¾~ýôùpTÒˆÏÀÀÌ)„‹€"˜ nƒ¿ÿó*?~ü†Âo`Ѓ¢à˜þùóØA G³°03@†  ’KBƒ@–011‚}L'@Ìc„¹–@^Ѐ; €Ü4à w@ ¸hÀ@î€pЀ; €Ü4à w@1¨ù)1œ‘ˆê €˜4ÉAÕ-©Õ,H9++;Pÿ_‚! @x¼~ý~ííÛ@ S` ØàdÖý,𺳰°[LìÀ†+PÃå˧€Íó‹{ 9 €µ Ë8óññã§‘jj² ¼@K8 –ZI à–¨¥ôùó†—/_2;I .œzyìØîõ¿ÿj"ä€ÂÛ1©®ž F†Þ+ÿùóË™‰éŸ''›‹;]¼Àö Ó·o_ÿå¿<þìÕÓ§¾{÷êâ‡o÷üÿÿï*02€Íyüm3€bèÞ1@ x60Í1£'’¼£°IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/cut.png0000644000000000000000000000431511550446572022021 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<_IDATxÚbüÿÿ?Ã@€bb`@, ÂÐÌ ÌùÿëÃß?˜?f`gcc`ùþá‹€ ''ÿ ûýû7Ã÷ïßÅøùù“TTT¼^¾|ùïÇQÌÌÌϰ©?sæ @±PÓ7@ËÍmllæi2222äææ.:ê¶h: LqQ4 þj_¿~uHHHØ6wî\M]]]†}ûöý{òäÉCþþý Ç µ š‰ b5@ÿ†0â‘ÿôé“V@@Àâ²²2!÷îÝcصk׎m,,,ŽEDQ"ùîׯ_¬úúúý2 þf8|ø0ãGƒù7Lr°#€"Úÿ‰äd Jt@šŸŸïÆËË ¶˜èNŸ>ý(·¤æPÈa@‡b5 €ˆw4‘10Ñɺ»»×ÚÙÙ1<}ú”áçÏŸ ?f¸|ùòv`?Gö=.@Ä'B`¢A¶”„„„Ò“’’$>³-0€•^¼xñ×ÇW°²²‚}¢‘H(4€f€ã €Xˆõ=ÈÌ ” J@ ´TÉÛÛ;VQQ‘áùóç`ËÞ½{ÇpòäÉ‹@ßï…¥z˜cüø! 4E››[]BBÂUì@~@au#4åÿGæ-ÿ q9Ø@ AÞžžžr_¾|§£€AÏp÷îÝœœœÿ€ÑÁTktŒ©‚‚‚±¦¦¦¾œœœŒ††ȱÍÍÍS@f †Å@‹¾10ˆq~ù¢4øËFÆ+À°úòùŸ?˜88þþûÇnll¯®®Êÿ`rôèÑßÀRÐ hY °$4””cffIx6œ={öC`”MÙ @p€,þùïßÇ…>ñŽ’’*¯¾~ý;ÿÁƒUwYYÓ9XY¿€ÔýD‡§™™™1(ƒ|2øöíÛ @ËY>‹åh˃bûöaíÚµïNœ8‘ÁÎÎ~d@ÀÌŸß>~T·ýógE£‡‡ã‹ Œ0Ø02²˜ŠˆD¥¼zõ÷ KÜÏ?Dt>ž(*'iåàNx ƒAøüùó @_3€õöí[pšå{6`ò50q2ìܹs0½äÕÜ€y €Àøúå ¿ý¿󦄄Ú·ïwÕíÛ½À0cn÷®Ð™%†Ï¯êóçx?‘„NN‡‹–– €Á¾xÙ29yy`¢'DsssPÖ„:ïß¿g¸ÿ>ùsçNß¹sg0¤V}þýRÅ@`ðøZäåeÅŒã)mx*)YÉ Æå?~8:¿zeâÆÁÁÿMAaA´ÃY OTœ~Õ¾:"¢¢ ¤¥¥€†ƒ* €?&ȽÀÔ¾hñn ƒþb+ ìc66o  OÞƒý;+ë#v BP)ÆÂò† "@‹Ò¾¼pð à %%MM Cbb~}<æLϿܺuëöëׯOã|0î/ô¹.À,ËÇÈ(*h„€)VŸƒÃçÊÍ›‹yyuÜ%$Œ€ÅóÇ ÎûÛ+!Ññ„‘ñ‘øÆSlLLXr—oÜ`¸uçÎÜ/Ÿ>•³Ü{`ðþ…#´¼ Ôâ °N|ÿ¾áöÅ‹Zªúú eNNêJwï”beeóûø‘ýÓµk Ó99_/+úÂó„÷Í›,‰ ˜döícxyëÑOŸž|““›ÂÎÉùŽZî“\¿ên>|øàó“'D€†dHJ ø}úÄuéÒ%†aáÝ3ÕÔ,¿-ç{ó¦¸MGgª‡½=ó E­?Ù)"âÄöÿÿx™Ob €À!ÀÃËûáô·o‘ñ§N9ppD ýþ-rçׯk‡„„fâç_ÌÄÈø™çÍ›Òv3³OPó ˜²wm?3ßíÀ.Ä€i‡Ôú €AqddaÁðïÍp{‘‰‰ç??Çׯo89ý¦ ö/J€–w{::2+z`½`&u†ãׯ34²².{"+›ÎÊÄôÅ÷@6#04ÿBªl”¦(‚ZD Ü@(I” ¤€…å 0¿|aáâbø LÁl¯^Å6w{z{3|6"ž:®,ùù,yxz>ŒÊag¿öRP°•µ((t@Ù©nAÄ‚ÖÀƒ¸ÄV£?¾)ôõ÷gø}ó&CÙ¦Mç¶²°Ô“ù7Û7oª'óò:ëÕ|ùâ´¡ƒëß¿¿¸‚ú°.øÌ PÇÀÚ™„Ü`cø Tð˜ïA®¥eÖoß´-µ´ A©û.07feÂ$,¼ŒÇ^¿æ½ÆÍílTÿ……åÃ?V ÿñ4ÝÑË*[@!ò(ÔvÀ à?`‚âœAP1c‡Àz^(ïõ÷oц¯_ÿügaùæÂÆVd ,võœáç_ýX0}'¢ïÀˆ–K쀠`& f&D¦|†ï\\WÝ¿ÆOEÅ„èë99 û÷ýZläßVFÝ¢¢ €uð 6ÁXŠZB €˜`í6 çäâú´õëׯé»wÿú ¬XØ!e L–Àêõ0TòDE—s@6ýD` p6405ÅéBPªúÿé“‹þ·oúÿÿk°}ýÊz‹‰éÑ)nîÕ?„„°°³ÿb$³ƒ{˜£ˆq {Ç4à½c€³¥ëÐtHIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/mix_unknown.png0000644000000000000000000000274711550446574023613 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<yIDATxÚbüÿÿ?Ã@€b„ÒÖ@Ä6@,Äx3OâD™$ÀÔ-ÉÀðÈþ 4–‰™áþ åƒ03PÍ?&†ßÿ€‚¬@ÌÄ@,PíU@ìÄ×ø#[B±'0@Œ¥  &(Ý ÄV@¬Ä:@ Ä_¡¡âFË( ˜ñq þ å¯â=P¶&Q&Érƒ—t9n(ýŒ )‚ Ê|Àx&=A.± _âÝxM0``Pºõ×?rb€ €°9@ˆ» ì6 ~‰S»)?ƒ"Ôr|ÿï?#Ã÷o‘ ÿÿ¯ tó ÃT V…:b)NC,A®ÄE¢ÏwbcdÜìlg¿Lˆ—O €ÐÄþ@|ˆqšcÁ´œ“xËAó㧠×ϋµ45·­2Å{N}ƒ'Ç€bARbBÙý@ü k±e ´\–X2ü#†¡àï_)†ï¿ó¥S bããÝýD¹Eî?{Êð÷ß_€Bv0L¤@n…H˜ÀäòÀXúúRÒá+`ÿüåføò3OD45=#R1Î;€ACH‘áÃ`nýO1„ì÷ñ= þ‚a&?зÀâó÷¤[ÁÎÈÆðóoGW˜‡n~l,ƒ®„:ÐÒ ï> `6N „€BvÈçÅØK É.œ$ú ‡Å wýúgÇð±žM—Á!/6’)Ç*lñ ÅlPˆît€Bv¨vˆb ž Äo¥3Ä¿p„ø¯ÿºÀJ§W‰=Fž›•U냌’00 ÿ+‘ß  ìXÜÌ&ÙF@<);6‹*C6%˜!ÿç¿<ÃÏÿyÜRœ)²¶ü|¢&\ Ù€Aýñ ïŸ ëÿa,ØŸ¿þþùó €ÐÓ(îÉœá5X„¨”ŸRÄ21"÷^†oRØy9Ê=EÄe­ù˜xYüëo†?ßÿ1ÓÄ;ÙW€8ÚX±ÆŠ"0ø¿@ëu†ÿ, ?þF3±±æ*[‹+Û‰0pK²1|ýö›á×W`Ê:”WÅ(’ *ˆ…H~†»ÁAΔ²ºM Hùñ÷Ï¿6 ,L-2ú"v†^r ‚À"ø'0˜¿,þ)äÈÄ®v.13Ô @ƒŒ€œ_Œ|ñç01V‹«‹ø›z(rHk :ÿ¾}ýçï?H¡ U@, üÐzï4‚AM§ï LùW˜€k„¤#­ÜÕù” Äiâ0žÿþÇ@-@,`‹¿#ùâÏ!`Käà.1uT—0µWb`ãfeøòí'ÃïÀtýÿ?#Õìg ”¶ÁïÿQìllÕ^ê¶®š ‚¢< _~ýdøþã°äed`adbøÏôŸá/ÿbfþ¢|F`à120ýƒ`V`þg¦Ý¿ÀR€ \‚ ;8‡33#8! 8Ïÿgðâb%uq;7}eE †ï3¼|ù‘á÷ŸÀî/Ão`|ÿþÄÿB1P,ãÿ§ °Z`™ñá͆çÿߓР¥ ¬ÿYÁŽÑ\ìÜ ÏÞ¾™Ç @Œ Yàâ·ªÿ„x¿²1±Û ¿€YŠ Ü„þô °ýð˜6þƒšÔÿ!bÌN3`ö(ˆn`àeäfàdÖš@9F°83˜fêg²ÿüedöîã%€bèŽ @11 0 w@ ¸hÀ@î€pY;¯Òɰ#IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/bookmark.png0000644000000000000000000000411611550446572023032 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<àIDATxÚbüÿÿ?Ã@€bb`@î€bÌÖÕ3~1333ÃFFæýÅÈèúï÷oŽ?L8~ÿ–gddäøÍÂòö ÇÍ/ŒŒ'.=~¼õÿß¿glååùY88Ü~ýýëÊùý»ûÏŸrLÿþ±ýdbzó…•õæW–Wž=ÛòâÓ§ ßÿüÁˆo€Bu Ã7†Àß¾•«üúen,*Ê "&ÆÀÅÉÉÀô÷/Ãï·oÞÞ¿ÏpñÛ7†‹¢¢ïî³±íåÿÿ_Vëí[ “_¿de8¤¤êÿùÃðòý{† /^0\ýóçýM†õ—^¼h{ùåË]dÂŒŒl?ÿÿo‘ùò¥Ô(fÅÀhiÉÀÀËËÀÀÎÎÀðïà @Ö®ex»x1áW¯™˜ ÜÜ €–3°²20Ìðý;ÃÝ» ¯€ê·íØÁ°ççχÇ߿Ͼ÷öíV˜â`°þóg¶Ñß¿)ñII !! \\ _¿B,†å :°á<< ·n10ÌžÍÀ`f ³@„… õðÆq<ÿ?{–áH?ÃÂÛ·ßïùð!åá‡ë@Jˆ1SCƒß©ê?~ÌÊÎÈ`à e`øø‘„xÈ`66ˆã€Q‚b12ɃÎÇÇÀðìÃáª*†)Ož<ØôüyÈ?γ©ˆˆÛ·o³3lm…„#"Þ¼ø§x1ÈÒÏŸ¾|a`øù»šß¿©:B^ZšáãéÓÿýãyþíÛ~€bùý÷o¨9+«²Œƒ0‘‚4 `ÑÅÁŽ‚?0|¿x‘áûÇ ?ß½c¦`hâáq½õრ@±°³š™ˆ$HA ¤d„¥Pv>žáëÎ _Ïcøñé(B‚’0§É 2hòñ‰nce5 ž?tùA–ùZ Nl1|¦øoG2ü&Ì¿ )PÀ@éo@Gþ:Bh#£$@±°þÿÏËŠ/PÂCBR| JŒ@ü>xáçáà ¿A驨ýu(bÿÌF PÓÿÿÜÄò—‰éßOŸøÀ‰o¸R36ô Èçÿ€qü Ü^¿ûø?3 Yc³€B èàÏ@{€á€bùúïßÕ÷ß¿ËIÝ»ÇÀ ¤I½ÄøÜ@ ?Îðûòe »!‡YâýEsˆÏ ÔÇtÀ`.úû÷ïg€byöãÇžó\\žÚ7oBBTÈ€²zN€È×ÿ%â¯Û·~ØPa…fÉ?,| Œsaa†;@öµ?>~ýû÷@1þû÷™$;»Ÿ*“ 0_ÿH!¸ØEÏÏ@ö/`H}9tˆáç ÀÊ n ºå‘ø u°^áÖ/€ö¬ÿøñÒ³_¿Vó§¿?2ã‚™ÙS˜…Ø€yõÐr6PÂ+0%ÿúòÇ“' Ïœaø|íÃ_PŽÁãSdËAƒ"Uh±¸œÃ! å+Þ½{¿ÿË—•@áíÄ2èÄׯÓE™˜,€VF…ò}¦äï@‹þéŸ>0üÆ4+ýÃÒø‡÷0 ²ø?0Údµ¤€¤$à  ç–¿yós×—/»€RÛ€ø)@1C5ÿ»ÿû÷ÁÏ¿‹~þñÃP„››AXb}xþœáåË—à †¥tKÐ} ó9¨Ða𡤩ÉÀ&$İh֒ׯ?¯ýòeëûÿ–¥Ü@Ì0ãéû½?v¿úýûÛ§¯_ÍxXYÙµ€¹‚˜j?BZ>`ó)z܃|δT XÓ¾†Àr`bñÛ·O7ÿ¾úËÿÿóÒG€ÄŒ’¿_üûwìÙß¿·¿ýjþÿ÷o~~`Ñù|?ÿþÅëˆßP, Œk)mm†[À"xé; Ë?}ºvø÷ï%@O‚|~@`@ÌØª“ÿÿ_»ó÷ï±O_¾¨~ÿøQAròò ߀éá30-`‹‰ÌÀÐRúš¨ö0°òYtïÞ÷¥ß¾¼úïß" žU@%7¡Êá €˜q•5ÀLøôö¿»iBàëÛ·büüŒ*êê ÿí„wÀ(ù”úA–óðó3h'-¨ÍW®0,yòäýê?6½üÿ.4Á½Àf@1ã+ð€Ný|ïÿÿ}ïýúòíåK .&&6M OßKA`œÇÅedÔ-,€õ;Ãj`V]ööíƒmÿÿ¯¶Bãû .;ˆ™ˆÿ×3†ã7ÿÿ¿úëÍÃÿŸ>‰¨CBذ%NE [ìm¿¥.üYðãǩ㠋€!Êç åN@ÌÄ63€^¸ŒÀÃ??Vþùò¥²0¡©èé1°ƒ|/°½·ìöí¯KÿýÛ ¬QæÕ¯âHõN@$#`ËAÊØÆÁñ諭þÿµ¢¢ÿÞk` •Á ”I1 €Èm{qê10¤«20Ä>¦ÁS ;^Ý ¿D(ÈÑ@QÐøcãŠ@,*Rø z#ã@÷ŽhÀ;§e€»72{IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/view_icon.png0000644000000000000000000000414711550446574023215 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ùIDATxÚbüÿÿ?Ã@€bb`@, ‚‘19‡‹©Žƒ‰ûßÿÿAbà€a1Àˆ&†^ÿÐäaúå1ô12þýóáÏÏ¿“þÿŸ×@Œ (àãM{ÚØ/Å+/ÅðõÛ†¿ÿ€jþuý:çˆþÅPö¨²Zý™”2Á4H=HŽ…‘áÃÓ× æÎ{õëë q€‡7+—„Ž2Ãq öoCY bù‹0æ˜å‘,ÿ‹„Ajƒèÿ¨jÿmüÍ!ÈÀÄÎÁ ² €Àø÷éï—/Ù?AÂdà$_ü…5Îþ`ÿErä(ýês˜<3а¿f3Œe H`bbøõ‡‘aåš ß?~g``‚Å#(Êâû?J$ÿGŽh$=LŒ¨)è Hø3ƒ´,ØN ˆf†_ÿ28K}`(Ì•ºô?Ø.F°¥Œ@ Ì@sþ2üýþ’8qe+vv°ÙAÊ€ ™þüøÁJkl¬Œ w¿dXrý7Ð_Ì`õÄq#Ão`*áaPU†ö°½…áýµË ÿ9¾¼}Æ íÇ Ÿ‚7[½Ûº‰áá œ ?¾¼b`‘Pe0éž v#ÐIñŸ ®€\ €‚8€‘ ’JÿþC0?œ>Á ûƒMæÃëwn`PÂâXaÆŒ®×‡O3H¼`uü î§ ‡Z®3¼{ÜÈÀ!)ÄÀÍö˜¦€¡øŸD0xÿþcDÍä@÷rsüfàø|Žé+ +';šÅðû+€¾dgcaàüq•åÐ!NNhùð^¸€æ&H4Á!À‚j?Ó§w ?®¼g`yÇÂðóÕ¦o?Ñý§a¡Àôë;ÃßGŸ~óÓ ÿ†×‹ÁeÄ¥@ 7@A Ž¿@Adc…ÛÜ‹áÝ5†ÿïY¾~ý V7LŸƒ %Z ÉejÆðù¶;×ëÌ ?ÿþaàÖVd`áçdøû˜õX!Ù \@s @A£€ œïÙÑü'^Ûˆ#©!ûQÔþûù›Ç?€A8(ì˜Àœð(ùãÛW†þÕËp00C¬ h0B\…V1¾}÷aýú-@ ÿ¸¸8ü½x¸¹P}Õ¢@‰ðϯŸ Ë7ídxûöØU¶¶– ÊŠ ß¡ñ õÿ )¬ € å 0 02 WÌ_>f8tðX#??ƒ‡›#ØÈ>‡”¤‡0ãí0•_<†áÑ£Çàt¤¡®Ä ¢¬6ãß?ˆpfc„ä€BJ˜-//˰hÑ1ˆ/`YXqýýO„¿ýf`âàb¨–ÿþ@‚ú?Pý7 G`Ž„äF° @püùÇÈ€–ÍËðîò5†ÿìÌ ß?`òðaPðóeøýû< ‰”ˆØÞ8Àðb톿œl ?¾b`•–cPJËVJx»š %þG.bü·›Ö0H»³¡ä;†7wî1<\ÿ‘AÎÏ%þ‘iF&†÷;÷0sb´ÖùŒÏNÏbcøæËÀ&ÆÎ)àÄú^_¼$eCd€\ÌÍÍÈ *öˆQ†‘™‰—áý6pB¶ÂþŽF`ªgcaa|Á T(ÈÅÀ'È ŒŽÐ4À޾`» Q@`fW@ L¨Ë·· ¿o¿b`ýÆÎð÷å&P5 -zQ}õ¨0üóƒñÑK†ÿ7€õ® °ô/´ÿCì€&B&h" üG-ŠAi„UNáù7 | Ÿ€Õ4¯³4>G„Ä?pãUI™áÍE†·ÏX~2k=^5&^†¿¿€Ù˜–Àêÿ3À«c€‚F3R=7Tºg:ÓÃ@Ùë7Ão6 ë¿ÿ„'>˜ï!©È¦vŽàp&ï` zF ƒ¸Y€¹qà’VßüGÔ†„šþÃÀL$¾|g8~â,8ÙXÙLõ• ;¨ÝŠ…ÿð<bÿúäܵ+ Ÿ?~›§¢¬Ì "$Èðh, ²!@¡$BX°0S(#çï–/^Î> ‚HOS…‡‹áçÏ¿ ‰V:K7P‹wßÎm OŸ>›à )&Âðè Pã†Ü,BD¾ù,ý¾3ü†–J<<‚ m­mð¤ÁÊÊÉðñÃWˆo $Aþƒ¦nHyžžtô_°<;°lø ~`Bgâ_?5êNx¬.`âåeg8!¢÷>Ø1à¦ÐoÌÀJRÙƒ÷ÏGHÁ•Ç=#ÔÐÁz aô˜+þ‚KOPVþÎðâ30§ðkGFHe@`üþÇøçÝ›· Üò ï¾ü§Rx«øR —Ñ,‡7·ÿCBÞ2ñ#šêÿ‘ZÒÿÁý&`v~OðvÀ¯ m<˜Ì› ïþûTÀÂÿ?–ʃÿ¿<Ô8Æ ìðïÏB@1tç €¼s @î€ÞˆmúìT0wIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/viewmag-.png0000644000000000000000000000543711550446574022752 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ±IDATxÚbüÿÿ?Ã@€b~~~p&&&†¿ÿ2°²²‚ha íÊËËg/,,l À¯ÀÀðŸùÝ»÷/ž>{véÕËW'>~ü°¨îî¯_¿¾|ùÂðýûw†ß¿eùLj›ÈŒŒŒÉ**ʹ6Öæú òr@±1|ÿõhø†ÿˆþþù]÷å«WÑ|òÔ™•¿~}éj}Cj#( CàÏŸ?‚¼||}~>^ ¶Öf ÷_°1\¼÷áÍGF†ÏߘþüûÇÀÌðõÿG¡ Zr¿ž={°dÙê³—/_Nê?KJŠ€…ÅÄÄÖf¤%ÚKʨ2¬>ÄÀðî?ƒ™.7ƒ²4#?7(Ž€¿20ÿâ_ Ÿ¾ùŸ¡ÄÂü ¡ÁŠ ï.ÜüÈœ£ÄÇÇ_ûãÇ&`t0àà @`S0¿²’R±›‹=Ûœ ,BÜ ¢ o|Fç?úÐò¯ d†Ä þ tÌ_ ¼¹­,Ãíߺ@°0ØÛÛ&ýüùSªø0ØŒLLÎöÖ?„nâbÆÏwˆÅßAÿà¯P‡€Å 4Ø@G¢\ÙÔŒáò& S#`ÖMùò0Ñâ @`ðóñ;i©«3<ÿÊÅÀÈÅÄðû/Är°`¾GÆP‡}ÿäH ƒe$™þ ë0°sp2())8-á$ä€;@DTÄ@DD„áÃ/nN`”üAXÆ¿–‡: Ùq¿f±“³ P¯°”,Pƒ¢‚œ4ÐhMB p.àçWdbagøf58@A t"0x™¡¹ê?8ÑBrÈ 87+ó°=#ÌÁðñ!ƒÐ9 b„r@ÀÌÌÌþ÷0ùmáôhÐg?Qñ ˆR` s(ØX˜!˜ˆÙ˜!à:€—‹‘áÝÿ Dr23!Øß¾ó÷Ï/a`þþ 2¨õP+;ÐrPz…È?¤: ",L°ÁÀ ‰¿À afü¬@a,2 €;àÍ›7Wß¿{«Î/¦Àðù'Ð vfˆïAñûÜÈE +Èr¨C`úöùó߯ OŸ=ÿTz‹ì€÷ïÞ~ôèqŠ˜ÃÛü ‚Ì ØA>úqr­ÍuÌ!LL€röë—Ø}c¸wÿáe ÷)¡" €À¹Xhl;éòGæo¯€ÅÈ?H€úœ@g‚BŽY ©„Y™ ˜ X\ßüžáß›; Ïž¿`xþêåJ`åÍŒƒ@C€……åÒ… ×›%Èiñ2¼ù)Á ΕÿЄ&aU("*@¹”?üúÇpùð`ê]wüä%öÿÿ—Ç-ùªa!U Ø,d Ë _¿~mÙ½÷€g„ 83ÃÇ_¢ À¬v!ÑwÈÌG0ƒ|4á}tß!îoî³áßcCãiæ&¬|"R Œ|’ ü¢ œœlÀ8‡ÄÁo`"ù ,{Ý»Áðôæ%†ÿ_Þ2|òU´´ŒŒ~>ÎÀ{/Ã÷9‹?>Û3ܱ9 h'@Cà ×3p,±ÿå`ÿ.6çòùË_¿yÝ¢©¡n&-%ÉÀÆÅ k.†À°µ¾ûÂðíÆoßï®\»qÿâÕ«‡\ÌÌB9þ3r)j™1ð:1HÙÝáÿûyɳÏ’¬Â– ŒŸ1Ëpɯb \ ¼ ºß4„˜ÙXÂD…EãÄDDLxyyXYáþ÷ß_`]ÏðþÃG†'ÏŸ_öøÉê—?.ýüñ~æËgÛõv.ôøÀËÃ`È·“ï 0G 2\ÝóåÉ¡§À„¸=â€46ˆs€†Cš=Ì lÙþƒZú¯ƒ £‚ “93›Äÿÿ¿ýøñáç÷g¯ÿ|zSì;7Ã`i5áôUv†ušA2.@ãï\V," Æ ¿¾³1œ Øýñé™—@v ; €Pð÷7ïÿ1 L," äÀð˜Êþ1ý&?@Þo`ŠCë?0çÿ¦ÿ?Ì ?]aààÝœ|ãC㦚¹1DÉÚó±8Ð  z2 ?°3œ ß÷öÑñçÑ@/î„9 € HYôŸQˆGxB{p{ž…¢%°ôû¯úþÿgD”Åÿ!Ò`»˜Ã—î_÷gÊš9)YYÖœ{Å`þê°·Ìʇ%PÁX!Š‚! y`H°2öÛýáÁ™—!@#ö‚@¤0‚„ÃÍØóáÎümb®®gøøX¦ w&FH™ËÂ@6¸ Ò¿þÿbÐÑbaTd°ÈðØpÿÞ ƒ¯Œÿ+o|Vëÿùÿ³0,²óbñS´‚:Bß?³0ìÚóúÉù×Qiÿÿï äŽ #3ØŸù› ½ÄÀÈÁÈÀ,m˜X!T`h`ÉÉðá߆lÃ,†ZÍ&`‘ÍΛ„¸îëg…o>~þþgëŸ%Π߃•,ß@BªœÀp\ç&ºÃgû ˆ@1!9àÿhG‘•™\“3Ê6°ƒÄXY -jp0B¢i¶(Û ?€íÅ´íÛþìºw ˜öß¼c`x,š.?aàúËÀ-Ë-² €Pºf@‚ùBœBÀ¢ø#;;;"€Õ(JÕ fýÇ lñ‚CØŸdW—@>çafØ'ÈÊ`öþ7¨ô{lÒ…nÚü{7÷@U+ ~†ûSÞ2\?ø|³Ð.€bׯLÿ¿ùôúýŸD÷gî¶~‹\Fp¹ ¯R!1¨úlõð3 0\º‹áí`‰Ä¬8XX~M<,Åàóé#°ä' #’7nùÍíð…Áí'ÓS†¿ïøýã_-ÈH€‚fCpjga`r×ñìÖ’Ôúÿñ/$Þ ±¢ÿ² {Ñþ1ï;ìÊÅës€–_„WÀz¼åÐQ Íß•¥¿kî­À¤ùµh'@€HÛÑî¯ÜïIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/window_new.png0000644000000000000000000000404511550446574023410 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<·IDATxÚbüÿÿ?Ã@€bb`@, ‚‘1)‹‡‹¹’ƒ‰"ÿÀa$þ31Rý‡Š1@ÅàêBu ˜j L¦ßßþ\ªIÚ| €AQ ÀŸþ¦eB¢0¿¼$÷oÿþüc`ø Ä€ªÿþb ‹ƒØ!Ä©û UÎÿƒ¬jÖV†««w2<;y¤‘½ €À!ÀÍÅÆÆ¯ªÌðK\”áßw Há?¨óal fò|&7€üÿ!¾eŠäÀj `‚:€Èfâ ÌÎÀÀ.. }&&€;àß?¦¿_¾þfxø”áˈ… ÿ >ÂFÿƒZv#Ô"° HjÿBi˜ææ9¤ è,&f€‚¤&F†¿–ozÈðçó`<3¢$xü2bdÀ® ø ŒA%iFffˆa@ØÿY>|ùËà¯òž!ÃGìblvR@~úúõCÖ²W ÏÿÀÄ@Ä L ¿€©DL„—AKU„Š™ š? YéÛ×_ ̬¯@É ì{P ˆó˜€‚Œ ¿ÿü%Ϩ ú0¢A42D3òõû/†àà…?0*@—üýKŽÅ_Âhˆ…q”ø ü“ 03=@ÆÅßÿäY jˆE°PøÇÉ]ÿà|FX.”Áv‚0@AC€˜u!¥E>ÿ„QqÔ1ÿa!‰€B¤ÿäúa!Âçÿ‘¢‚aÞ‡8€ œAö< €ŠK&Jâü ó9Äò¿À’‰Xºýƒ9¤”€ €˜ å() vˆäZÊÁÉðŸXô±²£øREñ=ÄÏÀ4ðçîR »å¨Ù ,ŒÛà`²™Y^lZÍð 9‹áóÕk ÿYXEü?`vgbøÇÍ@{ˆ  ¸a$Éräàþ IT,Àš†•“‰ƒáÓ' _v53(›fx¿f"Ð|`5tÄ÷ _8êYÀé €˜i€78,G-dPÁ4øË³ç §k’.w–3üù4ïûw1.~;svÎ Y9~Þ}ÌPz5Ÿ!úÑ 8Á h@sÁÜ>GXˆì˜`># íeÓTìä4Þ2\«Idøýè0`4üÿù“‡áãÙ› _ç&2dÍ;Í05n+ƒÜÇWÀÐâf &”\@Ðç0K‘S9Ô̧nÂðâÔ™°DeËß ·›sþü¦ NN†Ïî0üX˜Ê V©÷ífxÅ-ö8@As#Z ûü?Jñ ²‚ÿƒËvÔB‚•.6V2H†Å2è‡q3°þz TÃÉÀÏ~‘A·‰M˜‡aU¾Cü›†Ü¿ô>d Ô’V^#%8dKQ‹WHËÌÆÁðòÒu†Oo0°‰Š3Ü^'Âð+£Á´/‡áßky`\30hö»1üúô…áœÿ5†9ÏJdø?3X?ܦÐúç'@±À³áä$€°9DP‹Úÿ ,À|þøÈ†ç{šÄT”˜ßýdÐõæûO² _c`V7ê}ÖÿçÆÑ†E¼³Ø¿‹–È×3„¹ˆžd†æC&`%ÁÈ€šÚ¡ŽåUHlýæ$f†O÷¯3H¨r2¨xE2üÿõ hðW ºoÀBèPÕOˆÀlʦ$È ©ÌÆÀÂòh0Û™_Žq™ , ü–„Ÿ>ý`xýhÀßp‹A$ ¾ÿH邨Žs `¸ºàÃÍúI Ì| ?î=ezŒÁqi:P04~ÿ¦vF†¯ç^2\.½Ï°GÈè€? Roo\¶½s® €`i€‰—Ÿƒá솈É/áU+¸1ü¹e;ô?´Ô;Ø´bb/dø. š'Ïrd2xO-6}ùÞ-YÆ ànÂðõàQþ-7_¦NVfX!ÆÀðöÄFñC;쀟ÿý}óü °àaøöý7f+ø*ÿ/¬ÅË‘ûý‹™áÿ— ™+úÝصÕ¶8å1*3X±0ìm~Á ÿäƒb<öE ì wò¸ýßÂïÏ@`üþû¿äèÆ½™À#Ž*Y¥È÷ž¸þ8¾\&S³AK˜UÓ’aMXáëÒcÞïçë_UbdüÎrŽGëã„&…GË8ŽkKeˆ1µ?8ÄÀÒýêàk~ €‚¶çYôûPׂ‘o³Å…À(aü÷û¯è§7N×Vïžû¥cùëÍkùÂ…ÅÙÿHþ}³™GÂðσS¸¼rnŒuxÿ³åÓ‰o·rÞï8Åòž €XŒúÀÀHF#X¥ þyÅ`óéôê- §¸€}M†Oo­_ÎTøÁ¨ÆÌs _ŸþoxÚõú/Ãÿ¾«U6«¥·l ŸAÚˆ…š=]`™óT´J0|aøÃÀðâÁ¶‡›¾¬r{qÿïv)†7 |л‹ìM€Ó§—œ§±ÇIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/cancel.png0000644000000000000000000000465611550446572022463 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< @IDATxÚbüÿÿ?Ã@€bb`@,0F£¼<Ãß?€¡ÂÅÈÄTÃ' ðýóçcý**üÀ -¦ÿ@®f²™¡lôPòfp322¶òððøûüùP_ #ã{°~ Nùò¬ €XÐ]ôïß?¦ÌÌÝÚÚY&?2ÜâãÓÜùä‰Ä¿_¿â€–½#ÆWÿþÿg:i²µ®n¢†Œ ýoߎîßÏ÷÷÷ï8&fæ¯Èj% þýýËô›‘±ÇV_?ËèB>`¨˜üøÁà&*êÍÈÂ2ÿïÿÿ|DXÎú÷ß¿ÉæJJ‰F’’ Üzz †JJ V®®A@ñY@Gp€Bˆ jÿ¹ÿ±°L±·´,t}ÿžá¿»;ËŠ ÿŠŠ Þ¾eðôcae]ýAå|@ŸÏµ’—O5føÈÀZZÊðÏÅ…ÁPQ‘Á&$$ЉiÙ¿?Ä`zî ÁÕö¶¶™^@Ÿ³8:2000†×¯!z¿}c`øû—áÿéÓ`ÝzèÓýûg`ö<üûñ£tÇáÃb VV>æ«V1üZÎâãÃÀðšhq£†á÷o¥æf6ÏýììÿüÿÿÍöß?7`ÖbZÎò9Èr  88þ^¼ÈÀtáà‡–,9õ÷Û·˜½Ä+ ›¤¥þýþ-ÌÄÆ¶ÐËÌÌÛäΆ?ÞÞ ,žžG€ … çýû¾wu1<úì33ƒP?{f&ƒ ¯/D-ÈLZvv†?÷ï30?Ïð˜›ö¯^}êÏ·o¡,ìì’  ”lÈÄÄô–áǘÝgÎl¿$'ÇÀ¸q#ï͛!†‚Txã“ÏÒ’˜H%€ÉCŠ51‘A˜ÒÞ¼¨ûï«Wþ9Âðׯ?÷çë×06¶GÈ@¡„HØEþH²rr.pQSsÓ&FF`°²YYÊ„︸>:Ä4”Aç09úü×ãÇ ÏœaxLS‡8ÿëóçp ÏoÃ,O9«˜AEéŸ?|L¬¬‹]””ütž?gøô!'È 0G°±Ar Ìrhœÿ|ôˆáϹs Ïýb8tüøI`z ;²Ïa x"üDƒ03Ó'`ñ›xàÞ½¥l²²JÛ·3|Èel ±š0ë ƒ~ܼÉð ˜âßÓÌá Nÿýù3=Ø‘@ÁÀªˆ Š@ ¸°df~¬ˆ"÷>|¸é¨¨­Â®] ŒÀP⯠@ÇÀ …01þ¼wáÛ‰ o€f»sçÒŸ?ü×s|E7@¦Ê%@¢ÐȪ÷¿N¯dtÑDж3ÄWäñ`CBŽCß?¯–ˆõ;¢»™LœàÞZÚ‚PÞ=Õ>@å@õ†®<µJ¸_:ÆYO¤’’•uý–‚§ ‚‚( ®Õ˜˜¦Û*+'j½zÅðöáC†ß 4 r0¡ë°C™@˜X€E03 II1€¼}ôôé­ŒÀèÌwèƒÚ @8$Àj™XÈL6WWOÔVËŸ€–ÿ‡––ˆ¿€9à70ÛËFPbbý XyÉË Kkko þ?<µ(@1á°œèó¹ÖFF©ÆÀ<üéÖ-Ë‘0(î• ¬Š‹ñùÅ E`¨Zº»û1³±á¬EÃÿÿýcùÇÄ4ÙÖÒ2ÖXv»r…=ý‚,ù Ä *QRa#¾ë%`µlèÌÒsÿA´ €bB³œìÓ¬lmãL€Õï·³gQ|`Ëñÿ˜ç¿³ž00þÁrÜ@PÍW`ÔÉCÂ,4Ô˜h—ÍBV@È `Slª…›[ª0ο³Ó_lѲhñ/`cbº|”áÔG o…bØBEßîÞeP‘`0‰õÖ5 GHÀ¤ˆ )ÈZ¬ÝÝ“l–ÿ±ÿ°ø$Æ´ø ÐG‡ÿ>ýóÿ/ ˜ëñïß·¼†€ 0kþý‡æ hHü¼}›AØÄ3MO÷dâäìƒIÜÜbb>z|ÀĺgVŸƒ¢‚(ÿYT”áȧO§~ýýÌ^O€|†^Âé·o·¾R‚@5À¨ÄH7ÿ!ñX9)$**ö0q€‚;àû«W{oªH[[¬>ç&¦ÏÀî‘·oÏýúó' ØÄ~„ð$ã[`Ή9ûäÉö·ÀRØòù@qfUU†GÀÒòãýû§aÂwÓß¿µG¶o_Xˆ°™™1 §N^`ü½••e8ðôéùŸ?F°21=ÄHÍLL€ýŠä“7oîz, ù€·!@°œ`¶Œ£÷äìÙÇþ|ùR Ó@ˆ4ÀÌüŠñׯ¨#[¶,»t'°ÒIò}ý¨ùàÝ»'~ÿlŠÝÆY¨01=:"ôÌ¥K›žCäp`qÌÀ l?fé³gïûûéS°Ô¸ Ó@(Ù™•õËÿÿi'öí[wUD„ÃÆ†á0áºzõôP­ÆÌü#m€ê¤ZX,FGâ…3gv<ZÊ ö§ÀÒòìêÕGX,Ðò—Èú^LÆ¬ÒÆ— Р^II§oÞ\6£r-áÇØ|Í ­á5(”š"ÂÄÂ2I@RÒúÓ«Wg€(úöL_(Ô^€bèÞ1@ xï ÀïÒþŸ\W IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/ledred.png0000644000000000000000000000373311550446572022470 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<mIDATxÚbüÿÿ?Ã@€bb`@,0F ##Š3T$úˆAh- íüAï'ƒ:PH¤†¯êo³10\úhPìã ÚùÐ b\ Tê´8 ˆ­¸…•$ x„…™˜¾~ø òüâEË{·o3|ø÷ï3PËi c¦³†Ù„×@ß‹þe`èüÍÀ¨(-Í`æãàà  £ÃÀ €ªøëW†Ïׯ3\\µŠ÷àÚµN×îÝs:`=+C!ÐqÙ@Œ°Dˆ@—é-^ÀÏÌlàÎ`˜›ËÀ¦¡ÁÀÀÎtP- ƒÀ_ 3ÿ#dþ{÷.Ù™3–ÎËðòׯ\ É@Uû°E@ár€ÐòÝò<<qee "~~ œœ˹¸ l66Tüêøþ ?‚Ùd˜ÑÔÄpþÍ›¯@]@•»Ñ@ð\ðŠÿƒ¨}±/¯DRj*ƒˆ‰ Û7 _¾Sâ/ˆOA–aÃ0¹oÀdúª*C0äŒÅĸ"ó€Æ+£G@ÁðŠÚ»y ÂôõÔÔ –ÿøÁ "³A0ˆ ÃÈòoß2pIJ2¤ZZ2H31É7 h²ˆ )¥ƒ°+S¼-0¨Ùß¿g`øøb(XA™MÃ÷é#Ð,OVVfff' 'c‘@ȹ€èû0|9w”@6ƒBÆYâ#‹¡«êý~å Ã/˜7zŽ™‰Éh— ÌR€bAŠW^66!9 Âÿ@]ÉðñØ1`aê¥I`°øåP.`bB„(ñB”XAîßgø°?+ÐLP—†’8//ëËÝ %&@± å}Y e|@@£XAy¨áÖ- ü@ß°B,9ü €¢9ÂäAÿûÒ%†Àlr$q3på”EEž|ü¨³ €C@Mh(+0ÎþC%@˜è«ï{÷2üÆ#«¦&“¼<ƒ$`€…0øÿ?zÄðûÆ †·n1À ÿ+õ€f Ó##£ Ì^€bAbˆq‚$¾fEr 3>xÀð„yy¾;‚ƒR*‚‚d90Ñþ¦ FhþƒVfŒH70Ú€à‡Ù @,Hå>3Ð0¨F˜Å0Ç€äÀqJ”30<} ±|ÿÁX¬‚²0D˜€ì?¨ØL6¼Ø ¤áõoVVV`4üZ‚ì{°å 8Å=,ûƒæXiȤ™!ÉŠ4üêÿŸ`â„w€Ç’TÖ÷9È"Xª‡9äPü#;dHäP0j@9€ªìÀløˆx³ €àZqåéË— ߀Õ,°eBö9È0G ;– a(«ÂÄAzâLÀ”Ї~ñó3Üæ û:Ì^€B.ˆv¿ýòåË} ؆€]²æs˜#@ JÀR ŽA|É!;ŠA–pô˜p¿~ý—Z€@Á ¸Ëÿþ=y ˜šÿ2‹w†9†AÕ2Ã,‡9YÐ °%@ßFÉŸŸ?A¾?³ €àÞ gêu`Vº %…¨ïa!‡²ÅÈ–#ù%ÁCô¦Œ éçÏA…Ò\ uŸaör€Rê†?~lXL ŸAU1(^Aq ŠWX f0,*Ѓ9€00]üQVfX ,}ùr(2¹6 ¸@­^`qòh]þÓ/L¦êo :äP¢a˜C`Ñü 1X„YÌ ËçÕܾÿ#PG*¬„€bÂÒ~4.éܵkß&ãì3¨ Xž†H ÐËX®9˜ò©¨0̪Ùwù2ЙY@™óèö®ŽÉ~`Úö?wùòã&`Ù~è `E¶Ö,ƒµ @ù–Ar (ÈpCI‰¡ ˜žöŸ=û–ëïß è2l¼Qš-TþC+ÿâYhÅ Fnn7#`ûÎèm ÏÁm*…ÈÕ10$@UîM y>d8 ¬~útšéÿ±øÖ( ¼€V@ãã€~Keda1“’•eRúNh!0xAº¾Cá%ÐA7uÄ`…õçׯ‹@G·&¸ŸøzFDŒ K œ+Ð1 ú\¨CÚ5•íO)âï²1@Äv͈q {Ç4à½c€ehí[›ŸTIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/viewmag1.png0000644000000000000000000000526311550446574022753 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< EIDATxÚbüÿÿ?Ã@€b~~~p&&&†¿ÿ2°²²‚ha íÊËËg/,,l À¯ÀÀðŸùÝ»÷/ž>{véÕËW'>~ü°¨îî¯_¿¾|ùÂðýûw†ß¿eùLj›ÈŒŒŒÉ**ʹ6Öæú òr@±1|ÿõhø†ÿˆþþù]÷å«WÑ|òÔ™•¿~}éj}Cj#( CàÏŸ?‚¼||}~>^ ¶Öf ÷_°1\¼÷áÍGF†ÏߘþüûÇÀÌðõÿG¡ Zr¿ž={°dÙê³—/_Nê?KJŠ€…ÅÄÄÖf¤%ÚKʨ2¬>ÄÀðî?ƒ™.7ƒ²4#?7(Ž€¿20ÿâ_ Ÿ¾ùŸ¡ÄÂü ¡ÁŠ ï.ÜüÈœ£ÄÇÇ_ûãÇ&`t0àà @`S0¿²’R±›‹=Ûœ ,BÜ ¢ o|Fç?úÐò¯ d†Ä þ tÌ_ ¼¹­,Ãíߺ@°0ØÛÛ&ýüùSªø0ØŒLLÎöÖ?„nâbÆÏwˆÅßAÿà¯P‡€Å 4Ø@G¢\ÙÔŒáò& S#`ÖMùò0Ñâ @`ðóñ;i©«3<ÿÊÅÀÈÅÄðû/Är°`¾GÆP‡}ÿäH ƒe$™þ ë0°sp2())8-á$ä€;@DTÄ@DD„áÃ/nN`”üAXÆ¿–‡: Ùq¿f±“³ P¯°”,Pƒ¢‚œ4ÐhMB p.àçWdbagøf58@A t"0x™¡¹ê?8ÑBrÈ 87+ó°=#ÌÁðñ!ƒÐ9 b„r@ÀÌÌÌþ÷0ùmáôhÐg?Qñ ˆR` s(ØX˜!˜ˆÙ˜!à:€—‹‘áÝÿ Dr23!Øß¾ó÷Ï/a`þþ 2¨õ;fÿ ^Pˆüý†ÄÁÂqÌ,ø fÆÀ:†À"“ °Þ¼ysõý»·êüb Ÿþ11p²@‚“Hÿ:àû/Hbù %¬ Ë¡9èÛçO Ì¿2<}öüÐè[„@`¼÷îôÃGƒTÄÔ>0ò3ˆ 20Üþ–aÇé­ ~|d`Úb§ãΠ,¦Nt0Ài&ˆ@9ûõƒK 쿾1Ü»ÿð2û”P‘ @à\,4¶]¸xé#ןÀHÿÄ0aé †œŽ(†›·ö00ý¼Ïðâå!†úå¡ w_^`â„7³2A0°¸¾ÿø=ÿ7wž=ÁðüÕË• ,,ÀÊ›'€‡;+ë¥[×n®Ûºwgâô}›$…¹fä41Øê™3|þó‰—…¡iS=ÃÂ#½ Sbƒ£„š@¹”?üúÇpùð`ê]wüä%öÿÿ—Ç-ùªa!U Ã_4 ©Œ€Áôôý»¶úy³ƒÊ²3ù󢮿½Êà»Ú—áî÷» +ýW2Ë›2ì¿wœ Xº˜€43„ý È>ºï÷·Ç w=extñâô™ÿ¾9+9PBøÁ‰žŸP6ˆþu@°ãÅsP<Ü•“‘øœåÁ¿ôÒ"†¼Í úŠú ÷?ßµŸ¹á0Ñ1ƒoLÌLöìÍ7†Ó‡0|yx‰AW[‹AÇÌœáÙÁƒ9JW®ˆ¾b`Ø ?¡øuÀ/$¤EÄÉØ¯Þ½½rõÁ]{;†-q[ø8ùl×Úƒš ¬äß&°A_ÿgø ¬,Ý»Áðôæ%†ÿ_Þ+¤? _€­%cy†¶Y³µyïïmú>gqñçý7ãZ6âJ„uÀ?PJúÿãû·M}+ç{ôä–18*ª3œ|vZUÿú˜™áã»7 çaøüå=÷ï¾}|ËðñÃ{†+×oÜ¿xõê!3³PŽÿŒ\ŠZf ¼N RvwøÅ~^òìÀ³d -«°9 € €•³Ü\ËVmßhxâÒþ¨ÅM3¹d8«À†ØÇw ÷.œ`øòë Ç÷Ÿž½xqýÉãÇ«_}ü´@âÛ÷ûv+—‹«&yx|øqžãÙv¾w š+]yþ„î™ûäÐS`;Ša+ºˆ)7‚[IÀðN{ôü1Ûço_â…™Dàå/ °Tz÷éÝåë¯o-÷ãÝçoß¾âKÀzý+;0úrŸ>aüóç8߉ÕZ.À>{ X±ˆ0°s0h/säù°{éÓ3/#@IÙqÓ'„È`²aåøÅ Ê«H}f |Ëôæâ5†kíòÿå~0ýfsp3~¬À¼ L`“N–¯SÿïÆ%kÏÃÀ þ\J±éÉ0­sáÿ¾oÉ£ãÏ£ÊwÂÌ ˆ×¿AñWh®Å,¾ð/Ã?Ö£¬Gî²Þe`ÿÇŽ"ÿ’–?ýž|dÃúÇAm¹· ^20\zÂÀÎû‡Á|­³°„‰ø  g˜>€bb€gF(wÑ rȦ“Ü'rþüþg럵÷Žñ èˆ{/.1\‘»ÂðJâ%Сÿ1BØ^LÛ¾íÏ®{§€ÑñæÃ#`Ñtù §Ð_nYnp  &lV3üÿÇ ò¹¼€C¦a&ƒ ¿2°`YŒªÔrbÿÁðXñÃgNtI`ζܭ‚ÐM›¯¿}˜ÆÞCâõk†ûS.0\?ø|3H @AÂŽ55ýþqiíÑ­ ú* “ì&3¼ÿþaýÙÀÆÆŸ‹ ¬Œ˜ÉhJÃÄ-ÿ>£ICâ°]™¼qËon‡/ n?™ž2œ8ø}ÇïÿjAòîš1ºª iûÏÌŽ“Õ”å`g`güLÿñþOü#Ø@‹þCõûçÏOÀøõë'0Š13@1aÏzÌ@ _€ß²|þüʇ ”:Q.Ÿ#ø@=Ìß¿¿õþúõ-/(:@ DbûŒÿ¿@šAê÷ï_zÿ2KsqqÚëéiŲ°° ¥ü¿x¢ZZ%W®|ÑþôéÓ&`Ê”¸ tÈ]`A w@±@-g–²!||±22²Æ**j¢¢l22R ÷îÞcø÷ûjy\nüÇÊþLÔR’’ ^^µžÏž=ó|óæÕŸ»wï||ôèÁÅ÷ï߮ڷ˜¸ÔÿÊüýƒÛœ„…E88ØÁ–°²01œ:}Žá‹8ƒØã¯ ¿ÿ|Šþgø )FFÔì A&&Hè€RÿÍg?Þ}ü ¡¡Æ ­­²ƒå÷ïßÂïß¿s:qâ¨Óš5Ë5b¥TÕÑÑ-ŽŠŠ…&ÀïÀ¸ÿ6äÇ· Lœ\ <²* ï¾þgFFVp6e„fa&˜3þI Ãþÿbd`“d`fxòè  7X+;ÐsÜ nn> ÷ïßÏ;qâð€F/“—££“È×_¾|fÅ(²±±0¼ÿü_ŒA[W¨\0€À ²”bé`rø ,ñA•ů¿ÿ~“À_ f•``{ª,[¾3ðñó2|ûñƒáÀëK ¼ \ ö2ú ÆFæLçÏŸö nnnYYYpÞ•L0ÀÌÌ  ¿ø¥®½gÕË , _ñ mo•èÇÿ>ƒ,ÿu¨à‚&•@ÌüW„ÁŠå '+Ã×_ß~£NJ@„˜§$€éƒ_ €XxyùT………Áƒ,éþ ô¯ï?¾üøÍð’IáÓ6`¼¦Å[ïž~ûÏðh)ÓH ªT ²~âeþó™AŽ‘A˜Ÿ!LÀ˜Zþ÷˜Ö„ÄÄÄeˆE@@@‚——ô bXƒí';00>þüÏðö'Ð^02\{ ôýˆZFõ$(š¾q0Üÿ‡ÁDX®€B TD!3Ðvv.~€b–õÜŸ>}gçü÷ï_`T°21¼†õ»/œ 'î10<û-¶‰¬pAê~p3Ü{*÷!ÈÆ ÷$€<úï#+@[D¿­—ÛÀà /0^¸ÀÙ›ãý [Np3ü¬ÐfD©ÎQë(´Êñ'Ã]A o™~3ê„_À:á Ãë×>|øLô?ˆè"Pfxõê#¿V ¬ << â¢Ü jü )_>ýecøð˜+¾32|üþŸáPÇᅩ ÿ ¹ä`¦a¦5^`"ÄÅÀ Àþ—A€ùƒ™4ÃÝG^½ù¶äaP™ª€éç@"Ë%@¢ýÏàʵ'óà¥KÄblÑI»pòO`ì!¸EDHÁÚ¥(Rf¹±­<µ5‰Ux$ð—o;Ý;$qZUTþ›¯%å}´{NSì\0Í¡ôŸŸFÁ§À̈““X]þf•ûŸ>½g8p`˜ÿ÷/¤Ž€•à‚‡‘Zê1"µžÀ!òÿ?¼Fc`Æ7 °-Š{K °™ ö°¾¦ƒïïØ"úýðÿP#„h9°cçFÅ#†ƒwãì77¸TüÿŸ„6#´”%hPAJ²ÊÊJ À:hæwpcäãÇo ß¾}y@@ü¹t Ð"N $°éËÎtÝ`:àa‘‘Q ‚‚BÀèùMRsäKV¬XάŒÀ-.vvpãšáíÛ 6ÂC€…ÀÙ7o^þ&<6Pvi–מÀ„ÂÉ`jjtÐ_páÎÉÿþ3@º'ÿÁ¥'ˆ Hu©˜ÀÑd++ó38;{ð”AII˜»X‰œ HsCà=Èç䤳·n]»äçço" À´ìƒ‘‘10;Š33HKË€³Ô9BXø*Ãár f7ƒ££ ý{/Œ5¾~ýö (Þ¸qõ ‡ˆÙÄÄä×çϟރ˞……óׯßL …7nÜ& püƒâ„a‚Bd„†á¿pÂ0Ð,QQ~†k×î@ÓÃW`úzõ÷øñÃïΞ=ÕtÌ^€÷Œ€eÁš½{wž ê’Rÿ²èùùÄñòrs‚ŠeˆoBá?<Å`â ¨Ñ?³#0ÉÊŠýŸ={Î&¦ï€Ž~ñöí›lll×@v¼IÆÊÊrwß½{Œ{± ¥dHöúÜ  Fµø1ÀÅß½VFr’Œ¬¬03üfl…i Ò£€ƒ™ÁT’““á7Èrf¨ÐòåŠfï=¼Òž2pp“À†ßÿ2ˆ³«3‰¥1¸ˆþg˜øtõï Ï0ZÀŒ Ò À´˜Ú™Y –ð?ƒÃOÆ5šN¯MÝã^00131üþ ô俟 2œ Ö"© ’Ú ?Y÷2ü``¸u ˜`ß½†ç€"ÞB@Ë-Å€Y ü¡¥ç=†¿ ët¼^*;‡¼F/Ðòߌ ÿýbPà¶ZžÌ ¦Äpùç*†Õ'60l™(ÂðõüÛ‰ oŸ”ÂŒ â ÃŒs`bû ¶þ180üÿ¿J/à…¨…Û¦ @ùÏðïÿ5^gKáD>Vq†3ßç3¬Ü»‹aÇTq†ßW^Ö0||ÑŠl4@v€&ƒ0R‘ꌿŒ¡L¬hû¾æÒ6ÿÊÀÌ™ nÓá÷a0Œg`gáf8úe*ò-ÇöÏûùÿÆã†Ïïæ @ø` LMJ@ü -)ÿ2ä0sýž¤æó†QAû+Ðr&PIÊÂ`ÈÄ`"Êj >ô2,^}™áäb‘÷ ·$0|ý¼ ›„Û@‹AÿÙç Í,¿jä=Þ2ˆ+üûœ˜4ؘÙŒ" B~1|bØûzâ%÷.¯xÄpç^$ÃÇpY@Ø`ÈÎÀ Ìµœ¢îÃ4fÑ©âNï$þ2°ãœì|¬< –Bq Ú|þ _ž0ìxÚϰ`þk†{[¸/2ܽÉðë÷u| @˜àæk= ¾Ã}Î ôùbF©ïþ¼Ö¸ÿ3°¥X€–‹q 18ˆ%1¨óº3¼ýwaó= Ïç~ex¶‹uÃý‡1ÀBê9¡$@¨Znà Mp`ŸK-_Í ÿÍšÕð3'0VØAEÐrn)©`Š·gxö÷$ÃÚkS–ÎþËðîÃ*†OS€9ä31 €f&: åÀ¼ö,¬4dƒê7Mo ì@iFˆå*|J þ²i@ËMüÞðüÜ,†UsY¾ý3™áÑÛ" Þ?Ä/„p€0ÁóTüßß *ß5Ô~+/ å@‹™€XWH›!T!A™W›áæÏu ‹Ž-bظ€“á׉ï5 Ï>µ’Z²ÂL ˆýt;Pèÿ__.~6ý_ŠßÀ+3Äçb¦ Ši r<ò —¾/`X°o Ãö¥×ûÿG?…“k9"ØB|ÿï—“´˜„Uª©ƒ£5ñwÅ Þòv ‰j© Ül, »^ö0,Ù~áÊ&ÞG §?F2|ùsŒ’&@a)þ–Úx3 I+†ÅV6¾9Äðþßk†1¬Üz’áñN`?´üÇ¿ë”6¨ÕLMÿ°º‰3©20ñk>f?á`¾çf(\WÏððî†ï§8ö1œù ¬ìŸQ£9 @¨`þWøÿµ4c~ÿNa 9†/œŸ–ßÈpôÒ¹ßoÀðiï5ág*€b„õŒ3 ~³bx&ÇÊÀõ˜&¾ü`xõó<Ã}†Ý ¯vËÙ @e_©e1Ì^€B„3CÃ÷ßÀ”xç ÃM ¥öýyÔ̤eÇ €À.»F…!”‡Á(ÆJÌ^€bèÎ)@ xß €ÜQåpÔŒ„sIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/quiz.png0000644000000000000000000000261111550446574022215 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?Ã@€bb`@,¸$¸­Vt‡»Êæò°rüÿ ø ©ÿÌøÂþbƒÄ âHj€PâÁƒoŸW¯=žû÷oËBlöNØKeÄ¥XsœÎÀÀ §?@GüýÁ@ô_,4” V Äß~20„F2ðÞ¹y2h$VNð°þ¿þš¨B–ádžß@Ãé_!øçˆøß _ù ú;” ´üâ3!~^.6\öNüý÷ÿ? Ðç‚ âaxÿî=Ã?fvv> f Ü¿ï=°ä@ ±©•è›gO^1¬™7…áØî ï^=g`çädøüáX^QߎÁÐ+‹AÖØ"`Ça.@åv ÏΟ½ÀP•ÈðâÉ6vN†ÆÅ‡$”U^>ΰ´³”áòáÍ ×ma0 ,c0‹éd`üAœÇˆ`9ÀÄJÑÿú«sÁ–ƒÀŸ?¿˜™™xø¤UÕZ–1ð‹Jƒåάïb¸²s>+'q ‚`&¶ïßþ0<t‘.€yìɽ`¹ŸÀÄÇ+Äà ­f—¿²}ÃïïÁò„@tÀ?`Dòò³2¸Å ²¨ˆƒš¾)Ãï_>(±ýýó.ÿùÍ=†oß00QÎÁ42ü0>3*;ô,œ>¼Ï jhÍ ,-Ëðè{6`P?òŽáÉͳHš@øQQ@D%BP(€ÂÓÖÓ\Ò}ùL@K€9áÕË/ +:2¾~x WÏ) ÉÀÁ+Ìðÿ+a³ˆèlòÐ÷¯‚XÈ3\?s‚áôÁm Ƕ®bxñð&ŠZe‹pv6¢Ê€b!§eË­ '2Ù¶CN\ÅŒÁ(°”áÏOâÌ ²ò+Èh@Û>œÁ!m Ãv>†¯Ÿ‰3 €Èr$]ücàäágPÐ2fA5«@ M+†OÀhúô‰xsˆ,€ò÷Ç·/4L*ço€Xú…T*ÿýMšYD–@u½[°ŠgåbøŒëï_ Y•œÖ@‘Ü$ceùþ+3ñXø||û…•ü&@‘,@Õoß¾e¨÷b¸uñ¤Ô1cÈš¸™]˜,I!¬ömX ·î_9ÅprûJp‰H 2¢€‹¤ø%Iø,‚ÂL}àbúv> f^a ?¿cÉ-D˜ @,¤¦~N.†š™›®œ;Éð X!Èj[€Û†?¿ç€"èP£’Øüûb"¨U âXšƒ[Å Æ(HŒ…¢„™¡˜‰N°032j¼{ï!-bP“û´Uüëj³ü'´e jŽÃè_À¶Â3`‰ª»˜™™pF5@átÀ“·ÿÿE‰k½7‹@!êí=ÊÀò)(W€zP@Àrà/¤Ú†µ AlSE#1†5o>㬚ˆWç”I)7ÁÜP=[€›ƒç?°]ψ«kö™ í¦AÙŒÀBûé³_Î]\ÔñÿÿíuØì ÆîЀ÷Ž ²ç;£CrÉIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/make_kdevelop.png0000644000000000000000000000412011550446574024030 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<âIDATxÚbüÿÿ?Ã@€bb`@, ‚‘19‡‹©Žƒ‰ûßÿÿAbà€a1Àˆ&†^ÿÐäaúå1ô12þýóáÏÏ¿“þÿŸ×@Œ (àãM{ÚØ/Å+/ÅðõÛ†¿ÿ€jþuý:çˆþÅPö¨²Zý™”2Á4H=HŽ…‘áÃÓ× æÎ{õëë q€‡7+—„Ž2Ãq öoCY bù‹0æ˜å‘,ÿ‹„Ajƒèÿ¨jÿmüÍ!ÈÀÄÎÁ ² €Àø÷éï—/Ù?AÂdà˜¯þ£Zþf0L)„`ìÿPõp½PÌÌ4ÿÇo ÙL ð` H`bbøõ‡‘aåš ß?~g``ÂŒ_là?rD#304‚¸L@ñÌl Ò²|`;A €X ˜>|ýËà,õ¡0WèÒÿ 蹓'”¬AÄÁÿÿaUöÈaÆÿÂÝ/–\ÿ TÎ  ˆë˜~S‰°ƒª’0YÙéïÏo ÌìXr6ØUÀhøÇÀÄÌ )þ“áÏ2ˆ:€‚8€‘ ’Jÿþ#ÚÂ?¿~1<9wŽáÓýû ¿^¾`øùø “˜ƒqQ1Ðlf YÀqÊe üh6/ï`Žø LÌp$ €þþcÄáPðñÑ#†'gÎ0|½{—áÞ=Q^ MŸ>1\9|˜áº…ƒ¾½=ÃÏ?ßÃð^0‚æ&H4Á!À‚Çâ··n1<9ušáûû÷ ¢FF ŠÂ¢ ìׯ1üyþžáçÇ ?¾|a}þœáÒâÅ vv‹€û~†$, û?4Í@A Ž¿@Aløøø1Ó'˜88Dµ4Ä €†á×™ó ?_¿aøýý;ß?~ƒ–“yß>†;—¯0hèê2üþúêˆcÀùšM™  HDðGô_]¿ž[RŠAÓ×—AèóŸß2ü†ï? )†¿¼| ø Lÿ€ø/Ð2±§OnÜväÿÿ0ü ²â]€b‚„#ÄUXÒ‡  P1¸HYö È2 øyy†_¿2üùöáϧ ?ß¼fàÊ}\³†áÍ»àÄJ| =0"¼ 6 € !ÀÈLŒXÓ ‚<Ë+W!.ÿûâ#`®ùÏÍÆðW[lñ_f`ªWÓ``HLcàZ°œÓÖ‘áÎî] Œ¬¬`Kaiœ Q,‰Àl€BJØ£@T]ƒáæî½ ¿Aê¸9A tć÷ ÿoß`øûhyE-ƒ¾!0Jþsñ0ügcg–’f¸±}ƒžJ"G¸vdÛ wÀŸXÊOPEÌÛœÂB ¯vía&ÄŸÇ2ü¿záÎp^ÿ¿dÃ1q†@Çüûøl¯œÃo ÿ-°l–&ÔŸ@_óÿ_fp<ƒ= ͆Ä‚œÿ3bYKK† 2b¢à,÷÷ç/†? Ä÷ö Ãß=»Â"þëÜÿàÂì/30$¸…ÞÜºÉ $- ¬˜¾ñf€VËÐ\@L°’ð/Z€¤^ˆ)CC†ßšš _¾|eøÇ Œ{p<Ö¯ß /œ‡Ä-#¤Rcb†Òï?ÀÂÏðX.ü§úÿð´v$È.h  LåÿýÇV×]ÍLL\vö Oß¼¿ÀÙœõ€¾ýwö$#°púÇÍËð ˜#n:Îpdj?ÇÀà×ІÔOpøóô‰„Hÿ‘‹âÿˆ1€®•vse¸6o.ƒ8°Äcü ¬Í€•ëoÞ`øzp?ÃS`è¼¹xŽGT˜AÍØ€AÁʆ訟߿A!0þBÌ4´(ff@®‡`–ÃØÿe‘”d`óð`¸Ó׬õØ^}ýöç†7\Ü ÿV-c³±a°ˆ‹cÑÑe`ÖŠ¿¿ÿ`ø ”Gä`îù÷ÚpDÔ†„šaÁ¯@ ¡rýo`"S‹gØ,å>¾{ÇÀfl ,– Ì-¤ÔÔEžøõãÃw`ÅÒ vÅà(bx4#eC€bAN„°`a¦P&hŒ€ÚL ‚˜¤$|6mbøòõ¯°''°þVd?~‚} r$H,311þ'@Fh›Ø&7FHKš |ÿòƒáËçïÀŠå?¢LÅ(øÀÙç+;/ƒÿûõ—áÇ÷Ï@ A IÝÿáÙí¤È„X ,vY€v0û¯Ÿ?âœð h"ddâåeg8!¢÷>Ø1àZ ê†ÿ‘ڈІ&¤^ÿö/,ºþC³2r?àßDšbfúÆðâ30Óñq2üe„TvÀïŒÞ½yËÀ-/ÁðîË_°&X«Þ f€6¯‘ZÃ0þ?¤–1R Ý ps‘XVüxOðv°xŸxlãÁ|&P£íÿÿØZ·="lüÿøå¡Æ1£ |‚Ĉq ;§4àS€pþ³‡¯ïÞ[:IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/frameprint.png0000644000000000000000000000354611550446572023402 0ustar ‰PNG  IHDR szzôtEXtSoftwareAdobe ImageReadyqÉe<IDATxœ­—ßoTÇÇ?gîÜ{w½özÁØÆ`S~QBh78ý! @j ¨jÈCÓVâ¡ô¡Rÿ„ö¡}èêKÂs#5o©Ô6RÒJMJ´UD,›ò˃mÖ^ïÞ{çÎLv×6\@éìì9w¾çלsGŽû+‘snÓŽÛ~¿yó†^çœ{”ÜéÓ¿ÚpñâEªÕ*ó,¯½öÆŠ ä¹=uê?xp¿ZI®Z­.nþ¸T­VÑ"²¢ˆXc¬â‡KxÀ?18´¼Ñ¶je%M®ÍHŸjµ´G)ˆ<”V÷<1xµZEçù4Þ{¼¢¨›0,ãý ÷ ½_Þùÿt¤Ak Íæ]œ3‹Cˆ°¨X€ÛpOzéQPJ“eóä¹eõêMˆ@¶,÷ƒ.ÁÓÒÿøW©€4­Q«ý‡ùù€i(¶}ì–±¿ï¹s®Ÿ„ªÕêr,‘H@–Õ©ë,3ßQJ…K ,ÿ3ÉyïqÎâ=ëŒÉvY¬ïê*îݵkÇ ­;bÀgœÞ{åœ;V.WN ìÞºu[_ÿÚhxxã8“´_‘6`g„gâïÝÏ9úËW^9@__?…B ¡VœûÇ=ÈÀõLÞDðXgé·<ðæÑOWŠ1ÏíÜùÂÏŽ?ÑNÀ&IÒ 4I#A»èÙÊÌBŽ´#&"Ò>ÂjÙ†OÜŒ:øÓ“'ò›ýû¿M½>ˆà=DQÈìôþxîS¾qð xßru  ¤e{bÁä`€ÌzŒë@€ÏÎý=ƒåÞIÂGµOé¡‹½Ã_ᓱñö™Ó¿Ö¥RiçÈÈÞ;´^*8A HÓ„¬w=—f8‡ºéj‰g>ãÚºyßÊ'Ø5|]×é*†,d 2gYWYCÂÚ¡!ÊåÞ/ëžžòs}}}ˆ´@A°Ö‘5ê‰á µŠ¹:D^¸“ÀåY¸Ùð$”o… ¹ø‹@„s=ÍçÙ }½e¾Wù&‹G_ßj‡u¥RYÛÓÓR‚RŠ,Ëi6Sâj©gÚQuøçmáÒ4ÔsZ²ÿ§:Õ(pe6gtk@æÀã„@)⸋J¥·¢½—ÒÜ\“ÁÁ"J ÖZ´VÄ¡ânÝ0S/òñLÞ£•mò˜ÅWÀ%%&f­[9Õ1 Ërœ“P§©áÂ…ÏXE__år…BL©à˜¸Wà—È l{X–î£Ë‚ÒˆñUâ8À¨$ɘ›«sçN{÷šÔë Z)e¦¦jLM͆!ÝÝûKl[ÛË¿ºÀœ¸—jf›B­éi0VpíS!@¤¡BO «» [*AÆË뻿v©»uêõ„45xrm­™ Ã`S¡P Ïs¼÷4›7oÁúBÊÉçkè(&ˆB”Ž2'm–̈ß*éyŽÍ3ò4¥‘ÂÍ[–Ìd‹" ¥œ³u¦ÉM¥ü‹Åbc Zkææfùàƒ÷1Æ`m«Gtj€(”ê”ävÒ9pÞwÄ@Q (%ŒŽ~µk‡1ÆÆddYsF繹꽡XŒÑZˆãSS×øðÃ?‘$ ¥RA ñþ ê}»JZki6›€cË–Ílݺ$i¢uD­Ö Ñ¨ßÒyž_ɲ&¥R‘$8Ž0&¡»»›¡¡!^ý8«V­&ÏÍã+A@’$¼óÎœÄZCk &Žc¦§²,½ªóÜœ¿{÷‹¬»»iÝzqpp€W_=Dyé¥QŒ±XÛj½ÎyZ×÷çZnoµóVcrœólÙÒË™œ¼ÉæÍ)BÂPQ(©Õfɲô¢Î_¾|é߇­TÊ“óâ‹»)—Àõë‡1Æ.8ç–ºö\‡íâZž[Êåûö}‹‰‰ÛìÞ½……A TÀØØ'W½ç/Áèèh6??7›$É^­ãb–µ°Ð`ll‚ÑÑíÆZ‹µvÐZ‡s¶=vØ.*Øá,3ô÷÷réÒçí|X`jjÊ~ôÑ_gΟ?÷‹ ÎjA)õîÙ³¾xþü¹Â0Zg­Þuøðwßèé)›Í´m-˼à=°|®3ï}k>Ms¬…‘‘ÿÖ[o¿«TókÝíéé»cQ]‘¥O²0ÔãZÇã33³DÑÀ÷·oßüfëxùûÜí=»‡(ÄâüÌÌ<6 Iv~ûöÍßö÷¯! ÃÅ/mÝ=ܹ֯““¦Q×Ë/?jãÆa P*™é­x³xD—Ë× ;}{~|æÌ•37n,ŒÇ±&Ž[ÝD§iض*,ZËêf³^~ï½÷¯YkÝJ÷Æ•ïµK‹"Èõë“a¡~ÉZ7žç!vö_aÌ’Huô¼IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/toggle_log.png0000644000000000000000000000431311550446574023350 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<]IDATxÚbüÿÿ?Ã@€bb`@î€b1¸xÿ3|ÿÂÀÀÌõƒáïgVþ_ €4«à/ Ÿáï/f B"Lýù‡GQ[jÁë[/ß|Ù|±(ò—R€b¡º—~þcScm¬hR>yPŽaÞ•çÊü¦ €Hˆ‚¿ Lþƒ”n±áßÿXyþù%EÙ¼üü™ÁÒ“™Á&Ç2Ÿ—3—©D½4rÀßï2‘áÆ}íæÝLÂ÷\.Þ»Çà'®iÚÀÀÂbM@‘瀿ÿ1ñ÷ï šb-ÍþeÊ ¬ ñúÑ œL^{Àà“!+Çm¯ÖÔ)‹n@Q'þüg`“dLìLÉŽ—cÕbxùñÃ×ßÿrõŠ^]c`xÎàU¨aϬ)STÍ…¬ €Hwã?6`Z`je¦‡ þ­Ü8¯v_™H†Oßÿ0|üö‹áã÷ "¼" Yê w®ücWþÀ`–¥•Æ !Ì€”—ˆ¼@Ί¿~°Z9ªõ•;—ˆÿ¦Ó§ï¿3°²03üFËÓŸŒeõ‚ų®\Å iù›A>L£šÍ¦ €˜(Ju@%t9›ê#KÜyþH2\ñ•áÐuß~ýc`†¨”ýù;CŒaƒ W,Ã퇌|ØÄù@¡8”hÿ3²ýùùË‚Wæ Ž–‚«¯©ƒ¶»¶ƒ>¿)09^+«û¯~0|úõAX\‚áÃç÷ ï^a:â0z¾}üX\ƒcëÿ?QQ. #ÖߨİóþA†ëËžÞgxùdùPJ ¸˜X589þ¥˜*ýussŽTóÒób×ÐZ)Œ`özûƒáãO LŒÌ ÿþGÍŸÿÌ Êš ׯ_`xö䃠¸Ã÷_?þ0ÿ¦…ÿ ül œÌ '^aXÿ`ÃÅͯ¿ü:ýp;к@üd/@Á ¢È¹ÀÂí¯ylÆYÖ4q;+†o?þ1<øô ˜º1p±³0p³13|úñ‡‹ R-?ÿø——AVN“áæí‹ ß?eà¦üo üœ, œœì ÏßbØp6Õ‹^n¼qÌ ß߀٠@ð\ððè‹5Ÿßq1¬KQgXÊ&Ëpø0þ˜ÿSòN …¬LL ?y‹\óýf³?ÀJŽ™áûo ÿ˜Ùää´Þ>¿ÍðåÓ;`UÀÅÀÊÎÉðã'Ыw0\~x‡áÒü+W>~ÝÔ}’ €àøyìޔóŸ­|o"ưOï*òg»n}}Î ÉÇL@ÿ^~úÁÀLÙ@w-ÿÇ ÂÃMdÀ,Åø‡ƒ‡ABR…áå“+ ¿€!²áÔƒí —Þf¸°þéëÿ·_l€ýGät@LH)ðÇ›=·K.®úz•Ÿi'ÃÃoÅ ž”2üeýŒGVp–âdefâf&bPT0ùÀùõ èÈß âRò |" ïÜaxôü!ÃõknœüôûÝÎ+û€6l4zf Ô‚èÿß'×7ß*~z†ý=ûwAƒ¯«Ønt0ˆps2p3#0˜~üúÎ2 ´ ŒkUq^aa.Fi†W\< ßMbxòøÕ§Ï3üù»húhQ†³xþ~ç±…W:¼ä;ç|¶`P*r`Êc`(ádøýê+0ýbåå`à&JN6PÖúá?Õ×N¿ºÁpåã!†¿\§>¿d8¾ôé†'ïAA”å°7Äë02¢´6™…4:•©E³ífè¾ùA¨½E× ˜ÿ³"Dí¥go޾¼ÉpöíY†ÏÿÏ2pþyÁðõÉ[†ÛgÞ~¿yüóý—ßnzz)Pée\å@ár0råTBŒ6ê¦ hßàþÑŒA?k30þÙ>=ËpëóM†çß®1|ýr‡áß›/ /½ùyóÌÛgo®¿¿Éðîçy`tžšrˆ@”Ø@ávðpXØ8låódºøòƒƒƒ’0?Ãß?~¼øÀpçܳ_Ž=|öñÞ·ÛÀ"ò °¼ÔušØ>@«.¼ €ð;$®,œRî<ÝØDŽáÎõû n|øwÿÔÓg÷/>¸ýïͯ«ÀâèËÿ×€Jñkb,EDÐÀ¤Ï¦&RÁ+ÀðîñÇ÷ÿ_|½LÕ àYúˆßƒŠr›DØÀ*­A)êË׸R5© €ºw @Þ90£Z<îEJAIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/up.png0000644000000000000000000000347111550446574021656 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ËIDATxÚbüÿÿ?Ã@€bb`@î€p 2‡‘g"vUÿCð? ûþÏ ÃÀð;È êb ng``d_c`bd`y‹J3ƒhFãþȃ³ˆ…d'ÿÿç ´|¢³³²vl¬6;; úu7sW¯¾´­hóRRŒ Òð÷O3 ãôÚZ¾²RSNNˆöU''yÙÒ² ¿|þ)ÅÀÄÚM¬‘D|øó7†ƒƒqî´éî|õu–`Ëo¼þËpöéæ¿ ú «Vù2‹Šqu1üùSI¬±Dœ~ÿucøÿVï7Ž´]PB`ØÿCëQf†¶ã, +/ýgøûã;ƒ§‡üù^ |ül- ?þ$1024 €Pð #  ˜ÑÚnÇ™•®–Üq‡‘aÒ&†¯¿Nùó‡aÎÙ@ü‡áÛ—¯ >^Š Óg¸2qr2õ1üþç@È„êFfg„¤bfFn†?fÇÄé)V”™}~äÑ?†™çÁ‰›…á/#Ðlÿ3,9û›aõ…_ ¾~aˆŠPg(*3ãgøõkP“4>ªX˜™‘á˯vc)‡ÞN{&`Vºñæ?ÃìóL  €eþ÷—á÷Ïß ¿ý†Âo #æûʰíê†__¿1T”1xû«*3|þ5 ¨¬ †‘@aøþ7Š_ˆ#{Út71QN†7_ÿ0L=ËÄðá'#+Ðç?,‡à?@ Ì! ?€êÙýá̽o \,ÿ&ôÛ3(jù1|û]ÂÀŠä9$@¨€¹ðÿ%†ÿÚÚ;ì˜,M%~ÿþÃ0ã3Ãý÷ŒÀØùËð hÑ_¨Å`бþÿÃðæãO†¶-oî<ùÊ (ÍÁ0y¢=7k0=Xc €Bu(b%ÛÇ_¢cµå2“‰îÿ_†×ö=ÊýýËðéëO €qýæ€?` ŠŠ_~ö‡áØÍÏ ][_1<ñ…ÁÃQŠ¡¤À˜b'KDA6Tf6f)eßúJ p|¼þüŸáñ'FKÉ? ¢¿ôEþ2°1üaø #€ø( €‰Q_Š™ÁLž•ÁYƒƒá͇Ÿ 7ž~cxûæ Cf²ƒ¡•¤!Ð5èÖ#r{€QfŠ6ã×ß»Îö’Œ Qô°`:„ÿõÀ ¿dóW† Þp(|ÿþ›‡õ/ÃÌX1I~f`ZøÇðhî¯ß@=ÿ1 r0\†Šwø¶ßÿÿ÷þÿ¬¸÷ëï?¤ ù—áÛ'NFƼ?ÿ!ùôψŠÂr (Éßyð‘áö¹—˸YW£ØÁÌÄÊÀÁ|ÙJ€B¯ ŸsÂj6fD¹ÀÊÊ»¬ÜÌy @·‚ü/Ô¿l0füŽ6P(°põó°žgà`Ù DÖÃR7îêf9¨Xþ ,É à(!‚'Ðÿ£$J7ÿ¡21°ƒ pMú#ÿÃ@±à´”_9™ lfF…0þý M eT ÿz@%0W0üÂî€Ât(öÙs3!R3Cãùó—_ ï?ý–|ÁзoÀX‰ý…%&$=àÄÍÿÙ  ËA>çfF+- e((øA–¸hq3¨ˆ010ÿÿN ‚ˆè[v`ÿfEH‘ˈˆsÅ $¾ýƒØÕ Ëy°´Q€îaÎÉÆÂÀl eyˆƒ §¿ à;Øa@ƒ¿ÿøÍÀL7¬lL´¾¼ ¼ˆ „ª„{JaebúŒó#WÞ30 €| rÂP¢c€`ƒãý†W~-gfEo ƒª@×(åd9óù—»¡ù»D¡úž6‘-,ªþÿgþüûßn–SÄ @ŒÝ7 ïЀ; €ÜÑgïðKÚÝ2IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/player_play.png0000644000000000000000000000311611550446574023547 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<àIDATxÚbüÿÿ?0šÎ®`øö;Œ•i:/døÏð‹†àÿ™40 @Lp‘¿ÿʃ}Ô ¥D¹g1|ü¹Èwc`d 9 „~þaŠõ×`8¶4„!Å߀–â§ŸqñÉ{ ,lì ¹¦ §†0X;k»0üùèÒ@-j”: €`„øþÓ†w@Ÿþ Œ ûÉ'†Ó ‘—dè­qb¨«óe‘–OgøþëÃï?@Ýœä: €P£ä€_|Zþá'„ÿ H?†Ê¡» çž00X™É0LëfˆÏp‘äáçígøöó"0ZBÑÍ# 2çÇH¼ÿ ðè˜ï$x|=5 dÖl¼¬zäÀ•U ßlfà`me`d|êtÄTfæÉ@e8‹u€bAN„ Å?³2ÿ€Æ¿&Tn6`¶Ð’cHU—a8°÷ªâùƒç{þ~úÁÀÎVŒ–íØôF¼%>óÀ Cžs ƒ¡½.ƒ¢®"ñ½—Mžž»´•áïÏ ¬lõ@‡\BÖ@(ýïÐÀDö Hÿ!ÿÕgtóæ éÀôÄÈÃ``É`Äȯ¤Àð÷ïI†ß¿[€Jd`vFLÿþÇ@V!÷ 33AÒÐË 7ž30ðJŠ2è{1¨úûqpKJV}º¦ €°:€Zä‹^CäÐ\v^fV`Uòÿ¿L @± k%9€-4Àb@0íûùá ãçÞݼÉðï÷¯ ¬¬]0µÄ‚Œÿ3P\Ï€<ÎÌ¿ýbxyö&ÃóÓgþ|ùrhq3oCV @(Å+P„¨™•‰¼``†VÖ/oÞgxxì Ã÷W/Ÿ0°°41°³/•uèZÅ ËÙpqÙ$P/3¿yôšáÞ±s ¯oÜþ,N2°±u¥ŸãÒ@,ÈáÊû € bKB& Vv`í ,>¯í;Çððôe`<ÿÙ´¸(}‰~€B) A†±-ç†3!ÀT÷XzÝöiÀyÍ@`g@aD1IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/button_ok.png0000644000000000000000000000330411550446572023227 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<VIDATxÚbüÿÿ?Ã@€bb`@î€p iÜ„a*’’ ˜‚‚)` &õ‡@¡Ó³O'é˹"3@ÄW°õϵ¼NqD:²‚ü½süг•¸˜mæÈ€pØÌˆ·8 ²WÓ[\c÷@´F†ÿþË0üþ?_RB¢ÇÑÄP‰““;& @4wÀß?½˜˜wjiD:Ø0ð1³2üüú÷L €XhfóÁß¿þ5pˆò焚h3Ek¨2̽zƒaÓá+™~ÿ‡‡@ÑÄÿþü3ûÅÄÐ'§&im©Ïà%.É0áÆu†u®}dúñ?…‘é¿øÅf%Ë ¯#äýè`¹Ä‡'Èíÿ02î‘Öæ/ÎòÕa+00efgøñ÷Þç/fn}ÈðåÎï6æzPYËÿÑ¢ €à`ÿDzèêÕO™~²2º1ˆ«sûþþó6PŠ-{±í¨bàeÙhl+l\ênÈà+môÃÏ¿?N¾{ΰxφ7~®dcf®ZŽ·º ¸˜X/þzɰ{ïåW f‚† Ù.æ Â*la¿3N¡ì_3h£p9[«¯‡ …%ƒ§÷ŸLÀ‚î Ã¥OOí}ÊðæÊïÍlÌ,éŒLÀ2š x`úÇò—í7ã¢+—?îÓ¹Â.ÈðÝí;Ã<†k1Ÿ®0üeúÏpü?s½²‡d¨…ƒ•ˆ.0 p2|üõ¨ù+Ã5 å ÷=cx~ú÷^6&¦„ÿŒÿˆÊI„pÀ/V`pìüýœñäž×­ìÄm¥ý¾;}gXôùAü¯/Lñ¦Öœ ¡úÚ j\ ?ÿeøþh9ã†ß3¬:òœáù©¿WÙ˜“þ2ÿ{Gl3 €øÃ ¢~±þ`XróÊ/«ZGœD¼¼$]>¹nÆïOE=af†Ï¿¾3üüÿXsþ`xúó!ÃêcÏùw—õ7sÌöH)?á€ÿ&##Úw Þ¼­¦ÎwƒãŸƒŸ¼0%«Õ¬ ï~Æ÷O Â_ Ï?bXsâ)Ãí}ŒY0‡ÿãü}½Bç;FÜá@ˆDª÷˜å?ëk毬Ëo\ýÃpýãm`0døþç÷_>ýþÀðíÏW ~0¼øý˜aëùç w÷²~dýÆ”ÊÈÂt˜¿€vA Æ ÌÌÀjS`Á0@ˆ@°èómæŒ3ŠK¨ 3ü6Hþ}ý÷ÿpH|úûŠaßµ 7v±}aùĘÆÈþw'Óf`#†T@L°Â13#Ó=¦7ì»n\úÃp÷ë=†o?3|¦öo¾0¼ùó”aÏÕ W¶rþayÅV,îWQR{" €¹Ù€Õë´×¹]{úèã7@G|eøð÷%ñۯnlåf`|Ê^ÇÈÊ0—Òê €!ð‡3ÿg>Íð‚cÿ½ëÌ ¯~ñÿ5Ã…'onî``~ÌÕlØtP£þ „þ±¡b–¿¬?Y|¾Ä÷ïáûw WŸ~d¸¾U„á&÷4&†r`B¡J €JBf, JÆ­ ϸ/Þ» høë1Ãÿ+|ë™Ø~kÕÔjÁRAÄŒMþ3ã_¦Žo{$Z¿3íÙ@ËP³ @ŒÝ7 ïЀ; €ÜëŒAt>zIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/mail_forward.png0000644000000000000000000000502311550446572023671 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ¥IDATxÚbüÿÿ?Ã@€bb`@î€p Œº˜áï_†?ÿ3€\õŸ‘œ<þ3‚Ù ðû÷? Ÿ‰‘jþýƒÐúþõÿýûOå×o†n¯/ŸŸ/ÿá\7(122bX~ëÖ€b¡†/@üùóÏàׯ¿©‚Bü~áaÊ2ß¿È3¬ß²Wñô™å«þÿÿö»Î9 D©Xýúãúÿ?c’´Œ¨Ÿ‰™«»‡ƒ 'ÃÉ‹ÿ"ãnßL({øpv6 '8\Ñ@‘å€ÿþqþùý/‚‰)JEUÆÙÜB•QÏ@’ABœ…AJœaÅò/ Â*œ † Æþ1/žïèýó÷õ=&&Lëˆx0‚ƒZüׯ߾ììlùÊ*2:V¶ ºº’ ‚ ÌÀ„#"ÌÀpå†_LÿDD™ØØ¼|ÍøÎŸñ(zútAîÿÿÌÿÑÓ@±¿ÿý“ÿýûo"W„¾¡‚º¥• ƒ²Š0/ Ðv6.`3þÿÇpúÜw-3^V Þ_¿,,ô ý"_¾Ø:é×ïg·˜˜XQÌ œ9ô÷ï?ºÿþ1æðòñëè) ››«2ÈÉq3ps#¨“h+„ÍÅÅÀ°gÇa !†?¿ æðñ10øú› ]¾PüøÑìtffN{ˆ3~ÿƒâؘ½²DÄ„ŒMµxôôe$%9ØA}ËΡY˜!!rć7 wîfpógEõ¯OüÿÃÀ`eÉÇ``ûúåîé?=º H‚ dp}ìÎðŸ9O\RÒ^ßPYßPœ°8@-ce‡XÆÂLxgšðæëk†Ì…e {¯ìb8ðч¡Ê·AJDˆáëOˆ=¢ÂL îžFœçN;æ>}:7ùÿ„µŽc \¸¸¤dóÿ#Gžþþòÿÿ7ïþÿùúÿÿ×oÿÿÿáÿÿÏŸ¹ùÛÿÿ?ýÿÿûÏÿÿøÿ¿ÿ`°àÈâÿŒQŒÿ§ïÿoTjü_5Qïÿ‘S×þê{þüÿÿW¯þÿ¿~ûÿ¿À½ïx¸µ ÙÙ…88$ÀöRœ›€J¾3çî3ìßwžáÒù» ¯ž½bøùý+0qýfàFƒCLÌМ êÓÇ¿‚ L%A†ÝmëTT¥œ[íÖÞÌ Ä I#RÀác&("êZøûÏW`Âþ ¶ €àa,PÚyx„j™(1\¸üžáÑ«O ß>¿fø÷û/;0¢……¸$$xDE¹DD8¤e8xy™.ŸùÇðâù/`º`bØô~)£Ð†e•ÓÊgw1Äô‡Íéa(‹Êføt°• 7ƒ¾a`È‹[:þþ}} d/@ÁÀÆÆ¼æòåGÙ>FfÀ„ôã(Žÿ1üþþ›áç·ï _>gøúñ'Ãí;.ÈÌÄLl ìLü ¶¶Â küexóæ áU wî1´§æ1h˪3”ôÔ0ÜyraB~+ƒ¶ƒ£›!çù3^%Ï_ÌOÙ @Œ°IHÈb†ï߯ØÚ/ŽH4dxýšð€˜ÊÒÌÌ ÿÏðóçO†¯_3ðr³3°p~aÈ™S̰öürç-^%F% † ¥L†ËŸ1¤VW2hˆë1,iœ LÀ2 ¹YG?îÝSàõñãéc„RCaÙ©S·Î={ð‰AXÈ03B0Èÿ ñ ÂLÀÃÃÃÁ -ÍËÀ'ÀÆÀÏ)ݬxC…{þ‰wnìûÀpâÍI†â³e úÌ ÛfÏfxñóƒCf(ÃÖýgÄ„åùØ™xu@vrn`ffþ÷ãç—Iûvßc6,@ËÙ˜ù ÊãªXƒÜ÷—‘¡5±ŠanÁ|†k0ÜØü•áæ»û )» îr\dØ3o2ƒ†ŽpÜ™ Ò @H¹€œ¬99YVŸ>}ýÔý;_øù@¾E8d9 31!h°c@ ˜°ã݃vOZÇÀ{G‘ááJf†—ÀÄœµ³†aîýy ÓZrr‹<Þqsÿ-/ ² €B€ŒÆ~ûó÷û”믂}.ñX–!cd1#A•¨ š3Dëw1|?ÉËðé(Ãç?ßš÷Ngh¹ØÆŸîÄž*ÃðñÇLZ€ÂZÓÂòËWîæÞ¼¡aªgÀÇðã¦@¾aPI²îÝa`ؾåö‡ÿ~:‹YÞPˆá•Æ3`Vfdäd8óê(Cþ‚_ —6 `gíé ¸þ3üCTDLŒþüýÖ±eóÍUºú¦ÌÌÌ a˜ZšqW¯üfؽë ÃîG¯]yyðÕ3öý¦®ÞZÜìÖ ›ž|bÖT²B| ï 1lÝðú °Ô*eà`ž² €!€ÖXaç`Ùvéê­“—/iZ™˜òÀC%?¾30\<÷—aãúë GOœº~ëÁöþ—̧ÿ³È0ÕúE™p?W¸ËpüÁ9i!Nq~†G+D^œdÌÀþ?˜ÔvÁì \ d 'üû÷³cýº+ ô-˜@Å0ÈÇÞ‹ë3ÀgË-†'v}ÿîÞìÛ<[×ý—þÏÉ'Øéš¤Êu‰óÃOƒàA†;+E>Ýe;ÅÀñ/hðMd{oƒ„yëµ÷N]º¨m¡gÀ˰yãG†mÛÎÿ=ñÀ–'O÷Odcøwâ‡ïÿ8|sNærþÊp„ñûgßä$¸ØŸˆ0Ü^)ÌðóóÎ@#?¢Û@püûÿ[³ä#ÓÏæ%K¯ný½àç§£Ç×nzûöÂü?>îcF“4ÃÎGÀ– ‡¨´úÌñáÏ—ï ÒÂ\ ÿ/ˆ3Üß*ô÷ÏÆ6Žÿu¸< @›dÀfØö£Çz>|¸ÿí¯_ïOóòÊÛìÀøùÄðAú9(œ€`üûTj²ÃÏCR o÷ |v!ŠØþÏÃg>@t##3°ð|Ç—/M1)plA0ü`bøý˜2ÿ±‚0 0xð1|Ù(Äðé ßu`|'ãû!óˆ¨V1¨9Þ˜ü+,&ÿ}†$W E¿˜}Ø ­û÷ Ë`|çÅžc6@1t÷ ÀKƒ¸2 ®™IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/kgpg_key2.png0000644000000000000000000000443511550446572023113 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<¯IDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €X@###öâ¿@üˆ20ˆýb`°da`ò‘pýýó×§OŸ?œøËðç$#Ã6†»œ _xÉðÅ+ ÞÄ  @Œ  è 3ƒøw†h>e]Y#5#9i y5>†_?3<ü‰áñÝ î}þ~ÿò˧/ß,:`+©ÚÃpˆí pÈA%Xùy4ø¹K¨ 1Üyõ‹AFöƒŠ®»8HÅ)†w Æ¿>™Ï9Ÿlÿ¬RÈèäl%5ØA¡¬ e ,!üb)k×o Óv 0¼øhÌÀüôïƒo.1¨¨01hjó0¨«ˆ‚ÃÉô…á¿Í7†H&*`„ùMð?;Ã1 úW¿¡bvÀ_! ¡ï^3prüe8qòÃí§² îΚ BBü /_~â· W.¿d8zä9ûY†Ì”7 2ʬ ‰M†f?ÿü[ÆôŸ °ÿÀncøûû/Ãß_2B¬øJgL _¿üeؽòö/_>²20ÜÙ @`üp aàX9ñÓw¦-W 5$%ÄÄ€ñ//ÎðõëO†OŸ¾1¼yó™áÖ­Ç =}›Òbyj?AchÑ_þq(Œá4Ðq¿ÿCä?ýdÐÑUÔ˜5ñÅž×÷_Ee $ þƒ¢áÿ.eF e3†ß¿¾1lØzˆAMQ†ÁØH‹AHX€AX˜AIIŠŸŸ‹›››aîçë+lÕÞ1üúÍIÑ Ï2‚| 5h(X (ÇÄÈðÿïY“ e ÒÒí…ì»J8â æoN²RÚš’| 6ìü÷ùüÙ·¿CCEedÅØ9ؘ™™XYYÔÕe88X¸y|Ž`à`œÎàäöãO€XˆAI˜^î1(¯*ñHòß´à1Ç SAV ¼D’’m”W–üøñ7ƒ¤ð+&¿À[¢WXÿ20111üøñƒ………áï_`)ðç0ZÄ€¡ô‹áñ3=†K4œ~Ì¿ _®íb``ça`PvFíU†í«©K6@wÅÏæÛã ÀÄØ² €X ðß]ˆ=Ž—‡‡G€á‹‚+Õ¦ ÚZF ÌL~-YÂÿþýcøüù?ë7ïÞ¼ºÍ«~Žá@ÃÍ ÿ~ÿ`øyé<ÃI`Ðrugð»~™áíµG u@+^ïÚÅ*.Ê`qó!CÈrh,1Øl󸸘˜99…€àcPQVúœ‘‡› h!3Ã÷ï?ÁÏ v3301~aøöõ0×02lÛ'ÁpméçÓ±‡±0üøÇÎðç 0þ[·•!høy.H$0|üưúÝC` úä?4Ÿ‚@A£€ñþŸ?ŒR7n\dÐÖ6:B˜þƒãýÇß`ËA>ÿõë7ÃÕ«÷ddDäåDøøL.óJ2üÿy˜÷ïçϪ, ÿvÿyÿ†éõsÎ;×Ö2üý/˜!ø ’å @à¢8,,‹}??K$77;ƒžž5м@GüZÎvˆfffûþõëO ‚‚œà´Êß/ü‹®2\¾z}ͯ?kYÙØn0}|ÇÀ,[À–|ûÂÀrñ$#ÔA ØŠ Ýv@xx8Ó°²²ÍäåeNag–zš& ¢¢@‹ÕÓ?`"df`ggbPhÓÀ«ÏÀ”ü‰AB‚X^Cç/ÃãÇ/NŸ¾øùþý½Œ,,},lìŸá>:ˆÂ,·.ƒ-­ŒîPÞ±YXX{ùøØŠ˜™ÿ€Óƒ¤¤ƒ””,8îß½{ ´Lô¼à<ÇÂÂÉðâÅG å?€jxy¹¾|ù ,¬îráÆ›7ojÙØØÖ€j[&`Ò—Ocxõï4÷ÿg °¢£s ì7¢‘ÀÄœÎÍÍ•ÎÁÁlÈÌü˜H9ØØX˜ìÀ‚ˆ"‚‚B@‰3üþÍŒ–Ï  çªc:ö3Ã… ×.]º²ùÇŸ5@ý—@éè-0$®\8,ÞŸ‚@`ÈÈ(188x¨;€Šå£3''G"0]øðñqó¾{÷õ6ÐÝÿ¤¥EÔüøÃÀÅÅ !PÎá…ƒ€€ÃG`rºXpƒ«¹§O_3œ:uþûýû«!ÑòÈ!·€QqúôA€;D22Š 66𨀈€‰Íãÿÿ[€ÜwÀ,ÿ÷ᅦÀBJNTT¸XBЉˆpñhƒË‘¯_ÿCåÐLÀèâdøöí7ÃêÕ[>½~ýVrAöïÒ¥SîÖŠîî¡àRTâ-$\·ÿýËõçÏ_)S&&Z‚ìàè™ÅÁ!ÌÆß€>þÁpåÊm†“'Ï£g#LïòåÓÅGˆ1hiƒVh´ôû‹È·@µè} PËŒ..®  ÜO  ”TT”€fðCƒXz~dX·n몟?†Ãì9 €XÐ}ôîÝ+†#GvƒØøP×G Ÿ8È@àÏŸßàø†Y sÐâ9Ÿ?ž •ê—/ß;ŒNN. ÃÛ· ª›˜ÀÁL@a„F«’’rÀÔ- æß¿“AQQÌ•VÏB`‡€*-Dˆ€B興ˆðÄß¿_ÿøñÓžß¿ÿæ„ó>¼ùþòå3`9ò ˜@0ã@wÍhÀû4à w@ ¸ .í/׈³Å IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/noatunstop.png0000644000000000000000000000100711550446574023435 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<™IDATxÚbüÿÿ?Ã@€bb`@, "‘‘H-b:Øùˆf10|…>@±@xÔé`ûY ~ÁÀà ¤6ñ_€‚9@€Hx{x0HxzÒÌòÛ·3œÝ±ƒá#ƒ«ÄwˆYÁß?~½O3€ÌGÌ  €Pðý;ÃoZ:h>: üz÷Ž® Ì(øð^Q„†( aüÃ4‰ 3 Ð9Füûó‡føÅl€bAWðŸ†ÀhÀ+#€pЀ; €Ü4à w@ ¸hÀ@,计¥‹þa ô&  ð ‹@± s8èDW` €Âp;½]C›&öá3Ø1Ù €`Øð…Ááƒ,­-&ÄÏ·nÂøÄêŸ122Âø:4NÈà%Ðî'„îPQÀI'|Ù `ãÆ~ò B‰pIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/view_text.png0000644000000000000000000000333711550446574023251 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<qIDATxÚbüÿÿ?Ã@€bb`@, ‚‘19‡‹©Žƒ‰ûßÿÿAbà€a1Àˆ&†^ÿÐäaúå1ô12þýóáÏÏ¿“þÿŸ×@Œ (àãM{ÚØ/Å+/ÅðõÛ†¿ÿ€jþuý:çˆþÅPö¨²Zý™”2Á4H=HŽ…‘áÃÓ× æÎ{õëë q€‡7+—„Ž2Ãq öoCY bù‹0æ˜å‘,ÿ‹„Ajƒèÿ¨jÿmüÍ!ÈÀÄÎÁ ² €Àø÷éï—/Ù?AÂdà˜¯þ£Zþf0L)„`ìÿPõp½PÌÌ4ÿÇo ÙL ð` H`bbøõ‡‘aåš ß?~g``ÂŒ_là?rD#304‚¸L@ñÌl Ò²|`;A €X ˜>|ýËà,õ¡0WèÒÿ 蹓'?€)ýd°ãáî— K®ÿ&Ef°8@±@\ÇÄð˜J„ExT•„i“ß@qÂÈÈ )þ“áÏPp@B € `d‚¤Ò¿àhaøóçÃÏŸ?Àîå¸Y©êÇ(Œ’ý8 ö?`ˆ‚|ÌÏÏ ÌiƒD30ØáñvúÔY†é3fƒ-9ÄÄĘ!77nèõë7úú&†Ý¨©âÛ·o ÁÁA@ì–%ÌÿL( h0‚Cfœ„¤ƒ««ØPhÈÉÉ „¦°°0ƒ““3333j(Cm†9à?0ØAì_¿~3ÈÊÊC¢”ë@ ‚’:â`pü  ¨(Ƹ€¤¤8CLL(QQÿšmAQöÿÏ/p¢gS&ˆLàüÎNlz‚ûôÿÀ¹×PþûûàòïÀB‹@‚b5@AC€âªÿ„,†Ä+#4ø`4(&Àåýˆ£@–AqÔ¿À4ö÷ÂaÍ`½-€q Œ˜ý_¾|axõê%P X777ƒ¸¸8TUUaèìlCJí°¸þ‡ÿ 4°òùýXð1ü:œÿC²>J"üõ//£¦fD‚ãââbÐÐPò‘Ý?hƒÑÿáüŸ?òš3 ¹ €à%!(þgÄLpè©$ö‰ òfÌ·°¸É#âÿXþ°Qðÿ;´ bÛ  f&pÄ€Ô@ƒÄ)"µƒ\)†ÿŒ™)¾YË 1BÿÚñž™ Q@ˆ4ðQß¿ÿáØ±ãÀDÆ´ø7ƒŒŒ4ƒ­­-ØÌÀüûìÙ3†ƒÓ,@¢9G@Bä¨_¿~1¨¨j0XšèCá?¸€UÇfh=OŸ>gØ´i'0p€K0# ìÀ3CëÍ›· ;vì;³ìgĨ@f°±ñ0ؘé#Pj"„™™ÃÌ™ÁAò¨ÌùÄeKe`eÔ‰TÚýGI„ Ú9‚£šÁDʆ„’aÁÂÆÆÆÈÕíŸ_þB$3°zfgÃHõ ôìPœÿû ÿñó78¨˜ÁÍ"DA@ð9àû— _>gøý÷?¬‘ÒÖÅþƒæýÿ°x‡ÒàøÉCsX ÂfÙÀ¦ßÏŸ@ANx¬.`âåeg8!¢÷>Ø1 ‹a¥ã¿ÿHmDPÊg€Èƒ-ƒ6Z a„»–,þ!ÕÌLß^|:„“á/´" °~ÿcüó˜°¸å%Þ}ù ÖkÃ[Á Ðæ5RkÆÿÇ€Ô2FjA£›n°010ýx\€;à×?†‰Ç6ÌæMPxbkÝbôˆ°ñÿ㗇nj:`êþ³$@ŒÝ9 ïœЀ; À¹ Uó;ÚMâIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/next.png0000644000000000000000000000306711550446574022211 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÉIDATxÚbüÿÿ?Ã@€bb`@î€bÁ%Áh2Ë HÕ1|ûeÈÀÌt‡ƒe2ëf6 F¦ald>šºÿ3y±Ú@¸Càßÿ™¬ÌLÞé‰&RÆz’v Ÿ~­døû"PF€š!@ø ËÊÂĬǰb²7C€¿ïÿy@Gle`dР–_ø´ˆáîÛß ßØúkšJ­xØØ¬¾ýÝ”‹¤†·!Òÿ˜:äCLÃŒV{yyAI†/2ügl*ä¦Ä„ÇÌ,ÿ™Yþ313üøÇÀpÿÙG z:â ËzìœìåX¾ý«bøûo#Pµ¹ Ü`e½õýdž{î3|ùÁŒ~†;ïßc`øÏÆÉÐ_jÄ“ ÉÀÆÌê ”< ±@r@¸ÀÌ’ ÄçV/¿È0iÊI†×ï~Cƒáö†7î}`bÈ Wd˜P¦Ç .Æ- L(k€QÒÔÉNŠˆWQÌh¹˜Yy¿áçÿt!o}I ýæ#P ˜FLäÌ^¾ùÅкø1ñóÀxâbÛÅÀÆ– Ìÿwˆ)ˆPIøž‘1ƒ›£ðÍ«¯_Ö®<ÇpâÔ“_}a`XaÝy6†îl%†(o ff7†?Œ»J¼ˆ €"H%»90WÌbøÇ¨'£*Í ª§Äðó ÃG CÔ%ÂL”EvœþÂзöÃûO ߸ÙÚ˜Y;€úÿà €"Á š]”‘¥—á/C,·ˆƒŒª<ÐûÜ oQ" ,£,lU‰õño†þŸ.ÞûÃÀÀɺhN!бÙ@¸`µ h! jÙv+È!‰ÀxèafaRg`äàaxt/0ù…á§ÌDLÿæïýΰêäo >æ#ÿgòØb³ €pVF bj@W0BJ$0e ' õÏ¿ÿÝþíç† Q&HV¥‹/@;}ôÄ…YÅÉPY‡Ë€ÂíF&hiȈT42rëˆZ`”ê«r3ä”`xò•›áÐBn`-ÅÃÀ Œêë/ÿ1œZù“áÑó ÿ™™O]—‰Ë€"¥=  ôêFæÿŒþvÂÌž þr3üù ´œb±0?Ãß?îÜýÆpïñ¿ÿ˜Yf-÷ê½€ËP€b!Òò`†ßÿûyxXeCœ%>³1LØËÀðh¹/Är~`ðþí†'Ï+LæÀöC PßB!–¡X/ÖJIq±:˜K3ÜøÂÃpâ&0Ι–cVˆ9Ùþ3<}úáõÛ? ô2°“ÔwŒŸ>HñL`|{«ª 1¨kK3ìÄÂðü5$#ðã[hùÿ¿îÝýÎðí;¸þ˜L¬…@ÖGbã €ð$BÆyÀ$ìÆ+%ÂÀ*.ÁpäÃ`¡Ã ̉‚<÷õó†—/2üùÇô‘¥¨i*P'IÍl€Âãfc& m‚¢ ß01|Öˆì ˾æaÿÏðúåW†÷@yœõ*0ÈÓ:ŽBìf$©6 <µáP[à 0h1@,æ•¿ž<þÊðXUãb0»–‚ªrÛ„ÛLÀÆ# Ã?Œ œ\`ÿýý'ÃÛ7_m¦oÀønú¶èë?¤úž6‡€!ÀÍÉÈÀÇõŸáË»/ ?þ…Ìm \ 0´Q`/ž&Ë[P(0ýùÁðXÐü²œu-°`qÊ¢V« €˜ðDAвŸÞ}õýÇ¿KÀ /€¶„S³_@ŒÝ9 ïЀ; ÀÄž,´WX:IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/misc.png0000644000000000000000000000544511550446574022170 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ·IDATxÚbüÿÿ?Ã@€bDèèXÀÀÄÄÈÀÈÈ–fddb¹‘‘ñÿÿþüù d33°°0Eû~ÿþsíß¿¿'€ÊOùW™™UT$1èé™õÿgððë¹wï&Æ KPìy €X45 ÐÝÃô÷ïß, cÂþÿÿ× äï†Iüýû/C__[^X˜OþÅ‹·žïßdøøñÓÛßÏJW‡„$0033=ðû÷/##+†«WÏ3ܾ}Å€b‚1ÔÔt á@ßš-ß'##5ÙÜÜЖƒƒs зIË›sqq9ëè(3˜šª1øúZ2DFº3XX ?þ2 ÿþªû 5XÈEE¥3ðññ£8 €˜€€ÁÏ/š!#£ŠáׯŸàhjhâáá9bnndïáaÅ`e¥ÍàädÉÆÏÏ7èˆí@_­:ŒIL a++#77;;7ˆ-¾A槤£ˆ‹±± Ðg†oß>ƒãŸ.@WÖêêjƒMŒÿþgPW—aàà°exùò‡˜˜ ƒ  ªa,L@Gð‰¨«ë:¹›þüù£úïßïP`lkÓUPì-;;;ƒ‹‹/ÃéÓGÁzˆÅÙÙ—áçÏï`33+ Pa…¨¨(ÃçÏßÞ¿ÿÌ $Ä N„ÿÿ31Èɉ3(*Š)ö---ÄàîîÄ)**²æåËçøùôTU•8¿ÿÉpåÊ%> ?`èþ‘`Žë NN.¤TùOŠƒƒÃ‹‹g=zŒ3.P4T $‡033`8„››ÁÆF›AAA’õéÓWæJJ2 ¢¢<@|gøðá£Ïƒwš€¬¥ii9°€b%DÊþûèÓ§;¾|ù¶è  Cþ³ ˆ r$K2Å€©û?¶bDFFˆÁÜ\l9 r2xy9ùb5@n++Ø  &h~új'0oŸ:BëÕ«—à¸úì[ÅÀkúüù+ÃÍ›.\¸ÉpîÜ-†‹ïCê5Ãð8ââ ÊÊjÀxW{úôaæÕ«‚ňâó?éRRŠnÚÚjÀTÌ Î6¼¼Ü`6(+ &&&`|,PžSóo ™Á¿?~axñâ=ƒ’’$ƒˆ/†åŸ?ÿ`8zô*°¸ôwÇŽµs>¼Çnjjý $@,À ãääΑÐb.x! ³˜<>}ú LH÷€ôg ¥ß@¹…”~€YˆyÁ޾wï0”¤„…yÒÃùów¡uöÏÚµ &-_ þnkë–  ï€©U–ƒƒlÙ¯_ÀA JŒÐˆ%¸§O_ƒûüï'öízðàö©ß¿“PÑÖ6r××7•WVVæ>†çÏß=Á Ì¢Ìo––ÀÐ{òíâÅ3sYXX_ËÉ)s¸Ìa `0è°±±ƒ9ß¾ý¦d&P9öÈÿþ1‚⇟._>}~ëÖÕ© ü *WnݺÊpâÄAY33ÛJŸˆLS11`”|†&"*$%…i@šÏÖÖ%WAAi¢ˆˆØÍ_¿~刅‘ñ¿:;;¸‚yüø5°°a2‚‚@!rÐß@ÆKPI “f×ÇÇŽíÖ ?¹¹y øøLÀ¡ˆ øù9‚‚¼TT”3é ñÝ»WÛž«J] &VVV}P\‚²(Qýøñ‹áõëÀ,öœý@C áf/EM FÁ°°x}} o%xx UTT­xðàÖ—/ß@Cá` É ¡!ÃæÂžžÌ¡¦¦xåÊyp½@,¯_¿8çÎu áÀ¸ãc…ÈbPt°±±‚Ù ‚C\\X[ê‰ÙÙ¹HIÉÕÊÈÈ}ú—ïÞ½†˜ÐÏïß?o}õêU>ÐOàÄLÃàôƒ\àBîÞ½Û hd –9s&ø ‰ø¨«kGš˜Øx˜šÚò ‚³(ÿƒ‚”89Ù€…‹ 0-¼­~üøîwff–> G€BNJJTœ«02²8ˆˆÓ'Z gÉï oß¾føúõó= €X€uõß—/Ÿmúv#0*¦«åLyyi`Ì ~XÃä÷oPY/ÊàééÁxøð‘Ö»woFÿüùm7PÍ  @KK!cpCähPЃJÌçÏ߃= ѧOß³òû_¿~y r@ "==c`uë)ÇÆÆªˆ@ ôÿÀ%"(8AŽ¥ II†À@_†'OL´ž={¦õãÇ`ÔñÓ€ƒ¼¼$¸Füóç/8€Ò(÷€,5L@¥éÍ›w…Ö£g?þx ² €ÀpvöÅe¥ªª®×/_‰‹ šÿCŒ`6È G©¨È1ŠÐЉœß!uÇháõÜ7n<W`ÀÄÌžŸ®_?ËpäȾÉ@³@!Ç@,**êÀ’í«‚  Xª¸¸$Ð’ßÀBã5Ð' ß°sÅw`‚üÎ À .ža!óÿÿo E¡5%#´¸†µ%A…ØpyòâÅ+†3gŽ‚ø(Ï|ðàŽõÏŸ?[*v@ ;;Ͼ|üøö.°&TÁoß¾ÆÐÇ¿@Áüýûw`Âá–jค$²Ðr‚ )Õ3BC 熆š §Nø¿~ý’ÎwïÞüôéÓ# äkX¢ ¦%Kæ€è7kÖ,‰¼páØWPCÔjaffúü¸öùä;P=*'`åÈ"P|üø•áÍ›OÀ‚ì%~­¾!rBBÀ2ÜQVVÁðãÇ›€âöÁÛÄm2¼zõâÜæÍ+³„jk›-{Æpÿþ p;NKËX´Š@Ó#´jf[òóçopË Äf- ’âA!õíÛW†gÏÞ‚ÌU`?¡mÅ_Èå@!¬.¸ÿÞ¢íÛ×è=}ú öÆËÇnݺ¶hðËr—`-ccp!*#@¡*¾A!ª’Aé„ œ@Aièׯ¿à(¹{÷>Ãñ㻟Ÿ?¶¹‡€;àìÙpÓ§O”œ;wz!0€Jªw@ü˜>>|øðj#¤eûìkVVfp¿xöì© ïߨKõè €Xˆé¿]ÿæóçw!ÅÌÏ/,ÏÁ•ÐíÛ×–ìÛôæÍ»å ”½}ûæËÀ,½ØêU<~üÀì»wï-ŠƒŠÜ/¸Ì FbÍxèÐ7`Ðz ‹ª‹ˆˆ+‹‹ËH¿{÷âýÖ­£iâ,~i@X~èþüùë*´Ý€³±JÄÄ@¤PZß Xáà`wfW7 [˜Üž1ÈÄ8ÐÝs€?Æ·l„š)IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/reload_all_tabs.png0000644000000000000000000000470711550446574024344 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< YIDATxÚl‹Á €@“ÓníÄÕX?‹Ðä¢{Á!ÃÂÒ6¸ÿ䮌[d©Ñ_6ˆ'î¶B“#Ò¥fàúó~¼Û%à#fÒgøó¯ƒáû×µ@㕈5 €(s4d@!ôãǯ8ÛX†8‡¤@†/Ÿ0üýKŒv€¢Ü  ý âßÿþ*‹(2,ÌšË01u–$#ˆ_ûÙðé "maøÿO“áÏU†¿ Ü@ÿcøp0þføÁ øóûo†OŒ¢¼íÌ•÷3ÅML*¸õàª6§0(4^b3 €ð;àƒ"ïÿù@Ú•‡›_]VX–™›•ä°4ð’~|ûÉ $¤Êð–á9ÃêßÝ ~ù [w2„¶Çº¹xh#§`PÇ t+ˆk.`d`cøÍPôm¥›¶W–m6ƒ‰Š;'#Ã_ g±& dbdb¸òçÃÞŸ‹Á†¸ñE0è÷enŠgØwfï N!/†ÿÿß#ç€ÂæN`pÎ’’™5ƒÁNÏŠáÔ ¾eøðç5Ãïÿ¿ÁÖáJÿÿºû/XÍ÷ÿ_ìx|b¼+cÎݾÒÄÀÊ^vÀ¶`„Ì@ŸÏWWß™³“áÿC†ò‡Ñ ~¿føtè Äi7°1q0p2q‚óåï7†£?2*§3hÉé0œ»zA…™E=@± ¤æ?ÿ#E8EÂ×&¯c¸Îr’aÊVf&†ÿþ2Èq*1èñš2ˆ±J0 jføûç?ÃÕÏ.~9Åðóïwi9†jÅI 3W®bX¶sùNžéèÚ9„¾¯k lf`üËÐ~¥– h*ã_†,ùR;N/†‹÷®1<ÿð$ h´âï?¿,,¸øV=]Âà äÎС8añú- 3+}žTÝ„pÀŸÿž*Þ:^ Õ7óÞ~ý ¶ AµƒAã‹)CÀô†ÓwO¾`øó÷¤(fbdøÏ ŒŒÿ¾üÐ)Ѝ4õTdðg(•nbh_0“¡gõÄ/ lÜé LÌ«áñ÷QüÂ?œu]ïþ¾Å°ñá6pb ‘a0øgÍà<Ñ™áùë' 8x‹˜þ¿…ÄRÙ¢Ù™·ÿaüãá+È ùÔ!¹«„aljm÷8Ò€–ï[þªöÂÄ‚”t-­~þùÁ`Íg zf†lù†•‡V€,? Û eÀTLá,@ƒ~1BbdØ?V# # Ãæ£û fÕ2¼|õ|3p60Û=´¼@„p#£ÌãO”ß©0äðARñ‹_ »nìz–u0Èÿ00}ÁúbÐÐß@Ë¿pB“?ÃÒƒ›ú×Ï}÷T)qóu30ÿFXü{m @ˆr …ýó?&¦À¼)^ÁÅ쟿LÀ"¦ hù Öß°ÿÇ$ ¤ŸÝøŸą́= ¿þò10±d00ÿ?ÇÀgNh†<íüù¿ïæ.€BŠFë¿ÿþ³ü•òÿþCÒ ˆ g`þ q†¿ÿúnrlÁj>Ëb`fy¤¿-©õª]Èðýç Åÿà`daa`ãF ƒ1H@!gÃï À¢ùöJ3ÿf·_ž@ÃzyxÄ4¿þøy^‚ÔàøÏt ¦õ¿~‹È‹É OÊjL\  €fdùÏpîÎU†êé½ðT@,8"‚Yþ€€‹áû÷:6f޲֨~FF&V†’Ù…À´À̺ÀR ä[`ò3#¬ÕÌž_?Ú:jZ3øYÚ2ìú¿˜«~0X2¹2ð°[2üýñû=Ì*€Âî&xI'ËðåÛuI-·i³´­fîY´7@‡€Ó –j‰áÛ—l.Nþè,ÿ†?70¬~3 XGücP’6`8~ñ0Ëÿ~S @`´óþ›2|þ±ÄÛ,@maæ|†Ë¬ûÎÿÙÏðïPêó_-Ž/+`‚&,XBû¬.•¥…¥'ô3Hk°3´>™Çðï/ƒ°—ü§Î°jï$`´±…Ù@ȉÉîÿº ß~lŒuL–œ–:aíÇ™ +Îd(“ïfpRw`¨Žoeaáƒ7R¡ø0+J*2Ø™1üyÍÐ|/Xƒ~døñï;CœTÃÉã·N_<÷ X¯¯‡Y@,X*`±º6Í-G²?±ƒ¡÷q%Ãáw»µ'éWÇl„x|CmÁsÀ4ðæ×s†…[.\=ÍÊÑ?ÿþdð“ˆ`0úãÁ`=5X±1̪¼Ó@ˆr šz¿O6S²ÎÙQµ¡ñ~>ÃɇøYÀr?>ùùï¢ÂÚ,ù®¬@X“FÈ$0D æ1Ä×–3¬ß»ã7 (ÿ‡¸ €PÓDèý篟¾~úÎ À ŒïÀ¢œ˜€A LH PF|L`âäeæe04eˆ–Nføóœ—Á½6•áøi ¼ü@÷}FV@˜i€™£ûúƒËö Ó3ì–eÌc`ùÇÉ0÷ÑTp» B,žÁ[$á7°Yƈžò" G²1²3ðüãcøôúÃôÛ–n[Ëðþ0Áò Õa´ 3 üÿÿ™“?|ï¹[z"Œ¦Ïb–e¨ºQÊ Á*ÅðöæO† [¦2°±r#õ”!æ†ï?33ÔΪxÌÀλ‘ ™a=$& ûÛC`9q˜Ø® ×ž€¤€ÂÝ,ÿÿÿ0$¼n<¾ÕçÖ”ÙZÍîÉ0…u °îç½ËÀÁ]±¹`D°ÁÿÇ“`! €tL€å';OÖ÷_ÿ.”ίi=ÿðŠˆ ÐLV&pÃ\îÿGËŽ„-EDDÏh 3Ë,–ÃËv¯ÈÈÊåÊÀÊÅŠa/™ €ˆìšlbºÎÀÁåýÿ/s%°Y¥õ&ÅN0^pñŽÆWÉIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/exit.png0000644000000000000000000000461611550446572022203 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< IDATxÚbüÿÿ?Ã@€bb`@î€bAæ¬fdÄ©Qÿdÿ008üf`0²5€bb@šé/Ã[ }¨äЄý@ö Ã4 õHÑ@,ĸ¨\hi>öU31bàURb`çåeø÷ç/ÃÏwoÞ?xèôìÚ †Ož?ªÝ Ú‰ 2 €:è“ ZdÍ ÅU’“Ä]ݘE%88AtÒ—¯ ïß10<{Êð÷Ùc†ggNË\Ú³'áÚ…+!@é6`ˆôù…Ë|€bDÎhQÀ ôI''7G±aE1ƒBv>ƒ (DæçO†'§Ï0œÝ°žá/­cdÄ ¬¢ÂðçÃÖŸ¿˜Þ½d¸uøÃî-;Þ~ø¼”™!±E@á F †.^~Þ"«93„C¢ Áñ—áÿ·o øøŠå b@‹9N¬^Í ÆÉÉÀÊÄÈðëóæŸÔ Ì8¸ÖnÜýìõ;V†X µ¿Ñ- ¬¹ä)ì¼\…Öóf¢Xò9ȿ߾eàZhÁ`ÄÀ'"ÂðíåKÆoß¿gøùõ+Ç÷DDBœùxÂqPó¥( €˜°$8E ¢£ÒBF¡ H¨‹þñW %ÿü[ÂüçàƒÀÁd3Å€øû‹ ,@ù¿?¾3¼ûtƒ§>Ãf¦r ÷-Ñ@,èY ¨¨XÎÜPL>¯a9œ›1ƒáÁ©S RŠŠ †žž ¬@qFhšaÆ)Ëïß Wfxøå ƒð§O †jj €zÿù3ƒ&/ƒ¾ŒûɇOŠÙ‘ €˜Ð‚^èo•„xF~A`æ¦&&†s&0¼»ŸÁ¹½á0*îíÙÃÀÎÂÂðèóØj^^¾Ìð˜-=æÍc`÷óc8sä30$¾£ì×‡Ï & ÌLL®@õí %¤ÄÄ„8þf- %Ïwîdx}éƒ}[¿Œ ƒ˜ŽËӧX¾å P¨±ñ‹[·„ xY2°¸»3Ü¿põ×/†ß¾2pñq1H ð#ÊÙN€Bw€‰˜óÛg ?: þ½yÍpwÃFÝôt&†W@Ÿ.[Æ akËÀJ@Ÿÿg™? *ªª ïæÏgx|è8T ËÊÞƒþ70ÝFfï‘J­û·bA+÷ßý–íÿ…Àùä:`Ê…ø˜â?ìß …§@‹Åþ?~Âð´·Ÿèë?7®3üúõáãë‡ ¯Ÿ?gº5@G2õýøò°˜øõ”ξ Û @è¸ñáåkGF]E†¿\œ Œ/¿3ü{õìn`¾~ùôÃë/þ±31üíûûÁõ /ÐT E¿þëEepõû÷͆ÿÀPùô3 07|•3í ô’ðü³Û÷þ2²10ŠH0°€¢áòE°x,­ø-í~+¿Lÿ€¡ò—M˜Œÿ½ñ˜þ|&" 5~w7p¨ýêý̆lÀÄÇŒ¦'@Ý{ÙB€bBãì}ñèÙóŸ1p*k20ò£uóF`pÿââ`nne`ã`øõd!¤Žýõ‚~f`àgbcPnicø#!ÎÀLõoÖ®cøJŒ\Ü ïüb¸÷íÛ [w"Û @èåÀ=`íºvô‡œ»²û¾öõãìæ Êë60ˆé[0°¾¦¦×@ü À2K^U›AgÅ F__`*cdø9g.ÃC`ÑÍÁÉ ÎÉÅpéÓg†/ÿ­9l'@¡´& 0¸õþ02õõá‘áax°y-Óóß ŠSf2üKOeøÌ~ìÀ¸ý·w?Ão`jÕ¬ÊÊ ,N ?@Y˜h¹6mb8Épççw-1†/À„²ìÕÛ¿þÿ÷æšóì L€V.ÀtTÉ+À׿äÅÀþí=ã}û8ÞýgP*)c`*Ècø&&L'Œ ,ˆÄ Î[ÜÀˆqî<†‹ 7?bPbà¶V¿zËðøÏŸéÀ"; ¤~>’„â€^D‹ˆ˜ÖŠ Ey¸Û3pS×Ó'þ=üÈ ­¡Î ÅÀdjÂðO\‚Øa|õšáÿ¥‹ ¯V­d¸~æ,Ã{6F` ж oÞ1Üùõ{° šû Ý„Õÿ!阀fòñFØ›2H ò2¼~p—áí½ Ìo€¨be׈?~ýexä†/¯ ƒ4ÃK`É·ã݆G¿ÿìç``ˆJ?†Ùƒì€ÂçfÖ^UŒLLåš 2ìÚrÒ l, ?¾|bøòñÃ/`ÿ,9òà|Τ?S;(Áýüõß·ÿÿgƒ½æsl Bc`ΰ:¤€•‘ÑMZXOX«*PÙ*^A%Ü`ãã °î¿÷íÇ/ÿÿ¦IÀ,¶[“ÙD”:À¼ï ¤ \PÅ*Ûü {d_ÆÂn ÜñÿzŠˆq ;§4à}C€p‚¿š…Zµ«ËIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/project_open.png0000644000000000000000000000310311550446574023711 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÕIDATxÚbüÿÿ?Ã@€bb`@î€b15vp‹Jæs²3süû÷ˆÁÑóHÿƒÒ@þÿÿ 9( âÿƒÒ(â6Ø 4³~}þt€á÷€ÿïâ>Ü‚ây½ jœ¼ ?~30üšñˆÿü…°!üÿp>˜ •‡³ô_¸zT6̼¿ ÿN/>ëðáêM µ{Im)€ ÌGFtÿcv‘\I}ÈЉÃg ›4›D+:a±Š«=ŸYdïÌ…÷0B‚Hè7…„ð뉒¼˜‚ÐÝî`Pþû´ù?PÓþcÿCà?ÿPùØÄ°©a&PL€]v@!ÒÐ'Ÿ?ÿfxùæ #Äåÿ!>ƒaht¢ðAÆ013 ’cý‡¤¦¨ù³ 0 ¡ÁÂÀ@ñ‡ß¬„ß3¨Is2üþƒV>0¢P€‹$2äA¦³0üú‹0 €QJ¡@Z^AœAEá×ïÔÍoŒ ÐùËÀ~úÿ?Ðà€BNà`çåãfààâdà I®ÿL„ŸþýC8 €Pï´,šÿÓÂh™± €˜C”_i þóî¤ &ä4ð÷í‹^HnøÏ„´HèÃJ&€BrýBQˆ00R.øOTxñéCÆÒL†÷ŸÞ³°Hý*T˜ å3ýïÇw_ó †2Ÿ|¬•ï äD@,¤†À¡Û‡îºÇÐÓÁðí×wH‡º›…™…áý«O í«&3d»¤0°²°¡‘ M„Ä8€è[NvVÉ_ ¬?30‹8F ÇÄü‡A™GXâ±2x4‡202,c‡ Hßß?_î|±c`c6gøõŸ ì€B ÿx [X 21üþý“áý·— ?ýfø dÿb  \ÎÀÿÿCijÃ÷_ßEàã€ú>þe(™¼žá×i`p}[@HE1q!Šïß1|ÿû‘ááËg ó×nbbê‡ød3# $m@}KÌÙD˜¾Û-gxúúQ#CÙ6€bA*!ˆJ„ŒÀøóç7Ã×ßon>»Ê Â)Á0;cÃÏ?¿p—¢ (·þ2|ùþ…AŠ[’Á¯"C$@$‡(¨ÿýÍðéç†ß¿2|ù=¦‹ ˜ÿB U&(üFÙÍ×wܹ|é„ý'H €°¤ÂQðèÛÏ?ß2üf¹¿þ0|úþ†áßßÿxë°~ÿaøùóÃÇïïÍ5ˆo£6deÁßPfca‡À ¾Cà7°á÷à2ž€~ðý÷'†¿ÞÛ’µÄ‚ìµ@E^}ægF´: ÏÞüjþÇðæÛG†Ï_¿Cƒ‘áÓ¯7àGعã3Ãûïà!@püûõ‹éÇw†ú­ÀøóÒŒ• Púß?H&|óØdùÇðôÓ'†÷_~À †ÿÌl'9ß~õÕÿ5™ €àøóåcÕá9‡“™™ÙÑÛú Ð>ÃV†ÿbG9…Åžú؆dúÃÁðù×[`ACŒþËŒï o¼6ù !@ȉ°ëß—÷ý@¯2ƒý?Jõ‰ˆßÀ’Íb‰Ç¯_ÌëŸðý3 ;0H?›[LÐâý?00|æ„7ß_ÃC €XP‹9¦ß@•¿!€:ÙLÀÊ ÊM@öç? ¾11üâüÏððýGFDƒk^•GÀfÿç ¿X_À  Ò—L÷=c}ÅüNTˆáÃÿ/lޝúé½ÀjÅÈ5$ Tóï70§}düùžù%È8€bèî9@€ñ¬‘_¿G0IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/view_multicolumn.png0000644000000000000000000000415311550446574024632 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ýIDATxÚbüÿÿ?Ã@€bb`@, ‚‘19‡‹©Žƒ‰ûßÿÿAbà€a1Àˆ&†^ÿÐäaúå1ô12þýóáÏÏ¿“þÿŸ×@Œ (àãM{ÚØ/Å+/ÅðõÛ†¿ÿ€jþuý:çˆþÅPö¨²Zý™”2Á4H=HŽ…‘áÃÓ× æÎ{õëë q€‡7+—„Ž2Ãq öoCY bù‹0æ˜å‘,ÿ‹„Ajƒèÿ¨jÿmüÍ!ÈÀÄÎÁ ² €Àø÷éï—/Ù?AÂdà˜¯þ£Zþf0L)„`ìÿPõp½PÌÌ4ÿÇo ÙL ð` H`bbøõ‡‘aåš ß?~g``ÂŒ_là?rD#304‚¸L@ñÌl Ò²|`;A €X ˜>|ýËà,õ¡0WèRX DÒŽl #.'1"‘¨.ødÆÿÂÝ/–\ÿ LŠÌ`q€b(ebø L%Â"Ü ªJÂTÎhÿÀnùŒ&fIñŸ ®€‚q#$•þ…¸úÕ–Í o¯ÞføÏÆÆðóÛq S)gg¼QñùâE†gÛ÷0üaaeøõó;‡„ƒRd$0³0üfƒ¿ÀÀËû˜#€ìÿÌp$ ˜˜ÁÎ ˆàÓÙ3„Mß0°ò¿dx÷æÃÍy>X𚞯XËÀðz3ƒˆáO†ß\Ï®,ec³waàW‘;¤+Œà„ùŸ  Fp°@ æágaÕyÇÀ(ñƒO^ˆáókv|É ØX™„4¿2ð병0óãì ÿ~þ§& ùÿzþ8Œ€‚8 `c,?ß0ü}ò˜å0ø>ýdàeba8séê¥K˜IYLLŒ!??bÿAyŒ™‘ù/0÷¼ºÏÀðèØ/L œ?…Þ¾{Ï0­m-0g}û<'+#œàDþŸ  F0 )v¨‡˜Ù%/ãc`àcaøüå/—µ4Ã?vF!!^°oøù¹@%(#ã0 ÒÆ&*Áðf¡û3L ?™þ3üfgàåçdàåfg`ýÏvÈÁвb5@AC€\ZÁjF©®i ?ž¼Ç“ P‚KAhƒny "mM%,°` $&3pظÐ, _Dˆ‡CFš!G-h!0ñŸÙuÀ™×À|Á €‚–,À4ÀQ` æbÌD÷Nƒ+¨P"càâbà0Ñ‹ýùý—áÏ·ïÀñ è ÅÀr™\ú‚KDh‚ D Ð,€ ³âP(@õû7Ã_ e qPè€ðp± %8ÿ?´ÆdÛ wÀŸXÊO ßC ý÷Â†Ó G°³£Ç ²‡(öëóg¸åÿÊf°ëÁn†fC€B$ ð¬òþèQ†wWï1üc*?ÄLuDŒŒÀ• Ì!0´øëÍ[ ¯÷aøÃÈ vv)aqgGp–û LG ‡€1´Z†æ€‚—„`W1C‚åAO7·â3áwÀÄxŸáʉ@ÇkþCCæpP#”‰‹áÕ² ÿïm`àÕþÍðëß3†Û³¸x´1pÉH€£9Z@ŽúM f&H nFUûO ŒR_¾¾`¸°òD1ÔÀÒ•áû÷ŸˆP¦Af Rf¿øLÞ10ˆð0¼½ÉÂð÷ûo6vF`"ebú ö8]ü:$ - @ëŸw ÿ^>c`þŒSPA,ß/\½Ã°sËVp‘*$$È à8gùÿwž þÉÌÀù‡Ÿáý‡ ëfÏcø L ÇF‡ù2°²ò€Ó ¬: h0Cs$ÿq2<_t±ÃçÏL lÚ ¯¾|f¸{÷333÷ob`‹¡ (˜¹yÞmþÏðé °bûÍðç#ÃÖÿ Ýcø Ô J*?€•##¤Â†: €Pá?ˆ$š&3|¿ÿ„á/0ß²ýþÅÀ¡¦À ¬¤Ä`m2œíþÃü'(ipÜ~ùÊÀÇðCלá¨)öëŸ0›²"CiA1Xϯß„x˜~ݶùþsó!@!%B`mM™êª`Œ þüþ©D@yè{P²Ô®6sE…˜=Á‰ò0ÕÿZøûËp©*1A4(›1ƒ,F*ˆðXn7€ Äøåþ£‚ñ-Š 4åÚô;  U ,0ûȶ ìñy]`ãÅÊZQ+yÂÆ|_"··¥ŠTÎ…(÷&¬pú« ˜xyÙÎßcgˆè½v 4µ‚Ú¤6"(1@äÁ–Ùˆ¢™Þ7€iÿJNf¦o />ì!•@ðûãŸwoÞ2pËK0¼Ö~ÿZÅðV0´yÔ†ñÿ1 µŒ‘ZÐèfü÷ ˜˜~¼‡G-@ðëÃÄcæ3mÿaIµuûk3ÿ¿<Ô8F`åL@‚Ĉq ;§4àS€pZBã9‰åkIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/view_tree.png0000644000000000000000000000354111550446574023221 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<óIDATxÚbüÿÿ?Ã@€bb`@, ‚‘19‡‹©Žƒ‰ûßÿÿAbà€a1Àˆ&†^ÿÐäaúå1ô12þýóáÏÏ¿“þÿŸ×@Œ (àãM{ÚØ/Å+/ÅðõÛ†¿ÿ€jþuý:çˆþÅPö¨²Zý™”2Á4H=HŽ…‘áÃÓ× æÎ{õëë q€‡7+—„Ž2Ãq öoCY bù‹0æ˜å‘,ÿ‹„Ajƒèÿ¨jÿmüÍ!ÈÀÄÎÁ ² €Àø÷éï—/Ù?AÂdà˜¯þ£Zþf0L)„`ìÿPõp½PÌÌ4ÿÇo ÙL ð` H`bbøõ‡‘aåš ß?~g``ÂŒ_là?rD#304‚¸L@ñÌl Ò²|`;A €X ˜>|ýËà,õ¡0WèÒÿ è¹d&3333Ãïß¿‰JáŒÈrØ€ñ¿p÷K†%ד"3X €X ®cbø L%Â"< ªJÂ8 |÷ö5ÃÇ õÁŽ&üÇå?`<01³0HŠÿdøsäHÄuLÐTý¯QGdhlêfxóöÞhùýëÃ/ þŒëïß3|â¯ß@¡ö˜#þ‚Ó̉&f`°3âp ?;;;++DÐt†Û}ý@‹€¾büÉðýó…X ++°#@‚²9 CÌg'ÌÿL H02‚C€…PœÕ z÷î=جÏ®0|»°‹A-…‡‘ë.Ã7nf´¶F±øß?†$, ” !) € Ç_  !°²²2|þü‘¡¡¾•á+ÏãW Bo8ÿݦ°¿ ¼‚\ _0ƒ Pœÿûs„ÿœ?¡Ù”  F8¿³pÀ`‘Š‚nA>†Wî0°mÞÉðçöOF Å÷¿103ý;âÿÿCéˆh`€” Ì«ŒWHÿþýeàààb°w°gàããfø¯­Ãð`Û\†'›^K7f†Ïïÿ2¤ë@ $ )„þJàö°aQ@Ðr€˜þ‘¥@üþý T€3üáçc\¸•áÏ·_àxcüÇÀ"ÄËðûÛw 3 €Ó$ €%˜ @Hi€ø*R@“ùyXøÁe/ÈÒ¿¿~ƒ}ÿZÃÒ,=@jLF° @püù‡¥ü„[øœ0¢dà¯_H‰ h1(›ýc€;,þ£ïï_f°ë!å$J"üψǷp64+ýƒ8Œ‰“\ä‚B• (õëË Ü/hâc€úè#ÿAB\-Cs@±ÀJBP6DvÀ¤š9þÿGÔ6 ñ×{0|{ùX²°87×g`bø÷ûRðÿCÊ– àôòšÀJT10aÔupŸÀĘ€¡ÅÆÆ¤9çñ3†Ç¥ ü¦l Ùž3¼ºô˜áýõZíê:†ßïÞAÒÄ_ˆÅþ€‚þ/<2A£ €ià?rQüž!Ùï?°†øüÐàiSç0°òp30ݼÏà¥ÈÊ ö•A€áÅ N†Û—¿Á³Ü_¸ï¡ô_hZùϯŽÌ Èõºå°„$**Ê ¥¥Êðìù#†ß@xŸ¿b`a~ÂÀð؆øÂÄÀôæ r¼#eApaôï, Á+#€BM„Hq+Å`qýóç/==cpÄ,Š¿]¹Íð6y-Ãë¥_þò03¼¹ÿ—Åš’âA!õ1(Dþü…„¬qˆ„’aÁŠ_&hŒ€šV`6PR¡ü þý´L^’¯qÃÏ7-#;Ðb†_¿õ€¤l`„¶ €-``rc„dh" x€ð˜…¾|þÎðûïD™Š/PðA£"Ð|VamÏÀÊjÄB£êÇw†¿?A+>Fˆ¥@ǰ0ZSÀ¦ßÏŸ@qNx¬.`âåeg8!¢÷>Ø1àZë?¼òøhÜ=‘ÿ¯l}°‘Ú’°Zø?Ø÷ß^|f:>N†¿Ð| @`üþÇøçÝ›· Üò ï¾ük‚µŠá­`hó©5 æC ¡HMôHMud3þƒûÀÄúã=<ÁØ¿þ1L<¶ñ`>¨Ñöÿÿ?l­[Œ6þüòPãÿý–ûÿþ,‰ã@wNhÀ;§4à0J©Vþ„ÐÂñIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/player_pause.png0000644000000000000000000000226111550446574023717 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<CIDATxÚbüÿÿ?0šÌªcøñ'‰áÏ¿¿@.D˜ؘÿ1°3·eæ1àŒ ! ¿ÿµÍbòþaÈ33q0p²lü&-Ä F¸t§}H‰Ðã·Ôgøþó/ŠNvf†Í‡2lØvû;“%ª…Œ¨üø³ÎÊT:0%D›áÛ?(RìlÌ Wï¾c˜¸è§çÒùAbÄ—ýýÁÆT–!ÖMžá’>󀪞¼ùÁ°aÓ lLè>Feÿþ÷OEN!Á[…áÃTi 9;ϼb˜´à<<„ˆ)ÿ?ÿø—áæ†¯ßPÀËÍÀðöË?iÿñÿˆ9¿ÿc¸ù‘áóg $÷rr00<}÷—á?’9Ä‚¬ÿÓO†—_¾}G5÷Pù—ßh¾Å@!ÿ hÎço¨1Ä ŒÙ÷?PÕ rððú+Ãw4|:àë/â,™vМ¯_QÀtÀǨ ”øtÀ  ¦hiüò‹ÈªùTÿ’h!ÀþH @¨!ð¿~¢šÉþɌąÀK å?¿¡ªg:ìZŠ@!ðò+¦Øþ@@$øþ¿¾%¿ !€ä(€ÂpHã_4ËXþ !ùÍ#̬@ÎJ„’¾5¼ý†éf ßHÈ?ÿ@ÌÁæP4#@(ø÷Q<õKáŒ'@jÿþÃnH Y €X•+0ú?ùà?Ä‚®RËH5 €˜Ѐ; €Ü4à w@ ¸hÀ@(å 3°æc”b(E(PŒ™™ÈŒ TÃ,iØY±›²Ù€bAÖÈlÇòqËp´ò‘•Ø&`!ÞWl@µü@s~3¡Õ|@GýdGU @(Ær€À Õˆæˆ V ©¼ s0ð•µ( p‚l8þBsÔDVfˆG~¡;hùG6Tµ„pÀ?ˆx¹0ÀÎÿp7Ëa!uÀÏÿh-" ¸8P•f€€f('$q˜!æüøÚ&dc‡¤3d@XÓZ³ƒ‹Ä4 Ö¨!ÀÁu’9„’ 8–ð5²¡YÄAJêea8€å/Z«˜39ùy™$D€Í¯¯¨Š¸x@iƒ [Wkkˆ‹‰ABšâQCò)?3JÊ ¤^+óƒÛ¯Îð±2üDëœrp03<{üè%&V‚íB&–·¯?3œ=ú ØÁù‹š€‰ãÎ­× W1ÃĈ©{>‰áÏß0†¿ÿÿ`MëÌLL@ÃûìnNH6üê~ÿeÄšj˜Ù‰d;°{â ^WªWÜ…™IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/package_system.png0000644000000000000000000000557411550446574024237 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< IDATxÚbüÿÿ?Ã@€bŒŒŒ Ìl Þ[~ÿc``òÿÿgJ°2üûÿáÇV.-¡Ý\̯/ßû|ôå‡_›6ºÜ`°ßÄÀÀÉÍÀðçÃo’,y €À`7e`P‹F–3 r’éýýçóæ=O"~ü}ÄÀÎìß©feªÆËpÿÍ/ÿˆœi:â) €‚8À° æ_&¦¼î íî7I¶o¿9\»ñþ”±ž°‹ª,/Ço bÂl ¼ìŒŠ`½ÿ€Qøã/Ð;ÿ¦²ŠCòñ“ ‿À–301+üûÏØþîë?¶/@½_€¡Z®¢´C‘‰‰áów }@{˜8-9̼ÿë„'_™š™ˆD¿|ùáûíƒlQ ¿þ[û$0¼xùŽáî±¹@,ÐØ¥`<þûÍÀÊògÙáç Ö’ ¬ÌL €¡ÀÊJ'% Ì _޳4”dSêÍÊûök¾š"7ý§?ŠÔ?x~¸¹ZCàù?5~&†»Wµ>]G 4@,ˆÁ`ÀÄðŸñçïÓ¡¶ÒÎ,,L  (`ª8yÿ'É[Ÿ¾ýøÍ  ~sU~a>°Ã$%¸ÞC[FšÁÔɯdÓÉ%‹~ÿeºþT.ýÏ Š'œ ˆ~þU67?P¥Îÿh©œÃÇïË—|Ç0{õÙo?¾~øÄÆ+"Ä.,Á¶íâG†8;q]yn†ï G²20,Ýøøÿ¦IÅ“~\¿ý÷¯$g}¹ÃÀÉÉÁ --Ï ** Nõ'Nœ@q@±@R¡¶º¿– ÛÀ44”ç÷Ÿýe˜Þ\¿ô×eý ß½þÅ)ÍÏ¢äáwW3ªj!WŽ';ƒ0/ Ã`òyúà cc®M +«µÚóo/½{÷n)ÐäkŽ <<<ðl‡Rp°Z\{ú•aï…Ï â¼àc 7î½gøu}Ãb†ïÎ2ÈÊH1I‹ÿt×ùÆ0ãÚG†3µùþ5(k*20‡(&ù++~ÿúÖ',<šhL 0ÿþ ˜888~üøfØ,\¼šþb8?÷:CµC¸ƒ ÃW`(prq20° Š 03èéêiii.ŽÕexÔu‘áá `¥ÎŽeu †‡O82¦=d7fd`gý/ó5ƒÒ333ØREEE†ëׯƒÙÄ"þœjŠÿsnÙ†/Ÿ~¹ó‰áÍçà,(«ÀÍ `—œÊÅ#Êü÷÷· ËõDDD€:~1X«r0ðu?0m‚ K9E~vQ†ÛwŸ2øùúÚikk‡~ûöè!!¡I_¿~U‡½‘‘˜ pü±{ÍŸ÷÷ÖüaÒ˜)n¢’öë#Ãï_ bXÔe9­Ÿ-°ýý—ý¶gNg8obÄÀΧÈpôÎ?-†OвáÛÏ Œ@=/ž½gpRa`‹K×34[uúôéǦ¦¦² mmmÖlllöÀèøòøñc°ˆ<૽ŠKVCt_i™½9ˆÿç¤9âóW†«gn1|||“A@@€]L‰ALYœ› ’¿þúÏpññw†oßÿ1ü=wŠaZ&?ƒ‚’Ð\&p°ÿùó Ÿ?f(,,\}ãÆ˜W¯^ýzÿþ=@ÁË&vƼß"|æ—|fÐVàcxýéØg|<,àÂG×Zá÷_5†_ uÕ_ Å Ò’˜Ï¹ÍðöÎ5†?¿ÿ0˜ \f_wp©õýûwxêgeeeFï_¿TïÞ½+ %%õ $@ð™‚ÂñÇ?`r>tù%Ã7¿ž¿&‚ÿ¿t…ä%ùþ-¥vP`Bæ/4„@…£€ˆ ×}[ɾáâ–fXµf3ƒ››+ƒºº:ÈBp(}ÌPUUugÇŽ¹@-ïeddÀV82È72üûús‡K}÷—áôŽcoìÛ÷èëÇ? —ï¿gxÿõ°¬&= ¥Ï?üb¸þô3í'Ÿ>ÿøÎkòîÿw†ß,| ²o¯0¤æK0((+2(À—{æÃ£•‰@?^Y Êj ´ô/0ø-é› tÈ!||| !!!*** ÉÉÉw@E5@1Á-}P .ä2ûî‰ã;­^Hóe=\pIîÆ†0ëo ¢’ oÞý`0Ô—aÈŽ‘æáfü'''û_^^žALL \é|øðÄ< ÁB–@‰òõë× À(„_Ï€)l¤AÌ2‡0üæàÝÂËûK3Ô_¥ËÅÅhÀ_°A_€ 3.!]’‡OôÀ¶mÛšÁ½˜Ïß/ ,õâ  T䂲"(|úô‰áåË—àŠéÂ…  Død@! "(`gggÐÑÑaf­Ûwî3 ‹ :VWW§«X˜€Í#p}À’Tª]¹rå+°|´\POO[\\ï°ºh)Øç -^¼x0ÄÅŸ zõ,  µÕ/ a Ð¨âççW:yò$ƒµµ5XÍ›7o€Y ìX`ùz777`Ó˜d(˜Aâà :Xð€,} tìk #ÿ>xð (õ$@…,ÕBk1.P”\½zìkø“'OÀE²8ÎAÙ V½‚Bf(þAz@…~¼{÷n¨5ß¡í@€bBwÀÇÁ‰¾|ù’ Þ xÒ À|ö¨\?räH^Ý‚*|€ý{÷à✜œ ÞÞÞ@3@åÀ[ þ3 €0Bd0~@)Ì@Ÿ|yÔVãðÐ÷…Š…¥¥eº¦¦&È— ß‚ðÇ€…ØRå ‡ÊÊÊ2ƒœa×®]ïâ_Ñí ŒD¯œ€A bXMvùòeH›˜á+4­”‡……u(¡‚£ÄÿöíÛw ×¼ŽŽŽÒ 2˜~þnذ¡UZ ÷ŒˆWkä‹k×®1} v²Fhn¹RÊZ/^¼GÉìÙ³×C TÙðCkŠ“““ÛñãÇ/œ={¶hÙvt3@ €p† €|'--ÍpéÒ%q999-`î˜L`ê@yq`"} ´,(uª„˜x#€Ùö4}ÔðÂÖ7 bzǪªªb ’šˆ€ðF™?ÍKjç €º{`bÝþ$¢t-®IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/email.png0000644000000000000000000000515111550446572022314 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ûIDATxÚbüÿÿ?„†.fÀþýû ÄLmŸ?¿={vQï‡Wn0P€ì &Bо}ûm`c£ÒÑ^¿WV6¸”MD€Ž ãÏŸŸXüùóI@€³!,LOTVV€AW7HÊÕU¯kÙ²ýGnîxýzÿÖÿ¾}#×Ä„l˜‘áçÏ¿áúþ ËA€‰!8XaΜ£šš†E«¹¹¬Èu@1ÂÒ@@À< É?þ©©‰íïîöÑcgg¦ Ã€˜‰= ·nb˜1ýø·M›¶Î}øpó¤ÿžÜù÷ïÑi €à Y„–ðþÐ^[ëZai)ÏðûÄr0þËÀðˆÿµ²±Tú솙3=ݽ{ëô·o×Oý÷ïób@Xûúõ§¾‹‹Ú±âb®ïÀþ´ð?Èb¨`Žùò,ÐÜ\ ýcرóôéÛ/œ?·¥íû÷#›~ýÄç€bANí0úÇŸ ""Ü ‘†`Ë¿~…û_´¹ýÔQŸ?Ô0189h0ÊlÚd±téÒ};nßZÓõó×…#¸@X²á†_¿þFûùi ó3¼{J ß¿éï$öè¸o 1 ýóDìùS ¿¹b"-YgLOõ5·(ÝÅÃã]ô;6 J|0‚|ûKT]]´ÔÕY‡áÕ Hÿ…úþ?4èÿBihìÓˆÿíû_†W/ß1¼|õáÞý§ Ÿ¾~cpô0ç|ððNö—¯ûÏUìAw@!•À ……1'"ÜXÿdž/_ –ü…30pÀŽÑ ¿~ûËðæÍ'†/_3¼xñH¿ex÷þЬ_ÀÂë/ƒ¥µƒž‘ ƒ¨¤ô£‡,:@‡%MRáo3WWE9†çÏå$¿ƒú熿0ýúòÃã§/=zÁðáã'`P‡+ ;7 3°``aaæ–ÿ Ìlü ¾þú ªJ ÀhàdPÕ`àäÒÒÿòåŒЪ·È $ü‹ 0ðÿøž•áÊ•g Ï_¾dxøèÃû÷Ÿ!óœFX>dZÊËË´ ÈfbHÌ L@šh9¸äüÎÆàhÂ`mÉ6— òò| œÜ r_¾0)mº‰D ¸xx9Ë^¾ceظù ÃËO€†ÿcààd);7Ðff¨eLÌŒ`ƒ-gùœÌ~þòƒ™ƒƒ³#/¨àü,¼€Ú4Tyø…äß¾V2ú÷ïÎ.P! ³ €àøþ퓘ŒCZ¦2ÃÙó®^}ÂðñÍ[ á \Üì@ ˜ –‚1ÄBf0:†™…áù› æ6b ¡Ò œ@ËC * _Õyô ”î\—Ðg`¸# ´î)Ì^€‚;àãÇ÷‡¿¼ý ¯o+Â`¨§Ìðø•Ãõ[o®]xÂðèþpà O66V …ÀP¦ZP¨€Þ“WÿäeYâ¢åø%"r±ýTJr02X˜H3¬[!£ ŒIidÜïÞÝ?þìñ›œÏ_U€!Ï  ÆÈ $-Âàî ÂðôɆ³gž3\»ö˜õþ1°‚¢…‹*o>±ÕcHORfàbÖžˆÚî VVäcV‘zó†[˜OÃÒ@ÁðèÑÞs·n¹¼üòù83# Ø& O€¡Ì  ÃࢨÊðöí†7?é{`üÍðí?0‘~e(L—æ .p ùŸañ_h‘ *ªäy45µ„Ô:I à6@Á‹bNNþ{¿ºñüù°!¿C4ƒJBPqûù3/ƒµ•Cb‚:CT”ƒ¼Ô?†ˆ!--!P“ä/’¥0½ èø ¤¹ùØ´4å€&«š ˜½w믗/¯_~Œo%H3ÈpqüR|úJÝL Š  Y)* ö¶Ò`Çý†ª9ÿŠý¥ f9^`ˆ*©—„Ù @p<}zXô>;}ñâ †o?!AÙ†aÂ,Yúá#„;fù/yà'ˆŠ}…&0·hh‰2 ©+00ðëÀ¢ €àÒÆÛσ<{ûåËW†?Œ?‘ªÙ‘cƒ-ƒa¨ž@úÇþ ÄŸ¡'£(Ä ¦&,šd Vrƒì &D6¼ Lˆ>}úèÊ›WŸÁÙçû$ü ”?~¢Yøá[c¸|éÃ¥Kw?|xõíï?7ž00¼~ÄÀðò0BŽMy2 €àPQINÀìøâÉÓW7ߥÄ)#Ëðî¤Bù PuÏ ´¬<@·Ãüéà ç¼d8°ÿ.ÃÅ þ=xtûÓçÏ·¾¼v‡áÍm`8é?7¡Eð(· î€OŸ®C«å¿YX~œ¸rÉÆÓYU–áù{Pg¼@‹ÿSÙ«'î<øôÝK†“'®ÿ½|åÚÇ÷ïï½þÿÿ°óØo|ªrñc 5m¾@kÀÿèM2€‚;àÕ«ÃpAAA#7n|ø™&ÅÀÎ ôé`°^?ûŒá¹' gÏ>b¸~ýÎ7`¡õüû[À`|ôá—[À yjÙkh£TÔþ#Ô7 x¿€™™¿€ -~MÍœƒÎNÚúOŸ¾øáüíïžÜ}ÿõë͇þ<ºô)Зï‚R1ƒÔ{PNŒ…èý€Br;’Äo`°K›ýüÉþŸá;ã—gÿÿ~̦÷¡¾ùð3(PÚ=0Rb»¼¯«³IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/run.png0000644000000000000000000000401111550446574022025 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<›IDATxÚbüÿÿ?Ã@€bb`@î€bAæÌdddøeÿbF þ ÄÌ@ ’û û ¥ÿBÅAý``àbu Z[v—¿¿Ÿÿÿ÷o-Pê²=“‘¢ €XÈu9ÈÄÿGª±=0(-Å$%uut´å••¹¤ddÖ-ZdxýÖ­©ì Ïp™@$9h!#з @¦ P£¯˜˜¹´ššžŒ¦&·Œ‚ƒ˜°0ç·o Ÿ>eøù2ƒÔ×LŽÝˆËL€bÁcÌ—|@ÚƒÚŒ“—×DÉÎNWZIIFJT”AèK~f`€¿|Éðëñc†§N1¼ñ‚á/Ьÿ2H€¢Ž‘Ñòßÿÿq%6€ÂpÐ"^ VZlÉÎÃc!¬¢b!ae-'iiÁ"afÎ ô)Ë«× æ1ü={–áз¾|aøûãÿ?@Ùú? Ãïÿ$ØØxYX¬¾üþ N/Ø@¡:€‘±XTC#DÜÜÜLÌÄ”IÄЀH3°°±‚Cä70H~‰ïÿØnÞ`ø÷á#Ã?…LL ÿ!ñhé? e ‡€h> _Š]ïÊïß@‹n`s@¡8€‘›Ûßqút ){{¸Ø¯?@ ¿ÿŒŽÿÿ@ øŸ¨ÃuMÆÃ³0üùäÈô? Í t„$ ÿH"Åê€B‰š__¾lÿøà!„ýûÃÏŸ¿þþþ I}Œ àaf&†¿*ª@_þaø ²ì„FÇ¿A†+#£9®´@Lh ïÈÓ£G~¡ˆ-ü÷BCø@ Ž¿ò ÿ€Áþÿ×O°o±…Â/ -Ô Ä¢ LȼØ@LhœËϸþíÓgFP¼‚-…àÿþ3@ÜŒ  ÏÿËÊ3üaøL|`KÑ1Ðò?2°øÀ ùû·60µ°9 €ÐðáÓíÛWß\ºÈÀ æÿÿþÃâûà´ðï×/†‚ ÿÔÔþýø I| A9áó'†¿Þƒñ?6vfgI;GN vë?Ð’F6*:ñòÄÉ( ¿a!À€ TLŒÀDñ_C›áÿªå ÿ¾~…XÎÅÉð_[—QY•YGŸÙÄŒMS›AæÔIö3'-Ëôò €XЋW ØÿâØÑŠ9@)ïßßÿ`Ÿƒ­fd'Àÿì̬¢ÄÀP‘°£ž³‚"#ЙŒ ¿ÿ`øýñ#ƒ0½ˆ*ª˜>¹z‰Xl}E¶ €P³!¤Ò¹òòÌÙ«Ÿ>2æü÷/0ŽAù ”à~3ü÷ŽX0^8ÏðÿôI†ÿyEÀÀµf`Úýû¢æËWHB†Ú fçd16•}xõ’ 0v"Û @,h¥ 8À¿>{zæÕ•«ÆJòr@ƒþ10Þ¾ÎÀ|õ2ÃÍ› ïÜføÿàÐ’Ï ÿ>}bøgŒ* K†ÿÀ¸ÿÍ-à´/ÐA X,ë2=h‰î€ÂH Pøó÷ïÑ·«V¦«¿y ôéE†ï3üZöìK`b• œÀøþñ §þGăX rÌÿ!¦Ø¿éC˜&8ÙØÌ~ÿúÅ„\=ºåÐ2ûøË;ÞüÛº…ññCH*gF°lÿ+rA… 0ü½|‰áÿ# VDA…Œÿƒ.  Ä ah¢ ô‚4²Ä„žÿA½|ÿþÂ;a‚|ÂÐb\ñ€¢íÕK†7¯Õ1Ás "@Ña3sp0È™‚ªrSd;ˆ GáðëÛ¯_^¼zÅÀ«``• 2Æõ¿ïßþËÀæÿû¥Œ LŒŒàÓÖº“ÉY €ðµ O<õê?85Ã0Zq Jà²ãÄ1`¢ü´‰ ˜Ô!ù˜€¿ÿþÅðXN<VÛ_¹¸8‘- låÌe^¼yóôë÷ï2Œ° ‡a(Øæ×ýÿ!Àxï.ÃUu†oÀ| =†ï?1|æŒ÷O1¼¿qáã[ îÝyó÷Ë—cÈvF9€Ä~ûþË—S¯ß¿—çæ†[̤A˜Dù?Qôõã†ß‡0übø̦ïïÜdø²ôæµ/@þÕ¯ïÞžøûÿÿq O~„l'@± è­£¿O¼zÿ>H˜€˜  ñ'ú„A-@üä_W/gø~îìÿ—.\úrÿî`Kú$УÀqî´U͈¥. 0c6ÏŽ½ÖfŸ…„>k¶OÀü € ïýõëÿ—?žËÖ³¿¯\>ñ÷Êå#@=×½aBj[2âIhÄ‚ÞEsÐåçŸ>]>÷æ.0-0|&¦/ß¿?ùüë×_ÿÿŸú ¬–~„ãHÕq €ð6ˆ~úùóçÚÛüýõçÏ`Zv(uèCp†cBê#ˆq ;§4à}C€pL\*ŸÏûƒŽIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/top.png0000644000000000000000000000376511550446574022042 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<‡IDATxÚbüÿÿ?Ã@€bb`@,ÈFƾ •Ä¿˜Ò égbV þñWþÿ_TS@,hš>ñS þG¤þá IF,f€ìû€,@è˜Äs|€ÏwߘhÐòÿP63QþY €X°(úŠU+#8Ž€~†¹ë_0¦Ü–ƒ˜m?Ðì¥à f„zœÈ ¢T13B pu†_‚‚\þ®®ê ììÌ »w?ˆ}ñâc"0J€êNÕƒ4üùGÐ!ÄB0À˜‘Þ˜áç ==)•3\,-¥ÀÂ×®½eÈÉÝc»ß½M ÿÙaÜÖË$þü‡„‡Ns¥8˜•º ÿ¬vsWQÙ¾=lùß¿~ýúÍ ¥%İ~]CLœž8Ãÿ_KþÿwDx¨—j@¨!VÌ¡‘Õÿÿ¯ÌðûÇj? ÅeK}xyXÞ|ýË0ý,×ߌ éú¿”D˜/ôbàà`š3ëü &7`(\D˜Ã Í¿¨A@¨!ò5 #"CÔr2üø9GÏ@J}ÖLwˆåßþ2´cb8ùœ‘áê+†æƒŒ ·Ÿ‹Ž¿z{œÝUÄ~ýœ4K ì!æbnT+ˆ #s¡§üŸZ$dø}')ÁÅðñÇ_†þÌ 7Þ22p³ügà–YßýfhÝÿ›áÖÓŸ |< óçº2¨hˆ2|ý=h ŠùhvFÜ#ã¿ÿ"™þΜîÆ` 'Êðó÷_†©g.}Í´ü/0þ1;ÆÛ/2´íýÆðøù7YIv†ÓxxYC~þ-=²¹H €0ÆT€>èÌ.0aôóQ üeX}‘áè&Ö C,ÿýëÿ†î_†ó~0L=ô•áÃÛï ÎR uMVÀüW LCÖ`GÀ0 Ì€d=v†Ï¿&[8Ë˶6XƒÃíÈ#†u7™8A>ÿýœúñȆ8æ'ÐÏbXvêÃçw_ò3u‚"Õy>ÿœô ¶\@¨`…f™?óx„8ýóA¾ÿñã7ƒû†l[~v¦ÿ ?~ƒÄþ2|âgÏ?3ø»É0„D¨3®\r½AùF TüýÇ/Æ0g’+7'DJˆ—Á™÷?¤"úh6ÃÆ ~}Ïüÿ8 üüñ‹•ƒÁY‹“A‹™••…X/~þþ˜ÿ³n“ñÓ/Ì?ûš4¬f%@¡; KKK˜áú÷ —®¿•€ ÿAu 0û‰p0X›H£ä0B,†„0:€ò¿20|ùþ›áÔÅwÀìø•ßÿi‡——•Á@_„áñ“ÏqÈ Tp³lþõû¤ñ «ùþC-åÀl  $@¨àgƨ.¡QÀJ„¼{véÕËW'>~ü°¨îî¯_¿¾|ùÂðýûw†ß¿eùLj›ÈŒŒŒÉ**ʹ6Öæú òr@±1|ÿõhø†ÿˆþþù]÷å«WÑ|òÔ™•¿~}éj}Cj#( CàÏŸ?Âüüýý¼¢­-Mn?ee¸tïûÏL _¾31üù÷éÿw–¤¿3èÈÿbxùêÃ’¥«/A:PÿIRB €P FQIIÉõi‰Öb’Ê +22|þÇÇ`®ÇÍ $ÅÈÀÇ r2ço O^30»ð‰áÖÕë f2÷´X¦ÏZôvÿþýA@U‡€!H”ˆêkfœ˜™žd-*¥Á0wƒ² ƒ¿#'+PÑ?†ß)Èdò¤¤¥øî™3lÜ!Åðò܆Ԥá÷>,9sú´ÛbB €˜ØIA~‘r š ËNr3hëó3è¨22|úöÍg†ß>ÿ„àO?€ü/ ï>10ðC%$@–ᛄ ÃÉ«’â£d‰‘ ø04è…ÔÔÔ lößädàåbZ´äû†@üí7*þ ÀPùtÌ/ ßÔJ’á£ÃÏ_ ŽŽ±@3M¡!‹ƒ@ÀÄÌäîho­ýõ¯Ã½/\ ¢" `Ÿÿ Á_Aø¡¿Bð*÷è/ÀP¦MU3c†+ÏØLôR@¾ü”À…A €À¦z{ 55†ç_¹˜¸~A}ýã/ÔÇ@_}ý¡ÁøÂq c`HH‹Ó¨˜.+'ƒ’’¢=0ó€²4. v€¨¨¨ÃÇß, <\ÄöÜhÁÿÙr¨ãþ=ÃLΜ "’ÒÀbcP—•­Êe¸08ðóñÉ32³1ü$Ì 1ð(xA˜T:1$‚sÁ¿ÿ b³2A,çb6 „ÙÞÝšÉËË”&” ì`žeù ŒVF`û t30qCÿƒs!€,eY ÔÉd°3CÔ‚²*ÈÜŒ o!>d„º/ °¾|ýúü÷¯Ÿ"|À üÔ Äl@ßÿ†æ}ƒþÁlg€„Э ,LËÙ€¦pi.VH™ÂÈð‡áóWP2eøLÈvÀ›×o.¿yýZ—OFáÃ_°O@†‚,E6€ ~…3”þúñ=Ëßo Ož<Õ × 9 €ÀøðáýñFéHªƒ]˜ -àýŠëp»!(]@C DƒÕ2AʆW÷Î3püüÊpÿÁó ¿*’œ ~üø±å̹óϾ¼`àdüÃðëÄrï@AËÁ ‰c8÷àD 7n?e`ùøhù#†Woß.V¡ ÿñ` p°³³?¸víú²«W¯kó1¼ú%ËÀ ŒVFh W¡h!Á Tûüóo†›G·1p3ÿfØìø FÆ-ÅÀÄøˆAe6 v ÃÏŸ?ÛwíÙç!"$¨Í' Œ!`¡ÄÉqj@J„ \ó˜Þoß Æò…áúã· ooÝÚ´˜tÔA5(„AÅ=ÿD¢B °@…Ðo>|´qëö­žîDø%¾2¼càããbàf…”0߃1(›£êæÃ— ïe`ùòŒAEK›ÁÂÅáÚµZîÝ»íÞ10lÖa‹aÿBsJ‹Ø;uíÚµ0`¾ÐÚÊ\V\âÃ/> †|b \œÀ(eÅO` õéã'†'w¯1¼{t‹ñÇg†'/^2ð‰I2ÈÈ+0”N.ÊùåtÈ÷©BÌ=)ÔÔ+Š@)ûïß¿ïðþýûz`“,FAN–‰‡—ÖìÀ¬lýù L´_~|úÀðõËG†@‹/\¹º÷Ö½{[|®]¯fcW2bPW`› Åð‡éS×ÝÙ×I”¡›Ü"òññ—Í G033ƒi`ˆXrss' 8ðñòJ°±²rk1F`]ÿëíûo_¼|y X~,yÿýûvý7o~&={¶NûÄÂÀŒ j73°qË!†›ÙÇn;Z Ì¥=ÈQ ´ €Xp È@ÖëÇ_½zÍ ÄZÀÐþ÷ï?Ó÷ïß>í çs ÚøgÏ@…Õ†OS'ê„=óꃸ8¨ÐfP›`,Ôþwߘw(ÓŽl@±lµBBâ+> ™0Çå`Í/ Ÿõß¿E—Ÿûsž¡[?˜~Cs Ч:3-þ21¶]™sTµtÁÌ jv2!%[Ï…+ œ8~6y}ŠA‹J ÖŸjLCÿ:/-¸Špp j÷t Žh>{æß÷?ÿ~v›û½åsx=n4Ý’á+S×…9×@9» €XhÑÝ‚…ÄésYÿ2þl³òþ/½µ–é$s†·7ß—€@,´êóAÑqììß¿ÿÿè°÷}ä`74¾}ÿ ®ªˆf€:â?кΣçþþýÇø³Ûÿ€uöÑOnŸ~= ¤ €hêXu ŠŽ£gÿ²¾|ÿ#ç÷ßg_>ü3Ø^› ’ Æîž˜RãÛ°úozIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/find.png0000644000000000000000000000264611550446572022153 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<8IDATxÚbüÿÿ?Ã@€bb`@,ÈF“ty9…jš: ´°ìÖõ+žf¸rd Cp\"bq@a$¯Àbý/’ï‘1/¿ChL Ãê%s~±{0ô<–gâcæcGÉÃw¿^¿ÿÈ Ãø„aËâ>†—Ïž1ø«L`øoÀÀ©h€5ˆWð£[ÑÊêZ ±é… ›Ö,g`ú{‚á¿° Ñ_–Û[Ö×oîÓiBa÷E1 ^¦—îÞ8Ïðì#P…†ˆk–Áa9 KHÉ2D§ä€kÛ×.3È~ý ÖÇÆ­À`oåËÀ/(ÌÀ,ÿ_lj`gPVæ–u ß›0@XCŸå0²sp1HÉ*0HÈ(Àó9ºÃ?Z—1Ø>‰ÁÁC”AEé+CìÍZ†] /."Ù@LøB—åb ØÅå­|^êçñ (ÀÁ «ö‡augd‘ƒÌ>€b”Z¢™Xä¬}žéç3ØùìUu6Þì|Û 3ôAöz\8÷蛃ŽÜäbÞ°@*Z‘Õ`gsˆ†Ãá÷Àºáò í¿ J*\­Ìd8æ@ŒÈS`׌Ÿ_ü€Š©µ»eÿÿýe໸àáÆD6 å¯Ü ¼² ³rg6ª Õ,¨Ó €Üy fgØK‚Áª:Ñf§O?žõ­9ã @¨}CúÇ”XÄ0ýYgx2=BIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/player_rev.png0000644000000000000000000000371411550446574023402 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<^IDATxÚbüÿÿ?Ã@€bb`@î€p#ƒñLj˜Ã Ä6@|ˆŸ°‘áÏ¿D†_ÿJ8Y6…Îg`ø÷ß…áëï@z##ã ¨c°«ý Tûé×.~Ž^®ÊÊŒ ÿ£ˆ‰ËU¾ÿ™ÍøûïîÈ@-§êtS†ÿ?~0ügàÀ¢V•áûï…ŒþíôòP³?²8˜!;J¨þï€b!Ãj.†_ò~þÍÑÒ‘ªÏ³`³—e˜½õ>ï¿?ØPŒäŠ3üü“¦k -Q’fÊàTËTrøêÃþ)`³/Ã÷_õbq¡º ©º ¼\Ì o~30¼ùü‡ Î _ÀÑðï_÷ß5bÒB:1!z ÉaÚ ìlL —Ÿ10H 20ü*†@ç€ÿÿÍ€AXÍÄÁæçdÈeÈ #ÅÍpç-ǧ ê@ÏÿÇæ ZW ÅE¬<œî¾¡z ‰ bb\ ×^10|þJ@〩äÛoHº ñ, î †ßÿRuMÙSbÌ´5Ež¾g`¸uê6 úæÃ7 ñë·83ÓNCK5†„h!†'@µW jAôç0^>1Ó-D3@ár Ãß¿YÀ¸Ë•U 2a0·Pføô›‘aÏu¨Ë™áÌô Ðâ=ÓÎ3Û}žABUš)8ÂŒAß@áз µŒŒ°˜x¿ð b@as€+Ã÷Ÿ ¼ÜV–& .ž ¿˜YŽ=b`øý˜@šØ€Žðèì]†ã0|ûü“ÁÖ×”ÁÉMŸá;ÃÑ‹˜˜ ¹€Äy€©äË/ €XâYƒá÷ïzFæ`US-V[Ocv†SÀbå0¸X@†}Í Ôñáá+†k»2¼¾÷ŒAÝ\‡ÁÖÛˆ‘›—áĆŸPµ¸È\ÀŒú ê€9@Üé@\Ê/#- ë`Ì £.Çpï3ЕA¢}ÿÊðüôY†çç/3ðKK1ا2HªH1ÜÆó—×P3Bp£€ê€bf—Eì‚^2æÆ JºJÀdÌÌpý9ÄR&¨aÿ€ô¿_?n¬ßÊðç×/µE-y`Æ``¸þª– b/¡Úý?ÔLPuÄÔ!Ì LQl¼< ÿ03ü&fFÔÈciüÏð÷çvvV^†÷@üý…ÜŒD•Þ@@ùÄÌ í·ë÷—/o¯ß4ýúú—°‡'Dö,y5°°0ð+È3|}ñ‚áñA`Â{÷[L”Ÿ¢î4ø‡03}ýÄpû­OÄÌ åû~[ºÿxõJþíÍ; Œþ2H 2pó±#’å@>åæç`ÐQcàaxsõÃÓ3瀹‚™A@Jˆ“›¬Ì@uÌÌx0Pž˜Y¾}b¸yöÖ'€96Œ÷XX–ÿÿ÷÷Χ‡ ÞÝ~(ÈÁÅÆ ©(ÂÀ 6 f6F-,-È o¬ÉÀÁÉÎðàð)†—n0p ð0H(1pÕ²-a&oVL çã†À—O ×ÎÜú@@À_ C.²ô÷÷®ÝÑøðô%¿/ƒ¤ /Ð>ˆá@ÌÉŒ=5 Cu†ŸŸ¿0Ü;pX,¿bãg“ä3X-fgEż\À2åã'†«§n} tÀÀ7`´ì:dû××ï…œ¿­ùýóW& i Ip…2œ"¼¼l zÖŠ ìì ·ú÷èê=Æ_¾3ˆCIT˜`™!j9X ¾9€JßÞ}b¸râÖ'€ÂåxŒ¸5À¤sêí½Z7Nß’d¦_EU!!AfpnE 0dÞ¿þÂpãüýçÿ˜ÓßÜ}ª|û f&fUa~>&p‚…(šÞ¿„8 €9–>î½²êßß¿]ºotçê^.nvUu!nHÜ>}ð–áÚÉ»?XYâ^]ó÷ן— µ÷¯=忦:5A.NH¨¢òõ‹O —ßú@Ä9~rhÁНo>ó-Srï-›¬¢ƒ’Ãó‡Îºõ (?¨ö°t:Ì>«¿¾ýÄwýÄõ?°JÊ 0ÈÉq‹âWÏ>1œ?rë@‘âø 4x3xóðôé·U¾|ùËÀ ôÚåÓúèÐ_ÐRçPÝ&`èí{ýàµ2Њ?þdÐ5døýý'Ñ]×?å­bP ÷÷Ÿfnv=` wØÓ2ŠþÄÚøó/X³•Š)Šj©éI1Ýsý5@Q«Y. ,.ý€>? d_#P‹ëõl câ8Ywã@÷ hÀ{F4à w@€Þ‹mF‰&4gIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/player_stop.png0000644000000000000000000000117211550446574023567 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< IDATxÚbüÿÿ?Ã@€bb`@,0F:#c熴¿ Gý£‘}Œ@ÙXVÎüÿ?$@Œ°(HfdübÄÈÈ-ËÁÁð‡F¶3ñ«Ÿ?Nÿû÷mÖÿÿÜ 1€‚‡ÐçdÙØüJKþsqÀúÀÈÈÈppêT†Ožü†‰ ’üèo  ÿ211ü§Xø 1žòîF°ð†ŸïÞ1ü† rÇ?ÇþüØÄ‚¢héïþ°²ÒÄ`+þþEáŠ@Vþ…- ~‰ @„Àøù ß,,´ 4 º‚_>0üff¦‰þC=‰œ5 €’¿A`¢]ù-#‚Bà‚ÿ–D@Qðÿ÷oZUOÿ‘ ( ¯ŒhÀ@î€pЀ; €Ü4à w@±`k61Ó°Iƈ&@(I²Ó0XX±˜ @!@k0¢Ç„5˜iìd@XC€K¥A+ RMÅò9ÿ¡¡ØÐÌ ¤üÈöH„:€VYî1Ä.v˜@± ¹nÙi†Ð“Æ­š Pf:`L €ºw @^Æc—"ÛæIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/viewmagfit.png0000644000000000000000000000624111550446574023372 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< 3IDATxÚbüÿÿ?Ã@€b~~~p&&&†¿ÿ2°²²‚ha íÊËËg/,,l À¯ÀÀðŸùÝ»÷/ž>{véÕËW'>~ü°¨îîŸë>fø¬þ™ù# ÃßϾ0MføÏ-Îð“Y„á;Ãw†— ÿ¸Î3pð|ÿø@±`sÈŒŒŒÉ**ʹ6Öæú òr@±1|ÿõŸá÷ï? ÿÿþýýó»îËW¯¢:þøä©3+¿ýúÖ Ôú†‰Aš“?]LHÜPUPMJ_ÊD\]RS\”W˜…‘™á޳ǿ»–ÌZÿàñÓt úÄŠäøóç0?¿ÀD?¯hkKS†ÛOY.ÝûÇðî3×ïL þýc`úÿåß)Áï :ò¿^¾zưdÉš‹Ï]ˆmûš592åô´ i ïÿ¿g¸úë2ÃçŸ>üyÇð ¨Ï[ȃáÄÞ; a%™!ÿÎßY @(!ðë×/QIIÉõi‰Öb’Ê K25ó1˜ëq3¸H12ðq120|úÆÀðä5ñ Ÿæ¼Î`&ó‰¡0?UÆ´Å{önßë3ïÏÜh¹éŽa|=w{.¹ÌÀÊÈÊðéÏ'†G üÄbX9¹d@vÔ× ?~ü`âã矘™žd-&­É0÷ƒ¸²$CŒ?ƒž#Ãï¿@G£–•AAš!Ô‹!2ÖœáÊOk†ýç¾1¤¤G‹˜é›-û{óïñþíýçØ¿p0D†30|f`àüÊÉÀñ•ƒá#ÿ?@ƒþ3üÙ @È!à)§´ü0ƒ¶>ƒŠÃG o¿ÉÂQÊ3ZAfüb^`¨„È2lÛãÂpæòvÿh¥›§nYY°JìÂ÷s õgÀš^ÿ}ÍðõÏW>Y>†oß2üþóë#È<€b‚½ššZ£ƒ Ãþ›œ \¢\ ÂÀôûî Ãw ñ·ß¨ø;Ðò@‡|ùÔä›[K2ÜaTeØøfÃÒº%R¯_²dìÏ`xÿþ=ÃÇ÷¢¥£4XÕ8þ°3¼x÷úÿÿß¿ƒì p013¹;Ú[ký+Àpï ƒ¼<Äç¬Lßþbf``f„øTlü…þó-?dÊ‹êˆ0<¹ËÇ`&eÈ´3áÅ‹ ÌÌÌ ¥&% Õºu 7d¯10±30,Ø»óßß@v8€©Þ^CMáùW.&.Fp<ƒ|ýã/ÔÇ¿€Ñð Bƒ1Pîûo(þÁŸ!a¤¨ÉÀÏʼ0¡Û¶‹ÁCƒ!O;—!G+ŸÁ®ÒçñÚ]{~‰™0\¹wý0!¼Ù @à5bx,@`‰ Ç¿ÿAâä{&FDbù÷š@¡ó2ì@“x8l”|vì\ËÐÊÝÎ0Ïw>÷oßBú.Ÿ¿zÌïüµËö@³<|ýê%7×gYv?Ÿ<#3ÃO Â܃}÷„A–ÁÉ`Ë@aM Ë9A`c`àæÿÃà¦àÃpèèêÿOrÿ¿úññü‰KC¸øKÁ½Ë¦ýf`ä~ÌÀÁö @,õXþ#–XV±°B|ÇÆ ñ(:þ‚,d@äfÅ@,@;3D-'+ÔŒ o™~3ˆù5éÒf#Ž9 ì\/~3@|òqÃÿ°Øg °¾|ýúü÷¯Ÿ"|À üÅ r¶ß(EÈAÿ`¶Cͺ= ËÙ€¦pi.VH™Âøÿ7ç__þ1<`ØÍ Àü¬ñ÷H<‚RëD|Øo^¿¹üæõk]>†YÀ> N ÿ°;äHPðƒ0($˜¡ô×ïXþ~cxòìÙ† ÷v|…ÚÔ ' "¸9 @àpøðáýñ2püýv6 (4Ny€QÅÄü ÌÁ >/så9€¾fE3$×¼ºwžáÏϯ ÷<< ò0zÀ˜oŸý€8 ØÀbxË™sçŸ3|yÁÀÉø‡á×?HÜ‚| Z% 8†ÓHqN„ tØÛOX>>ZþˆáÕÛ· €U(ÃfaF=P!Èp$78 ØÙÙ\»v}ÙÕ«W‹µŒù^ý’ûŽ•u覟š=9jŸþÍpóè6næß ûß#Áȸ¥Xj}â? údÙëï Å~1<æõ¿3ìNFN†ßß~·ïßyØCXX@›XO}`–fáab`†>è.9”A¹æõ×ß ‡·oacùÂpýñ[†··nmZ´B¨Tàÿ÷@ Êš×_2|a|Í3 €À8'zXÄþ{ûÃí(ÞÍ<{œ<þŠŠHýbxü…˜uß1Ëi‚ä¨ïÁ˜š7¾d¸xx/Ë—g *ZÚ .n ×®ÕrïÞm÷ŽaÓw†Å?¡a6`žæzÿ'Ôn0fƒÂ’A(*­òJ…%X6x©†±ªâŽÏ»?0þbpÑŒfðÕ tã?†ŸÀêÓÇOÀrÿûG·þýøÌðôÅK-Ccsc#6Î/§¾OÀð`îÉ2`ðwÿBrÌAÉ@»R+>^Áœp»ÐÒÙ»gÅ/¹³Ø•ï¿à¡I™¥ÍeŒòÖ1Ü»|ŒÁCÑ‹áËï¯ ?¾ñ§ _¿|V8/.\¹º÷Ö½{[|®]¯fcW2bPW`› Åð‡éS×ÝÙ×I”¡[ó € øÁÀ()&e0+f&« ·ü‚¾Í=G—å¬}Ïü–!}oC‡w;Cý†f†åGæý×ãÖúõáë‡?oßx÷âåËSÀòcÉûïß·[þøñÓÇ;í†ÈÀ¼Çx^lf`äüÌ 2ÕàLM·f_ÆCºâ€Ï À¤äë?o¢]ÃÙâ,c/};Ϲ/“áùËç ï>¼c˜8!oI ãÚ£›šU”|üñéæÏŸ?ÁùœXåÆ?{*¬6|š:!P'U¯€•¸8¨ÐfP›`LCÿ»oÌ»Æ ”iGv@Að—YØ@ÚXüêÏ+ =wzBCšÎ6?€õ9 ƒ–¨&°¬øÉðüÍ‹óçÎÏ`xËÍÄ,¶ p£X<²þû·èÒâóbÎ3tëqB’=(ÇãZg¦%Ã_&ƶ+s®‚ª–.˜â€ÿ¬ ¦³è`ëõ°yùùe &`Û XA•š3äj0÷Å_:qíp0/ÓÛ_3ð2pa-€9³çÂÎ??›Œ¼>Å å?ëO5Öÿ:/-¸j×tƒô48EDx„Y_ÿ¹ÏÀÆÈ Rv†7ß0$k&3TëÕ1XWú<ºtýˆƒ÷s†¿¿€Åõ`‹è/P-30E3bsDóÙ3ÿ¾ÿù÷³ÛÜï=¤­Ç¦[2üceêº0ç¨î ˆ~³1³›Í?þÿ`ø¬~Ûm_ÿ~e8ôìÃu¹« ^†nB—¯^óøÿšm>¨8ùÿ? 7ƒ ?¨œãüÏ„5$NŸûËú—ñg›•÷GxéŬµL'™3¼½ù¾䀂傗w_<þïeîÎx_þãw`@Žã7;3°)½?ñÙÃ7/Ÿ1²p=ùj‘2"‚²Ÿ™°wpA5?кΣçþþýÇø³Ûÿ€uöÑOnŸ~= ¤ € %¡°xúḚ́Îìì Ëÿÿ?ÿüúl¹>aøl½þúýØXü®°[¶æÄ`Êû좖v?¡u°4¬TQbÊùý—éëÇfkóI¥@kˆq »çž„î䌩IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/piano.png0000644000000000000000000000236111550446574022335 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ƒIDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €ÜÄc022©z Vâ?T2”ÅØ€˜ˆÿAí{ ĵÀÜw¤ €@ÙšOçääüŸ6mÚqqqÀggçÿ‹/þïççæsrr‚å;::þ³°°€ÅÂÂÂÀjæÌ™óÁ‚`= q™ÿ3fÌøßÖÖöŸ››,VPP𿾾þ?г7`ö²¾îÙ³ç?hjj‚5”””€ùííí`¾€€˜ÿæÍ›ÿììì`±©S§þG = q0ÿÙ³gÿEDDÀb‡þûöíÿLLL_`ö ¢ÚVˆ" òÿ_‹\6Úå¤ÎNI1ÒÜ?Ì ]™9„»ŸAÄôª"DNU7ßö0³ÑoØ­ÿ‡gõ¯ÂH„ ÅÀ †[M ¬¬¬`Ka.çãã‹c+IAâ09æåå…›ˆ]d)???0¸á)))¸ ߃ì[d5`111HKKƒ=SLS oß¾EŽn8 œòÌGÀDÅðñãG°< ‚n Èrrr À„W+** v¶ Ì(€8@VVEä A´°°08Z°9@^^: y111†>@s%* ,!ðì666 ÏÿCC€"ïß¿;ðïß ‚‚‚Ð`þ‡”åÁ••cxñâ9Ü ø =lQ@XŒ_a6v6†gÏžÂÍVVVfxúô)Ør ˆÿþÂìRÔÔÔ~|ÿÆðE 5 Ðûýû7ÿ#M&9€ Tüÿ{­\¨‘‹$ÜË”~ „®Ošœ&¸ÖR¤­VèêÆšZ¥tŒ$×½˜9­;IË9\™#ÿêÅ@L¨–ÿ­ƒ° ÃçO\\œÀâff¦à ÕÑÖf)n°ï¹89@E­%<í€Ì¶²´`¸wŠ2/0ñ‰õ•¨_›á÷ÏŸ( äxy¿rÅrpéõç÷¯ÿ@ŸY@?üý¤ÿþé B¿Àø÷¯ŸÿýüWÁ?Áüïß¾Õþ†ªý VQûÿÿþ}{@%á{˜½Ä‚êH ÈÌü™8ÿ~Bâöß/v wÿÿG8î@òÀDWƒHD œ@cfÁÔ²²2AR2’0@¨øû—ÿþü¨Òþ¢…Ü?ÜÕ.µL¬,`³‘s@¡8àÏïšøÿoÕþ¿þþù"@¨øõꀿ4r0Wüú†„ì6Æ?Ÿ@u0¨þÐȘþ~F± €ðèÐÁCŒ¿>0|ÿE›(à–®ç¯Üç8˜@1‚X@81124€JNhó‰&mP`fø,<û€ö® ã@÷ŒhÀ[Å4à w@ ¸hÀ`¥žÃÀÈù>IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/rotate.png0000644000000000000000000000314411550446574022525 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<öIDATxÚbüÿÿ?Ã@€bb`@î€p ºc+Ó 꼟 Ü<ìÿþûþýWPüXø 5õ/Ì‹@óþ230ü‡øõÿü¯(ʈ§A ´ù•¡ÔÐB¡5*Іõã—ï Sfíþðö«9+õB €XpXÎÌð›a¢‹·^vl¨ Ð3ÿ¤Ä…$¤ùu><þšÅÀö'Fà•½gøÃp¨ûÿƒ V¯ÿ`èö6Êô3ex÷é;ï¿xE8u¸t´e§21cI:ŒŒ Ÿ?|gxòèí»û^ßùòêû\ C£¯Cˆ½`L`*´sÕ싈¶bøôöï™Øy˜8ØY˜™p•LL ¹ÿ ?c8¼ÿÃáÝ7N|ûú+•…í Ã?ìi €0 Çw¥¨ÑS›ùÃ×™ ¡BTyÅÈÀ S6.&^AV†{w_3,Ÿ}ìå›ç_ÂXÙbs@a„å÷ÏïÜ»û†á?ë†_ÿþ2üøý—áן ˜þ2üaæ8ño`jùþý/Ç·¿žÝÿÆ &!Ào'.&-¸–áç_†ÿ˜Ù €0ðëçÿʵsÏßòì‡0ÐP å?€˜‘h<ÛO†?Ìßþ°@1ë†?l?à|fÞß "À$Ë tÈ /Ÿü``ç`cðŠÔfbbécøÍÄŒn@a¦8n`öû§Ç/ʳÃ'E[RJžŸáónÁ Û–ßüûàÊ›‹Ìl̉ëïÿÂ@O³0p2½ÄÂÇÇ.­k#)©e"Æðó3 ï/ÌÀ(ùÏÀ/õaËÂk ׎=÷ú¿æËvdû3°ƒ‰›åÒÇ·¿Ü×M¾²Ä%VEOÅ@˜áÇÏ¿ oŸ|{ýýõOGnæ_ ìŒÿ~ó:@€Á‰{!0¾X?¿ü&ýôÆÇÒg÷?§Ú)0üþÆÆðï;ÓÇ¿ ¦¢ 7O¾ Ú€â€ÂtÀ=`)øè.–ËßYÿym™ug††ùŸ_ßÿüõøÇ AÎO ¯9ëÁo þó k §ùT„ù7Ãï·äÙÒ.ízÉ(¡Ê“"£ tøWv†€~acàâ4A· €0pZư!Íúô¿!oðõý¯]€Aþ“q?á/ O€öþG3_C*—>“•2×ä›§ß'Š+ñ0ÿüËÊðûç?`Zø Ìl|èÖî¢dÁC Eß ÆmðBêFÉZÐ\ùÆÀÀÎöö·0ôÿfþ ÌELÿÿ1üû LÄ¿Ñt@±àÌÐ ñ@, ÔòG!Œ+ 櫃TA ðáú‰ÿ.‚@˃³0Ј¿1üû‹™ ˆOU´ˆ¹pA¿ !À Ä€˜ *þ—“UX~æÀôó÷?püùý‡áÿ?LCˆO±öˆ¢ï1¨ð%]DQÊÎÀ +úÿßïÿÀBìÃO`0ÝÄ 1   kSf(†^ åÆÒÀ0`dù÷ëÃw`°ÿ¦Æÿ˜AøƒY‰ Õ*v> å&²äLÀÁýóÏp`& –? À´ €¨çv``â_À- ¿€õȯ_ €|Æ€40þÁlÉõJ`¿™ Í/`jÿ÷”@Y(L} 4ðK. ê9TÓýZþD30þæŸÀDø÷#0þ30CäßF õjÁþ5@Eô_¦?2±ü`üÊðŸï.0YCáßP½€Qõr0Ž‘,Ž˜AEÒý¿÷yw|;(èÁ ò @Dþ¾àZn@Qê€ðø E>10ˆ mûûçÿoæèßd@µŸ4Š0°ÿÁp@1tß €¼g@î€pèIaøM :IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/player_fwd.png0000644000000000000000000000403511550446574023363 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<¯IDATxÚbüÿÿ?Ã@€bb`@î€p#ƒÉÌb†ï¿“X˜ç2°2ÍføÏ𙀠6âS@ü™RÃïyîŽÊZrâ<½ Ÿ~`øû/„Ÿ‹¦2þÿ¿‡áëï½@µAøÔˆ‰áûŸ?ažj G–3D†è±ýg\Íðí÷Z œ†êÿ Ìÿü6jȲ`ÈN04eÿϸ¨v%Ðúä: €˜€šÿ?÷‹A\”“av«Ê~ æ&rA _~bøù§¨F Å þýæf˜RnŰv–?ƒ©¡t×ßû€j[ò‚¤: €˜D½ò¬¬•„TUEn¼``P’åeòTg‘àç¸ûð£å§—ŸÂX˜¾103^Zÿ è€L3 EqMQ†o a1^Î[÷>Ø~~õ9¨ö#ã  Ù‰q@`f¡$$#tÀK†'ïÞ|¦2]7'U66;÷ßùþþøÍhø{`¼Û[Ú¨JÈÉ 3œ~ÀÀðჩ(ƒ«ƒ H­Ð­;oþ|ýiÅÀÌôŒ‘ñ!Øú¦JB²" ß1“ÐÐï ÷ßÙÿXl̤l¬”Þ|ú-ÿäᛆï?EµŒ”˜”5DîÕ¼ª}ð†á#+ƒ­¥4ƒ•…Ë÷?Ÿ=xËðï¯"0w]Úó—ì]#%!A)†@ü:àÛoˆCÞ}wh8;;ƒ••"ƒ†¦4ó·ß™N¸Æp÷éw F†/?¡ö¨ö5 ƒ2ƒ²Šã“çŸ >= Œ^&¦3@“~£; €ÀP7P⃄À`Ì}ý Áßþ@ò˜ÛŸ|``àáe°¶Õ``ààd8¼óÃé#—þ°p2° 2ü``bøúƒá9Píc ZA ~kuVnN¾OÞ9üúòÍ-/Ñr œ˜¡ €˜ļò”t•„X„Eîðhá×_¨øûoýhð“ ’Šb Æv ß¾ýe8¹åýk˜ø€€Ÿìè/? ~ö…‘AVE‚A×D™áǯÿ¯Ÿ¼gøýÛè›@‡<9 €À! «¥$Ä (ÂðS¿þB,Ćþ…8ä9Ðo²2(éÈ2Hj(1¼~úšáÆþ ï_maøÅÄŽJPÔ€ý郒®<ƒ˜¢,ÃçOßÔ¾¿yÇðÿ?0ZnØŠ:JBìÀ(x LýLŒðÁ…¡Åá c^ƒ›™‹‹AÑPM\†áÕ[ //^ePSa`bccøÿÌ¿~CÔ²óñ0Èëª10 ‹±|ÿðÉú÷—/Ä.]€&ÿý1œØ’•¨ˆ¿ýå Cx¸X98~~ø´øØœÿhj¿þå, ›‡—…d±@rèßÿÄ[2™‘h)0Z>~g¸è4ÛKW¸%ÅÔ‚üØüƒCŒ µ@[˜€ö}ÿ™áÙ‰3 ïnÝbø÷çÏrVÖ&€;€X)³ dg…°ñúh ;0 ~ÿaxvá&ÃÃǀå ƒ†·#ƒ¨–Ø·‘2+Pí¯¿žœ¾ÆðôÌy†?Ÿ?ŸjhZ¾$@, ß°ÁÃLÄ\@0bõ0Ø`6H=»þáÚΣ@ßbP³3fP0×e`çæ`øûª¨Ž…¢÷Ñ•{ ·aøòüåK ¥m  €ÂŸ`f È@f ïå$¢ÛÎ̱ü5°œ¾ºÿË˷¤´ô’<„¥…~ÓÁ`ªÿÏ ±„ŸÝÍpußY†'—ï|¦ö¥À¬ hÚCtÏ< ¸AAÅpÈ' ‡±Å>½ýÎp~Û%†›Ç®0üzûá¯c¬3³‰·ÃW`®ù n ã˜9!jß¾üÊpzÛE†@µ~þÚÊÀΪ%ãŠR€;” 8šÿýC$Dv ¿ýc8øÃÉmÀ |õî&0‘t Ìáá1àZÊŠk Í ¹À"óÌ¡[ Ç6ž%¶@µ@µ+¥g€be.`°üƒøä «gŸ0Ø Âë¿SèDnŽ©Àì,½þæ2kZNH¨ô^8õˆaÏš3 Ïï<ûTÛ ”˜ Â×Äd(€;€gB¼À`â‡÷?2ìXy–á‘›yiP²hËuh¦f:‚‘—›‰Xw1ܸöaÓ’3 çÞþÍð÷ïj Ú& Ú› $t5ˆd  +°=úŸaí’s 7^døúñÛ)NÖ:`PìÄÒ†bû÷û7úŶ-? Tûõ('{ó.ršdÄÈ 7í±…‹†Ì3`MôèÚ³û ,€uøL ÜO¬ê¶°°0{ýùôãÐÕ µS¡eY €@Íò6`Í Lþ«¾˜ ¾ÇôÈ‹PW`PƒBç ¥Ír€bè¾!@ xÏ €Ü4à0ª€¼À&IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/2downarrow.png0000644000000000000000000000431411550446572023331 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<^IDATxÚbüÿÿ?Ã@€bb`@,èŒÞÜ~2Ô2ücæg`aþËÀÄÌÄL ìÛØØê˜Ù~2°°10°°3€iF ŒŒÈ&€P)P<¨ÈùÏðŸáPâäÿ“–!Û@`øÅÐà(®§­*ÈððÓF Ýß10ì:úA÷Ó×ÿ , ™@Uïqxˆ™áC+sÐr°Û9îäãb`øó—áå;†V ¦˜Xî~þò_/×K h Ãw ¿ÉDZ’—aÞº—៿ýçaàdˆÅâ†ß Ó„™ÅEYn¿`[,!ÄÀÀ¤o=«yŒn@a¦N–ü½g>í÷ª¼ÉðõíOYN Ëß20HIp1„ûH3 qx3üaØT)ƒ¤‹rËä%X”Yž¼edàꓺ KW00¼yÏp5èÖ¦þ]ÉËxîÎíQ¾¼ÿÁ`"ÉÀðí/ƒ³µƒ€‡Ðk€ª¥˜èó%:ò,&@ËOÜe`øL’@ËYá{ëÃÇÏ §€‘ãT{ Ý:€Âž þ3|dàa ¿õäϺȮg /_þ`pS&§ Hca0Ödàác7gøË° ˆ·hʲø˜¨°2ì¸t?ÐD`Lé@Ë?e8´<¨ó6«_6üÌÀÍœðü#âä)oî=úÉ ÇÀ ŒÏï˜dy¸yØX9Xm?ÿceX}’!@–ƒ(ÎüdØ ´<È}‚Ë€Â_ü:‚ƒ)ñíWƾÌ.ßùÉkÆÀ ,tÝOF~~v.`œ¿‡$gi åÿ€ öк_À4LÃá@™×ø¬ ìåk`6çéÿÀTÁÎXúåSké¢ï »ÎýfH´d`°Pf`xûèol&-ÌÀð˜]ï?æš¿ s€–§ ø +±; €0³á×7 l< ¦qó3 $i²2Ö|ÿÇôµyýïæï¿™˜Ól™¾ÿf`Ø~‰A„h9ýø%Pá?†É@Ë Àz¡^üý¨à 0î>9 (Ö Vg}|LöÀ€W‚AXˆ &±1µ3üg~Û³aò»ï lé¶ÀÔtãæs /Þ€l– L -Ð" è …€…àw åÿ~AJO4@ØÀ´Œ˜?½€¸ú=0Råó ã, ü¯yfþúÇÀÆÉ¶ü0îË€–÷‚}ýTìÝúü8 ˜Ù¡!‰Ä‚7‚4j˯À’èÖ>qM9S9 X>/9Ê0h)_¤g‚ƒû/0¸_³û¯o3¡×¨ €XVW° 2èõm`4SœŒHf-ÐbPé ×Ë`ËA!õå-ÄrfVÜ) 0ʃ eHøM5‚k—7€EÐNqU`ü2Ü‚Ç÷;`ò÷} Ú˜[¡Ið?Ô `2e¸åÃ@a:àß߆¿?ó€ÕÐ÷ÿ åPÏÿç€y=è³Ç /®-F¾,Äè÷À´òö>Ô× @õ“âö`€Êåÿ `dü Ä bÈÖ#z‹ˆÑ`þˆee/wU†{Ï3üùÇÈðíç?†•«®2<}üñ 7WТûà„Å L”üRÀ¨¹ ){™€–²óq{ýá“&!V^`Œ °0|O}~ù™‚²}„¥ ú¹ñüég l ~r æ² Ʀò ©Ùö ²Ê&ÀÌ¿ h“!8müÆõ›{°BK‘áç¿mŠr|^Êzj Ì|B Ââ¼ òò¼ ¼ÜÌ Þÿ%ê½è¶¦X™ªoÞ~?+"c'ÃQ C”Ä™” 9¸‚cmäÔe4~ýÝTiv(Îÿ3¨2üú·VOCÀRQGáÞ;` &“ï?®\zÉðåóŸõÀPÊF· €˜°”ÿ?x9Òß½ÿÝ›Y|˜áàÁÇ VÀÜÇÅJE¬ v>& Rj2r ¿þ¬ªÊ êÀ`ßè`*b(£¥Êpè.+70v$õÂ/ Ë¯_y*¢—0°2ÇÕ~@· €pTÇÀtÁÅZþéǿ֢úÓ Ûv>dp6–÷À(ÿòƒ…AÛ\—ATIF Xà¬:d‡®¦ˆ¦°‚2îk, |@ŸK‰ Ò_n_*…g303¥Mý†Í*€Â]üÿÿ—ƒµæÇ_Æ·e-º>}ÿÇæ¯Èð˜/v\dfÐÐdøÃúDâûÏÿ OXe®^fbV!R@Ÿ}÷‰áþíw ÿ™˜;˜+ñ•ÄB :<ÌýÀð©mò­i¾ügKˆPÐÂŒ Ì¢² ÌÀ´õˆA–ƒÚŸ^`xòà=Ðr–j&ÆvB@. A®`ašûï?ë¯)sÌüü‘37^˜&l†+°®Ö†âÀèùðò=óGïÿ[MUÀÚEL¿ €XˆQ ÆÅÀFÞÛ…kŸ-xÿõ¿hiªÐ&†Ù{€íîÿ ïž½exùôÓW åy@‰yÄvLˆ…ÀÌ´•5|ÓŽ·Küf–¬L“eàçVK–?¦:6Ö å+I1 €HsìgàeóßuøÓšoŸÉ‰q€|þè°h`ñ»‹TÈ€ÊÿÓÀ¦{Бsß»ñ0p0WÅö’c@1tï €¼w `ÚW|¿ ŒÛ³IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/mail_replyall.png0000644000000000000000000000541511550446574024060 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ŸIDATxÚbüÿÿ?Ã@€bb`@î€p Œº˜áï_†?ÿ3€\õŸ‘œ<þ3‚Ù ðû÷? Ÿ‰‘jþýƒÐú@ì¿þ©üúÍÀÃÃíõåóóåï?œë¥3FFF„­PnÝžÃ@,ÔðÈ‚?þüþõ7UPˆß/,LYæûy†õ[ö*ž>³|Õÿÿßb×9‡ €(uë¯_\ÿÿgL’–õ31Ubu÷T`ädc8yñCd¼ƒÀí› eÎÎfaá„xý70Ôäþ0üõü6 €ÈrÀ¿ÿ8ÿüþÁÀÄ¥¢*ãln¡Ê¨g É !Π%ÎÀ°bùaNC cÿ˜ÏwôþùûúÐ:6 ~਀"ÞŒà ÿõë·/;;[¾²ŠŒŽ•­ƒ®®$ƒ 30áˆ30\¹ðƒáÓQf6v/_3¾óg<Šž>]ûÿ?óF ÿ¥@‰b,@±¿ÿý“ÿýûo"W„¾¡‚º¥• ƒ²Š0/ Ðv ¯¸€!ÌT{æÜwM3^V ÞŸ¿,,ô ý"_¾Ø:é×ïg·˜Šÿ%™!æN€íïßtÿýcÌáåã ÖÑS67We“ãfàæF>P'+Ð6V›‹‹a×ö¯ ‚, "B, €–3Íàác`ðõ7º|1 øñýÙéÿ,€¶³ý‡‡@±`Æ/(;ýóf©,1acS-=}IIv…@°³ChfH€òúÕ†û¿3X; 3p£ƒ èÈ/?þ0pãÝÎJ€a«^@ì›O§~¹t‰áÏ?FFfpf dp}ìÎðŸ9O\RÒ^ßPYßPœ°8@-ce‡ø˜„™ ñÎÈN ûvbPTædbbøðå;Cýú:†m7×0ب81t†ô1„Zs^xnÓô…õÂsFN· ?çµµÜÀ‚d¶††hL@€ƒ²ªØW ‚‰‰ êS faˆ¨°Ñ Û¯_ýÁðñóoOO!†Gož0$ÎŒe`dùÂÐUÊP<­œ!Î*ŠA@Yˆá‰Øÿx—85y†ê…uµ Rœ›€J¾3çî3ìßwžáÒù» ¯ž½bøùý+0qýfà&2‡Ð!LÌËýúÏpòÄGOWq†óÏ3Ø5Ø2 ±3ìl]Ç ª)ÄÀÁÅÆ°pß2†”A Å±á ³Sº˜„¿‚ʃŸ {À¥‡Gx¡–‰Ã…Ëï½úÄðíók†¿ÿ2°#ZXˆ›AB‚—AT”‹ADÔ2œ ¼¼Ì gN~c`8òp CROgøúñ'Ãí;.ÈŒ|A>^`ÙÏÂpôõL†y{úš³ÊüüV~™ÎpäÙQ†ý³2Èpj0ÌomcP†Æ„ç- ïØ3|zÌ"ŒÿÀ‰ €XQÀôíû÷Ï“÷l»¶8"Ñá°¬`ZÂÁÍÎ ÌÏÎÀ&#În tª¥X™þ0<{ó‘!gbÃ¥çG–¶Oe0&ÚÞg ǯ_b8=å-ƒ¦ˆ.Ãü¾F†¯Ï¯×0|f|Ïðüü7†s›Þ2p¼“š² €P²!0–:u«ÐÎQÙHTšáç#€ñ r+ÐAÿþBR¼ˆ #Ãg¯â[Ó>2¼aØ6u£ôG†Ò«Å Ž?f¸³ø?C¤³?C{UÃñOfœŸtô?†Ç‡¾1<<ÂÄ ÷·’áÅÅݧAvr‰ÇÌÌüïÇÏ/“öí¾Ç ÌÇ,@ÛØ˜Pó»˜Þ3gl¢¼øDØvÏšÌpŸç"CÊ\†=«ï1Ü™ÊÎP“Â0¡.añ“ Õ'[^¿ùÄpiÅ7†ç{DÔÞÄÜø~ãAîÇ/—6‚ì ¤(€Tœœ,«OŸ¾žåvGÕLV›á×w„¸9ÿ1ÌÛ¼¡¼«–!4Üž¡,?Œaá½ ýgæ3|; ÄÀyIžarkƒ›—*CΉ*†­w÷2ð~dxº‡åÏß[ìž³Oüñ÷ÎŽOï¾fbæÛ@H!ÀÆÀ@ÿöçï÷)×_ûTâ1ƒ-g`xüòCjU9ƒ_”-Cu‘?CÇ•N††#Ó>^beø³Gš¡£=–ÁÎK„!eOÃêó;þ«Þ×Ûx~Þf8÷÷ËG˯ÿšù?;ã_H« €˜ÀŒU«.!ÚiL ×^¼øä©©!/-'ω{ ÛøØþ«7ïf8óóÃ-–SÀ„ÁÄðƒõ'ÿOl €Ñ)– Oo‹s†¯¿2ð°ØWE¾,ß%þˆ3îþÉûñßOþ_ ¿Äÿ2Ô§ä3"€© †™ÿüùû­cËæ›A…3´Ðabbcè,Êa(ÍdØ7á ǽ ò bb¬ ,A÷.3ž`ØÕü›ýŽ ƒ¼?°>þ+÷Á%]•×L]'‡áíÏu YdþðüføÇ± €˜PÚiH˜ƒeÛ¥«·N^¾ô\û1‚Ûâ¹$1šaýô% Ÿök0Ü_ÎÏ Á&À !ÀÉÀêûœáŸõs†+sù>ePåc`cüǰìùÉÈ? NîÆ¾,ßw1üf0bø± €˜PÈÌÈÀüãß¿Ÿë×]ùªZAÅ0È!Ÿ>sÁ®/ Ƕq0(²èìu˜õôy¢ ‚_…$x¹X¬^00Þf¸³ƒ“áÙRInAnF†·w0|µ½Ã`¡¨Éü—iЭÄë-ÁÒùËôëëÑÚ*_ =^†Û?2lÛvþïù‹¶`úú×o9†¯_úÕT”NÌëî[ß?Sˆ“ë@±ÐÜò?„¾üL“ÊL‰ˆ”M÷ e’f¸÷ì)ÿÿˆ…F) Ï9¾ýŽââ,÷ÕÊ‹d0’Ò&…@ø® €X¨nñ` þþׇ™•-ÏÝßÙ9-,‚ÁNÝ(üŸáÃgV dc`‡k ê9T§ýüg¤KYÔü³"ÃY‹S®aZü h)¢€b¡Š¯ÿ×bøõ¯€W‘3V܆‹ƒM÷ƒŠŠ$8¸¿3üú—‹6F0 @”9àƒ$ÃÏ¿9œâœi26ü"bf\ ÿ¹þ3¼ÿð…á×÷ß ùÿátóŸ¿þþùó €XÈŒgN†ÿbX¹Yjå]„e옾ûÍðóÛ_pv«ÃçöÀ¤ÄBZÊ$ý¥a±¼•¨­ª½(¿Ãw o|ùÃðÿ6#ÂÄB¤jF†l˜X*dõEܵ¥˜DÕx~ýùÃð èë¿ \Å*bIE€b!Ô ÈÒ&°bq5áPgn=a`QÿŸáë·_À2椔c$? ΢ó÷?)`<J &›8) i˜I1°r13|ùú˜ÀþBG@˜ø÷ŸáÇïîcUEE.A†/ß~2|ÿú‡áß?Š|Œˆ© aÆa''[‰‰ƒª¡µ³ƒ˜$?×_?¾ýøLwL ,ìÀòìÏ`m ÁÌ üD3ùŒÀš–‘é³²°2pó?0³iH +Œ€ÅP-#È@˽¸PYSÂÚÅUŸAQ^œáÛß_ Ïž¿gø Œçßÿþ2üþû˜þ“ÿ÷Pì?0C€äþ@Ôü…bÚ_ÿÞ½úÄðäïK ú?à‚d=ëV°C¸Ø¹ž¼~Tû €@ ’b #ŠAiXX€÷++0?ÿbømpü5>þ3ù@üÒà‰A0¤‘fÿ‡òè^FnN&pã…,Î ¦ú™ì?ÙŸ½ûx €ºc@Þ& w@ ¸hÀ@î€pzyf­£¦ÃIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/encrypted.png0000644000000000000000000000401211550446572023215 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<œIDATxÚbüÿÿ?Ã@€bA Kᔑáß¿ ?þäååå ”——s“‘‘Ôa‚/ÞÜxôèé¾/_¾¯áââzÍÈÈÈÀŠՔٳÛPøÄB¬KÿÿÿÇðçÏ;³.SSs!!a66v ý 9Þ…œ?9󨱳uLLLˆ5 €ˆrÈçLLŒþ>>n uu ù_¾|ÏpåÊi†wïÞþdddú'&&Æ©©©Êàââ¤+!!¾zÛ¶}y@=Ó!h6@±`ú3MüýûWÉÖÖvž’’&ÿŋז_|ýæÍ뾿ÿFÍßÛ·oêݹs§ÈÒÒBQ[[“åçÏ_};w:´ÿ$! aßÿe””oQTTºÿ1ÃéÓ'î}úô1”õÐ÷à´ÁÂÂ|èùóg[÷í;°šƒƒÝX[[‹ãÆû==qÊýÄg>@a„#3(¸¡˜ˆ™ŒUT4ü~üøÃpãÆ•¿Ÿ>}ÊÆý9Åÿ˜À89¹îûö5îÌ™sïÿþÇ`` cÉÊÊêÁ6‚™1&@a8€õ߆¿ ,  ˜øûd0·Ÿ 70¾^¾|±•••e70¢þ1²0°ÿÿÊÀÁðá /Ð2vvökÏŸ¿\úìÙ qq1f~~~O9`Ë™€êÿ~Áp@a8ÀôÏ~¦Ÿ ̬@CY¸¹¹@YêíÛ· ´°•‰™…á3'Çÿï _·2èßÅ ÿëÐv E¬@5ÿ6³ä_NN>>>+ff`$õ0° 0H>‚á€Âp׿ Bž2üeb2 0žÕ@ùúÓ§?Á}é/#ƒê—C úŸ6Cë'ËïÏ 2ow2ȼÛÅ𤇉é60š^€ÍââTddü/ô…“AðÓYîo÷1@øÍÈÁ òý$ƒøï ¿™y>âeC ýõ/ëGÕÏû$^e`þÿ  À2˜3ó0¹À ûn;ÃÎo€jAièx¦¬,ü_n0H½\Êc ¬¹à÷µ»˜™ÙMØÞ1›þÿõóÃ÷ßÌÿä>eÿu‰í;#'(@1T0Ýð¿=Å ñóëÑDÆß¿þ2üøÅÈÀûê»øÛ­ì¿˜ÿ±²0þF· €Ñóý1W~!ž"nvžÿ@Ÿe•0áâáåøñýû¶Ÿ/Ï33üû Œ æÿhÅ4,ÓþgøÏú[Ö_@€óÓ§/ÿ?=8ÍÌôÿ×ï~¿ýqVÎÆ—+‘uF‹ ô{¥yjsòó2Ë^ ^`ðÿa`fbdùÏh` ±ø,ÏCÈþÿ—œmþ3‚ƒ™ñß/ Ö¿ÀbZ€‰Yɨ™áïF†] ö+ 8 €0À+À%Æ/ÈÍÀ   ̇ßv}c`ù¤YŽáï0Ÿá?¨lâÿï€ø;46€ôg q¿ØÀ‚šã ø%ø„A¾B„Yÿýÿçÿϯ Œ¾B Y¢ÿ~ƒX²üß'†G§®^|Áðëï?=-f9I 8Ðò_¬ˆAÊÀðƒ‡áßßÑí ÌDÌr Àˆá/Ð’?ß¡>„9(Î,¨îe(éxÄ0óÄóßæT|eà–•êaÅLíÿÿÅ!f£€Â^]‚úïg é `–^ÿ¾@h C~>g8²ç)Ãl åü 4Äk/00lØtà—÷}°``þgÀt@±`kx@Bä€_HQÄL¿ÀâÞþgE¦4ýƒüû˜~Ìôí?ôø ÑÿŸÃ6€Â?!øûŠ¿ABä` åhÌÁà&¬' ØLˆÁÛ蔿@‹~C ”~Pð7ˆ™X@awÀ¿? ‘ñ¨aÀ²„O_ˆ!Ý‘ê€83mHqµÿè˜RþýÆj@aF(/3ý'6pâùÿÊþ c €øý7†ËW!ùàÚu† O@}‚@ãþb+q–³2CÊ 4@˜Ù.`‹`ü‰È÷ Ëéáë¥/ ׯB!H飇 /.ÿgPæ6”©žÇÞö ì¢ÌŒ‹A`€Z  O^~aøvëƒ2ËI„?AÙü Ðé€v ¶ÿé¬  좰(…ç¤ø `- êËÇЦC¼,Ÿ2c)[ÀQ€i@aIL þûR²J1Æ¿Ðpš ÂÁÀ Á‰½Rö‹- [DÙKü5C€.þ‹”r™ ˜‘p[˜‚—ÿY AÄ‚Í~`5Ì_@Ÿþe¦Nÿ ä€ßÌ\…ˆ3´™9Šy˜¨è ¯~[Û†¾ûöéç;1v& l& 0¼ ߾ܸ.@xýòmõæéç+9¸¸@-¢¸:ª¤ô©¡Êôû×ÃßÏŸ¾ž‚.@ŒÝ=0nU 5%àñIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/rebuild.png0000644000000000000000000000400211550446574022647 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<”IDATxÚbüÿÿ?Ã@€bb`@,0£Æþ4^ñ:6f®@™ÿÀô$úß û •g€Ê¡‹ÿGÓ ‘géÿýýóÎÿ~¥­ý@Œ°(à1¿ú°¡Q[Ž(ú“áï?þóˆÿÁøÿÁ|0 Äy( åÿóÿCõ «»á÷Ÿÿ g—Ÿeø|ë¶; ó.€LP[ À0ÓØµìc vÿ³6‹}Œ}4ù8[i÷#rU!@_}˜2Ð =wžÆ‡:`œ=~š­Ãzœ´œ£y%ø @%åC0ôþ'ÞjS„ìK4}ª `k»î_q$ÉéXkyáïY¥È’tô¾àyˆ” Œ Œë DJÿþᡠy°(„XeƒÄþB-‰ÿEÿeÿÿA&(›¬h$ÒÁÎa ¸˜˜Þ¾ýÆ ÉzAQœƒáÐFF¨Ü°aÅC00#L-ˆôYßYQ†ß `†&L€‚;à?ÐK ŸéjJ0hËó1üøõªÙ äÆÿ¸®)(ˆ¡!@ˆ4‚@Wqqs3pòò0°ÿ£VÅwÿ? ŒL_€éí?Üw4NÁ*ÁQBýb b-,¡1@!JB àŸÔ/–_}zͰñìf çþó÷?¸ç! ¸@®úûúž~óõ-CþÂB†˜©I Þ>fà`åæ ¿pR"„”`Ô…‡ŸYƒ¾„CÂĆ·ÿëXYñ833" ü‡¥ÿÈ‹û—Ÿ^2l¾´…áô³ ¾~¦x&fF6†§¯3È1ø»3¨¨1äOècøõEh‘Ü_–Ï Ä‚ÿñgj`ÕÙU K.gPSbÐ×Rcàáæ‚×à¸6ePUaØö}9Ã7Ù÷ s«sÒ?M`8{ü$ƒüu€ÂâÒÀ¼ãóÖ_Ë”ÌðDàÃÍŸûþ!#¬檓¿2ü{ùŸáÇ¿o Ÿ…~3t0x”…ºÿùó €P³!‰‰ðæË› ‹,f¨/f˜ÿµ‹áýÇ÷ n¾ <ÿ„ Y Zp2s2ú²‹áÙï§ ¼– kvì`øûZâƒè€b¡$,;µœÁVÍšaÖˉ Ͼ¿bÈ®f8¸í,Ãë/Oi€, _¿|fp×tfÐ43a0au`عø*ÃŒ©Ož%ÜbzÊ@h‰ø(øùç'Ó×OŒõô&<<ÄШÔİyÇ! ]##/pZbeba8uûÖ{R~„1t-›Â°ë¾°švføûó! Ãûÿ „Që„gž1Üõ€Áâ³C ÃÛßÞÿyËã–¢NCú+Cý•†{2ä'0ü9ïðeÿ^Žg?,–3RüW—Äæ~N~1e†Ý—0ð² 2<ÿøŒÁÏØ,wêÎii!i –bàdã`0RÕc( ËaP–’e¨\½hÙu‘¦ ÌÞØbæÖÜ÷Ì«ëõÿ+÷?þ§´mêþÏ'òãé-rýæüw) ü_»¸óÍ¢îÿÚ >?ˆ ½ "¼øø‚!¨?·ÿ>f(]–Ãê’ÈðVåÔ{í ñny ·ß¶ÿB[@6–Ú /Å®2̽?›!^9“áʆ žÞ_@ðf9›ÂÖ‡¦qVr-âß¿þBÚ{à6°å䀸ÿþÂøÐ6à?v†'¦ÅÉ1¼ÕxȰùÉZ~fAf&6`ü‡:™‘‘‰áóŸO ßÿ~gˆ‰eºeÅQÛ¸íÝϯ¡ßß>Wœšs¨–‰™™ÿ` ”ÎÅ?°ßÿÿƒT¥ÿ³þgþÎ|ÒüŠœ£Š Ã`«šƒ^b>À4À/ An>‰? Ö?c¨[V¿åÓω ìœßŒ¢ËA½P™ÌÉÐ64¬- +¯-Z†ßÀ¶®ÀK&‹æâ ÷ŒV=[eæó?O0hßsf8zîØFv`%l[KÅÏ_¾}¿úðþ£‡¬jžlû,c ”ÔÄ Î ¾FŠtd6#’À?&POã;OçŒ3¿¸>ôîmL*fŸt1Ãê}‹Š˜83üeaw6þ2ýb`ã}ÃÀÉó•á×O¸•ÄBµv'÷ÔÝçwÝyÙ÷i2·*¯ä# #ï0üõX€ ëP zY @,Tkú€³ì;/ݽèÂ🫙ã/Øe,¿€ø³`¯ 2GÄ ¼¤IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/bookmark_toolbar.png0000644000000000000000000000467011550446572024561 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< JIDATxÚbüÿÿ?Ã@€bb`@î€p Üq†(øÖßH®sJ7TTœ gá4\%EZ:Z¤Ð#@giey×8Å>†ß@KÞ=zÄpóÒ%†“?~<Ãŵ”“•µùïß÷È ¸€øÃÂ"õëçÏy¬¬îA  @ËXY€.g† à ·n10Ì™ÃpeãF†Ÿ¿3ºº20ee10€ÌáæF¨ý ‡'O>oÝʰeåJ†}_¾œcââŠeýóçÌw0Øùÿ¾=XJÊÒ£¶–è°e?bF'';;ÃÁƒ5..K¿}c`@ÏÖÀcàâb`xøáDs3â7nÿçáqaF Èv@ž¶6÷߿§òógy1ÈÊ20|þ 1 2&rˆþþâlja¡! 6óhu5ÃÂû÷·p°³Oºrå@áŸÿÿ-eþŒs90þ@Á†Õ0tðñ#„FW r ÈRïYXþúÄðçæM†À¸·02b8uû¶ÏMVV_ ÊµvÀ¿_¿ìøùyØž=à F\˜hÁÁ(ÎA>æà€¤©‹¾<Éðù̆ïÀ(ø4W]PÁ˜Nîþûçr@Àõë—¹‚„0]ÿ‚'Aô1#Ã¥—/Î=Îðëï?a`tXÉH3H 1ü½páÛ®] ß®^eø L#aÃÊ›?Äi‚÷ï_]@ÀñïŸ,'Èå  ýû—ˆÒƒ…aÁ þ23hké1ã“áÂëW Û/ßd°xt‡! ˜8ÿþú ¶ j1ÌT`’eê:@Ä °€eÀ÷ D÷î$XñDÁ?qÿþ3üªç“Sgðdøòù+Ãÿ¾üøÆ°hÝr†¯·n3¤ƒü'’Ïa4¨Úñçïßß 1€Gà/FÆ‹ïA¸w’•€‰+ª™qû.CäÅ+ À¦}ëCßì) ?~þæÆ ¼< ù)™ }ƒNðp3°B}þ óãÿÐßþý»² €Àøÿ÷ïþ   ¿~áÍH:9 ¿zõŠá"+CHJ>Ãfvé[7tVÌcX³n  ; 0ð„ùxL­ìŽHJ}üjñop‘ÀÆÀ ÌŽ×výüû÷(Èn€;€ãÿÿµWÿü9{”€…ß/¾~EuÐQO€¡À!$Π¥ Â›Î°Nߌïã{†7W2Üxx˜ƒy€…AQJ†á±ˆ(ÃW¨þ@iY))†w@Gÿþý!ûÿÿ Av8 0ýû÷þ÷ÿÿÕ¾~Ý–ÄÁÁ$pçÃ~~v`Šfåq ‹ÿÓÇ·'~˪2|:„‹…!*1‹aƒ+;ƒ¾²2°ÄfdàâæºõÃ×@†…0Èå䘀Yp-0¿ýýÛ¬ ÀQ@,ð“açËŸ?óæ¿~Ý&*Ê! oß‚ñ_PºVDü ²çúE†÷ß¾0ˆðð2ƒ³0·X*³1ðq³}ÏÆðû÷/Ei) [†¥O3ÄsƒŠ Ã7`Ù°òÙ³ÿw¾oæ`a™Kè„Ò`gbšúúçÏÈ9OŸ¾>¬ø¥"Ð¥ Ÿ–ƒ³+\¹È°qßv^`pó?/'ƒ7'0w2“Ð%9i†ÖŽv†¾Á äåÞ͘ïÞïÇ_¾äñ02Ö«vp€×5ÀBT;J1`u ¤þÉ‹ÍY¦""î^À û þ‡À¢”XóýÖ%-ÍÀ‘ÈîÈ *'¬Ù~ýþÃð(ÏÉÉÆ (È Lp, /€Ž)«ªfx³aõåÿÿ½¿±²žú õ9ІE/_2V0AØÜ¿~ÿ®—çæ. PScæß»Àú· `[ ÓÊê , Ê Œ â˜J‹J,MµPÊ¿2”WVÿÞ¼em o0Ž€Žý vì›§OŸÀ­—?þÄp³°ôx«©‰k‹‰1<¯o?fÖƒ À’á14‹]Íç\¼ºú&2h+£8âýûO •Õµ ›7®iãää¬ùýû÷ ¹ O ‚mBvfæ%?~ÿvZwùò™½ÀÜ!g`À Ä¾åo`s…A -M:º qož1dg¥3\¼t®ÿË—ïÀÜÁÆÐÛÝÃàëTõîÝ»ÞÿÿÿÁ刨F)3#ã5FF÷#wîÌZ¬Ý˜€!fäàÀÀÊÃÃl\0¨ÙÙ1ü¦ ‘ç/þóÙ·-%+õÅ… 7…ꆷo?‹pfdèëëfHHH-üøñS0äÙ@fÁ(`²%%˜– &Xš'g¯±1‚°0¨^dxøþ=ÃÖ3g¾~ùö­ò!Ïä¹LŒZÊË'L˜Î¡¡¡¬d€¢ý¤¥ÅZZZfÍš:ñÍ›7Dr³œƒ™yÖ—ïßW;vûìýû §xÕ‘#w>~ûæÌÆ“ÿ[l\®^½ž——öéÚµëÀ(€ä’;÷ž+#F[[QÚ  €H8ˆª—±µ RXšµ³çsP™qXׯV8 ,ûéãGo¥•3f,àÖ¶®™˜™Ž9Ä’ïÇoA_¾|¹@dwL€Aÿ¨9 XygƒØ˜ÍÆÿÀàÜz÷îí€ôôø—×€Íù}{÷Ó@ÔÍ·o_{333_© Jz5„Z G°³³ï¹wïNXddà`1ýúÓ§q7ajˆq {Ç4à}C€ùÖ.îÛ4TµIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/lock.png0000644000000000000000000000446311550446572022162 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÅIDATxÚbüÿÿ?Ã@€bb`@î€bAæ0šÌ­SÿÿË2üùãÀðë¯1ÿÿ@11 ý(yhÂfæý@ñ; ÿþ10üùÒÃÀð„ÿ!ŒzY g QÎüÿ_™áçï|†ÿŒ^übÂÊ JR bb‚ œœl ÿ20|ùò“áõË÷NÏA`|Ü¥o ŒX}ñ![ @Lh5ÀùWŸ1°S:?'#Øåàú–â:0ƒù?¸ù ¬ }ô·þüA„#R-gøû˜~X˜˜€xý$sÙJ€Bu3óÞwÏ^>ÿì°bᄤƒÿQëgƒ@ûÅ0>0øA–1€£jÿÁjظxþ~úÂðëùËÀ Ø‰l%@¡•„ ÷€^Ûu÷Âu)!vA^P9 P‡áÿ9¨ý/01üªûÇ´á×?F°zFp¤ÿú‰X 3|¿÷¨ïç Äid+=SKß“+7ƒÅ•äy´¥Ž>ÿm†%õÊ@O0"åx÷èBMiVë€C”pKÕßo?2ü¸{,L€ŠQ'„ž @®¿TÔvmß±6Cwu Q†w¾3<~ûAKŽ ˆ9P ”F#¸í÷á°Ì¸ò‰UTœé/+Ãç³§€nú5è»èM4€bDî0Ê÷#öýçBn1‘(mG†ÿÙؘ0È 1€ËF`È3þ‡†TÿPŽZÎ L¤ßë‹?Øÿdøvê,ßWÏ÷10°•}‚„X#ÜN€ÂÕ"¦Ö¬¯Ï_1]Þ°3BÑÆœá(Ãá‹ï¾¼ý,]¿3€›H°D Êë „ŒoN`Kˆõóg†¯.0ü}ÿv?Ðò˜åè €p…¤ýèõŸ¿«™˜ÊEÔ•Ù…Ô”˜xxÕ4°±tÄßß öÀ?pag5†?Ÿ¾‚ÜO`œÿÿýk00+Ñ-G€"äýçŸ5°Ì-`daqU©¢Â ÌÜÀŠ˜·AEì_`-øû30›½zËðóù‹ ~Ç$ ‚íØ[ùqý&Æ£À–ÌÑÿÿ|yøÄó˽G†@o+€+`’Ö‚Ÿ¡%Ü%`ÙÍÀÈvhË?bŒ ÆîœЀ÷ hÀ`\}Çî¥AIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/filesave.png0000644000000000000000000000331511550446572023023 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<_IDATxÚbüÿÿ?Ã@€bb`@,ÈFÆ. VÎ&61 F†ÿÿ<„PCê?¦Lé‹‘‘‹‰™ù×?FÆŸ¿Þ}¸ÁðíSýÿÿåבõŠ8¹»Š}bô¬eäþ½aД`bøÏÌÁð÷ß? [€.b`ø$þCmc„9…„þCØ Šñ?##Ó¿Ÿ §ï|b¸øO“áÅÃ÷ºg'nÊ: [ @(à••rµ÷’gbg`Ð`øÃà¢ÇÇÀÀÂÃð(÷÷/ćœ?ÿ v1#™B3!ÑðáÛ‡ç ÷^}f`Sec¸£¥bŒ¸"£a†»‰÷?»G…RõM2?B)”ä…N¥,g†ä˜?ðƒ&Ù›#fˆHo õ`Cú Œ]qq[ÕÚ.Ç`­–€[¡&BFH삚 è5& I ‚} f$Ÿ‚,†2$ZþC‰"„ج¿¤õd5Œþÿýƒ‘åpEI€ Ô,§ÿ?X“äRtyÀ ˜X¥Ø=¢Y¯04Cºÿh: ’DŸ£÷ª­ÁÛ]æ"•oŽBËPüg[ÎȈð1HœùÄp`ì0üeD„ß_¨¯ÿCûdù?ä& <(* ¡‰ÃŒP0ª…  ƒÁ>…ÒŒ°HüH Ñõ’Œ¨`@O @(ùôÔ pð3 ’ 0øþÀ] q,(7€} ûMœ0mÌ@W2Ãý/4m0a‰€bÁ–"ÁÑ%¼@!rÈgÿ ©Ô  Ð(GçH€RÌXÊ]€ÂH„°à%BFF4G0BB$ú’ià†üƒ¥ïÐl N¨Œà(€¥, Œ4ÀÍ,°¼‡€R3, 2A$8B£,öâJ`$6ã# Àr0¾~ùÁðëß/`ðýU  zá?¬Xf|Ø¿ ’û ô*X-(ÕùÌÀ¢˜••…Th㊀Bu#"ì{ÈÅpðшÅÐ8„RpÇüG„L ÄQà œUþügfø L8L,ØC €0 BPœ=üÔ LiŸ¿KÔ߈Ü£ÿBÓ ˜-A…(zØYjþAë ^NH£€ÂšA&3PæÅýß ÜïÞ3ȈñQÙ!W¿ˆ*˜Ú ÷_01¿ÊÎÀ/ÄÌ iÀÉÀLKþàN„„‘`A r=ãß? ¹Þ?Œt¸Á†€|¢ÿÂ’^&nn&xû–H±…@a­ŒþBKºÿ@âׯ? ~ÿbxöŽ™áÑcN†Ÿ¿åo 8¦w˜À9àÐŒ \Ü o¡%㨰¥€BM„0@Û ?!ðý;0@Å$ÿÿñ‡áÇ,á *€òüÀ`çfdx MС‰•‹€bÁà¿!ðó'ÐÇ?!Uàï?þÏŸLXr +0 þ}c„4T -*l!@ØÛÿ ©”p¾ýøÅðæ3ƒ·Ù7=…O j’Þ¾gçytðØ`§>`À Ìß@%"#¼žÀ–ÕLŒ,  ÐÓÀÖ0„þòùÃÛw Ú Ê¿¾ÿbò¿b NfÆ¿ÀôÂLÌ ÿÙ˜€ú~ ±ß µ(3# º€BxrëÕåÿï>:IIñƒ-gú ,ÌÆ #ÍËðšèø°ôøÇð hÕoV†ÿ@“%?¸¿! ZšóÃ¥+O¡ë Fä®#c‡¡’–ô-sY=`êïÿ?¿8¾?­ rŸ‘`/Ø ?þ±3üã‘&`ú m±20?¾þâáåËÿÿ/݉¬ €ºo@Þ7 w@ ¸ ~ ð´Çe›ƒIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/2leftarrow.png0000644000000000000000000000431111550446572023311 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<[IDATxÚbüÿÿ?Ã@€bb`@î€p ŒÁ踑ç2±0üú]Éðé}<ëßy ŒŒ]@Ñ?ÀôÄÄÊÀ ¬ˆ©—‘A˜á÷ÿ.†ÌÖ \¬Íÿ7Y. ñ!ÀÈÈÀðå{µ÷Ÿ¦ø ef¦J m† ŒÌ (èFF&ˆzfÓ ßþÍ4VáOŠô”TgøÃX3 €øñÿüÂÀðûÐ?þýf`øú½hJC‹5Cl¸>Ã?f …< L K¡dŸÄ PËØ¾ÿ¥"˼¼A›ÁÖHPÌœ0kˆp€Ìøõ§€íï׿®Fksi†›O~2ügdù ôí?¸å ßrò30°p-€gmf†' qÄΫÒdà`g¸õîP”ùL@± ößc¿~ío¨·bðòPe¸ôœáû/F ç™ÿÿ*`b„ÛÅÀÎñýÿP‡ÿoàçHŸ[®Å ÎËpöPЉ ’N  €XðZþç_ÃçÏSËŠMü´ß„ÿõŸá# ÄrÈBÏÙ¸ løù¯„“•¥tb:ƒ²ŠÃÁ{ "BÀ˜ü2›™f @±à´üï?w†O_f¦ð&$1ì»ÈÀðúÐÆŸ K–]¥ý lÌW žúˆSáó¿ÿ ÙXX:»óÔ´µ„6\*ac`xzûú½o!Åzf@awÀ¿V ¾,ŽÕáKÏ2gØ~žáÎ3.¶¿ ›–ž`¸uåÅ]nŽd Ê7@µ ¼@X øó/‘ñCwUš2“¹‰(àÞ/ÀŒúïÝ/†Õ[Ÿ1¼{ÿg/s1Ì*€B8”Ò!ÙFá÷%Þ¾ª¢…%Ö û®02ú“ã/ÃÞM§n]{ú”‡#˜å¯ƒ-YÎʱüßÿP`ÈLËRdv·—dXzŠáñ`¨1ýaØ{à)Ãë·¿O0p°Äé;˜µ„ÿ´>~]åࢠXSç´œ‰aý  Ï9þ3\>t–áþÅ{Ÿ8¹b€ OÀ-gç…Xþÿ¿Ãÿ3ãä8B½d-?û—íÃ¥óÏ^½ùuhy$ЖçÈV²>~[nl.­ÞÐèÄpô ôÀ¨Fï½³çž_»ûž“3ÇÀª9€)žj9ƒ Ðò¥!^2‚IÁò s10ì½ 5ö 7/?gøðöûM6֠ˆ¼ „pÀ·ŸÝ†–2ºmm® 'p0´¯*Ê~|x‡áíõ_Ø9bQ´Rܲ@|NtŒ" þwz:H %+2Ì?ÁȰè†O_1||ÿí:;[0„n5b$7€BJÿx„Eyn¿ã`˜ôù‡À Ùñó¨äúÍÀÂþ˜”YØ,ÿ!E/000ýgãà`Øu‡‘aíi`ü*µEÈ/PÄò ˜Þ3°²C²È fD9@Œ° £Ù\ OÖ‹¨©*ðZ3|þÎÂðèv`§ùë"ÃÅ‹Oýfå c`c? 6d9,Ï30…3þg^"¦"ÃÂ+)Æðæ=Ð_ùžó/ƒ80£\ôëÔ?Ž  ãŸ‚=tÈÿÉh D˜üÿOÑoîÜþáÊYa¾ÿ BÀhþþ›™ATË€ÁÅV^X*®Æ€D' ¤D9‚‰aå6–äW_ÿúöæ-ƒ„00 €eÒÇÌ ºš" šÜf ¿–u ¡G@!*ÅXØSyäÛ»÷_¿¹r‘A X¶ˆ‹÷ÀÜðKB›ÁÊ\Zèˆå@G(ƒ’جÀz……Ä^ôŸ…¥àùÃ÷ÿ¾}øÌ ¬s¸Fnºô€”ƒª»Ão†…@]<àt„p(^˜ÀÕèA6Ž´×wîû&ƒÐÍ¢@|˜+˜d´ÔÕEµ€…Í `B–‚Ä1ROÿÏÄ\õäÁ{`…úAZRDì¼ÊÄ /Ãà -Îê¬F§ƒòÌZ€bBiL @ŽxzãÞŸ÷î3H}#ŒŽS˜˜eÔxDL€ÍÖ‚¼š)L™™;õD×ÇŸ~S£,P/'кãw™„9€É‡XŽ0¶Á”öêì1Æ%@ÕÙ¯ÝÿýéÉ3I o„ޏ÷–á<Ðk¬nÀ„hÍ H ì `]Ýwïþ7†þ0ÈŠAqë#°6Wݾ0¥„”ÿ!áÿÌÄ8 ˜å*\¹ÏðíÍkp¼‚ÁʪRAµ!0Θ ­ pKˆêz ff¦ò? Ì‹ï<úÃÊiRÀ„)ÄÍ«½á® „Øy’ !é‚™¥ï?kûÝËO¾¿ÿNá|Ü 2€é?Ðòÿ(-"p[êøÿÿmËüõ‡iý­‡ÿX€R ½<œ¨± @ðJA±$0ù CZ7¬@‡0 æš¿ÿ'ݺø„áï·o bB`3A0š¸€Y‡˜jÙ‰™ý++sòÏßLÛn= 4Jìxª ¤(ø‹„‘¢âÜ ,Ìþ1μyå°xý ,¦Y-ýâfã„$}P©ŠÆ÷ÀÆRä—o o<67ƒmû ³ €XHhÂÑ¥ðû/†î} ¦å@\@mÈûý $Pº|Ÿ€Žˆÿð…a sí ˜@1tß €¼g@î€p‡Ü©72ûÛIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/filenew.png0000644000000000000000000000350111550446572022653 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÓIDATxÚbüÿÿ?Ã@€bb`@,ÈF½DU~1©©’rJæŒ ÿÿ…¨<Œ ÄÈø÷ß?¦'woíúúáMÓK@¡8€K@¤±µ&Û5ÈJŠáç/2lÿÑóÁ…ˆý‡8‚hÛü7ÃÚ;&?ùóís133@¡8@PBRÇIWŠA’ Èa£nPƒÁt„ž Ã>AÍÏß¿200³0Šþÿûÿï×_¨sIÿ`¾G¦‘BÄæbe`øõûÿÿ/Ø  &Ì@$Ïw0KÐ Bÿu( J‚õÔàÈñÿaá?¨gÿýÃî;€";b$44ßþCf£%Nd@Ld[þ3xÿÿô9D``„Æ? 9–ÿGKp X,GŽ?@‰_|``øòa@±Pâóÿx|Ëÿ¿–>Ã83çŸõ @,”ø=Á!‹ƒ|üX–‚r5r"ed@ÍåÄB Ëÿ£Åù/ Å¿þ¡%DhN@ÄB‰åÿÑåü€9, þýG8äßDÖ…€b"+α2 ß}‡YËÿ\@̱9Á"€bÂ[ºñ_tŸÿƒú© Yúß`9$°Ø}³c7óþ‰ ¿Þ~`øÏŒV12ƒ1@‘X PÖúñb!37гœ@6;Ãûó×~¯Ïecèfø°r*Ã`åöá?9 ™ØÿIÿxÏ ÄÄ„«„ûûœƒäA©ü'ÐŒ@ ?ܼÅp¾$—áѪ5 Ì@þϧøÔ„$b]X~ À| O„0˲â?h´€0(Ÿß]½Œáû©E ‚’ÀVÜo;†¯wî2üûü’E˨ú0†þ3|Úx’I™!Ej2CŠækn‰ËŸ7|Ù@,hWF¤ÔþZ0@Cá/RŽñÄûË{,£ÍDMýÕÜ}`ˆü&`•÷ç#(BŠšßd|¿5?æWv`¤q°>ÿËæ@,¸ß¿¨-¸Ïÿ#øŒ@Éø3œZÕÆÀ¾ºžƒáóå{ bÌ7LgfUð] t+3ÃÇ=÷îLùÈð\Ç‘áÓ½‹¯í>Þ;ÿêÚÏ5Ä‚­„—ß Hl´\«V]m>Í¥ ÿ€ÍëS·˜ï$1hÕ•0|ö‰áçÑ üª _ÎcàÖbPxzaÍa†Ž÷šÇº/ðüp• €p:F#Hÿ°U.? Ñ¥› ßÅ38uÇ%0ìòèaPQg°cf8_sAåñO©< †\Ž© ï›…9ùß¼føÔ@(Ù‘‘‰‰…™‘Ô\†b   3A1’<°ovÑ«…µ –¥1 L¿8N5nb` íg`–Í¿¾00»Ç2ܺÅðvÞm©4Q†Ö¬vz?^™‚F„š ~|x}íåW†ÇŠÜ ß~"e;$_#G<“Ô †‡V2Ü¿ÉÍð?k9ã“ ÿoý+ú ¡/…• ǻ٠»f0|ºòë°úx Jô„O˜8m©Æ’­:ÒÀ"î?¡1¢Ne&H žó_¾Ë0üÜþ‰AâĆE¶ÿ8YvŸ~Ê0»ëâN[FÖenXßÝ—”Êðü(WZ`ÜòñæQ«7Ž(3ànIãè€ýÃLõ·20œÛòáÝ3ÖûonÔ²ß} ÷ò´PÃˇÓÏ0üÿÊÆÀ'vßÿ%ÓH¶0’”äpYIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/editcopy.png0000644000000000000000000000246111550446572023046 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÃIDATxÚbüÿÿ?Ã@€bb`@Œ F©˜¢ÿÿ³112–ˆÉ)g°±³±CéY¦—ÓF&Ff–o_?xÿúY%@±0`‹‚_¿Â½‚üZ» ‚¸˜þý'Ù^þ ÿýGˆ³±00œ¿ÿQ´¨ar?@±`˜RÍÌ¢lf¨Ë )D`Ù²æ/Ô!¬@O±kð3(()Ê 0 ‡ð†¿¿ÿ!Ë2%0ÿCòù? ÿ ô ¾ýªýûï/@1102"œI¡/Ñ-ÿäûHQ‚ì]€bA zFFò,ÿj VŸC—ÿI Ä‚b"=üeea&>+1B úætŸÿG8‚ñ?ÿ‹”oá4‚ýJúþ¬kž‡eQ EPN |ñ óÍߨeù?D€Ào Âןÿ€ã%ÿ3 9­$„•’„Õÿ°ùü?jyãƒÕƒ«XFŒÒð?²Ïѳ#T/@±`µœák¸cþ!…Z¾†¥ dc- P³$ ºåèÙ!!3Z,þÿ‡ç¸JBX¨€@¡8àRð"û›Ïÿ"Õ~Ñk>,YîrY€TšjüEóå<|dÃÿ¡6<`¾G/ ÿ£…  #fcâïD^Eöù_¤ニU&D¢¤,>Gæƒ@±|ûñ‡áãÏ¿ð ½Qžÿ£•`µ¡ià?¢¤ÄêsÔЀbùúýÃûïá!€’òÑâ¹ @vì_´†(z:@/þ!UvÄkýc çè%à?Ô¼ŽQrþGË~H˜ÃA €XPò>šÏaAŠœàÅ/ršaD ´&fJ €É2XAh)ëÿx0Ý vë "ò $,"VóúþÖÎüËf’QáÐt ¤!#ƒz_º o&ÅÙŠù{52L&bùõûLJK?HI1|úú³ÐÀH¡*‚?ÿ&äÏ_Þüçf¸ü–áËhºÀÖ1ù±üÔÝ/ _Þ<@Œ †)ñÜB <|‚|À–Á°*FDUÊÀˆ§žf„4É~þøÉðíók>iMfVxOŽG󊉙åËëǯ½T @ŒÝ; ïÖk-xŒ! HIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/laptop_charge.png0000644000000000000000000000565511550446572024046 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ?IDATxÚbüÿÿ?Ã@€bb`€ 28†bèûíoGГnÕ Ä%œË)¼ˆ7ÐJm­zòB4„árk…B‚úN)òî4Æ ò8Ä_î½#¥Äe;ÒnKÍdj…:ÏÔwŒ*ä¡O}UApèq2߈—Ëþu ûTÍȶDc Æ?¿^k0ˆ]=ËÀòçÃOq-U†¬¨)Ab ²~ ¿UÁ4£œ™áÍ!†Eñ³ÜˆÓb ¯~+°²±Ú320Uþÿùïß¿÷ÿþ~tħ߿addù `ü÷Ÿá¾™ƒÒ™ƒ ,¿~j©é1Š1˜¦30p»A,e@uý•e‹ÿß¹ÃÐ @`dük®¡n¸L€×Q‰á?+Ï&¶ï ~døùýÃ÷ï?>¾ýòùíó÷ï_ßúøñýé_¿~Þ†Á –ÿ>¾“Ubàü€Aéé-ky{ å @_ñ$ø¾îa80açA†¿ ³ˆ9ã“MSSevLtºÒ£{ ÿ20°r10pð20°s1 ' ƒ Б2ß¿2}óæIôË—>|x÷ÁÝ»w~÷~ýK‘C&·1<ß4áÏÏ¿|òŠÌK€yãË󿛈ÑÃ# R °@Ò#(¿£(ÏtïŸ?ÀyŸ˜+ÿƒB‰áן_ ?~€æo†Ï_>2¼~ýJˆ•“=«>§°^îH‹Q“1«\0д°âÈ|Êðëþ!†¿ÿ€å ÐsŒ>3lÞu €ÝÜ‚¡áÿ—•hØ™€ôëÇwN`q$ÌÌÄ,äÆ #ãw Cßÿûóû5#ÓG6¶o\a0øÇð¶?ã»dv,P©<(@ðZþ}ÁÈ-|Ù­^̰9f] @± òÿ8 ?þÚ°²°úó Kró «ñ ŠÉrp’3Ãï_?¾~~ÿóÓû×~~ûüð—ùùø¸Lä$Þ]?Äðoé&†_ßþ1“1ƒ”(04ŒöòB%ï7—NTn?ùï×ÿIÄ‚ZãûçO+^~2m='cs^9^>.`º`e†Õ?ûúíû»?Ôß¾ù¢þìùS7¥‡7½~Ä0ýøsÃ× ’ Œ÷—2Èúx1€ãá 4'|g¸Ô¶éßë»ßZ€™ô3@!9à?ã¿¿Ê­­­ëÃ8µTQJG`t3ü†&¨l`šÃÍÌÄ ÌÍÅ /ÊÅ ­,ÆðÅØáþ“ ×ÔÝŽ<ºÌ ~x-C|®“€4+þýë#—®Ì¼ÒÇÅȰ…h.@±@Òÿ¦ÿÿ™›dª-M#>––Àˆñìík?ßùh‡8ÃÃ'| {ï0ð¸Ë ¬¿ýƒ8‚‡á㉠gR.eüý¯”ˆåÓç ÿ˜8ÄØX_ ½/ePºhñ#P½Ápñ¢à ®Q>†ïŸÑñTŒüeãšÆÀÏváö/~ýx†o_YÝûÊðê370Õ¾pŒeà{û‹A\0ýòí_p*ýûæÃåÂã7ýSÎ €bùËÀd(Éý{nÇsÃýk ŒÀÚóÛ[†ië9.q”0˜†0°ä_ sùY0h±W0Hþ_ NT·._`x¥Ä ()À ¢ÉÏðæõ†Ïo„Xÿ¼bý|–AH˜}>-ÿ ô=3ý–ÓÞžzULÃOaé €XDØ~ÎXè÷ÖÐHå¸òºl^´lçbØüZð—Àô—û®np‘—wLõæeðÐÊÀÍp œ³î\•b¸ÏPÇÀÃ-Àð˜ÐŃˆ8;ÿx~01(ò?–€êÀ:à8èßn~ÄpoÊ•¹@ŸoA.üˆ…á÷7>‘¿~Í]v‚‰¡á×ûçÌ\¼\º^¿| +ÊsO'ViŸ`40ÞY¡óˆgle¸ÆÛÌ ë tô?VV&°@õÈ–ß ¿¯]f’ýiÅüÖ'?3ܬ>yôßïåèM0€bdfçŽ2äú5Oœñûž÷¬gs°æòp°ÿùí7§4÷ÏÍk;ªþç¨;wÊÖ23lxÄ}GPDDRDU[RJ‡AYÅšAFZX.ügØ}bƒÄ‰ ¿–uʱqù«å¿ÿnýùhÝ= ïO 7\çs³0CXÙÄxxøØØAb ü¦R ×¾Uë³ †ÿ‹œþ«°ƒRK#°µÌÓ æ'×23snR½/"¢ýDœiâa¦ ÿþÿÿ4þÿËVóÿû*öbÃitë~P9Ë lÌsÀÊÆs_¦£$÷@)PïàoT ,|X€˜ZmÃ0’d«€Éó¡Èÿ·¢ÿßâýÿ”(ç–C@WJbÃÄB ã2}ÿs†S@ZˆO‚Z˜8º æç›™@X@š~×Q:îq×…—?^/U!¸:€ÄBDïé,! –Ê ¶b`†pà³”d{=û*ûCO+¥úU|½O€b¡FÿN ˆm = oo¾š}õá—ëï·Ý"BO€bèÞ1@ xï Àk‹l +èIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/apply.png0000644000000000000000000000330411550446572022350 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<VIDATxÚbüÿÿ?Ã@€bb`@î€p iÜ„a*’’ ˜‚‚)` &õ‡@¡Ó³O'é˹"3@ÄW°õϵ¼NqD:²‚ü½süг•¸˜mæÈ€pØÌˆ·8 ²WÓ[\c÷@´F†ÿþË0üþ?_RB¢ÇÑÄP‰““;& @4wÀß?½˜˜wjiD:Ø0ð1³2üüú÷L €XhfóÁß¿þ5pˆò焚h3Ek¨2̽zƒaÓá+™~ÿ‡‡@ÑÄÿþü3ûÅÄÐ'§&im©Ïà%.É0áÆu†u®}dúñ?…‘é¿øÅf%Ë ¯#äýè`¹Ä‡'Èíÿ02î‘Öæ/ÎòÕa+00efgøñ÷Þç/fn}ÈðåÎï6æzPYËÿÑ¢ €à`ÿDzèêÕO™~²2º1ˆ«sûþþó6PŠ-{±í¨bàeÙhl+l\ênÈà+môÃÏ¿?N¾{ΰxφ7~®dcf®ZŽ·º ¸˜X/þzɰ{ïåW f‚† Ù.æ Â*la¿3N¡ì_3h£p9[«¯‡ …%ƒ§÷ŸLÀ‚î Ã¥OOí}ÊðæÊïÍlÌ,éŒLÀ2š x`úÇò—í7ã¢+—?îÓ¹Â.ÈðÝí;Ã<†k1Ÿ®0üeúÏpü?s½²‡d¨…ƒ•ˆ.0 p2|üõ¨ù+Ã5 å ÷=cx~ú÷^6&¦„ÿŒÿˆÊI„pÀ/V`pìüýœñäž×­ìÄm¥ý¾;}gXôùAü¯/Lñ¦Öœ ¡úÚ j\ ?ÿeøþh9ã†ß3¬:òœáù©¿WÙ˜“þ2ÿ{Gl3 €øÃ ¢~±þ`XróÊ/«ZGœD¼¼$]>¹nÆïOE=af†Ï¿¾3üüÿXsþ`xúó!ÃêcÏùw—õ7sÌöH)?á€ÿ&##Úw Þ¼­¦ÎwƒãŸƒŸ¼0%«Õ¬ ï~Æ÷O Â_ Ï?bXsâ)Ãí}ŒY0‡ÿãü}½Bç;FÜá@ˆDª÷˜å?ëk毬Ëo\ýÃpýãm`0døþç÷_>ýþÀðíÏW ~0¼øý˜aëùç w÷²~dýÆ”ÊÈÂt˜¿€vA Æ ÌÌÀjS`Á0@ˆ@°èómæŒ3ŠK¨ 3ü6Hþ}ý÷ÿpH|úûŠaßµ 7v±}aùĘÆÈþw'Óf`#†T@L°Â13#Ó=¦7ì»n\úÃp÷ë=†o?3|¦öo¾0¼ùó”aÏÕ W¶rþayÅV,îWQR{" €¹Ù€Õë´×¹]{úèã7@G|eøð÷%ñۯnlåf`|Ê^ÇÈÊ0—Òê €!ð‡3ÿg>Íð‚cÿ½ëÌ ¯~ñÿ5Ã…'onî``~ÌÕlØtP£þ „þ±¡b–¿¬?Y|¾Ä÷ïáûw WŸ~d¸¾U„á&÷4&†r`B¡J €JBf, JÆ­ ϸ/Þ» høë1Ãÿ+|ë™Ø~kÕÔjÁRAÄŒMþ3ã_¦Žo{$Z¿3íÙ@ËP³ @ŒÝ7 ïЀ; €ÜëŒAt>zIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/power.png0000644000000000000000000000414211550446574022362 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ôIDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €X9<<| ¦¦v ¢¢’ þüc`ffŠMåæ’·²™þøû÷ûûŸ¿¾¾øùãÛƒ?¾ßüýû÷5`:¾ÎÌÌò˜………‰ â§?~3üþý Œ·o_Íðÿÿ?°8z¢ ØÚz0ˆˆH0üýûhÀOF99©™6ù!¯_ 30³20pñ30°sý•gaþÎÀðï3Ãï_ï>}zÉðêÕã×ÏŸ?ºõòå‹£_¾|Ý tÄQ&&ÆŸÄ„@¡8€Ÿ_ˆáçÏï`ö¿LÅÅÅCþ1†¯_.]:ǰ|ùª›W¯^Îþøùý÷›7/¯ß¹s½páÂÅF¾¾v¿~10ˆ‰ñƒÞ^è ñÑí ˜˜ØsÀ F)`–b³¿ÿfÍÂÂêÃÍ+hÉÍ/¬ÈÎÉ'ÀÊÆÎöïïßÀìøýû×Oï8¾~ÀË+xþÝÛWwµµµtA¹˜+Ái‚rÒØâ €P ¤¤Ì‚Ál`døõë›°h…¥“µŽ¾!ƒ¤” 0¸X˜!•0üøÉÀõùË_á7o?ª>{öÜUUÏ•áýë‡ ­mS,Ì ÔÕÕ®]» ÷OØ@(i 44…áãÇ· ììœ@×OpuóL÷öe€«–/ þ‚  ¿|»Ù_¹øÅ« W®^c¸rñ+ÃK†Ó'w¾>uéüéÛ2‰|‹$~´k  Ÿî10<¹~‰XâS$¸A¡£ªö‚AZ†ƒáýG†'¾1ܼñ›ƒAO„áÛ¯ï ¿¼†Èg†g/.£øÃ-tjðúÓŸK…ûÆþ<6 Ï^-¹vއáØû*9ßJ†??€Y5ŒÀÐRæêbçèfx~Ÿáåû­ š†F ß>ýe¸pê Ãû7?¾ý|Ëðñó{`h}ùÀpõê2†Ç/OZqÝ„R8iýßûìëûwjvs1¬~Êví÷ÿ/uÀ2XŠC¨³Ò_‚³Ìç>70{ÑŽÓÆ Äç0ˆh€%È8PYqìÈ1†/_?sÎR ^¹µé@+>¢—„çŸþÞÚ³‰Å›Øzé¼Äöïî¯ þhbbb{)/¾srÐ{oÃ7 ÀÂæÉU†òÕ¬ ‡¾ 2hêïdPzð”AVV ˜E¥ØØÙ~üøÌpâÄT†[·¶®fÑåØJB€B©™YØ€Es;oæøxP u§S³0°&•Õ3ü_íÉð_‘ è_æi@Iw n:ò  ò ßÿ¦¦©ÿÅÄ´ò “€X—} @(P͇ˆ*ò1\›jÃð?Yœnq–Ê X"0øq{!<€Û„’@ P#žmŒÌâ«ä´‚ÑÓ@1t× €¼_@î€pЀ; À[^=?ÿcIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/redo.png0000644000000000000000000000311711550446574022160 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<áIDATxÚbüÿÿ?###%ÀÞØx?Ð…_ ÇΞ=HŠ^€bb XÛó308”É(10°36Î'E?@Qì˜!^¡¾ “g42hŠòN†Èz Ãø‰Ñ @TqüÿÇ `ìÁл`:ƒ·™zà#ô i ê9àï†_¸DJ»;Ò£Ý ŽÀ%ÄHn"ÏÊÀÀ ŒÕ ÂäAFB0];y˜¡½~ ÃÃÿüe`(&ÐèæÉZ\´°@QLPÀÊR—ÁÄRŸAK_h!ÌbTúëûç Ý SŽ\yá;$—\D6 €ˆv(µãu¾,ŸBRœƒ–‰ Ô&$K¡ldqþ÷›aÑô +·^øð aæQÅ#0‹MÈ Ódðòµd``á‚΄d1 Hl$ñÓGÎ0L˜¼•áñ÷ Ÿ=›2 €:ÀÖØx¾<û¿„æCuu4Ë-aFâ3ãgdxýâ%Cgûz†³?_\„×@Ëë–74g+1(¨(  e3BBc“Cæÿÿ ¤ß3|åec(LÙÎpøú“X€bÁìþRl@Ë“ù¤Aþã-ÔPf$Ca£³aê˜A0‹~a`ø Ä¢¼ ~ò3L*ÜÇpãñ‡³Ï_½z@XCTŠñ10<¨p}-`¯ (AV^ ¦f6 áÀ ÈÂp ˆ¥…ÿ!ìÿ ÿû ñ5+ƒ–ÃÁC¯¦÷g¸óú㬳׮M*º @XChÅ'¥/öšŸ•ü|ôÍıD3² ò™øŒH|QIu=†é-G6n¾ùùáÇ 7îÞÝ´æ¨ø lÙ èÏ„Û×Øã† XÄK£” Ðp„øÉ Þ ªUÑbxÍ$Êз‰áôõW7o=}ZòâõëS@™W0%„á`àxi|F×oTin Å: Šz §<`8³þÃÍ['îßz 1†ÕÍìƒ/P­–)Ãé³úÖ2ÜyûyÙé+Wº€2·€ø;²}Ä‚æ{y`L„˜¢ù^Ý‚ÁØ“áàæ› Kó–1ÜúéÙÇß¿|þþý,;›¸"W\­œƒ’âIgV,»üùÑ—/½WoÝZŠoP£{ €ÐC ÁNñƒ(’ï-ƒ^sª2LMßÌpøôÓg/¿~4p4?m¤ËX€á gÃð•KŒ¡;g'ÃÁSOnÞýºñáÓ§€òÏqå6€Bq0]˜)|B ’†äj£Ö2Üz÷eóͺ>~þ|(ƒQ©083\»ô†¡µx9Ã„Ú @™/øJY€bA~`,˜(B bÂðà¯Cmú†«/ß÷ž¿qc.41‚ñ¯™™aþ¬³ ?n€†Vµè €@å¬z-vÓúÿÛÿÿ«¤ÿyÓù¿0Òí¿™®î& ´&¤¸Ã쌌6Ùê럑—–ŽreH©Ö@Ó ô¤ ¡eɰvÁ5†3×^ž=uùr!ß:wÔâo„‚¼E ~ya`‘PaxðIaÅò+ ·Ÿ=kÀ•zÑÛCÐDù…Ô† @1!åQ^`±«íÀ° ï8ëïßg èù–Ú €PÚ„ZjlÀÊBšáÔ™gŸï<~¼_ö¡ &XñËbÈë1lý[`!ÌB‰JÅ€‚‡€(°æR³d8 ,f_¾{·œ¾€B8@˜™áô•¿ ¯?ýx,½@qÿ‹ D‘e¸~öç?Îyoè%^8ûœáÓ·o ²û3½@ð‚èîÍ· ¾üb6“NÑ:ë!€‚ÅÆºº‘䥔€ò Æ]svIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/gohome.png0000644000000000000000000000503111550446572022500 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< «IDATxÚbüÿÿ?Ã@€bb`@Œ ~R¨"ÿ¡îúË–føÇˆûÇ ÄP¹ßÿ ~ýícøÏÈÃÀÌRÎÀʶŸá44A4##ÿG6ê_P¨ƒ0#@‘?¾û°1üßЕ_é8»¶Ó”Ÿ“k×Ïñä@,h|n ö…Òÿ€èe†+@|a@}ù’ÉË'Ô3µ°…+Ö=,,%"&’ÖV5ÿéãGò <üm@ïý!ÖÄ̠΋̗†ÒV`ð„ƒÇHûÃé0&¶åØ>~ìQWÔl^Ù<“Õ×ʉáÛ¿/ ?þ~cБWgp³´c pÁ SÄ»þý¹Èðéã[¯ÄeuÓô•5ÞýyÅ0ýyÞTÙôTÅTÝž½£{ùò9kÖ“ Ì̯þãw@À‡`~ N²xáêÿüùÀðóGL‚_‚×ܲ ‚" Ýe˜ö¼žáÒ—3 ¯¾`8ÿù8ƒ4³"ƒ²€ ƒŸ½+ÃÿäN]8íòïï¿ ,,ð9 €˜´¹C€©@u¼  ´Èü§Þ”\«Ø›ÚÀÀÁÊÆpáë1†)Ïkÿ¸ÇÀÁÈÅÀôŸáͯW ‡?ìj`ÐàÑap5·f9pêxÀïï_ŸCã.3ƒ²0`âeøö™AOa^ñt†lïplìþ¸šaîˆϿ?1°üç`øóï/Ão füÏÄ𠘾ÛÅðý×7#nK3=CmÎ=§Ž}}ÿŽ‘ãj„€  fCxø 0AüOcøòžWUF•ayå"og†¿ÀD½æÝ †5ofÙ@eÿXÀ–ÿùû—áï¿`ú?°¼øÿŸ‘áÔÇ£ ¿=dÐã4¦MW †Ó×/9<x_†c?ÐÒ_È f# ÿA2Üÿÿ²@ËS¬ œ¹–”Îg0QÑgøú÷Ü×m »ß¯7Ãf¸å` uÀ_°cþbf8÷ñÃÅOçtÙ´dÕñ…“S'‹xe ;HéüëÿO†×¿^0<øq—áÿ_&°Ïa-b¸å`ü@üýÏOK1Îÿ\ ýa°31cÐUÕd?yå¢Ï‡OŸÞ ãÿ?MMÑ­ v1ð*”$¥Ù”XuöüÝÄÀ 4øëïoÀ þ÷)< ÀC£åLì/+0~ Á¥É`!bÅðƒñØàŸ?~2øÛ9ê8¶¨ò¼2€bùÏÂrpÖ¾YÛÎnðëÇo†Û†$ÇN`>"Î"Æà'L„,@Ã-¥P¢û÷ Èz×?_ÃpúÛY Ü Bœaÿ© VÎF=+ 3ÃÛOŸ~21œ  HÅ™;Çwù £ß ß¾2øH‰J&‚ÀÌ v‹C¤h°Öe‚ä¼5%¨ôd`8ûî áߧøX€e0£¼qžaמ[عæ30³q20³ƒ‰ë @ Àü¹Ž hò_`vdúÆòù÷·DY ׃|ýóï/†ŸÿuË/f†Õ'Ö3|RLL,øú)áþõ²±°1Xx2² €ã$'À*¦_~z,à9÷3pð­cæ°à_€BTǰ¦3Ã×ßÞëŸÿ ÜÀä€?À`gffføøå CùÂêŸ/žÞ߯ÀÆù˜}Y `ùë/3'Ÿ—•¦)Ÿ˜„û˜˜DØ„Á½ÿòdö`‚†ÿ‡$v€B8V11¼ùòõ#ÃÏß¿8™¸À­ _ÀÄ÷¿ "—‹“ë 7W13ç}pùÃÌE¸¸¹ ùþƒË„?Àä:@”á߯ €fÁ;°=¬ÀÂð7;¸u@LRø?31|øôýÓﯿ¿Ó0°8À)þ?,¼™Àe1ëD ½¿™ÁúÁ*ÿƒË n `êÿÍðå+8Þ‚=É ¶Ÿ`‡ ² V†AÜa“QöÿÙAËî¶D»K|ÁˆZ5þµ4‚¾î9bàÜš]éF©Oˆ5BP„icú9¯‚¢»|÷X«Utsìv ˜‡'¦Ìõ| uÙá/>ÄŽ dÌÄøíýwÞ|yÃÀÌ2ÀÁ óT(»r-çbå&ÚO ï¿Æ?ÃgˆZ¨z Z€b7ß1Óÿ?¿ýüôêó+°Ä¸eÿŽa8=ÿ— œ,œ \,\ o>½exÿíÓG`Jþ†Ú@ @,à†&*¦ÿÞ|} æ€ÒÀçߟ@ ¬ÜLƒZŽÜÆ€¤HJ:àÛßï |À(9âõ§w Ÿ¿þtÀOH[ˆ…£a¬¯ÿ¿~ûå5˜§,Jßüx ´Tßÿƒ4–Qð‘‹A©T4ÿa0à5`å ÈÛ/@Ïüûõ‘…ý7z› €XÀA‡ @¶¼üüã3˜+—Ä#—L,À ê°àd„XÆõ <Ù(Î,äXØY&[L‡Ãç_@é  ¿à†€baÀÖrfbxtùÙe'x –öÀâÃÏÀâ ©½ c1ÔügºùâPÍO&`ï ”n{Épþþ%™O˜£û €2±•èj, ,³DX…µ€fü†ä>FP5Ìòîç§÷@ÚèݲŸ¢ŒŒL›„X¸T%àÏÿ!Ý: ãYßÿøñèçßÿ¹@SŽ£[@ŒÝ; ï!‚X¯À°IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/fileopen.png0000644000000000000000000000326211550446572023027 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<DIDATxÚbüÿÿ?Ã@€bb`@î€p ˆ` ÙÇÀJ ÿðáP¨áÿ_†3ù œ&Á11¡~s„ø8ØAÒø,¥1½üâý÷ï+ÌJûqaù€;€‘Á€á׿@†ßÿØ€–üǰô/Ü!Œ@µ¿X™V5]‘“—óœëÀÎE¤oÿAƒüéÎÃÛV…™Kâ€ßÿvé*ñŠÊ±3üýóÈ43•>yý›áò…Q ê332þ‚›ŠËR¤@ÃÄ @f6°.€‚8àç_Ñwe†8'Q†¯?p¡ÃîcïB2®I3üz£úÿç§ßÀ0Á©ÙÈŽÇ4ÿÄ@ö­Wÿ.=ºå"¾P  Š 00|øTðƒƒ•A¬böo&9iÆÿà($Îr¨9€!ðj @AðáÐÜ/?±u#¦>~e`“äaÈH3ffb´0yúå1ïßÿ¸Ø1ÔÂÁ€À¿ÿBä_Íy÷ XD}ýùŸá3PðÏoH<ý:ñÿ¿ÿ(¾zÔ(ÀÅÃàë¯ÃÀ´sËOÀûÇðŸÅçÿþc†PÐLH.øƒ”c_¾ÿ ŒÀék¯Öî½Áð¨‹ÉƒþÁrÐ4Ù_ ±.Z oÞýëp´‚-þsô†ß@KC‰ŸAL”î  x|†À @‰êе7 Ò‚L Ua*@ÍHaÊ€S& -WŸ½bàåbeà`„:¢:ï>ÿaxû郌û¿ÞüÅ ,Ä 6Ù„À4Œ`.cøôë/ƒ'ƒž¶$Ð"T ÐrƒˆŸúÎÀÂÂÊÀv´ŒªeÆÈ÷ÿžúÇ ¢ÀÆÀþ˜Æ~þ' £þ"E@Á£à4 ¾ƒ–ñφ7@ ç10p³ j€—á ¼ûÍðíÈñÀ,ùø (´ä±_Àôôè‹¿Hé5ðídž¿¿!¦%v€Bà;0´€Ê~i` -%0P€Ü/¨Ü¨Èô( x6@Ÿ¾ÃÄÿ˜>|y »X€©ùåg†7ÀœL`‡ÀØÀ„Ê¢ q°þ1ÀCà/’ßA|Œp+Ø,ÿQ³ ²¾ý‚X a„‘ *@€äþ‚ðkÜÿ~ÿD?€:þÓÀ¯¿p€« ìQòåohPÿB P"ýó$‘•ý°: =ÉÀtò Ф¿ 5ƒÀÅ„=@5Éo zv`ÉÂ΀…ˆÍ Œ`Ì+N еLÀ¬ÁÎ )µÙ@4 Øn€‚ç‚ÿ ø ËÀTóÈ9€»@YíPÏÎsϤ…¸€ñü^úŠÒwÀÄñˆÿps20ÿùÌe¿nþá瞇o0|}ÿÈ€B„Ж/  ­ rá3 v€âYZZáäÅëÀø¨‘A‰Øhøú‹á°âúøû ÃÇÏNoÛóŽùè|`P20Ü|¤ßBläüÍðäúK†gLÿ- xëò?¢Õò uÂÿï_þ}û ŒN`xõ (¬4°¸ € øzwÃwq ñ_ 26 ð¿ ¿>ÜCk#aXžûÑpEi <ºüRž3?¿ ŒŒ° FPΊ4 3 …/¤¾ýõ€“!(±[<ƒ Œ¡@ç÷O†Ü<Zõ bFe@Ë…€Âø Ô²hø/8Þ10±r1¨Xg0W÷0Èkˆ(üüΰ (áŠ-î€_¿ øï?Ñß¿óñJhù¦2pˆšeß@-þµü7 “ûv—ˆ*ƒ{n.ƒ‚–÷¯ ó€‚Êè ¸þýƒà?¿º Í@×Y]D jù(þŽÆþÅß‘0²ü[6^I·Ka&™?fÙ@(&8×ÿ˜âÕ´Ø89>@ƒü4h¿¢± a˜ã>1°³¿g°q`F1³0ÉÅ"; €˜²3Ð…yB"œ ’2@×|}tÕ+ Ìg°!ü £‹£«êýÿŽáÃ]Yù¿ *Ü NJpÀì ä’P‘ÉJV…˜à€qù _ÎAƒò¿Gb„ò‘ÅÐÕõ~»Œ‘ÀÌó—AÛh“PÂf)@ÁË`påäb—¦fÆÜöáЭÂÀXÓ‚&0Xü²C£æþÐÄ÷šX¿@¢áï} {ö‹Ô¿`%2r¿„yY?¾ûèT*1¹ Òfààý1d>0ÕØÂÀÀô »!Ô’PI˜‘ÊßHòÀ ÿu Hžù q/Ð(&Ο R " ï^~ÔY @,H…¿¨x1Vΰ}õc/0.ïíÔ*” ACÝ@‡þ´ìPÏ-ˆ4RÅô“A@ð?¨À‘Ù @p°°0ˆ±s%™AB–٠̀†€0/Ðq¨#8 ¥â¨å/¡÷¢Ÿ ©€„p@±ó€8Œü0{ÙLLÌŒˆÒÝ,°âdâs ~…dòˆm ´Ã ´™ LÿQ-‡%y&FdQ€B8€™áõ¿l* ÀjŒáÿw„Å ‡€êd°o9 ìPš)þA$DF fšÁø©J…„À¯ŸL <ÿ & @p°²1ÜùýÁ’‰ ¨ÉÌ gsA1²#XÑÒÀhQÍͺ@}LÀÍòn9 'ÃÇ÷ ýÿŸÁì ¸€µß•¯o_0üù%ÀÀÂó)Øa–s1'Ôì8ðŠ™¡Ãü\Ä‚ñïËûŸAzf/@Á ¢¿ÿvzÿõËÛ§ÀzžƒšÅÙ –ÂÁÄÀDÈÀ‡† 4/T L='ıàddxùHáí³7™Y!eÜ?¾3\þùóïɇçß,uF 4ð a.´â€Öõ| ׎þføû÷'È÷`öÂ?þüùË0õÉ­× Ï.K"3” 5 Åh¾ç†ªá„êƒaV†ç7dîœ}Jks¡ ²~ÿaØðë÷ '׿døñIšº‘³Ì!°àE²œ Iž ÿcøû[…áÈò¯ÀŠèËY`{qrm@p€Z½@ü˜ò_?}ù`ï¬_ ¿¾¡;‚)D¸ –óCÃ÷-Bí_ åŠ æ³1¼¼÷à#+;C*´Ô‚€Âèì#`"Iºwñú·]Ó>CBªì?4e3ÃòRú`Ag„«ýóS‘áàü ×_b`ãbÈ žG· €puLö³s1øß¿tùñúö .Š^A¨òŸHͯÐFÇ/¨Ø/¨åü Ïnˆ3¬o¿ÇpõÈ™·ìœÿb€‚˰Y@øšå{€Ž°ÿòÁŒ­^¹)h0hÚé2Èj K[¨¾A}üÀ¾à `tí𠆻§/3üýóù4ÐŒt ›Îã² €ð÷ þ3Üöv¼ÿÿûwïì¹Ôûç.˜ JÊ1I¨ª3Jò;&àöó놯¿1¼¸}—áÝ“{À¬öç"Pß|`©>hÆO|V1=£?À”;•ƒa)0AÚ|xõÀõí“:@ËBó #¸öŸá)0í\â½@|Ú6#ˆq {Ç4à½c€io -¦‰VIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/openterm.png0000644000000000000000000000373611550446574023067 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<pIDATxÚbüÿÿ?Ã@€bb`@î€bóyxx¼ÌÿÿýcE (jþÿ²ÿc²ÿAPq(†ê‰ÿûæ!©c€ë³þýçüòåóÉ… úØììì±±±¢@ÍÿÜ÷¦ ‚¡–!,ÿ±l!#ˆqH¬åÃ?¨þÿPs™þüýË0uÆ\C €X 6ýâççgaÜšXÿÿe`€9l(Ðgÿ ;l),Ä jþ3@ä@ƒœù¨Œ…™ù7È8€ba€Ý_ $¼xñœáî“G`_€\ËL%L@m`♌ÿ!⌠qFˆ” "ÀúÿCÅÁŽgcaeâæ+ùt,¤ˆÅw@0oË*†Uö3¨I+0üú–l#Ø`0ìF¨cù ¨êøÌÌÌ _¿`H±õdð5°`øøí,ûØÈñþîûg†7O†T†Oß¾‚ ù „¢ ¹hE…/?ÃÔÍ+ž¾{ X€bA×À ªŸ_0\y“áë÷ïP_@æÝ~u“aþæ9 ¥…ÐDŒð @±À s3ë//î¾½Ãðýço ígàæâfX¿}רXÙÀ‰œ=!Ùƒ € QÍÇàlŒ¯7ŸÞ2¼e8ÿø<ÄŒ˜"q11ü|ý‡áÃã/ ÿž™“áïŸ_ÀÌɺÿÑB €BRÜ2ãé×ç× ª* 3‚¦3|~÷™!gKî{;Á>)cþÏ ¤!Ò_&0fúÃÂÀøhÜWf†¿þ2°°²2ügªp "ú?P#¼^A„@±Às/4üþ÷›A€G„auÌj†#»3|åüÆ`øÉa׫} ¬ü\ ¿>ýdøÏÈÁÀÍÊ Ñø”¦À©œÀ˜%(¤¸þÿçÃ?`”þg•´ V¿üƒ‡@Aðï4XþÒ'ƒºˆCõ¹:†õÖK2ANq & †ŠØ<†EÇW1¹}Šƒ…ƒ^A1BCòÈ2äL@G€|ÿ—™ RaýƒVpP¢®ƒÂÁÊÎðìÕC %Ë–×-gèɘÄÀ')Ìð˜°þ|aø Þ©Q s’ú T €>Z n&660ÍÄÌ,,1`–f‹±€ò7$"ת@@Lðø©ZY€šÿ|à`HžÏÑ™Èfİ>w!'+'Ãw†ß ™«*f\ÄlÅP¡ŸΪÌlK™¡–3Â,9H31 P¥ÆˆTS‚@± ”ñÿ¡µ'ƒ°7ÆSËøE$Ma`axÍý•auúl [ˆ¡¸­’aÍ• \2¼àì(fý?hEªc™@qÎô^¯ü‡B X…1à/°®þà Â+À°¥l ÃãwÏ”%öîÙËðôÃ+ yy†m;w0¬9»á½È/~5V`"üÿj,(ÅÍù Lx J”(!m¾àêû?, üc€‡@1Á«hAÁÌ:ïc˜´~ƒ»š=ÃË«O‚g¦1°Èr3|þú•aÁËí ÿ4yÄ$$ؘÙqÍŽ&X¼ƒ¢‚ü` Š +8Dþ3BŠbX@, ÈAòÒˆøýë;Ã’K«¾MÿÍðòáK†oJ, ü@Kþ5sñò}ÃL @o0C[jà …´z@€ó8GýÒ ü\ýƒ–‚ Ðôo⟿ r¢â ²BàŠäøÝÛÀ,È ĨÂðÿ;#¸ˆ—vLŒ°r¥-ðï?RÍ tÈp©´ï/öÿ RÂbÀfÙH±­ îøòã+ƒ½–>ÃéÆ%ÀäðQDÿc@J¹°ÐBèƒÑ >¸ýðZDƒ#"ÆÊ@‡|úôÈg†; €à€5¡@lv`žÿÏÄ -±@)Bÿ‡7±Áþ…§ÿáõ;¼! m¨Â*HÿG([BÄñs+¤e É& V+¤Þå[P\2B‹QZ&Hó”õ  N`>ƒ–nиÑÐb—ÖÜeOpZš Ê!ÿÀv˜øñãÇÙÙsðsÀ¿¡m€ˆ¶,¾;"¶>4ùBåa‘°(9ÖE€–ÿÐÄÊþüù‹+ =Ä8ÐS€ð¾!@ ¸ °VôD¢<`IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/previous.png0000644000000000000000000000306311550446574023103 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÅIDATxÚbüÿÿ?Ã@€bb`@î€bÁ%Áh2‹|S¼~þ-døóW“›ó  [ûÿã±°) *{ˆ›áßÿj†/¿Štõ$Ù­-åæo¼)õó×9 œ&6 D=02(3üþ7ƒáûww†¾G†O?–ïxÈðóç/Q\ÚˆZðaøö{2'‹BA¡5Cr¤>Ã÷ÿL wž~aøÏLfÌ,pi JÀÄE ŸÕJÊðq6•Ø3¸ÚË3ÿÁÀ "ÀÀðþÓ†eK/3?ò€“ã0$²q@,$øZ†áïÿÉ Ÿ™É1Ô;0(* 0ºÍÀphÏÏ¿ËoÝ~ϰgëy†>3%ÇR åE@ݯp @Ä:Àžá×ßiLÿþiùë1fX“+Æó Çï90ÎyÎ~Èprÿe†Ÿß~ÿ`àáhºº“áÿÿ ŒŒ8  bPÀðõW wn¦5CãwŒ «10\~ ‰oοŽ»ÌððÚ=†ÿ,l·¸82€úöã3€Âçq ë»€–Ç©kK2åØ2èꊃƒ|Ù †o„)ýýë W/^`øô˜88×S}Ƨ ŒÄ-@ávÀÿÿ‹€Åª[@°CJ‚)Ã2 ¯—ñû¯øþðêûó‡þüþó•‹»äÓ:ÿ‚ ÄPW0â®ó_ðƒ —ägøÄÀưã,ÃÎK ߯3³ö`6cùþ‡áïP!Ãú˜^00³i`FafcÓ, š’Hp€bÄÕ Ö†jÀ˜Îü÷Ÿ“¬®*¿0²y>|úü Ðß!•¹Ó‘O7.ßúôÿ;Çvö`p}b`Av+ÃÿE²Xí |í[À,äó—½ïÁåûnîØÅðûõsaAH)ÇËÅÀð˜Eœ¼ÌÂ<Ùþ3ä2üù¿ pZÄæn€"Ð ùÿèˆbî¸_¿¿º±÷(Ãëk×yÿƒÓ€ /0ÿ£bòV†obš qš ¼lÖ ?ÿ&ÄXb@Ķˆ–‹S·ŒL'_¸ÁðèÔyNÆŸ Â@GðŠÄM§Î~”`ðñÖd—ç&Å@‰v >ƒˆ”&ÙE`brfµÉo¿`¸uì Ãÿ/ïD€Q"L®lœ çïêSmm&†Œ@GlêUÁe(@‘Ú&ü ,Õò88’~ûùúþÙ« ŸžÊ4IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/homepage.png0000644000000000000000000000610511550446572023012 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ×IDATxÚbüÿÿ?Ã@€bŒ, Ü@ô(ÀÈÀÀ ÄL¬ ÿA|&†¿yþ3Y3p1ÙòðséòŠð(sðqò=ðÿÛ§oï?}ü|÷Ç×OW>8ÀÀÆz’áëÖ¯Ä8 €A!€×?ðR:’Áv^ê¦ÆÆR úê¼ Âì \, øñÛo†‡/~2œ»ù…áüù¿Oì;uöÃC˾m_ÌÀðé=>n=Íð‡Ñ[\I¤+$ÛR+8H•ÁL™¬î7Ã_ ff`²™ázɧߘŽÜøË°iã]†ýö\zwkU5Ã[p9 €°;’,ꜣÌj¢òÍYu™­bd`bdK²±°1üùûè? ß}gøûïPö+Ã&v†›Ÿøö^øÆ°iÁÉoç·Mébø¼¾ä%t †“þÿcfecí Ês)ÌÔbÐxÃÀüí Ãë dðƒ•l9; ;ÃÏ??¾üø 0F¨w 3Њlo´ù˜sL¸D$›vÏcäeø´¾hÁ7dëÕQëR`%Ä À|‰á÷wF†W@‹™ÁÏ!Œs›hņ÷ßÞ1ü:‚”HÑýÄR¬_8Ÿ1ooJý‚© „Å@üï—GŒ]¢ïÉÇþÿ•`øð›™A€[ŠCˆS€ ˜8Yö±£þÝ×÷ ¯¿¼; ÿ™ÇÈÄÌð˜(tD…®=Û ïäÂ`ö±ªôÔò›WþÞ[s@AœŠ÷ßùåUd{•DY>ígæ–`øó_”A˜W—AG™Uá÷_F†ŸÀøëïÿ ï>bøöý'úò…á#ÿó#0=p2|þú•áË·ï ¯?}epR°dxö|ƒ¾», j|%#—6ÌÄ„0¦LTkµ—'2¼zx›ŸßˆAX@›‰E€á;Ð}ßÉçÿb ý ß<f½G b¼J âüêÀLÃ Ì–Ò Üœò@‡-ÿòƒáóç ?š¿ÿdax{ç2íWË\ÃãuX5bFp€l ¨þòªj+3)~cxÿ‚‰áÌ+M†S¯ø¾cêÔÇ Ëýƒàkî2œ½všáû×? ×ï_c¸|û,÷oü¿ ]cøðþÐbPªef¸÷ä9C㜉 gÎÝ`8r ƒª!?ƒ–¯ÐREÍM„ÿmŒ\U/^?Ì È§Ë -kÏpü)ÃÝ7 zb ‚ | Ì¢ÀÀÊL o>~d8töÃá g¾}ý Ì·Ò Ÿn?exòüƒ–¥—æ‘˳íþ>» @`°±±ØpH²3>ºv‹Á. “˜ þ}ý˜a?f`¸þè\!–ïïNßÏ À'ÀÀÉÎÉÀÄÌNp€¹äûÏŸ _¿cxùöÃû÷¿†æû7 ÿÿƒŽ‘ XvSíoN†;7O3¨¨$20p)[2|~¶ €Àà`×U‘a`¿ÏÎpáàdm 5fPÞg`xtÈG`Šfgf8þü?ÃåMS8¹À>fæ`IL|¿~ÿü.œ@®g:PNÏ…áùý# <ü’ ß¿¼aøþú5㇧Œuâ˜y$eÿ~f °DE”^¿»ÊðèÁ.†?_?2ܽ¶œABÁ†AEÇŸAVÁžlÐ\&`Ý`ç]Âðýï7†ûwö3pr 1üþýÿï€rÀ¬ÈÅÄÀÎ)šÿþýÅðýÇc6^yM{†w/¯1ˆy1Ü¿»›ƒë¯ÿ×ç <vïûÀìÉô•KXèß OnaxþdÐÂi ʶ ?€Qý è6`IèèÓÎ`öå7;ÃåóëŽjF#¢(—†ì oÞœ`WòFÓ+»tV–ÿ ‚ ¢¢" r” 8ˆRúþÿÏÆÎÂÀô ( ÙÜü@_üf8q¸”áó—UF`n|@ß-L ì(,eÈÀÁÇ.æáE2Ð!¿ePÒôbptíb`úóáèÑf†_??2:2ó‹‚Ì)f °~|ýúž…‰UŽ… R"ŠIV†?>0|ýúX¸€ ñ$ã?ˆ<¨L`ã’càªyôXüÏŸ/ ì¼ æVåÀÒ““áųK Ži ÜÀzÌ@M“áõóŸÀZX‡S @ËOï>ÜeûÇŒ/f#X8A>üÌÆïUÌ-ª˜ª‹P r#'P X3²ÿaà”`06Êa‘a`&È7Î3|ú~Ÿ›‹X”:èÿ/ï¾€êu€›ûæÍËË\?e„„…YA)h:ÛN>a%9' *6`Úbg†Ð zT°Cƒ(À/¨ÈÀÈö¨X[òð2È+83h+{3ð},ÌÍ ,²¯2¬>œË0qs4Ãù»;ž<þÎÀðíÙ+ Õ_ì€ÿöx{‹ñ‡žªÃ/–¯ Ù¾1kF2${o`ÐJìL‚ˆˆ¹X!˜й€®ÐWOa`†ÂO¦· b¢ª šòÎ ÂÀñ‹ƒå7 04ÿsü†ÎOe1]†Kç¯ýaøyëÐê÷- o:´åô…¼‹cüÄ9ÕüŒ³Yœ—Xœ«\`Xƒû(èÿ›-ꃒîy…5t”ÂþüûÌ`£š ¬d8&_~X€)1¸h{1¼úv•ÁPQ‡áç{y†ËÇ:ƒà2ÈuÀ›o/Ÿo^zo£…“×OL@¼ ¯€±Ä luýúô70ÉÿïÐøÿÏ€hƒ°‹dýZ`cÒ’E(”8X2( J2Ø()38ª2pqq0TøÿçñÞó@e@é €Z­_°ù’5W&3ï;`=“AØ&,A$Ì¡…°P (Š€iƒŸ "ÏTç¡îÅ ÉÇNC抒 ÇN20œØ0ë!Ãÿ'>Ù @6!<ï»›Û·­Kœ$Ȭ팄Ý>A P€¢á/4 @¹ ‚’… âspbe”0Ü,``8tó'CLÒÜoN”ÎÿT ¶« Í "Æ¥Ê+ª¡¹oº%/Ѐ7Ÿ!Õ16€ €¶à‘ÀJ @” ÄäE`ý”¼æß½•{þݵ€÷‚¤ €°ôŒ€ÖºuÙúïþåõïÿ߀ ž~úÿÿþûÿÿñÍ×ÿÿ_âË/!øÚ+ÿæˆÚwßÿÿÿùç?¸þ㿲Ç*`1©´hvó [@ 8ºfÀXulÕ°Xþsž·ÿ}øÿñÿê‡[þ_yûðÿí÷ïþ¿þò÷ÿg EÏ?ÿüÿýçÿÿ~ýûŸÿþÿß·öÅa“)ß‘,D· €Ð¢P!„ݯ<06\ß<œ‘ážØF†Œ€‡ ŠŠ üÌü ÷¿>`PçWaPPe0ä7eûkΰûÔ'†i³O2œÜ¶ð>çM@Ë¿nšwTð [@ølš ª±‚¢>¾Z–vÚBZÿ…Ô1°J»~\?€ ‰áÃ»ß 33|¹ÏÇðþÚŸ?7Ïì~ôïÍ~`6{tß·áqŽˆ€;¤ 'aÇÀ lÎÌ*¡ÀÎ+ÈÏÊÆÁÌŒ¿~~ûýóÛ›Ïÿ~=Íðï °„û*d.ñC þŒÏ`€"ÖHÑÂÀÄB ê0fHŸÜÙõˆ?ñ;\>F΂â¦~ãIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/1leftarrow.png0000644000000000000000000000306311550446572023313 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÅIDATxÚbüÿÿ?Ã@€bb`@î€bÁ%Áh2‹|S¼~þ-døóW“›ó  [ûÿã±°) *{ˆ›áßÿj†/¿Štõ$Ù­-åæo¼)õó×9 œ&6 D=02(3üþ7ƒáûww†¾G†O?–ïxÈðóç/Q\ÚˆZðaøö{2'‹BA¡5Cr¤>Ã÷ÿL wž~aøÏLfÌ,pi JÀÄE ŸÕJÊðq6•Ø3¸ÚË3ÿÁÀ "ÀÀðþÓ†eK/3?ò€“ã0$²q@,$øZ†áïÿÉ Ÿ™É1Ô;0(* 0ºÍÀphÏÏ¿ËoÝ~ϰgëy†>3%ÇR åE@ݯp @Ä:Àžá×ßiLÿþiùë1fX“+Æó Çï90ÎyÎ~Èprÿe†Ÿß~ÿ`àáhºº“áÿÿ ŒŒ8  bPÀðõW wn¦5CãwŒ «10\~ ‰oοŽ»ÌððÚ=†ÿ,l·¸82€úöã3€Âçq ë»€–Ç©kK2åØ2èꊃƒ|Ù †o„)ýýë W/^`øô˜88×S}Ƨ ŒÄ-@ávÀÿÿ‹€Åª[@°CJ‚)Ã2 ¯—ñû¯øþðêûó‡þüþó•‹»äÓ:ÿ‚ ÄPW0â®ó_ðƒ —ägøÄÀưã,ÃÎK ߯3³ö`6cùþ‡áïP!Ãú˜^00³i`FafcÓ, š’Hp€bÄÕ Ö†jÀ˜Îü÷Ÿ“¬®*¿0²y>|úü Ðß!•¹Ó‘O7.ßúôÿ;Çvö`p}b`Av+ÃÿE²Xí |í[À,äó—½ïÁåûnîØÅðûõsaAH)ÇËÅÀð˜Eœ¼ÌÂ<Ùþ3ä2üù¿ pZÄæn€"Ð ùÿèˆbî¸_¿¿º±÷(Ãëk×yÿƒÓ€ /0ÿ£bòV†obš qš ¼lÖ ?ÿ&ÄXb@Ķˆ–‹S·ŒL'_¸ÁðèÔyNÆŸ Â@GðŠÄM§Î~”`ðñÖd—ç&Å@‰v >ƒˆ”&ÙE`brfµÉo¿`¸uì Ãÿ/ïD€Q"L®lœ çïêSmm&†Œ@GlêUÁe(@‘Ú&ü ,Õò88’~ûùúþÙ« ŸžÊ4IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/bottom.png0000644000000000000000000000404211550446572022527 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<´IDATxÚbüÿÿ?Ã@€bb`@,ÈF“Y¸Ô)3üû?“áÛoE ûP%¦ $0™8Y^3°0fù°öÿLœ @,8 A¿þÈJp;gEi3°±02üùûjŒB ›™ bÈÜ ·”oÞýèÅÀÆ„pÀ¬î Tü™Âˆ©ðç_i†¢h-†?~-úÏÀTóïÐbÚþ÷ß?†o?þ2ðñq0<õ‚áæÕ·Œ ,¬¨æüƒb$€*r·ˆa¨¹â$Xžý·a‘;¤üp›"#;ÖK-p;Й¼µJÂ3Ü"Šñ~8¯Gø‰ i(§Órì+bi0ã•àÒ²ÒÔµøfüjúTȉä ô)3#0œûv¼a8{ë 09üùõ›á ÐarÂÌ KеØY™>EöĨåh¡ @,XÓïÿØa!1Èeú´L¬¬ÀÔÆrýŸ‰……œ€Š@ â/ƒŒøIºØÒ@±`Mó … –²A|ÆÀˆg†; '+ë&pÂE;; Pމ‘‰P=àŽÇˆo&ð ¨ó/00ÿA\r3Ьll ,ÿÿ€•±ƒ–… b9##Ô =0:@6˜ƒ0ŒN÷ÿÁCºª0}ÒæHû¤½óL‡`tGù“n„³4Ùò2°ÀÌ4ˆš@ë ³À@º=f0þûŸòÿÛ&$·ÿcøòKò×·?`,`feZÈ t#8 ²Ó3+$t@ðç;07}þ 40^Ús.°€ºža5׳ €PðõO¦©¹¤^J¤6Ã_`õÄŸ_¤D¹€Y‰á'ÐR6`dÿÍÀò±¬À`e…$@ç³’t\d¥ÙX™¤AF€ÌáábeØ´û!Ãö‘@¨`b\úøþG½@EAN´xùÇðÿçO O鬬ìÀø1l@K8ùâß?{If'I†¯À¬÷ó÷_`¢:މ™aòìË £Ö#[ @¨`ašöüþGÏ´Â}+çzÃî?Ã'`áqç=0üþCrÅ e?þ³2°±ÿc`ú )‚naøËø—áìß À„ñó×?†?ÿ0(‰±1ó03ˆ‹ñ0T´Ÿa¸vöÕ-AöNd+Õÿaàf«Ü¸öæþ.ò©1:À²ÿÚ›¬ W_30°}ü høßßÌ \œÀbè$l@aõ Xv4nþ”ûÅðéË/9&†‰±R R¼ »¾`˜5û °„e­*}l%@1aäFÆÿ˜û+«3\ºþ–›ƒ•!Iÿ/;°bfF0þi€” 4+CÄYYþ2±€Å‹}%Td¸ž¿þÅP\v„˜ˆ— µèÙ €PðZz±³¶¿}öõLU݆?ÀJF]”‰!^˜±Id(²B²"Ä1,`‡°³³³> C¢0ƒ½C{ß9†Û—ß>`àúdöoÔê €°7HþÿÿÌÀËš¹uí­]ýgÁÊ<ÕÜ5Þ_P%±”YAa…„Ä÷, NZ¼ ©vü ¢< ‹WÞa˜3óÊ/¶<`ÁôRÆ Z@LhiÏST}kÃQ†£'žƒÛ±ºÿtD€uÕ_&pH°‚£ä¿€>WggÈwâaád8wé=CYñ!P"ŒÖÍàÐ…a$@˜€E¨fcšúíëïe)i;<úÌÀÇÁÌoþ—A‘ŸÀ g:ä7# ƒ8?C• 7ƒ°Jþð•!#s/Ãë_0p17á+Š3 0!UÀv0WäݸüòrRÊN†OŸ1Hñ21”XþeàÕ°L ¿™ØxX*ٌ؀!ÁÊ[p€áô±G÷8ÙR&|†‡*¬‚B„êP;àÇHËè7ÿùÿ–3iÿî;/‹K€KT9~f†Jë¿ *‚ÿ¤øªlLä€Õ CKË †% .}g`åH*¾ƒô 6Á׿(V#r³œ‘±Qi°€+¤èùçÌøkãô…&Oraàåeeøöó/°5ôŸŸ ˜E32ÔsMgÇño Œ,É lÌ+à!ùï?¢z§ñ"¸±„#0 BdŒŒÙb.¸ð&,|#ÃǸؙ–³0¼}û›!%uÐòc?–çKTˆåÿ füú³Z ì!€­j¬þ'Tk`+u‚‚‚°I` *0anÚt—áêÕ·€©¶X%n§£¸-E€"Îæ/Ð%ÀÆýo/PeŒ¯}@<È~Ž»mÝ„­EÄŒG'Œõ¨¬hé,ˆúÿzñZÎmÂ@¡; ˆC zžRþÿA2‡‘È®à ž  tè±´K jâ¾F ÆîЀ÷Ž êÊDbºïIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/ok.png0000644000000000000000000000330411550446574021636 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<VIDATxÚbüÿÿ?Ã@€bb`@î€p iÜ„a*’’ ˜‚‚)` &õ‡@¡Ó³O'é˹"3@ÄW°õϵ¼NqD:²‚ü½süг•¸˜mæÈ€pØÌˆ·8 ²WÓ[\c÷@´F†ÿþË0üþ?_RB¢ÇÑÄP‰““;& @4wÀß?½˜˜wjiD:Ø0ð1³2üüú÷L €XhfóÁß¿þ5pˆò焚h3Ek¨2̽zƒaÓá+™~ÿ‡‡@ÑÄÿþü3ûÅÄÐ'§&im©Ïà%.É0áÆu†u®}dúñ?…‘é¿øÅf%Ë ¯#äýè`¹Ä‡'Èíÿ02î‘Öæ/ÎòÕa+00efgøñ÷Þç/fn}ÈðåÎï6æzPYËÿÑ¢ €à`ÿDzèêÕO™~²2º1ˆ«sûþþó6PŠ-{±í¨bàeÙhl+l\ênÈà+môÃÏ¿?N¾{ΰxφ7~®dcf®ZŽ·º ¸˜X/þzɰ{ïåW f‚† Ù.æ Â*la¿3N¡ì_3h£p9[«¯‡ …%ƒ§÷ŸLÀ‚î Ã¥OOí}ÊðæÊïÍlÌ,éŒLÀ2š x`úÇò—í7ã¢+—?îÓ¹Â.ÈðÝí;Ã<†k1Ÿ®0üeúÏpü?s½²‡d¨…ƒ•ˆ.0 p2|üõ¨ù+Ã5 å ÷=cx~ú÷^6&¦„ÿŒÿˆÊI„pÀ/V`pìüýœñäž×­ìÄm¥ý¾;}gXôùAü¯/Lñ¦Öœ ¡úÚ j\ ?ÿeøþh9ã†ß3¬:òœáù©¿WÙ˜“þ2ÿ{Gl3 €øÃ ¢~±þ`XróÊ/«ZGœD¼¼$]>¹nÆïOE=af†Ï¿¾3üüÿXsþ`xúó!ÃêcÏùw—õ7sÌöH)?á€ÿ&##Úw Þ¼­¦ÎwƒãŸƒŸ¼0%«Õ¬ ï~Æ÷O Â_ Ï?bXsâ)Ãí}ŒY0‡ÿãü}½Bç;FÜá@ˆDª÷˜å?ëk毬Ëo\ýÃpýãm`0døþç÷_>ýþÀðíÏW ~0¼øý˜aëùç w÷²~dýÆ”ÊÈÂt˜¿€vA Æ ÌÌÀjS`Á0@ˆ@°èómæŒ3ŠK¨ 3ü6Hþ}ý÷ÿpH|úûŠaßµ 7v±}aùĘÆÈþw'Óf`#†T@L°Â13#Ó=¦7ì»n\úÃp÷ë=†o?3|¦öo¾0¼ùó”aÏÕ W¶rþayÅV,îWQR{" €¹Ù€Õë´×¹]{úèã7@G|eøð÷%ñۯnlåf`|Ê^ÇÈÊ0—Òê €!ð‡3ÿg>Íð‚cÿ½ëÌ ¯~ñÿ5Ã…'onî``~ÌÕlØtP£þ „þ±¡b–¿¬?Y|¾Ä÷ïáûw WŸ~d¸¾U„á&÷4&†r`B¡J €JBf, JÆ­ ϸ/Þ» høë1Ãÿ+|ë™Ø~kÕÔjÁRAÄŒMþ3ã_¦Žo{$Z¿3íÙ@ËP³ @ŒÝ7 ïЀ; €ÜëŒAt>zIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/button_cancel.png0000644000000000000000000000465611550446572024056 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< @IDATxÚbüÿÿ?Ã@€bb`@,0F£¼<Ãß?€¡ÂÅÈÄTÃ' ðýóçcý**üÀ -¦ÿ@®f²™¡lôPòfp322¶òððøûüùP_ #ã{°~ Nùò¬ €XÐ]ôïß?¦ÌÌÝÚÚY&?2ÜâãÓÜùä‰Ä¿_¿â€–½#ÆWÿþÿg:i²µ®n¢†Œ ýoߎîßÏ÷÷÷ï8&fæ¯Èj% þýýËô›‘±ÇV_?ËèB>`¨˜üøÁà&*êÍÈÂ2ÿïÿÿ|DXÎú÷ß¿ÉæJJ‰F’’ Üzz †JJ V®®A@ñY@Gp€Bˆ jÿ¹ÿ±°L±·´,t}ÿžá¿»;ËŠ ÿŠŠ Þ¾eðôcae]ýAå|@ŸÏµ’—O5føÈÀZZÊðÏÅ…ÁPQ‘Á&$$ЉiÙ¿?Ä`zî ÁÕö¶¶™^@Ÿ³8:2000†×¯!z¿}c`øû—áÿéÓ`ÝzèÓýûg`ö<üûñ£tÇáÃb VV>æ«V1üZÎâãÃÀðšhq£†á÷o¥æf6ÏýììÿüÿÿÍöß?7`ÖbZÎò9Èr  88þ^¼ÈÀtáà‡–,9õ÷Û·˜½Ä+ ›¤¥þýþ-ÌÄÆ¶ÐËÌÌÛäΆ?ÞÞ ,žžG€ … çýû¾wu1<úì33ƒP?{f&ƒ ¯/D-ÈLZvv†?÷ï30?Ïð˜›ö¯^}êÏ·o¡,ìì’  ”lÈÄÄô–áǘÝgÎl¿$'ÇÀ¸q#ï͛!†‚Txã“ÏÒ’˜H%€ÉCŠ51‘A˜ÒÞ¼¨ûï«Wþ9Âðׯ?÷çë×06¶GÈ@¡„HØEþH²rr.pQSsÓ&FF`°²YYÊ„︸>:Ä4”Aç09úü×ãÇ ÏœaxLS‡8ÿëóçp ÏoÃ,O9«˜AEéŸ?|L¬¬‹]””ütž?gøô!'È 0G°±Ar Ìrhœÿ|ôˆáϹs Ïýb8tüøI`z ;²Ïa x"üDƒ03Ó'`ñ›xàÞ½¥l²²JÛ·3|Èel ±š0ë ƒ~ܼÉð ˜âßÓÌá Nÿýù3=Ø‘@ÁÀªˆ Š@ ¸°df~¬ˆ"÷>|¸é¨¨­Â®] ŒÀP⯠@ÇÀ …01þ¼wáÛ‰ o€f»sçÒŸ?ü×s|E7@¦Ê%@¢ÐȪ÷¿N¯dtÑDж3ÄWäñ`CBŽCß?¯–ˆõ;¢»™LœàÞZÚ‚PÞ=Õ>@å@õ†®<µJ¸_:ÆYO¤’’•uý–‚§ ‚‚( ®Õ˜˜¦Û*+'j½zÅðöáC†ß 4 r0¡ë°C™@˜X€E03 II1€¼}ôôé­ŒÀèÌwèƒÚ @8$Àj™XÈL6WWOÔVËŸ€–ÿ‡––ˆ¿€9à70ÛËFPbbý XyÉË Kkko þ?<µ(@1á°œèó¹ÖFF©ÆÀ<üéÖ-Ë‘0(î• ¬Š‹ñùÅ E`¨Zº»û1³±á¬EÃÿÿýcùÇÄ4ÙÖÒ2ÖXv»r…=ý‚,ù Ä *QRa#¾ë%`µlèÌÒsÿA´ €bB³œìÓ¬lmãL€Õï·³gQ|`Ëñÿ˜ç¿³ž00þÁrÜ@PÍW`ÔÉCÂ,4Ô˜h—ÍBV@È `Slª…›[ª0ο³Ó_lѲhñ/`cbº|”áÔG o…bØBEßîÞeP‘`0‰õÖ5 GHÀ¤ˆ )ÈZ¬ÝÝ“l–ÿ±ÿ°ø$Æ´ø ÐG‡ÿ>ýóÿ/ ˜ëñïß·¼†€ 0kþý‡æ hHü¼}›AØÄ3MO÷dâäìƒIÜÜbb>z|ÀĺgVŸƒ¢‚(ÿYT”áȧO§~ýýÌ^O€|†^Âé·o·¾R‚@5À¨ÄH7ÿ!ñX9)$**ö0q€‚;àû«W{oªH[[¬>ç&¦ÏÀî‘·oÏýúó' ØÄ~„ð$ã[`Ή9ûäÉö·ÀRØòù@qfUU†GÀÒòãýû§aÂwÓß¿µG¶o_Xˆ°™™1 §N^`ü½••e8ðôéùŸ?F°21=ÄHÍLL€ýŠä“7oîz, ù€·!@°œ`¶Œ£÷äìÙÇþ|ùR Ó@ˆ4ÀÌüŠñׯ¨#[¶,»t'°ÒIò}ý¨ùàÝ»'~ÿlŠÝÆY¨01=:"ôÌ¥K›žCäp`qÌÀ l?fé³gïûûéS°Ô¸ Ó@(Ù™•õËÿÿi'öí[wUD„ÃÆ†á0áºzõôP­ÆÌü#m€ê¤ZX,FGâ…3gv<ZÊ ö§ÀÒòìêÕGX,Ðò—Èú^LÆ¬ÒÆ— Р^II§oÞ\6£r-áÇØ|Í ­á5(”š"ÂÄÂ2I@RÒúÓ«Wg€(úöL_(Ô^€bèÞ1@ xï ÀïÒþŸ\W IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/filesaveas.png0000644000000000000000000000445211550446572023352 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<¼IDATxÚbüÿÿ? 02öÉ¿PL)`f`gúËॴƒA€ã“µ´Äß>3Ÿ÷™µ›ãï FF†™gÎ0 ¦FƒþQÁŒ ÿ12üüÁ¤nãöyIHø'…wþêlÚ.ìxâ:Ç¿Í U„æ€ÿL@"”‘SŸ‘éÿÿP1"9Ž‘ÈàøÏøÿã_k«—Á±%* ¬ÂÖ |¼³²ÄŸÉp,ÿ»èÐ%! ªC„î€,YOÛÉÚŽ ’ _ĸþ‰á?Ð!`§üºéÔ!ÿAá )`4B¢ò?Pþ?;ëç?¯U3äU²1°Jg00üJó‹30þÿÁâÿ^àÖž& ˆ@¡8€CF*7¼È’AI’AåÏ+W]n&npŠÈò¿P d&PL•0AÂ…‰ñ? 0ØýaØ1)‹ÁªòvÃO ‚Ó Þ00H 0°1ÿfàäú¶ €PÀÎÍÉÃÉÆÀðõ#Ã`úñã?#ÿçÄ ‹ÑÁÌuÐllŒàô»urƒ±îQ“: å‚ _¦ů20pr2üeabX´çî½Ì© ýÄ„šlþÿ[´Œ h2Ð3`ƒA˜ Š‘Ùÿ¡Žú Í4 öæ)í šÊ+TÜË~Ë00|[ôÁE åÀÐädbXÙÇôâðÆ‘쬿¯ƒôJ€ G/È@o1m‰ýg†ÎüŸ挈´%]&`H\²ˆANd:ƒž_>Ðru†ïK€ Nã–‹ûÃú)ìgÏ—+øÏÄtšå$ûª˜ élÐr& í à§/&Hæüÿb9رРgšlÍ6®ŸÍ Ö)i@EV@ËW}¾/ì <ÿŽoà`hXýûÒs¶+ŒŒˆl@L!IÔ`À4Ø™alhÜsò00œÛzáß‹—¤0  ;0Þ7}±h9/Ãñ5ÿ&Ÿ®cø¦4í+Ûÿÿ@Å̰9€™`E0‹¡–21CÄx€–_9pžáÓ\4 …@ ~î°b4Ëo†Kë?3L=RÊðÕ"“ñ´,a€B‰p"c€¤tf&”B‡êhœsãüê©Û Ne3ød˜3°pGƒýЃ«Žø.Îoíý̰ûd ÃoËd`t€œ„YÂJÀâ”@¹'hŽà:ûÑõ§ ×÷e2ø¤)3p ¦00|>ËÀðjÃëw@ö7†ÛÞ2¿Å`˜ÊÀÊòŸáP@1¡‡´ÐaffÄp̯ž¼g8¹!‡Á%RKXʽ=tÑ †Ï–ÿfxvúÉ[± Î9= |ü, ¿CJul l‰ì,@Îïï ¿þýòÿ‹Zf†·¯?3ìSÌàâ÷‰AH¦èãÛË?<ç×//>0ì9åÄ ›”ÃÀôû)0:¾-#¤lÁâ€Bq3#"Ÿ}ÁÅpóí†?!å<¸(fecx»s ƒ¯ÑS ݆—îô30¼:â/3Ãïwæ±gxë:“áë7i†Ÿ×¾Í`øñ— œ&™±ÔcÄ‚ž¡åÀÅ×L þ±1‹u†Ÿ ¢(ñíÃ{»ŸïÔ[€Á}“áÆd`|\j`eøóå;ìㆠ53p0Ê2€Ê¹?ÿØÁ¡Ét<'/ö( liäV`V{ûâÇ{ŸøÉo&N†ÿwŽ38ð00òé2ü;7•é°ˆe¥™ß [ÏÊ2ìåÌðÿ§,ÃÍ_€%/ƒ¸6'0*ÿü…ïXB €0BæP†ùùíC¹÷gKC.†@¹ƒ+ž2h™1üþú–á§B ÷¯ ¿nmgØyN€Û&ÃJ?S†ã§3Dµp10þbcø²èP(üÇ‘ˆ óŸQãý•x@ظ¸>}øÄpûþV^Væß/>}úȰó&ÃÜëA üA lü<˜þþ``fcfff¶#€‰ïß_ˆyà¨Àâ€bA/ A¡ô ÆÅ`øõë/ê•§v<Âðâû3S†÷oÿ2Hj[3øT2ð ó3|~÷Žõ?Pí^^FV.H± ~æÀâ€ÂȆÿ¡ŠA¾¥|åß¿ÿeøôðÃç·/ÞÜ’b`Õ7e°÷±bàdøýó'ç÷¡•9¨íð—Xó²p32|úmâþƒ˜…- f"d„Ü¿øüŽáÙ;~†K_'2Ø8i1Xxq2|øø›áÛ÷(ÍD°€E/#°†ddøˆdùìi €°&Â?ÿ`éÏß`±bQ þÉ[I÷>ø ¤™1ÛÓ°ùÄËÃÄÀ ïÿ?!°‡þbO„îFX.`„Ö ß¿ýbxóŽ‘Á^ï3ƒŒÈ]¥ oÞs þƒi(Ê~³-°Á Œ`Cô´âûǀ݄ŒL šh0õ3€ ¡/_¿3¼}÷—AEš‘A[þ7°ÁÉÄðæÍWì-q`‰óý;¨š¶¦€!ðë¨ ñû?pý„ޮ <ºùúòß7¤¤€-×ß@GüÿÌ %ÉÍ ­-Æðý'zç€ /懟>ÿag`D’ÀêŸë;DN XÞ_wXU2¾FÖ@Œ¨]³N]%-É)Zærúÿ3þù A†· B|¬À„D¸CÊE¾üaøÄ(¬¸˜€Ü„cfad~óøýÛ³ûnÕ“Õ2˜þÿ/c   &†4à w@€ {CÎþ×É /lV(ehVœÈ È¦Î?£–aÒÚ™_X¹Ò˜˜WÃC ©H „~28;h;0r°q0ôÝîfxúñ+Ã4ÕR†7o>0M bxùæÙBÞbæÿoÁ%¬lg„ÐìLÛ™™=„8Dž={Ãà?'Ža墳÷8ùÓ€–ï[þªöÂÄ‚”t-­€Ô?†hÉD†XÉdG'†–Í /_?;ÎÀÍ—´ìРA¿!q2ì+HŠ‘‰aÙµ …³ë^½z±™G0hàcpYýZg €B8€‘QæÕç× ÇngPú§ÖpäÖ †ƒ·Žóë†ÿÌ€!ÍÀúbýhùNˆ~6†¥72LX?çÝ?P¥ÄÍ×ÍÔ)¬˜pä\€B”)ìçXþ1)íøóZº1þgføó—‰ã?S3ƒõ7$ìÿ1IégÀøÏðNfÖ†_ÿø˜X2€ÑtèX&p™‚ZcBÓóŸÿûnþi ¤(`´þóX«€2ð?h|h`Ðñwæ¿  gøû¯$²@ [Hn„k3Ë3 ýèXZO Ú… ßþZøXªBÀÈÂÂÀÆ Œc&€BΆß ˜! ì?”#8²y ëåáÓüúãç!xˆ2ÿ†48þ3Ý‚†)Dý¯ß"òb²Â²Z8¹€…'#ë?`ix¡zz/< Žˆ`°å\ ?¾×±1s”µÄö323±2Ï.¦`Üÿ–Š tÁôÄŒ°V0ο~³µÕ4c°texËðXºcfÐbàbåføûãÏ{˜U„½=Àô‚d¾|[¯*¦^¾­bc©O¨ÌøÏð—Rc©–¾}Éæâä‹ÎöKÖ#¯šŸg0LzYÃð‹á3Ãñ ç€Yþ÷C˜j€B„F;ï¿)ÃçK<Í|Õæ§Ícàeø4â×Ï_ Ÿÿj1p|] t¢MŽc`\3)K K÷äµ3Xèè3Ì|ÕÄðôË3†p‘,¶ÿ¼ «öoFÛQ˜-„œ‘ìþ¯ËðíÇÆp‡É…@ËŸþ»Ã0é~)C¡|ƒš-Cyl(3+g¼Mm¬‚ê%)eSYq1†Å/'1ly³‚AžMÁG0–aËრç.]þÄÀιf@±`©Ðd¾þX›ä’.97mÃé‡Ú”€ ¨'Ÿ1HËÉ3”&ä“ÈìÕ1°B¹ûå2CÏõ9 翞`b•a(Pleøý™‰¡bZ/¨13¿`:Q$ð@D~}Ÿl¬hžs¤n?Ãñ÷ûïå3°0± ?6`žUCŒX$ë ¨Ÿ ïÿ¼eê`0å³a(Sifþ/ÃQSÀ°yïîS Ü<.@¥Ÿÿ‡¸ €XPšØààgyÿåÛg†O>1ð1òKX6†÷?1pÛB¬"@‡°àu€ 'ƒŸ#ƒ¯Xƒ…°-ÃÅÛwB:cN9s—/¨õ3²€B„@,Lˆ—áË—-ºnvk³—3<þw!Ø.x÷û Ãu Ê\Àv)Ó_Ì”u32þaf¸ýôÃì«ÖìØÊðá0Árpóîx›ðÿ H¦Àe7‹Ãç/[MT-–g.``äùÃÐp³Š¡T©ŠáÆÕÇ S·Íf`cå‚&>D Tú~ÿõ‹áÑëW _¼xÿÿÛ3 lýÀT¿#³B@8êV±Ê±@]FÛqJB/ƒ¡’&ÃÏ¿¿fl_ÊÐ<·þ1ß"H6dBʆÀ’è?ó&¶‡Àbï40±]A+®1@xšåÿ1pñyÝ||§Ï·#2³&¸”!×3ž‹ès6Þ» Ü5à¥@bƒ-þh¯áD còÿТ¬¿þ]¨YØÜzíñmAa ™¬LÀæ/¤Õ(‰’°¥È €÷Œ@¾`f™ÅÀÁrxÙîµY¹\M,Vôv)¹ €ˆìšlbºÎÀÉåýÿ7s%0Þ¡Þ¤Ø yã‰}T¥IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/mix_recmon.png0000644000000000000000000000175611550446574023376 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<€IDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €Ü4à –ZFF0”ÿ1#TÄÿÅ P$ÏŒ$¢ÿ ‰1@Õ!«aBbÃÔüb`pge` º…#ÂÁ?™˜*jk¯çt &zÅóo¹ï ý2**'rç̉Ë_¿ž“]Hè@±ÐÚr`tý``HÉtKHµIMeàWScx}ïÿÿˆêø n Å@‹£x98ŠÝ´\’“DML€’@ÙŸ?¡Šÿ3 µãâÀ öaefγ·³sve·±Š#âÃNN†€b¡¦Ï>6R¥: þ®ÁÁ¬z…… ¬À´þé0<8¸¸0ô 5| L`Z@\ ÊÂëÄÈÈaúÈ“1÷o‹±hfd ŠÌR’ÀØÌ‘beMsäæ±3п@üb–ÿp¸š‘áÿß¿ ÿþþý@,äøh,'0¸cxXXjÝ……exyxþóù3Ø×Ä´0þĈ$üƒÄ³?09[KJÚ:ƒY–…b1(eƒ‚[Pãð±`o ´¸BOJÊÝYE…I™‡‡áëWH£ U@,Dij0O«ˆ‹‡:ééqkIJ2°ü†ÃÇ p¤8÷ ž”-¬0 $…„’íÌÍ…L€¥ȧïß%Säkd@,h…(žù€Á"ÀË›cem­hijÊÀÃαšÈ¨ ˆ© aâžk[[CkGG!11ˆÅ J\ ÇÌŒÀ Ò „Ar0 ­žÁjAeEP!°RX81‚ÔõÈ@‹½¸PYKËÚ.8˜Xc1ü&®÷1üÿ,XAT €0Œ ¤ÿS>ã¯_ ÿAY- 4´”[úŸ?gørÌbƒ€4«€Ãû§OþýþÍ @Œ5ÀÆÂŒŒÿøÅÅ¿2ý¦nPŒ¡… ¨æBƒ²ÿhhbü‡$þX60s X ¨àA)`èýùû—ýó³g—ˆq ;&4àmB€pЀ; €Ü4à w@€³¾+j ­IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/save_all.png0000644000000000000000000000454411550446574023022 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<öIDATxÚbüÿÿ?Ã@€bd`èRÿØXXþó÷ï?¨Ô_>~Ž9 '&&f†ÿP—þê`üû‹õ‘–ügøñ›‘á;˜ÇÈøŸåÉÝWÞ½úR@,صügàáæhq/÷Mÿ!«t ໌¥”…~½{Á`/û™‡‡‡áï¿ÀÅÎÀ°ïä† /”$8˜žøûê•Òêº-œÄ‚°ò?3Э@þû÷‡UVMÊ䧜å œ@U¿öH±ÿgÁŸÿþ{ËÀÂú…W²±21°²ügø ô9+ó_†Çÿ0<| ô¿ Ð3¿”äÅ´,äŒê€ ÿ@cÂÿ÷ïÿ¿ß¿~AD@˜Úß~ügxù†h(§;Ðìy‚ dw}cxþŽ‘AA†‘AMŽ‹ý'Ð!ÿX@Q4ëß/p|þ  þññ𰦉HXÿö†þþgüÏȬövË~Á?¿X˜A±ÈÀð‚õ?Ã{ ÍÂø“áÿop@¶Ÿhøï¿@µŒ¬ 7ýg¸û”Á@ñCG­ ??Ãs&o I˜æþ /{»g±[£²*ÃïŸ@1ª/ÉÈ Á tÚëÇ n¸yyÀ‰ó0øÿA“ÕŸŒ¾ç`cdØ~è5Ör †n ¬ O.>d˜4õƒ‹¯0JÁ! rȱ ä@,ªÒ¾54ÎÝc``gbûTœ‡Ÿd7Ãã—OXßÿZþ=û€ÈP¦ÿ ¿þiæ >þfxó‡A‰á×7I+ †Oïž1¼~ùŒP€2@±0233þý L4 0€ðëÇ_†·o‰˜ò˜…€ÙèdH$ ÷ ž¼øÆðå'#ƒ 0ÄdÄ)èE&F > rþ÷h6;XœèPþ3ÁR@±SÛX"óëç†ÀÇÌÂÄ ÀÃÀ Ll@uh`§…é›XVìg¨ŒzÊ`ªËÅÀÉù“™Ô,PŸ‚…é;Dć ç?Ô°àù L¡¿ÿgàåÆ+ Ð!ÀB ‹Ø€Ù ¤–á#P+' Ð"`vb„ø”ß –ñÓ Ó'h"d„D!ÈH€b|,Ð`d:?>üc&*vV&Vì`ùÌ Á&±°0ƒÕ²²þXÊj@Ì ŒÛ{oþ3,;”ÓafEpB9d7@±ü‡r`š@¥ëO`¼}6¿Á!ÀÈŒ;¸Ø€ ˆã'0Ó; $¨æ q†O?™ØU„ä™~ƒÒ "8ÀQÀ uþõëÃÇÏÿ~ƒ—ƒ¼ÌÀø‹Yâý¦¦üØ q?$…¹þ2²¨|€Æ5Ô6`Ž2RøÏ ,Æ£öÃ/HïÄó3ÔÕ ’ê0Þ½–Ž@×òóA$þÿE©*`åƒ?B ÷<\Œ(!úè .`TEi~gÐÐüÊpá #ÃúÛ\`å Ç ¬.åPüúö÷`Iö’…aÁ¶ß Ø+fÄV0 +Чn0£Qà€’<#ÐP>n.`zà |EI„O`×-ùLļò Ú²ì`3o!äa9L3@Ë„$b³+9~FP=Âʵ©ÂüóÚ°l@à€eCy`œ³@jF&˜¡PÅLŒŒš ‘hárš 2ÀØ`ø Œ¶¿ŒŸ22B‚êïß¿à¬2äP €À‰¬˜øì¥Þ2èñ¿bøÃÀ 6Pbbªf%*Fˆ‹@a‹AåAå$¤Äa•‚ ŒàT~û-ÃÖû‹þ!â T ÁÊP8Â|ô÷×wqn^q þƒsÈx0ƒ‚`31ÂJ5FDº×µ?}ø !ˆE°4óêp"†@ðê€? •ÌlÀ‚‡\HÀ‚œØ k« ¨è032 *˜ þ̽ Œ@,°Ô ò¤°ù­h€Š!‰˜ Z±€Äþ3Cø Pß30#â€}Ê)õÀøMÐøu@!ʘþ#ŠQ÷/ÄM÷3AÍ +ˆ |&ÔønÜB,%FX(#;VÄÐÔ .í@U)ˆÍ±$ô)Bf)˜u,'Á\öh0#,±ý…†´Õ K*À†#@A "¨¯ÿBËeh‚‡øôÄ¥0G€… ŽCæÿ‡†Â"påö’n@ ¤Ôhá¶’±ôüg x.`§ÿ`„¯ß‚R,rH@J9ˆCþC-þ 5 3ÿ i ÔHýlàœ}ð•á5ýä3+Ã3 ø•£oÞÝ|x €À!ðª \jù€*$P- Š?FH¬€½Šÿa銺p÷‚"ýÏH\³‹åg/¾ýŠ Þv—…“TW3ýùÏÄúíýû³À*· €€M2VÆï2|ûôŠÁÐ@œ§a%8ëýƒøÄLÀÁ‹hB©ýÎAH‰ ¤çÏ߇ßÞ¿vbxÿáD8Aù‹ €X€qÅ,*&ÎÀ&Ä ú œÀ¦7з zã?4Ã|þ™Ö†`bDTé M v;¨XgE ,û€Zº,Hõú?€bùöìù™×ø*‰1¼6˯¼þÅÀûç0:þÁãÒ»ƒ„õ?$>¬…ÙŒÐö°8Få«¿ì ïrwÎ|bøxçÙ3`d¼Btsn ¯C“‰O°›SQ^•éß_f`#àÿ?ÔÞ#Rõ c3¢VÎ>´ÄüÇÄÂøë?Ó—ûOnþ}ÿ¦ èóÓh©Ä8ÐÝs€{a¸ªï7IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/signature.png0000644000000000000000000000264311550446574023233 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<5IDATxÚbüÿÿ?Ã@€bb`@,茌½ùŠMduÅ{üý.÷öö•+ÿ~3ìb`_ýÿñ dÕÄ‚iÀ ”„e i»Hiž;v–…q»Â/®ï> Ìñž@I/d„Åß)tÀ_^Añ9fÞòš§ÏÞbøxe'ï?@O‹y00|äy® €X¨›,þ3°ð t;GëºÝyøšáÉé >žb`0d`ø£ý’áóoŒø ,øF†ÅŒÌÈ•ãk’öŸå/Ã…=‡þ½ÙËÀÀ'ÌÀÀaÁÀðô÷D†ßçÐu¼&Ó.æAí2ªÂŒ‹§í`ø÷h90:…\@Fîføý­(€¡ €°8€ƒÈ”þ‰ý[SÞÈ`¦›.ϲY¾ÜÚŒÉ Â@ŸzÁðõuБ?!E„á̓ø“ㆯ¿ØÞQ€úœ_@^JR¡¯ÒÞu—î?ºÊÀ  T¬ÌTOš€×°Y„á ±§xÀ L£ï¾± äýc`â–íK,Žtº}ò)áõÀ`g8ÏÀÀTÄmÀÀðòù2†ÿ¿§C‚{‰ @øõà3Íùýô,Ñ…ÉIßžýgX2e7Ä£,o¾·ºòí†_K¼æ†þªþS óO!Æ+ÊÍí\,Š ó{6%nñuAu`QÂø‰áëÃl sŸ^ãÃÒü„“àç Y¥Ef¯øÄy&¶ìdø÷û1Pô¯ 0`€|¸ÚŒ‡C@@\Œ†n¾"œþüfP6bãIŽ`üu•¡oâa†_Þ10° œW–0üÿÙNl‰ @ŒèÕ1###!=Ò6Ê, ¬¹]´L´ÂC%žÞ¿ÇP¹L‰aÝÖƒWÿüüâÆÈÈÿ g þC©‹ˆ…ÄGÚC—sÍìÙ埋3ü{q†aÃÜå r†® ¥ÑJ ï.¬mú…á 0 ˆ(¹i2.™7-ÆBÒ<‚”º_ÞÖc˜X¶x³Þ™;´¥Ô,T¶}ø)+ˆD¬T½46Ì™à¬%i“ Ì«_ÀékæÄ‰ŸOÜÿÕh Ápö0­ñs3iA @Ä8@ÛUaÙ¼Nu-qû ` ä&”g —^c˜½xõb _Ï~ø) ~þ%”æ1@ª{læ,é’лÿWƒ¡¢XÆÿ¸̇_¦O™õôɧÿS@Š– ¿·ß Ž ^-ì éeÑŒb†ö ÿM"½åÿ—s Çv`X½åÈ*HÉÛos>°1Ä΂£€Â|ÆŠ ANV žé0hY:“Ý:`åòaÖì½oßüf˜^~œyŒ!ã €@å2FqRÿÉùÿèöÎÿÿ¿Nûÿÿ‚Çÿ¥uÖÿyYúÈn3¡Ù@8 ÌŰlC¿ëÿ—w7ÿÿölíÿ½ýúÿìxþñ³1,JsQ˄˶Ïn«ÿtSÛÿpK¡¿|Ì  †B(´ÙË@-6ð s2ì©I4úßšïñ_š‡õP,ŠW‹‚B†3#C¯±Ó7=þÿsW qâIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/noatunloopsong.png0000644000000000000000000000450411550446574024315 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÖIDATxÚbüÿÿ?2`dddÀl‚ ÜÊ <@,bÃÀÀÄêcd°aøõoß¿8YK‚O0ôþz]ÃÀðþ \ÙN€bÄëN) >V> $ÿ?ËÁ†ÿmÐ1”ªçåeg8¾ïîCV¦Væ9@™?™@ÃÛc We¾ 8 €˜pa+­zQˆåÿÿ-ÿ°~ÿc”“ågX6Ń¡ªÁM^Dœ:Ã×_GþýwAx÷D/Èf)_k»„Ì”3 .ÿûb6ÀÈðýû÷¿ >30X¹ª2ôMað33gbfÞÍðã×"  e¸Z9,¼ 2a(F VƒU²!€èqc†¿ÿô¾óáŒçï?ÿ1<FóÃw \ìl Á f Z&ª ëWœŠ½é®/C+Ë ú¯`üý†b@a¦­j Iò H)&–áÇŸBv&CqqnP|ƒÒ HãÏß šÆJ Ö~– Ï?Ó&#$‚89€r@»nž{ÈpdÛ)†w_^e`c©c`aZ6òLÜx€Ât€Ù ß~˜ÜÀÔ=‡…™1ÂÆIÁÄ^_\èwV¨Ã€h!3xñ‘áí ›æfHÚãæ:èëg.3Øváý믛8Xk€¸ ³ €0`2 5þ®çåãðñˆwfàW’cxùá@·!)±…–°-{ûÈl4PL ˜‹e¸~0Yw„áèþÛïÿ_Ì‚© ìiàßÿbV6Ó0O†·< ÷ï}´„ „™Qð ˜1þƒûãwD $`€Ý}ÁÀpöþ †O?‚]E– leøý»LÁΚA@A‚á'0Íp Ë"`Ùóãë†Ïo?2üƒfä`àäe`a•!HÊÂÆÀðêá[†›ûN2¼¹óà5P¨œ˜†l@a:àï¿D6>!{mA ˜ Ø€øÆÙû '7gøüñ3fX6ý„ 7z9ÆÆÁZ(¯!oè|úô˜¸?2 ; €0ÀÂÀ£x6<-üâ|.>áÆ ®ÞZ BÂŒ ;v>§m õ?þÈ«èÉ0Ôvz VHá´wÛm†™m»¾"+ ¬©µ"Åðów3;kº±§‹Kƒ¨8Ã3`åôXPýø .€M&y¸™ÿþùq¦©*XÝO :`yróÈ÷ÿ_"@XrÁ_„ÜŸ¿é@ƒj¤5å%,}ÍäÕľ}óñ1$SðëÇ`ªþó;á7“7Ôf666=_ci=5†ûÏ eÖŸ·À¬rî1( A¶ €pÕ†.Àpkå2Ó°7eP2T§Ÿ{OQs%700Å5ÕŒyÄ™™X˜8AÅ30®ùD%øž«Ÿ@÷±ë’û—3¼{L¬,s‘­ ,–ÏæàLáS3a4ÐeàæccxöZ·3 VżÀtÇÅ-ÈÀ¡(È€\j|Zúå¨^ƒÔ¢|À†ÄͽG@!lŸ3B6 €0ðûo„††(ƒs´>ý, ¯€m=vVô*ânvPˆBáL¨… ¨6D8~|bØ»h7Ãç—ïî ÊC· €°$B×ÓG4?º»Üņºš Ÿþ02|ûŽZÂB@F˜A b)¬–…ÆŸoŸnŸ¿Ë°eÃE†w¯¿\Zj?G÷ @áj’B"˜ëä5¥•l¼ PKXQBR=#¸I ô!0>>ƒáòñ ‡ÃÍøüù'ÓG>½ùöçó€%e+PøÄ`ût2\-@áv´‡Ì‚¥À*1OÝXË7 ˜ Uy>Cã°Þ—¶ìÖÍ?Á°máñÛÀø8 ýÀ”øhéE`óëÄ×°f°0¸ZÏðÿË=¸@aF3´OvØ;`ÐUSಛ§®5Ý»ö0ÀË߀!$T—KœXù£‹ T…`àdIÃ[xƒ,¹RÒ"€Â¬Œž¬‚XÒ€è0^fà` üýógàÆEG/—¬c¸r샰%ÄËÍ RΊ«ë®[˜@ÃýÀÞËb „½s î”z#ÙR0¡V¡\Àº Ð%®Þ¢ÿ€ú÷n¿¹˜­%… Ëÿ‹ÀŸÀÂàÑr†O×°öŽïXÀXÀÆb¯þû}ÀºØnpæÅ" ØRc?^·€©ˆ¿?è]‘í0½Ãù¬26ÐWIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/ledgreen.png0000644000000000000000000000465111550446572023016 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ;IDATxÚbüÿÿ?Ã@€bb`@,0c„0’³þ10°ýâß Ì~p20|áÑZ _Ùœ>²è1|aPg`ø/ÁÀ„ÿ_30³Ýfà`½ÂÀÌ´‡áÿÿ @Sðíÿ3gÀ4@±åÌÿ  ¿d1|ÿiÅÂ!(¬¥ªÀ +£Í Ä'ÈÀÈÈÈðñó'•k÷îZ^ºù˜áçÛÏŸ˜ØN3°³Ng`b\CÈh€ÂïFQ†ÿ;~}KTRPf¶ f³ fДÒ`àfäCQú‹áÃÍw6ÞÍ»|çë91°°¯g`e*zà!.+ˆ–±D>Ãÿo 8øY ’œã’mÒ”…TXÿ³30þgb`eda`a‚¸ÿïÿ¿ þÿaø ‚L¿yİxë:†i3¶0|zùûk2PÙ>lQ@D Aeø¯ÃðïënQn‰š˜r;EwN dgæ`àfæbàdåd`cdCqÀ￾ÿùÎðõ÷W†ÿ0ü`úÂpöáY†æ¶E ÷Ïú tD Pént"übƒà¿Ì¢ ¿þ.–””È KcPÕex÷åØàßÿ~} ² Ëý:ä÷w†w?1HJ3ä”y3(›ðq3üø7h‹2z™ ø7C7+“±©.ƒ¿û¯o¾ÿýÎðãï°üùÆ ±o¿1H†AêÀjÿñõ=7·ƒu¨ —ø?†? ³€6±!; €‰ð#ˆteae‰“ea¸ÿâÃç_Ÿ˜Y™Øÿ°3°1³5ƒâ𕉕™‘¢õÿ?°ÏAûúç+ûqÜ ¾ÿú¿î{†¿Ç¤œ~þù 4d.ÌZ€B8à?дÿò$9Yü%×ß^}yÅÀÌÍ̆@iPzùûï/ÃO–Ÿ`°0²Àðëÿ/†Ÿ~‚-ÿüû3ÃÇ_Áô»Ÿoî¾zÀð‘ý5ƒ°²4ókLéÀ4¶¨íH/@¦É Œ‚/¡È´EjµÑpngP©ŒÖ ]Š! ŸŸBûf¶Ú}¿2ÉŠ$Ö.,hÇUVd´‘c@xñDÈ£×àNìÔ‡õÚièCCYCº©Ã¼Í‘G* â^ä®$¬¹ÙK!9à+7?§Ðޝ þ³!7ñ—ÇDD4ø5Á–ƒã—å; ;ŠþýûN„ÈøL´¾ÜgØ÷t?Ã_ž¿ Àb‚á+×+aIuÖ—?ºÁ@üý¥/%-Åðã1È»`üaùͰëÙv ¡Ÿ´tübøÎòœؘØài– A¡ð ˜A¸ññÑW¾1f`ä†Pé'Ö ò  /ïÔY @°üSãdeøÊòÈf``egú”…‰é?Ãé‡^ý~Â È­Ê Á.ÅÀÃÂÏÀÎÄ,ö™À‘ó÷$k~ùû™áõÏç ÷¿Ýe¸ûù60]ÿcàfçdøõçÃ/ÆßÀôñá7ïwFfV˜µˆ(—a †¦ØVñƒâÂûßɸQd5-ˆ‹Yç‘dò¤¦Ç&»‹ö&Ȭƒ'@¸²<#ús š¤EaK®¡Ê8î«ÎØt#Œ¢¢°0šK„¥7ÑTµŒ"¿CŸêOö€©*H†aig.‚ÿÿ¤^ÜJÓ‰· I~hnLÙÎE@À¤Êj¦4/ŠéÝV¾õ"zºJij©=±L3j œ^Q":ð¸»Ýòªfö@0}ÍÁ̪ÂÏÁ 4à'0 ³-;, 6ÄWLÐ\ÌžÿÁ ñÃ`p331ƒå™€lx.ea`IÄ ,Sþÿÿù &@È!pçÿ?– �†ûäcØXQÂrÃ|Æ.þ1°‚Á ,3@Ž€yä8 þ”šÍõ•Ÿáÿß7Ï`Ö W<Ä ¢. L­¯Qâ Èbfh(À}²ä Ëaqþ*÷ˆ¿KIa`5óöÎO gÿ_‡Y @H%!ëÖò}åáã ô<ØÙ @ŽX(@ ¢`þ920‹ÿBå8¹X„Þ+0\¹ÿö/0ïY @ˆÊè;Çå¿ß˜O>:ÿžAŒCXÈ0@â)þáQÄœìì œll`ÌÃP²!é™ÁÄüŸA”[”áý v†_?}Ïxf-@!ðƒØ¢àœúèʾgò@³}É ŒSP¢ƒ‡Ô2ÅÜ@G€0ƒÄ£‰šXÁz9™D_k0Ü:ñ XþUDŸaÖÂß8€U1džßþo¸´þ-ƒ“&¸Q N #@Ža6 äKo¹,çc‘Ô‚¢èó/yU†[+ÿ3|þöù,3ó äê €øÊÂÀ$Ëÿäλwæq0(²è€JT ¬Å 5˜œPG€cf†¨'P`2ü,ÊxT^.e¸yùáG +Saµ f¿àÃ#VΤsGï|»>ƒAžQ‹…ûÃ?¦?BZ°01,ža ZÆüc&F`‰'Ç¡Âðx‘0ÑmÀhçfÌJžG· €˜p´†÷ËZÿÓGn<ÞSóûšƒ§03ç†ßÀ2ýïß?àÔ .ãƒøÁXÍ20qüeädཧÍp¤î?Ã-WÞþçfŒ–t˰Y@ˆF©ƒ4˜ P ‰‘A‘áÇïœÌ\nú–ò fþ" "z?Øk·ÐÊXÛŒÿØ~bcxáüÖ göÝgøüóËi`ü¤có9¬Q @ø++þþ‹cøù/•‰™ÍLAAœI[_’Gæ??(>~|úËðå9#ÃÍK¯îÜ~Æðç÷Ï‹ÀÊm>0EΖF?ñõŒˆÀëK ¶aøýÛØ2Ñö~dº Éâÿ'†ÿ¿Ÿ«ÇkÀ|º(vˆ?Ó5 ÆîЀ÷Ž ¹¦¬§wœ'/IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/1uparrow.png0000644000000000000000000000311011550446572022776 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÚIDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €ÜÄ‚Ìa4™EŠ^q†ÿÿi~FÆ8 }‹XÿϤÁÙD~üÿßÅð÷¿Ã_s†ÿ§E8‘$ ` rPÀðéW\^”.ÃÄrkæß€Žh#ÐH&ü  –Û3|ùÕbb"ÉÐ’mÊÀÄÅÆ°òàS†cnæ1ðñœa`e_ÎÀ q €H F†_§ñ ppO¯µe`á`cØÿÁÊÏŠ_R˜…áÏ¿ @Eú¤D@‘âV†?ÿ'3ÿý§Õ[aÍ`¢%ÎpèÃùÇ ì¼¼ >ö ̬lbÀ¨˜ TË ¶TÌÿÿ‡‰‘@‘â€"†O?Rµ’4Ž?c`¸ø’áãw†ox¥ed @–šƒ¿™ è2në01 "ƒÞ˜èZììäºJ­.¿ad8ñ„áÕ'†_Þ}b Í«¢ËÀñæÃWÏrXY/0°rÌc`Äo@Ò ßÿLçf™^ïÀðæ/+á Ï–ýÍ ˆåï>hF†ÿ2†Àu0ôþÿe`øÃ  ¡`&¬,ŒŒ*jíø%vÞ``xúhù/†»w^3¼þð—áÃ`(¼:ä'P £4ÐÞ§D!7‡…ݘ8>00±BÁxÿöË'/ÑÁÙQ™aßm ¥ï¾=qïþ{†ƒk÷1\Ø~€áÇ›× ß€b?uÓ#Ÿ£˜0M€é¡‰• ˜=ɘ‚‘@ás€Ãç_µö  Æ ‡îËZ`bû´äÕ»? 'wŸbøõóÏW Ÿ¸^^aˆ3üÍÀÄu0ñ³ŠH30 J‚e&P ’#þcä€b‘蔾ÿž,#ÇÇÙVáÀpï +Ã¥çÀ þIõ'÷œcxÿäG'{ò•[ÿ¿¹sƒÁM¨Õ CYXød˜9©þc°¾0bôD @ØÀÍðûß Nv…º"{†Ÿœ| 'î30¼Æïg`¢»|öÃÃËÀ¸àâ\T ªÖüc眲~ïs)¦g :Ê`70°1•p±2ˆ+Ëc€]RsX9%8P, Lüû_ Lõ.Ù)f ÚÆò G€AJ`_€–ß½ý–áÊÑs@ÓÙn301 ý NY,L5?™X®Ûù€AWøƒ(?3Ðdv g%¤¸”4$€AÏ Æ.PÂ@¶ €Ðà LtENÎÊ ^¾ú Ç€Ùí0{}ù *l~3\˜½˜MëÚO²ÿÞ2¨i2üFÝ{`¹ÁÎÊÈ -ÅÉðöÓoYd+ˆ¹_lídaavcaaaø¬·ÿSì? ýç(i³Þ``b²*{…дTX…á YŒ\@µ[˜™Ù9ØÁõÿ&f ÛX€‰hóÙÿÓ8L`FzIØþç÷_¹?¿ÿ‹‚Õ2#‰…•í 0Ñeƒù–¦ºÀ7 åi Ì, ~þfÔ``fšÃ z& ø7 9ÝÈŠˆq {F4à­b€pЀ; €Ü4à0‡Ø‚¤àÇKIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/edit_remove.png0000644000000000000000000000164711550446572023535 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<9IDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €Ü4à w@±ÀŒil JŠáçïZ†Ÿ ž@6Æ  bâ#Óÿ!ø”þÏgBƒ‰ƒÕ1õ220³e`çiª=þç=°½Ä‚äA åËäEí£¬bD¸Eþþû‘‚‹—cøi&F&†Ÿ¿~3l9ºÓãøÅ“z ÜÞ@É Ä* Á¥a2S¡xžäÿ³Îý§x÷éÃûÂàÿ ö’+`ö" üüçgÇ`$oH³øäåg(IFÉ?[˜@!G´° ˜ñýÏw†²­e ?þü``bbb`db‡�*‘Ù LP1Fˆ(¨ábHêþ2þeÈÑÉaPåWeb`dcçY €I2¸a`•M\ÉéÜÈ™Ð$ñqIyõ’ò œt*Zog7œüxùY¼8d I~MŠZª ÷±¢t lAÔÎ À!Àð‰ù 3 Še ƒQøL‹°9Lð›ñ7 V«hÀË€pЀ; €°F 0‡2|üñ‘á×ï_ ?™¢$>5 Å™™˜q¦?ÿÿ`u@!;h3˜ÁÊÄʨÈðíÏ7¸¡à,59ûÁ,'BP6dDu 8{³¡»˜ÍÌÄ„ò„ì€/ï¾¼3¸Ø¸G.£`ÃÑB–SHÌŒÏ}ùþ…áßï_?`â„HlŒû–[ÊðäýSx(°2³‚³2‹3aŠÂàòàÏo†Ù[–KÿgaÖ#¬U̘Î* ,w™©Zh%Û§2ð «ÿþÃKó?’Ï‘+# u>#0j@fm>º“aÕžu_€5bÀÿw÷‚T²@ê1üø],§ÌÈäC«c¤ª¹úÅY3¡VÛÿ‰á/Т?o1°óN&µ@€í ÆîЀ—4à w@ ¸hÀ@î€pJ/P7šÒÔIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/kgpg_export.png0000644000000000000000000000474611550446572023567 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< xIDATxÚbüÿÿ?Ã@€bb`@Œ” ÄM@Ì‚ä`˜rüc`Xd*-ðŠß‰Åþq?©†>@1á (Ƥ€¸M h¹Ð’õf*\žÎÌ̌ۀ|d5y@l eÖð‡úäÚ@üˆŸñO4u½H>g…øP‘‘a ‡®–ƒ8;ÃÓ÷¿vïyûîë÷¿Q@µ;ÿ@ͩφ@a„€-ó1T‘8›±±ÔÕjPõÿ ü_ ÖÌŒ û=Xuµ:¿e>þf–bgð –dÛôƒ!J ß¡úÅ’@¬uá(¹ø7ÔAò@lÄ6@•g€„L0'Ã?F)‰ß€&|âo@G¼ýÍ ÄÃÈ(Î&%É>ÿC ²w3{B-c€8‚å/jÜ2À‚ˆÏBÅês!¶ÚGâÌòú+PÇg ~õ“ûï?† 9Îf ï§B˜ €Àâ¨áPË …D„/ò Šœº¸èCUäÒâ”]Ì“€ Š”`¿‚ôþü±ø дO@üÈþÄ/1°Ù^z¼ Æ2YÀ([2 €XXâý/ÄpnNÖ…•½æZ<Šª Gw¿09¼ãfýͳ7÷}ý÷}9ÐÅ;€N uˆÂ u{örõù dûõÊo ç4™f`ØrÿÇo ?ÿ32È”£=PFò=0¡LO+ÐÈp*Óg`PÔýîí+?î~Îptçµçîßž LõÀôÀÌÎÀ  Rn`´g`y˜ØA>Sò$€Îe:„™‰áöãï ón| ­`”¬ùÿÿ@±(!Y4(ÄÞY"Ã)Y¨ ,ÀL(¢,mØÔ¤¾2¨Ùð3Ää¨HÎh»Y·aÙîÓÀb@–á90§°­ø Š6fv%1†ÿš ŒB@§üƒF+ÐEï@åÑ×Ï@˟â €À ’˜äe¥¹¦'–I0œZáî ޲ nïø€yƒ˜Gx48y1¶|e`üïU¼nù¶Àò¡˜†˜A¡,änÆ ¢§ÄÀ̵øï?DÂá`cøíО'(9 €X ‰Ž XbÍÍl–y~ëÃÔºW‡>20,p[ §Òà-7ß *`l3E¹€ÁúŸ!¿í' ³wõ†%[¿é¬ÿy-M˜U€Qûý'féÆÅÁð‡÷8'!€bÆ{Yt²˜³²3Ãá‰AVíJ,ýú™½å?7#¸(ÿQ Š(NF 5†œF`"ðmÛ3o›Èÿ¿ß%%…²0‰aq7Ã?á“ fz$ @L@cÝŒM¹|³¸€2²1Ø[³W©h(ܪÐf¾ TöˆAñc ¾ RQ`ð–ÁÕù³10þÿ}øðƒá×F†Ÿ@7¢bF†__ÿ3¼þø䀿¿ Þ€bÌàf|Ó²LJXXèïßÀ ææ?`ö&-A ÅBo€–Ê ahÁ,)3ýgø}e'COì»Ï—¯ýÑác`ðåabjádeeÿ¥‘LgŒýz ›0Fh96¨ €X¾ýü¿ÿÌ–!îÅÀ¥Ï¿À`æzÁLÐBû?ÐÝì/üÐhòßßax|E˜áêµO™þ°ãvêûÿÖ¼ûù“Oãã-І/+¡ü@ @Œ±À L«K3Ê8CmÒ€>},-ØþC23òÿñ³ãl \’¢ ‚òÀÚî-Ã…’ ko½öè È ó™ ¹Š Od¬Ä†@1Ê) ŽŸÝõýÀù5@ßI²AÊÔOв†1ĤÅD10ž~Êðüøk†_‚ "ï14¬S´õ3ž÷i10lDÿ"Õÿ±¥z$@Œñˆr]Õ{J§2¨»µ=û)B9PCƒRÿ: €ì œÒ  dñ‚›aß"†ï|þô.¨t²¯a¡òˆ7"…@1¦"¥H #ä€eÈî°,5«``LB²>Ø0‡°ƒ²sC2Ä»‹@ýòâ "ºü ,À*øÉQY†yÍ/ÿ_=uT642!Œ¶"9 €µ +¨#˜ ޲ó%Ò<"D¬ü€‰DRéÿVA¬ÒÐpüÍ@M?.ò“‹ÛHšŸóÃ߻ kgr0lžuîè¿¿ß2‘z¹ÚŸ‹ä€7Ét m´ßH.:BÒyJÒ )¾1 ‚Œ@—­]ÊðÏÝŸÉØf{rXv]ÏjÁs-Ã-`”=¹û¨ ˜@gÂÌ>)IÀ x›Ðêßh‰èy ¢B §•rõ@¡E)†ìçÏž«j2ÈE¥X£1]ˤ ̵Àbîý/>^] Þ?¿¾\‘bX<íáõçV±1üÍØ P©rˆ÷@(R`«\IÿCª!R2#¢¤ ÊW@Çñ³2ôð:Fú ¼­@I  z`ùæ 3Ãy1! u8neXÔuâÖßoß,€æ¿%¥Ù@F«Xˆõ Ï¿hÁ€†±3¯¸/Ãî®I šœ°4j#ÿ#›ƒ€¢°\cb˜˜÷áÄÁ;n,º†a>ÐÄŒnà;hü‹#>h®c@jzÿGËÛ@üâÏ¿~1p\¿Èàtå(Ó…CÀô 4YĘYD¾3|xú•á/°žøóQˆáìÉ×wRAæ440 6_ý‡¤)P%¬ M ÐÞŒ47¢äÂ}70lù÷€˜a”Ÿ=f˜_«ÀÀÉ lþdøÏõ“AÕü'?—í·oßàv àe¸ Ä·‘ø× Õ´)§ˆ0ä?D9¨ æúc…Í«:œY÷-°y,IŸ½y l™ýµÜÙX å@QÜ7:BÍá@ƒYÍÀ]ü¼ j?3Üýñá:0=]NÇ@µ!(¦€bèî9@€ ] ¯|~IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/colorize.png0000644000000000000000000000526311550446572023057 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< EIDATxÚbüÿÿ?Ã@€bb`@, ¢\ŒUô?$þýRÿ!øÏ_ˆøïŸ B¿3hþb`0 )130(°°3J11ÿgªÿñç'Ó_ÿn}x‚áІ÷h¶0Ì@,¤¸öß_f Á6@‹C8¸,$Ute4ùÙµ¹„$˜89þ201ýf`øûáÏ÷Ïf÷¯p0œ>ôáîµ·§€ÄÁÀ°ÝL€b¥¼!~3ðÿúÊàÃÄÂ.©.j¢á Äià,Ë )ÇÎÀÁñh!0 ~‚T٠߀^ÿù™áïæ¿¿îœͰhÊí÷žÊÅÀPÄQ€Âë`ȳþþÊÀÂΤíbhaè«Ç c.ÁÀÂôåû ?~-²ÿU2ÿaøð‘‰áÌ+u†c¯ ®þTc`cýÏ Êõ!Xn'ƒ4Ç=†m—N{¾!hãw{€œø“Áèï/†vMGm7çü%#a¦oO®Þ¸Á°äÕ=†O?3ÿâgˆPQbàeax÷Š‘¡öZÃy3†Œ¬ ¬‚ @‡3<â4`¸rKa¦n3CN›)Ã×ÂãñWο~ŒŽJUÄ‚Íòßß8¹ÙgºÖĉY'¹2°~½ÉÀpÿ ɧ¯r™3¼‘ÿÌðÿÝ †õo0l¼ôˆašªËA†cO~*²2ÈMg¦JN qü LOþ3üxû“AP‚!4S›á^Á‘¬?ßþ¬Úv €0²áÏÏ é¢rÂË’–OsÈñf`}t€áñ†oÿjŸÞgx.ÇÊ ÂÂÌÀt¨  ÃaÕO ÎÞg—b`¨î`¿²šáÁí§ oò¬ Ÿ€±#øí.ƒ˜ð RÓ`0°—àF\È>€BqÀïï áÒâ3RV/ãTÒa`¸¸ß¸ÞäfþÂÃÀ¸ë1Ë»o>¾úÅðíá£ËÌ &Ââ ì\ _vøLg˜Æ—Ê {u9Ë[>ž¼Â`øw308þ#ƒ†! ³ÈN€‚G0¥+òñôûÖÖ2üyu™áñ‰µ Œÿ¸Øyy±ÂÈÀ!ÂÃáb wœŸáì•g ÌLÿdøx ÅäÔ€Žý Ê ì ìRâ ÎÒ¿LîÎf¸ûf —ÜW E`00ð7¨@abàff`æd”Ù @,°xÿ÷›¡ÆÐÃA’Ÿëƒ€ì65^†Ïþ¾ûËðÿ++Ãû›ïþ«Ë2X¹è0X}S‡úˆ™AY”÷†3‚faeàבd0&&&n +Ãç_ÐöŸ™å?3;ˆ @`-7W6 ‰gøù|*§0}–_|@ @u< ß¿¼cxÿè3Ÿ0bAº@Y ²œm™!ù—›áÓ˯ ·æßf`¼ÿ‘‹“…Í\ŒAÑN† T^0üeøüù7Ãÿ? Ÿ@ºì€??;ùƒ Ðr% [š¾ên/ºÁðÒH‚Sòã[¿÷ç2H €ÀààdPâS`àøÎ ªcÌpcÍCö_Àò’“ERA/X—hé`<²µüeD”˜ Ì´ú#8 üF (u ƒ²4Óá=~ÿƒáÒ¶ ò ÷/|útö f&V ï€µŒœ¹ƒ”¹Ã_G¹ÙX€×@ã˜A¾:äÿo¨åÿá)Tp3¥Œ³Œ.Ôdx L¡x Ìz¿dù´ŒEõ¾ ^~9ÀÊÈpd7@4ÿíßÏ/€q¯NT,ì@ÌÃM @SÙlY`éýˆŸ}Ì ©£™ ) @ü˜—Ÿ§¸0<Øûáýý l<¬ öfR RZ, ÷_?a¸4ý0ýŸÔ®’1Üþøðªµ¬½3$á †0Tžß~Æðôæ#>ic5§X¦7›€Žx.PÀ ¢Äþñ—AL‘ŸA,M—áï¯? ÌŒ[^½¸ÊplË7†?¯úk¬¦ ¨Þ3·JЉ)f¦ 9ï^?{ÁpåðU†Wç¯1°{ûå-ËúßÂB‚‚¢ºZ@ÐàÆ¤äûøöÑ=Ÿîzý’‰å_5( Ã@3+'ÃÎ;'Ï¿üúð,ƒ´Ã+×öÎÝÊðlûÁŸÜ_OäçøgÀõ¡ûëÍ£Üÿÿ °¥à¬ùÉ1 ÓY¾Âpòôk†‹›Þ‹ú…̬ 7AÌu?@C$w>¿ý¿ýôŠ) ÒN G`øÿôí nn†|`šÛõÒûðï?´°ù÷‘ mµÿÈ!ñœ·~{Âpâüs†‹[?3|û¹‰“a9zå@`€\”œtfíþ°rý{ý}Ðòl`ó$ÿ븴Ôá”T—ZÀÈÚÁÍÿ‘ð?¨©Ì _¿-?õ˜áÒÖ Ÿ¾™ÅÌÎÐü÷/fÓ €àuÐç|ø÷ïówm^>†n ØwÀ•(²“*§„"0seçQhNø÷áP‘,ß¼¹Ëpüès†[{ß1|yòa0]0üfÀÚþ ” 0Ç­*^ sÈF7 +73Pù¿? οÄv(K²ü`xüøÃÑ}¯žÇðóͧv&6†Ú8,€ÂÛ*þýºþ|eøþ÷°XaQƒ´ÍAÙð?´ ò¿Þ0\¾v—áì· .¾ùþûó÷J`ö›ÈðK €p¶ AÕûŸÿðÜöX³žyvb¯³ ¡°`âf5`¡ Ư /_~µ.Í``¨ºV@Ôs€¨¯Ðì¿þÏß‘Æê¬½nš?€áoÎÃd/ÂÈ äÖÉÀÈÂÓ@LŠŠŠ Làש8h±úý§­µÒÜ3†oßâ?÷Ÿÿ­x%å•8äÝ`ZˆIBB‚„YXX˜˜H .y!3ˆå @ËüPÕ7RXÕnÎùüñ=>^V`ôÿúýAF„“Á\[ˆCÙ¦ €˜þþýËÂ`Ðr#ˆl@Ä­€ÁþÂÿûKˆM`]muŒÄÇ—÷AñÀ ##È ''ÎÀÌ ñ˜µŽÐR¦ Ý >@EAY‘äìÈ ŒFakfÿÿ_V†+|2’tܸ.]¼ÄÀÅÅÂðçÏ? ÍÁ (ÈÇðã×mE>f~a&Y6€9@ú©@Zúׯ_Df^`( šAhPŠþÿá7à $×ìP†ï~2<{þˆ…™™æA>> ÍÈ ŒQa~>Fp &nn¾%%õ³úû'œ×ÖÖnF‡vKnebg``$:&ˆå üãW¼G\’·¿6;0¼~õšáûW LH`ggF/37+ƒ´ÐF› ƒ€°áJüƒf·ñ"Öa^á¶ ÏßEÉáÕËç ß¿&l&¸@é‹ èV& `ô1rHäˆéׯSÚ~ææ­ ¢bâ 666@qnDBúZ èNHƒòù˜å_xô¼g9Ça÷9 2`€¼|ùŒáÐ% Ã2¬¬¬ L@†¨ È,618@ùŒ^¿zTôàþUý»w.©½~õdIiic;0Ò¶oßÔùƒáÐaû”>˜ÕYYåÍòìÒKD$„˜Ž^f`xüXs%'ÐÄ_¿™€q-ÍpîÜ-`.øË É8à¬ÈÈÀÍ N¼àÒ €€ L¬¬l?ÙØ._»vÖèÈ-……5l¬¬«6î¾¾šSÈ„UPÚˆSBMƒOFCD@Z•ÁÊTXȰ2œ¾ÅÀðî ÐçÀ˜’:€ Ô?ýcðöödpp´fÈÎNgxøðƒ‘‘ß³ûÀga^`0_?Í ýå5ïg/^nXËðúÈ!›¤d† ^©F'†§-daøôæ+Ã[`–ütäÍ›§Ð?//`Yð€ø tèóÏaõë!ÈZ€BTþ ü FxñùêàæU‡?W{ñšú3ì½t–ýïWãÛÛ€EäfÆÿ Þ FF Óšvkæ1üÒ cxü쿨4ƒ‚‚4ƒžž.8ÄþA#ÿ/°Pµž?&6†ÿ`j댡¯/Îõç¤dy2ð¨3ÞàÑV?ÿ.òÜeÈ»u‰“kÃ+`Buób¨^8ƒA¢¨˜aʲK ù[ äØ8x~ÿú ŽsPñûï߆¿@‡¼xù–áÍ‹'À„á)È€Bu¸Ìÿ k,ËžS{g¹9Ê@üˆ¿&â} ™B·n‡(K´w@G 9º2d.ZÄÀ——Å0oVÃ÷ÙK¸e€–þ…WD¿€Aÿï#ÃÛ÷þ~yuä?@ÓþÚň ’áÄþ/ÿ¤ynݶdfOÀè`Ö~Ñ3ç2påe2ìžÕÂÀ©mLF§¡`bøüù;'Ãé3çAv™@xŠ7f¬2À°ùöö?CÈŽß½£Â Töè&`pöOaø’žÎ°ñøK>#apÁʂ߾}gøÆú‹áÔ© ÿ ?sP¶U\ —oþúï8åù¯E‘ïڛ迟Þc8{üħCoÿíû/À`bhÈ0ÁÖŸîߨj9Šl@‘Ý9öT@aPÁê0pSmÌ͘üèãé? ž30¬J…¡)°> do„ºÞV ÆîžÙ¬½è¹ýIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/forward.png0000644000000000000000000000350411550446572022671 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÖIDATxÚbüÿÿ?Ã@€bb`@î€bA`4™eñ ¿ÿCØp | ÿOeøòG¥™áÿÿ“ âÿ€ê€Êr pþ_$±±ÿ¿ Qì Ü!J¬@›ÑUüþ§+ÌÇãê¬àÍüûï†ïª¢ìä†@áf 8˜QÅþþgâ`bd˜ÑîȰzŽ7¢, Ãû»€!¡KŽ¿þCUp *û Ò?¿ÿ1º+1ìÛÌ›¨gÇøåÏn`h¥ÙHq@—!ÁÊ„æ6p¤2(Hó0,˜èÊ0kš›¸ˆ G?Ãç_ éD”XqøM”,àÔø’ ˜Øž@FJ´6Þ-! Ææ’ o¿o&8mbŒ ,bª ?ÿÚ0ü&YFH)òì óÿÿ? ßþhüá`e`ŒŒÿæ_bbâe`ˆÔùà¯%°k}0CyÍ!ã9Ó/ìæ’|¦Uø@,X|»ZI†W_› ˜ÞþC<ÿšµ€ÔïïDùØØX˜þÿûÇð ˜M_aexø‘‘!Åð/ƒ´ìɮ JеU‡Vüýó_ˆ•yö €0Ë¿ÿ”:K̼¬¤¾~ÿÌŒ ŒLL¢”€,f`ısÈÏ¿!ÃÄÀ?ýœ…áégf†<Ó¿ :⠕Ŧ â\Œ™é»'ÿüõ‡™y"6¶4ð‹è»?}û‹á7Ð’ß@öß_þýÃ_ýý熿À¨ùóçߟ¿¸˜þ0¼úÆÀÐvŒ™áà}Fpp%Æh3L™âÂÂÎÂØÇðû¯6¶44ô/Ðçÿv]øÀ°ìÄGnNVV6VfV †Ð¬¬Ì ,l,@K™˜9ï×¯ß lÀ øó Ä3L _€ÙÔ[íCJ¢×/¿˜ óvOe`f»4þ6²]Ä‚3çñË÷¿NÝúÈÀËŒsv6vˆCXXÙÀ–³Ù\ÀÉÆÁÈðç$°ËDF&†Ù˜€éʆÜ,C†Í›îÈìÛó ¨*ـš ÿß?PÂ&V &G`Vcù÷ŠÃÙÿ@Qô= ƒ¢‹ $4y0‡\{õýŒ YÙ† o9¢Û@8CàßÿÀèþ4ð'Ão6F¤”iú?ram[€ò 0:¾ýeaøü"ÆÍ * 1JI€bÁ]ø€Š[`bûö›èPúc† +0á1CÙ€lD怚 +?ÿbbˆÔûÇ`. _¼ø (uA· €ð„À`5ðŸ‹ù;0.Y˜D3£h #0Ž@QÀÈð›Zbý‡ÔÂÀ@cÑcbˆÕVd,œ 7ßcX¶øú`°Ì@· €Xp½Ÿ¿ýap7b°ÒZÌÈÀÄÂÌÀ¢e3ƒhPÈôìþÀpîÉ/> Ï¿ƒJK`°Äš²2$Ë N†ƒG3¤¦í™ZËÀÄxÝ*€ÂâFfv6&!NN` ggZ WPj-1~Ëß¿þè?p:ùt5''C¾7C¨'/'ÉÓ/¢£·2¼~ñeÛpð €ÂpÀf†/=K® ¬ÞËÃðû"Q1þc‡ïŸ_ÿ„yØJSu@éê0Õ¿ûô‹AW(æÅËà¨Á¶|óŽ II;Þ¼ø6‰‹½œ@™1@,XªÞäƒÇž9ƒò/¼)ö^Så_Ya!ÎøÔuv†¯ß~1¸-­òfÐáb`dç`è™r¡®úèïïßÿ´1ð²6õâlz¶4° Ø Ú DŠ„:„LÌÆ,<¬ñ d,ã’„tå8¤Äy>~ÿÏPZ¼ŸaáÜ+o8X28YV3hõ Ií'HRçÊ?Hae¦ÂÅ (ÂÃpúâ;†¼ò# çŽ=;ÏÀÏ–T{Ü%ˆ8ÀZ¶ÈB@Ëy¹Ú™Y&̾ÎÐÖsúÏÇ7?1°WÕ¿$Ær ü`„Åÿ? aaN†ço~3ä5fØ·ýÁ3`pç1ð±­[LBg €ð;\ª ™Ì“ÿ€åAïÜ+ k×ÝùóòÙ— ¼le@WÝ;–D@,xãû¯°2Ý~õñçñi³¯ð‹Ãn^ö¥Àú['ã@wNhÀû†4à0ÛCr *c±IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/identity.png0000644000000000000000000000343411550446572023060 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<®IDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €ÜÄ"ŒÓ2ØÙYÛXÙXXþýgüûŸ‘þÄ `6ͦÿÃi„?FÅg†Ÿ_€ñÿŸŸ‡áåõí ZY ªªÒP£€éƒ5îQù ll,Xýýî€b%šß WýûIÕ@¹¿¿?2°ýZú h9;'H0±|†Ì†Ÿ¿1|ÿøœ¹¹8ˆŽûÿ ÞÙõï?Äu$@Áq60Ų 3üþñžíç †‡×Ÿ1|x÷”ÿ¤dE>½}Ìð›U‹áÞÃ7 ÷Ÿ`àä`EŠw&,l& ^&`vWgâÛõ<„À`*þds‹i2¼|*ÅðýÉ5†£»/3HÉ‹1¼xú–áõË \|äœËÞûÉðùÓW†9âŸÉ tÀ Mˆt f°]ÿ¡!@ˆËß¿`aüÏðò#ÃúÇ~ zŒ‹„Ù^¼zÇðûç'†·ÿ~Mgpû£Ã`¦ú‡A-?)ßÿŒ÷ 1HÀ‚rÈrHzƒÂÄÏþ³Æ?&F†ŸÎßýÉ #ÃÆ hYÌðQ²€áɬà ï^h3|p^Ç`eïÊðíã†óÿ‚£…^ü Zkk€Ä@Lÿ0A!40B8•üc8÷‘á׿¿ zjÜ \\ Â6 e¸t$ô˜¸ÿ22ÜxÊ täw†#Û0ðq1‚³$øY€4N†ßàìq)@ÁC,Œÿÿ2¼þðŸáÒ`¤p±2<ûÆÂðX>}xý†A^R”áý†?޼xËðà+ Ã'Fn†ÇŸø¸ØqÍ Ä,à8å}Dz`‚;þþýËð ”¡A@(iTu¼ûüŸáõF†×¿˜þÓ0P¸ždÿþƒáÛÍ[ oßüg¸tä—÷L`CÔ ô¢¼x†2ƒb0Rªøš~ýü¶‹’‘ €ià0²0þcx 4\øÃg oY’ weÁ•ó ïÞexðøÃ6Q†ŸÀéÍ`Ø}üÆðõ3÷_ŒiÂfD)ˆ@ià(ÇAs@Aë&`"üËðýû?`=#øÿ7é{, ŠŒ ì@ü”¶døå’ÁpEÃŒáÇ?~†ß¾M¿té5Ãß7»æä†+4øQŠX:å5.6H±u@Áëp6&BFæÿ ¥^&lÿÀpñ ;Ð †Ñý ÌÀ´óïÖO†ïŸÿ0pýøÊ ùˆAÛX h9´°AT@ ‚Vk[pH€ÒÉ?`âþýç7¼  ˆ€ÎûÍ_¿þaàçþËÐôŸáƃ Oßÿeøòã°°& j6`¨*22¨Ê02HI*3üZþÿ¤jƒÅ7¤ðŸ½qJ#?µîpnƒ8 €`ÕñßÀßwð<0$ ZA®æÉ2Bª fP1‚2)0î®ñ”sþ3`ëU0ÂíýÑHÕGo>þ†6D €`åÀœÕ»n—ƒâ Ô6€4« Í­P#aÍ.ì˜ \–ü‡æìÿÐ&,‡!7?AM²¿ Ìßþ2¬ñˆq {F4à­b€pЀ; €Ü4à0‹é° -þIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/noatunpause.png0000644000000000000000000000125011550446574023565 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<:IDATxÚbüÿÿ?0šÌ:¤ ð?_Â.¯Â)o<ÓH`À>0|¦Âp­ñ-Èn€bA’0èÈ·dÐSƪ«|âq†Ë—ž9C-x…Ãp] þN 9¸€WΆoýÌ%@ü €À /'Ì ©!…U#ŒÉŒÏ{ u¸Ì€ƒÿAö‚ ü@(xÿ赯ØõüþË@©Ãe6@(øð·æ_D:à‰ Ô:àåÊC—Ø@a„Àëo8|öÈø‡Û l €0Ò½C €0¢€Îi €P£Œt΄â€/¿€ø£$2 €Ô}øA¼ˆ…‚ÿh49Ÿ^€bAWH‰Eä˜@L  hÀ@î€pЀ; €Ü4à ”r€‰‚±F" ddÀm6@(à6’x8°+d&2¬@êp™ ЏÙx9qÌL¤˜q› Џ€àá™…È©ã#Á„ê60ïÀÕËÏ‚=gáë~føöàŒ @ŒHÝs~†|þ|ãÂÞÚüô™áéú[@Ö þˆÓÝv3†O7pwóA–¿>øȺ´û/@€M¦:³zIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/artsmediatypes.png0000644000000000000000000000364711550446572024273 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<9IDATxÚbüÿÿ?Ã@€bAæ8::Ê(**.ÓÐаr‰5„‘‘8¥þüùöìÙ£Ÿ>} ßµk×3@1€B†===={öì?1àß¿`ü÷ï_0¿ÿã_¿~ñÏŸ?ÁøÇ`ù#GŽü766ž³ €PB@BBBORRÃa°h"F l¬L ¿ÿcøýç/Šm³ €˜Ð‚è7º¸06ËYY˜@v=ÿšáíÇŸ lÌ Èi Ćˆþ ”@ø‚¯eØ,ùúã—ß ö3ܽñ”áÍ?>†mŽ Ê2ü ?~ýAÑ Š:˜Ä„îdÃцKž™äÿ-?Èðëåe†tn™¿ •SŽ303á× @LØB€”`vVF† KÎ2püÿÈ +ôáý×ÿ a ·ï¿d¸rû8jÐBn'@á b|bss³2ô.:Åð‹™ŸA]샰/7ƒ+ƒª4'ÃásÑÃŒ¢Ù„â1–C ùÏÀÃÍΰqçE†•çÕ?ºËÀÇÏÅ !.ÄÀÄÄÌ §,ÈpåÖ œž ¼i§å Ÿs²2\¸t‡¡té3†ôT;†?ï2|øø(ÏÈÀÆÆÊÀÆÁΠ$ÃËðâõ†Ÿ¿~£˜„7 àJì¬, /_¼bHŸt‘AÛÝèi†'0üþõ^*²±±1ˆ q1|ÿñƒáÛ·ŸX=„øBœà€¾ûûëCz÷AnW†·¿8J|úô™áÛ÷× ²ÀúÿTñüa`üÿœk@åD/j®4ðÈâcgPæúÈ j ‡€ñ ’øÇÀ4€…ÂúáË/ ›…áÍPð_V¹ÊàZï0õ33þ†Jô"; €˜p¥P].+.Èðüñc! e_Þ}cøñþÃ×ן¾¾úÄðûÛ/†ŸŸ¾3|ÿðáÍ'`Õ_¾tˆAOO•A˜;€†÷>3p²s';Š¥Èl€Â™@>PU’aXµùƒ(§.ÃÓ ï˜yú×÷Ÿ ØaP“e`ùûä¿pJ0óð3(«H@}ÿ\Z>VB\Àº€(ök¹@,øÊN.;e†‰3ê¸~°1°;;+ÐWgwó20²3p3°1\xý™ÁÓI‘ƒ“›áÏoH±û˜bï?|Ì  +N¥è¥+ ÎrÄþúõƒƒ½5ƒ¡ž0ý0,Ì,Àb–…á칋 Ý›Nçfx~J•ÁÌÈ‹O˜"þƒøË—o >`p° ‡²Ç£ €p¦ø¬H¸y8¹XØxþ3±3|ÿÅÈ`dbΰi~)C]ÿ_+»ÎÀ!ªÇÀôÿÃçÏßÎIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/player_eject.png0000644000000000000000000000274511550446574023703 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<wIDATxÚbüÿÿ?0šÌb 02H1üþ7“áÿa6æD†ÿ 7IÑþÿL˜ &r#ÿø“«"'ࣣ*bÉðýO5PŒ‘£ˆ<üýoÁð÷_~^‚ C}¡- S,04É1 €Èq+÷_¦f œ¶ÖJ ZÚ îÎj ßUåøH5 €HwÀ¿q,ÜìöQa† Ÿÿ01<þÀÀ`È ÎoÌðûo>©Æ‰q/Áðíw…§»ƒ–Ž4ÃíW Oß30J2¸yê10üü] T¥IŠ‘Dš~ü.•Vñ 0b¸ó†áõW†·ß¿c`0´ÑaU—᪩#ÅH€"Þÿÿ[3üûŸãèiÈð‹•ƒáþ[†÷?Þ|g`xñ ˜˜X,=L˜X™C€Ñ@¬±D¬¸~þj•Ñã2²Òd¸ô hñWH€è7ÀPx !%YE=5`TÔ£K”ƒˆ‰È„ÁÀÊfoínÂðèÛÇÀx÷b12~ñ™AÁʘM€×áÏß,bŒ b ÌðëO½†¥>ƒ”ŠÃÙÇ ý ¿üÈÀð›—ŸAÒPŸè€`´©2 €;àÏï vAA9g]†[¯ ýÐ’ ¿þbÇ߀!#¬«ÃÀ--ÅÃðçO#!ãˆìþ2¤¹˜00ñp3<=3¤$Æ…ÿÁÂÎÊ ciTÌ _|ž<ÏLx|r2|VÖj ·^ ‡e<\Rÿ‰rÒ Âªª¬ ¿~Õ…xqY@¸ðçoÐ+> _þ0‚S;+)eƒ”¹ +/¯10*Êq© \FJ#»RÉ\—ÁT_œáÊS ą̊†ãÂðúê7§0?ƒ˜ó/(¤Í"€Âî€?*™……ý|õžËúÏ¿ ¾gb„`F<˜ 3¬´‘¬Œ0ÃïßõØì ,%ž#ïéN>¦ *rœ Û®10ˆë8f²j{`‚ä`bÐt2c8½dc °<ñc`bÚ€,@,úñ»JBS-ÂG‰á90Þy¸€ÙŠ™l 1})†75n»ÜÌÀÉ~(ü&@¨øó/•‰ƒÃ%6ÑŒAhëM`ð‹ñcúžG¢ÃÙ€`g`°ó3`xrõ¾Î÷¯?J ª &@,HN•gøþ»À5Ò!ÌQŒá×-qHÁ󔨀…Ï?P©ü’Ýþc )[þGdCl@J[€Á9Șa˼C)@¬ ‰Â¿~ˆ«ŠªEFêK^ ÅLÿ”!"[üê¿à**s’Zþ Ä¿þAŒg£ˆÃKDoœ{RЉÂÌLÜ?¾ÿfhªÛ,þÁƒ”‘‘pc•gD*µ`Á ÌJï?üåi.˜@!ÀÄTòñý·Í_á„zŠ€˜ ~={ &@Hi€ÁÑ!ÀȦþƒÂ…‰ èP¸l ¿ÿµ«ª‰[ª)‹+Àÿ4±Ÿ%Ûå«O ` $üáUWaÐñÒcøù6áÏŒùßGî1\¾øˆ &@H‰áïý7~Ü€Ôf´ÌÀòàÍ‹? ÅÄ‚žpAeøFÚ8V €bAN llL ÀvÃÚ8€…ƒáj¹@È%!ǯ÷ ŸŸ1üµ­h‘³0|øùp{á6Ö¥7OÝÈ»yâ¡R•‚B€ñ?3° Z0Iý¶;*ª.!IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/roll.png0000644000000000000000000000460211550446574022177 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< IDATxÚbüÿÿ?Ã@€bAæøùù1üùó‡áïß¿ ,,, ŒŒŒ`>333ï_¿À4Œ’æ/_¾°³³ûóððýúu[5Ó?˜™ uPµ`”cذaœ@,¤ºä8 –ú÷ï_$//¯›…©©)Ÿºº:î]»´€†ssqq-úKŒyD”@>Z* SNNÎx)))7kkkaUU5 Š Ÿ>}fˆ‹‹©Í]¿~= 77wýÙ„Ó ´´” h©ÉÏŸ?c%$$ÍÍÍ5–2ÉÉÉ1 1¼xñ’aéÒ¥ ?~|c033cdˆŠŠEQæÚµkY€ŽÍ²ãs@±`±˜éÇÊ@ö‚‚‚q†††–@KY€–3ùà(¥ƒoß¾1”•U1¬Zµh!ƒ±±âEóøùùÀŽ‚T`t0ÓG>GŠ€ñêL|™FFFn&&&|  ùÀP`øþý;H 8tXYY‚ƒƒøø„Árúú: \\œ`Çø Gppp$­ZµŠ ht&Ð_°9 €PŒ·ùååår@ÀÅ~ÿþ ö5,Ã,ÿóçÐRm `tÕüaæ°ZƒA!ÊM1K–,á:&›#ˆ ™ÌJ< Í KAäp^f;å 9`‚ã>""ŽÁÑÑ•ÁÍÍ‹aáÂEðìR ̢ ¾¾¾ ‰‰‰þ@‡¯šÇ‡î€bB‹‚o/_¾d8þ<Ø ²fÌpHYð˜ðþ1ˆŠÊÕð0|þü (’g†;VV€¢ÍÛÛ›!!!Á:K€XÙN€B‰  ,}ýú5ÃåË— à=¬@QUUfؼyÃýû€ñÌÆ ))Œ÷_ iFxThPšùô郳³ HÎwùòe €Œ˜Ä‚–ß4‚ ‰Û·o3€ ˜A ¸ñâæM›üeg½ÏŸ?ÃCš}¡Že›ÅΔcùÇàîiÏpæÌid;=þ„ù¤d°Tc••)(u§¦f1lÛ¶¬fÍšM 7®Ë!E#СlPýcø÷ÿ'ïß_¾~ÿÅðï/ÈqŸ‘- € €;ÈÏŸ?g( """ Àrž!&&†AZZl‘µµ4Güêaª&D¦ÿ ÿÿ,ýÈÀÈŒ†ÿŒ ÿ~ÿ‡ (í|ÿöã+²…„î€ßèµ#È'Ïž=[ÎÇÇLýÁ` ©?@ÃYYüŸ ÿ}gøùë30ÿб3ìß{Žaݺm î Övæ ß¾|føþãû7dókÀ%YXÀ@!bƒ¢ê4`pÓw ýhñW†?À¸ÿ,ýAYõò¥‡ -Í3NÚL¤Â ήv ¿þ¼•(!@LhÅð/äjTÃÒÈa¯^½Šý²¿ƒó0~ŸÝ jÆß à,ð”˜êoÝ~ÌMïlm‚Bü¾|†ÎßÀ¨û„5@ydikk°pâ`hll€çÿ_ëÏÞ½ûÁÐ×»EÚ:Êxx¹êÁYYë1´w–0¨©+2ˆ‹‹Ë_úŒ'$@Lhø… P¹Àİ{÷†‡B£”µþBKG† ¶3Ì›·šaíÚmÀbø;;ÃÛwŸÁ¾åàfpu³dbøöý4½ü…Jq @QRTLDÌÀbÔ“ÁÜÜïÜàTe#™€Yò7ÃÃ/€9„ƒ¡¢"—AYYØÒ9Ìàï“ÌPSÕ*Ž€ÿ„8šTŽþçÈ” 4ü†Ä?3°2ù¬h ¬¬Ì€`g5V €AùlnNN0CL¬;ƒ©™6ÃÝ»ÏfL[ÅpåÊ `°Ë1°sÍ÷€ÑóœAHXˆTT€¢hJ ”&º­'NœøÅÍÍ…Ô„.àÙÊçÿ~ÿúË  (Î``¨ .ïA†‹Š 2„„ú1Ô7–£ä'CWûL†@ßX†}{0pqó€ÍûÿïJ. ”*k€u€$??ÿ$GGG°Á°l‰Ô®§è_¿u'з¬À¸ægèî-b`ã`'ÆÅ ¶1lÞ¸›áóÇO lìàhýŒ¶¿ÿþ¢„@a´ˆ€ù|20”€mƒ`»\ü¢6™ lÀÂæðÁs oß¾cpp²`àFÕo`<ûòÜ2ÒÒVg°sˆb`èþ†–˜L(i €X°5@¥^ùž={D€­ÞP[9$@ä? ›èÓ;Î0””´0<öáð±MàZñ/0}üúõƒÁÚVÁÊÖÔÈaøòù;ãûONž8ù˜›n!Û@,8ZÁ¿€Ñ‘¹uëV~`ñë«££.” ©?þkÅCÀÂé ƒ‰‰°U$,‚!e>¸nxÿöÑý'®^½öúÉã'›~ÿù½Ø2:Œl@álƒšOÀ K¶é¶a¦¢¢Ì?ÀEí_Pj&Js`M)ÄæÁÀËËþÀ”íÊ]†³§Ïý¹ïÁ©>Ì&Û½@=šù½® FdPM‡Ü‹¶ •v¤§§«ˆ‰I½ÿ ˜Nþ³"(8€l`‹èˆÇ_0\¹|“áÌésŸ>}º˜èæKÔÀ ÿkЀr¨@[¼x1Ü|€bAó5FH+–»?~Œ?þÆÌÌ,1 )`nù LÙl Ÿ>þ`8}â,ÃÉ“gÿÞ¾}ïè—/Ÿç­Ú LÈÏAHöň¨žЧ'€-¤øeË–­NN‰ãùþãÃù³×Ξ½xëÉ“'»€¡¶š……ù;ÐQÿþýe ¥Ã @D9d 05ïxøðAV_ïäf`Çåæ§O—ClÐÒW°ÜCŒÑ@1t÷ À(7¿Œ…IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/kdevelop_down.png0000644000000000000000000000313411550446572024064 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<îIDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €ÜÄ‚Ìa4™eÆðïÿL –rÿ@™YXYo3°°d0°°] i²ù¤!4* Îê5f`bþÄ @ÌÂÀÌü–‰¥èÿ2•­0…Ä‚¦±Ž•Ù€…‰áØ|&F&†/ßÿ M˜q ¿‡(ýpª8€r3þ3¹±°±)&'€432 ÿg`ªª; €Pðõ—an† CqŒËoÀ6q²11,ßø€aÊ´ F |ŒíÀPÈ``feû d/#r,‚UÊð“Á[^S‚AR^äx†¿¾ÿebøøî+×wï”­ Ô4ÀÂtçèéç <¬ F²| †@,*ÎçÃàä¦ÂÀðí_:з`K!ÃÀˆ€ Á ?þ×: 2„¸H1üb:”•á? ÃïÌ ?¾ÿêc}¬ €PÀÁ:ùäé§ÿÒZŽ“Ð÷ÀTðñ#0`~20d¤2H)câÇ¿f ÍæßþCÖ­Ìðû¿Œkˆ»ÕÌ _¿30|ÚùH¿õŽáÏ AÌÌó5ªþ3¬aà场rË]†þ•78ó‡O \Üì ñ1 ìÜ<@{gCB4ÀÔ;ƒ•U6ÔC–aÿ#v†;/~ÿf`øþ‹áÓÇ/ ¿¿}†0ëZ -Ó­ ´løäÂ:Nöc S.0¬=ú’A„‡AÝ/Þ10¨© 3øøi10üeÐcøÏÜËÀ ÓVËð›ÁÅÛIŠá+§ Ã¥'@! Q߀øúå'ÃÀ`df¹ th!ÿF¶ €PÀJXLØX’¿üø÷¼¨÷í'ߤyx€R¯€æ˜˜Ê2hs鯱ÀD˜ÄÀ.ÕÒb–•`8z辿Ÿ&À¯ÞLþ4;H?FO4„êN>6NP»ÁÀÍ^üèñ—ßÅ.1|þñA(Å4ø#0$íT„e„€%Åÿ†¿Œ ø…¹™ ŒåÎ=bdøŒæ@ËAô×÷þÿþò}ÐôCØ "€BKÿ˜a90=t:þ’aÒªû \@w) }4ø0u›Z(3°²±]Á$.«.Çp÷=Ã{ ã~î7ïñþï'0õ±°,:½WI@¨åoe!fæ6`Hì[°á>Ãæ£o$PZùî30Qòó0èš«2¨(1°ñð1¼FϯßPŸýÅðçÛ'PH^Æy)0šþ@+Z¹ÁÀ@hÙÙ¹@|ú õÏ?ÆÇ½‹o3\{ø“AY”A(ýh>¯¿ˆ8»ýø Itß~þcøýù(A}d`bJ2^á« w ZJ÷€ÅaþÛ7¿ÿMZyŸá÷ÿ zÀ4È,pA¾þü ä`ŸóüÏO@ÁAñ*rªŒ¿x=7KË¥«æo~¬›Œ %ñ§ïPñÏ/_€™ÿ(¿ÏJM…f-,- ø°``x³p€ÒE0$ví?ñ–aÏ™ âÀBÑ@RÒJÊŸ RîçÏ/-å÷ÿðŠ #€B« Ø018A‚Ê|ÆŸ ,ÌÙÿ˜™¬Ùõ’áÊý_ šÀ¨Ð ?€AJtŒL8d‰mqQÀOw€áŸýíûÿïö¿¦‡ æÀ’’õ3(¿kZæ šc¤4Hˆ#ŒŒÛ€µfÛ“§?›wŸøÄ $Ĭ°€ÁÏÊ:½sñN T0ÙBcdê``g5:ã{ 30ï1²ž``¶ÈÄBfSØÌ&4&f`ÈÌdg’ïÈ €ºg@Þ* w@ ¸hÀ@î€Ðháø`BõÃIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/kgpg_photo.png0000644000000000000000000000317211550446572023367 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< IDATxÚbüÿÿ?Ã@€bb`@î€bÁ&˜œœ¼\@@À‹@Q‹¦ÿþ1 ø !ácû÷ï?Ã?~?~ü¸ôðáÃóí ¬ô/++çäææF± f2ÌC‡‰1À嘙Yî޽Ŕ”Bq@¶È `‚c4‡„üÿ±Em“riAv3ீªú n„;~ €R÷%cî5»|%VƽGÄ0«´Ö)åûñGauÈFF&†‡Ÿ0ôõÏdàæ™ƒÿY8þ}yÅÀúù.óßo Xø~ñ¨30²ò20þùÁðäÿÿø÷ƒ 0CqqÔq Y €°:l|ÿö‰‰SÁÎ7•á/P++ÐrÆÿ \O¶0(°~cwd`eùÏðóãs†çOÞ1ÜþcÎð™×…áß7`¨}êÿò‡áÆÝ^ ­p&B€bÁ›E€.áæegà`&$ Ã˜ø.gÐ×fbàÒÉúôß^20ü|Í ¡yAáê:†ã/~2¼ð†Hš‘!Œ8í œÙ×@0 beƒ`®÷t¤>2piº20üjýõ›˜F~ýòÙÕ ô„¶1°ÿzÌÀÈÔΊJFH´á(ï‡ @š™*Ø€>gÒâÏ1ðÊ*30|}ÍÀðˆ}:à;8‚ðŸ_ÿ„$ùÄ5¢ ˆ™ þÇî€Â×3 `ªbüó—Ÿã+Ð" ¼š ´”°þ~:â30¸sËo`l33ð° ¯ïügàfÆŸÃçÙó ÷ë© ß12üüÍÈ ÌÅÀfàÖføÓ³ ˜…þ<üÄðé'ÃÛï ¹ /02Ü~ü•ÁŒý^N€‚B¢ ²¢„ÿ-c`~©^A¡4›á'#4xeýÿýW!  fb [$A¥†ä? )p•Œ+ ÎÚä&`iW˜Ÿ .ýÿ!nÔ0qÚZ€dá¿ÿ™>}úŠ3Þ(ø¬l~üø O¨- l­!äÖ¢…ÄÁÁ‰Ó€bÂW`Ö ˜Y‘Ê‘i›OU Ä„/ û·z Š!«Åo`oˆb n\ŽBec„#22qp°ƒkAì¡€éô@¶dÖ—/ì Øâ €°:à÷ï?ÿïܹÍÀÆÆ†a <Íc± ¥5…DƒÒÄãÇ@ýƒ¿èv#¶ø144ŒåââòµÐQûÿ¢f ¦( £GÏ?`½ýäÉÓ?~ÜŠl@1tç €¼o@î€æSâr?¿=¡IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/bookmark_add.png0000644000000000000000000000471511550446572023647 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< _IDATxÚbüÿÿ?Ã@€bb`@î€p ŒQ‚(úg'“,`o/6{Ë4‚—ñv–Á+bië $f'̬›_üÇõo¶º¦„B„œ¶‘hPàŒœÇnY’˜í©FÛö“ûþEÌ÷ꦦ”ïÊ|P¢ «žâ<ÙlçÀ/‹¼×"r÷'¹êçØÁ uã/€A‰Å,, ßþÿbûúµT…‘QÏTT”IZD„ƒ››ñëW†ÏŸ3<}ò„áÌÿÿÿn ÿÁÎ~KäãGýOŸ$õøùdeX€êÿÍúôþ=ÃõW¯Îúôõ9ÛFVvöÖÿÿ¯3!9 €à`:à/ ÿ·_¿¦éüùäêÊ ÂÀ¨¤ÄÀÀËËÀtPÃçÏ OŸ2ü_½šáöâÅ ?}b0êÈÈ``°±a`d`àädùz @GüYðãıØÔ‚È G°²2<:bÂÎï¾psÛÓÅU€'¿ÿÿkû– rf c<Àm2?^2h)=ôÿÏioo¿‹…–¼yS °þüýëoÉÅ%Á¯¯ÏÀðìÄçääÐFßïû÷¾_¾Ìðåüy†¯3C (¿›™Ùåý¿êvç¶ÚRR@AOIñ ò-ÈS§O3|ݱƒá+Ðò_¿3üŠýâwÀPbPáã“8ÎÄd@`püý«ÌŠË/_P)¾Y Ì)ÿ@>Þ¸‘áÇ¥K  f1!á?@0ÕÉõ0ýù# @`032²0~ÿÎ2àà#588þ¿~Íð˜+~:Åð”s@IÙhQÄrÈ¿ŒvÀoFÆÇß?~Taxñ‚X˜@Ùhà_`üþÚ·áÏ»w`‹@øÃØ Pš ÒÿÙÙ^Øÿ¾ ˆþý;úà×/GÅ7@…r^ÆZƒ0A‚X"þ–nßF±ô/š¥ÿ¡b Ì,QÿCìÁ·oŸØþÿ?@`°üû·ùôÿÿ…VOžp³ƒ|%!I 莥Pq Œ®ŸW¯2üâÿ¿£1Ì"P¢{ÆÃÈð‡Aà-D–¨WB\œáÐÜ—¿ecd<@`]rê°d:øógº0«ü–ZÌÀ’”°@ŽY tÐ_`óèëo·n1ü–zLHñ bÿe¨(ˆùjŒ$\än8¬gà¦oyy†¯ÿÙ¶¼óáóÿ>€;T9°ÿÿ_½ÿógS#+ …?9â0=0]ýhÙ7`úøùö-ÿoߘ¡ÂR ˆŸ‹‰á­&ϵo Jß!rœ’ \ò2 l¼ì br ¿€*ï¼fPýùíšâ‹Ÿ‡@å@=Áª"Þ2ÿÿºùÍ›Ó[%30*þk²{ÇŽ1<æéwÀù´¼¿ ùÄÿÂ.2 ng634{0܆¥`Zúû냰˜(÷¬ /Ì?2œgp¨–2ýõSO˜[¥AÌŽ÷X}¿y3wÐÂoÀZP˜(9xxÀ “ßHìŸP½Ž=a¸¿y=ƒvqƒx³-Ã#ˆ"f`X=|ô–á•íÕE _22È €ÂhCå'SÊÝ/_ræÝ¹óå!0œ”‰ç'’Ï‘ŠKÙ7ÿ®GOax¸|2ƒzM ƒnÐr`íøóƒHƒÚ\ †¿/.x]ÝñúðûfÆÏÀôÉ@àÚ°NLŒ ÄJÀè`øóç0jæ¸ÊÉ)[ÈÈ0¼VROîÞeø”g4 ¼…¦Pt<2l§{1Èǹ3ü“›‰‘í-Ã÷ÛoÎE}üñê·\`Óæ #+ÿ+„׌À8ü÷÷¯ìï¿gˆ‹{zij‚ëõ›Àbö0+‚ñP†‹A©9Ї—ŸéÇG†o_Ø™Þ2Hù˜20Šƒê`áöï%Ãç}¾Üÿò‹•ÿÿO&ÖßìŒÌÿXÞLÿt €X¶Z¥$'3sÈ¥gÏÚÞ}ýš``À¬ckËpóìY†WÀ\ñ[˜Âýý¸Ù¥Xÿ¿É†ßŸŸ30rÂ"”"ÿ3pé‰1p›ñ²1±ac`Vã,?¾ŸâÑ ‚!Àeƒè_¿~EóqpLs×ÕåÓÖž÷.\dxøúƒ …÷¿ßnÒºÚͼ_Îgøÿé—–2×Ëç„‚´”ž|—º\xýÉÏ?fqS +0ÕÉýV&¦ãÀ¬êrøúõ5Û€5ßÙ»·–?|ÿÁ— ãUåÜÖÍývçÃîðÏ_ßúó~ §ÒÎ?|¹üòOé<.ùÓY¹™«þ£ç0ÿÉøIÏEnô•ÇKv_¸8ïã¯_.ÚnêŽ «|¹y“a“Ëš'ÿç³ñ°üefcdøñåÿôã k_-»Ç ž ΤҤT ,¨´@¹ €X(èÔüV[½ÿ¡åÁ§'ߟޞÝÊp~ò½/î1Äñ008222±ËrPÅÉùó×ÿ†‹97ùµßþ®þræÓPãd@±P£{*ž_û˜½&mód`árØþýö]€)ä?(Ô˜AeÆ÷ê¯äÝZtøfH}Å@,Ôêããò'_È© NÝ^pîèÛC7U¾ø»ÿ/¤àú Ä×õÓ ªkõN IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/connect_creating.png0000644000000000000000000000356011550446572024534 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €Xà¬ÉŒ €4'Cì†%gQÔy022” ²0ÝþúúõëÓ/_¾gff9ÄÏ/°‰ã-;; +VË®\9ƒ!@,"@wüø",..±0--[TTšA\\AWW…áË—/"7nÜÔ_µjM±cÇ/~ûö­è€¤†@aF0LäX˜Áï1üþý‡áïß þüeàg˜8±èóÜŸ?¦³³³1°²²¢`l €á%ád¦h!N&Æo ŒÿºöOöÑw‰ [`Pÿÿý‹ã߆oL* OB8Ù˜<øÄ`n®Í ))vÈNNv†Ë—¯2$$¤Þcdd2&Ð7 ˆ’öÔ©ƒ D"üó_šAE0AYáãO;`bøñƒáÍv†ŸÀTùý'Ãïû\ ÷˜ ¾‰H-caxýúƒˆˆ Ø Ì zzÚ nn®J[·îôåáaŸO¨¤ ä(XÌpéÝ#†çÀDðþ'à  åO€ø#PÉG`ŠüÊÎÀú÷ƒôÙM ¯>|b`búËðëÿ;„!ü ..Î \\\þŒŒÌà, ÃØ@!B€›áù›Û?æïzœÀÉÁð÷;;³¬°°(ûÿ¿þýûÆŒ¿3|f¿ÅðYùŸ$ÐŒ ß¾ý`¦|˜OAÏ %%ÅÀÏϯõãÇOP±ñ_ röûÃò¿‰QçWפCŒL;¾ Ÿ›9}’ú‡¯¾~ýÂðýûw†_?¿1ð³‡Ào`tüú ¶ôë×o`Kaà÷ï¿à̾ÿÿæ`ccû‚Ï„ì5 N†_„ÿ³¼=ò—UŽ÷%ÿß· ¿X~0üdæn†Ü ÿü‚úö?Ð?QÀÆöHþ…ËõëçE>|x‹×„p+ó<C k`.`ˆHþÃý—áÈÌÿ¸xþ3p°|c¸öÊ”a3[Ó¿¿@ Z¿‡D üæ–ÿ~1¼}ûVðéÓ›€B™@|—á€ÿÖM²fPçg`øðœòø‰ïÛH.øÍÆ òåƒÀç— ï¸x‰Œ¬íëW„@Yš••áùó—@¼þÒâ@ İ9 €BàÿŠŸ{_—|Ú÷SšèC6`\þûñ ßXþƒ,øÏÀüêƒ ã1†×–¾ <<|àtñõëw`h@¢T(‰‰‰0œ8q ˜:˜b€B:@Üijø_Bw@± UB/öïú™qìàk .`È^g`ÐäÒ2Ìðñd¸|å8hÿK= Q~6P"FÏŽøv(ŠˆÅî1\ºtå‚””ìî+WNnæ7 é@œ Äéè „€ièÙ-ï¶€’Ñ%AÁOìœnÙiiª¯ÎŸe¸sû(}üÿõƒASR œÚß¼ùN  ,ÊÁÁŒ‚? 7nþL”5œ? ¥ì¨,°E@¡Ô Åìuaq†/òŠï¾|±f㊠–z ÜLÿþ|zÏ !,Ì ­­ËpïÞc`É÷\üF°Vܬ)_× ¡mþüf€:àÔx>l ,͆ÀFH//oßòå«ýÔÔTµƒž3ÓE`Û.Y²ºX™³#°åó—™™ñ33óI&&ÖÝ@ñ+ „l–1ìÛ·f9°Y𠈵€øOÅf@±Õh`b~¬j+XYÙ€ ˜Á©„A娲yøð6çOï`Ú@Mšg@| ˆ“ø56³ˆq {F4àÍr€pЀ; €Ü4à0{à•nXÑ•7IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/view_right.png0000644000000000000000000000426211550446574023400 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<DIDATxÚbüÿÿ?Ã@€bb`@, ‚‘1)‹‡‹¹’ƒ‰"ÿÀa$þ31Rý‡Š1@ÅàêBu ˜j L¦ßßþ\ªIÚ| €AQ ÀŸþ¦eB¢0¿¼$÷oÿþüc`ø Ä€ªÿþb ‹ƒØ!Ä©û UÎÿƒ¬jÖV†««w2<;y¤‘½ €À!ÀÍÅÆÆ¯ªÌðK\”áßw Há?¨óal fò|&7€üÿ!¾eŠäÀj `‚:€Èfâ ÌÎÀÀ.. }&&€;àß?¦¿_¾þfxø”áˈ… ÿ >ÂFõ‚Õüú äC-[À€¤ö/”†ÉinÃA>:‹‰™ € i€‰‘áРå›2üùüÏŒ( ¿ÐøIþþ ,ÎÏÅ4ü?¦Z,à/0N•¤™™!†@`ügdaøðå/ƒ¿Ê{† °‹‘íÄÈ:@””,eø µém‰@Ÿþ#˜ÚAŽþúõCÖ²W ÏÿÀÈ 2ˆ € ``bøL%b"¼ Zª"De.66 ©šÊBxTAó4+}ûú‹™õ(Y}ŠG€b8 (ÈÈðûÏ_¢óïŸ =,Ðl÷Nƒ¢D#³A4#Ð!_Ñö¼àgF@ABè’¿I-˜ É›æA˜…>Œ J|þ‡‡É?˜™À h¤¢Ä;Q€‘ ±PcÿþEˆÃ@4ŒÏ+ À…#ØN h0³#¤”#%@ÁÈÀÍ0ßâ%÷@ó( D 5˜áÙf!Âçÿ‘¢‚aÞ‡8€ â ½O â’@Õôÿ?R¨3A a`€[Ž a>‡XʦŒÀÒíÌ¡ M 4ÄÄ)@!ÀHÐr”b¨¤ Œ@K98þs‹>VV`ÿCª¨˜ iˆ‰ € &ãÿ X‹WX¨!BÏ ÄõÌ@µÌ¬ /6­fxМÅðùê5†ÿ,¬À"þ0ë21üc„æ ½Ä3 7Œ,‡Ðÿ‘rÄÿ€y˜‘˜¨X€5 +';ç;O¾ìjfP6=Ìð~ÍD ùÀjèˆïÿ8¾2pÀö@1!Ò#Ã?>‡Å+$Ú!¡JÓ¬l ŸŸ=g8]“Ìp¹³œáÏ yß¿3pˆq1ðÛ™3°sþ`øËÊÁðóîc†Ò«ù ÑæÀ v@1ÁÔ_´V6ŸÿÿÔ@ûÒbadef¸µl:ƒŠƒœÆ[†k5‰ ¿Œ†ÿ?20ðð1|<{“áëÜD†¬y§¦Æmeûø ZÜ Ä„’ ðø5¡ýë• ¸ûÔ̯nÂðâÔ™°DeËß ·›sþü:Ž““áó…; ?¦2¨ÕCêã}û…^q‹€=@L°àD tŸ#ò5$1Có#¨Nø ¬fÿ1¨…10*%0\l¬d ‹eÐãf`ýõ¨“Ÿý"ƒn;›0ê|9†ø7 ÿ¸9~éÿ|È@¨%!¬¼F*Ûåû?DÅóÿ ‡3±²3¼}a8çaγRþÏ Ö·)´þ9À @,ðlø9 ,FX¥–ZÎÂÍËðôØQ†G›êÄT”˜ßýdÐõæûO² _c`V7ªÖóçÆÑ†E¼³€Õø`b‰|=C˜ €Xà‰èAfFX!Ç®>e;˜ËLÀ†#(þ€)ûÓ½ ªœ *^‘ ÿ½Šªû,„>Uþd€æS6%AIe6–—@‹€U/ùå—@±ÀÒÀ?`IøéÓ†×oüý·D@¬…6ø€ŽdcebøùóÃoï„ÎθËp³~3Ã{O„Þcp\šT ß?€©‘áë¹— —Kï3ìò:àƒÔÛ—mïœ+ X`âåç`8ûD€!bòKh±ïßäjÆgdxèL ÿ|¦ƒ“µá»8ÐeOž1äþÈdðžZlúò3¼[²ŒAÀÝ„áëÁ£ ü!Z o¾2L¬Ì°B,Œáí‰>â‡vØ?ÿþûûæù`Á!ÃðíûoÌVð?T>(˲ˆ3øüÇ?†?¿˜þùÈù¸‚!¡ß][a‹Sƒ ‚0ƒU ÃÞæ úOþ0(È3Ìa[ÄÀÞp‡a!Ûÿ-üþ vÀï¿ÿKŽnÜ› Œ\.FU² ¤qüÚØ¦Žÿ\_.“©Ù %̪iɰ&¬ðué1ï÷óõ¯*12~g9Ç£õqB“£eǵ¥2ĘÚb`é~uð5¿@AÛŒó€F®Ö›ìÿA] F¼Íbônã¿ßE?½qº¶z÷Ü/Ë_o^Ë.,ÎþGòï›í Ì<†ì˜Âå•{ pc¬ÃûŸ-ŸN|»•ó~Ç)–÷ Ä‚dÖFFÒ{—À"YðÏ+›O§Woéd8ÅìÛh2|zkýr¦ÂF5`žcøúôÃÓ®×þ÷]­z°X-½ev-@Úˆ…š=]`™óT´J0|aøÃÀðâÁ¶‡›¾¬r{qÿïv)†7 |л‹ìM€C7T•;ØnIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/player_rew.png0000644000000000000000000000337611550446574023407 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?Ã@€bb`@î€p#UL1ž$€xÃÙôÔÖÉ â€b¡Ðb}°¥ ò’< ŸZˆC­?H-?›BU²1ÃÒm·.]d@LdZÌÄó¬ ž6òWÖF2Dx¨30üùf Æp¤ñÌý@Ö†Ä …s«"ÒÃt¸¸Ø~ 2,¡š¢°@SŽ%ƒ£‰0"¿ü‚«`ƒ;: Ú’ }å ª2¼`µ_jý…( ,!7›BQŠ%C”—:3а_øØQR›$DExªrṲ̈þþc`¸÷ž”è$x€ž‡: €Xˆ°XH.ų§›C~œ1ƒÐFa@”èˆCÀÄ*É`8å ''›Tp€1Cz¨.Ã?`9wùÄ× À ´‘‡Ä‚7ž¾·¢²$CyŽƒ²4/Ã³Ï ×¢©ýþ™áÄÙ HÙØë0¤F3yé%矘FËMþõ –ƒƒW€G !ÁÁÆPŠáé'†ÝwQ•ýüñ“áøÞ³ §Ž\aRdhlŽdPÆów çßàTPhÁ¢ €XÐ,¶7+;›‚­«1Cˆ·.Ã{`0ïºÔðÕ›§/3œ?t–…!,Õ‡ÁÑXŠáÁ†-·'§¯¿Q@,Hñ J±Ršj 1Q– ˜Ù¶ÞF¸><}Æpy׆_?~1hX3Dúé2<&Ä5׈ÏH?"@,ÐlÕÀ#)É`ëiÉ ¬ Âpê%Zª‚¿¿~2ÜÙ¹‹áóóç b:: nÆ œ\ØI€ï_hˆ(d,-´Ìt˜™Ž?Á^^¿¹y‹áÛÛ· :‘‘ ’¼ /üò…ò² €@%á…çgÏ2\;u”¸ ä†Üݵ‹áÖ­g!DnÅ@Ì Ï·ÌÿÏg þéù;µ±s0pòñ20MCÆlÜ\ ¼Âl ßß¾axzö"÷7o¸ÅÅXÙÙÁ“b¹°°>~üï÷ÏÏ3(z^<ÀðíÉ–?ÌÒ’oï>Vÿñî ƒ˜¬87°Ä`ge€c!Aai!n^`ZxÅðøÔ9f` K 3pp°0°#”¬!ÂÀpôØ-†ŸïžŸ f¨£~1ü|ùœáÕž] ,<'¿gWyré¦ Ðp Yan`ñÅt70t„¥$$äxØØþ1<½z—áÙ•[ \Ül@µ"u°7Ù“·€¡ùü,@1£—i Ÿ€¦½Ü¹‰Wíó»_Õ_»ÏË 4\Z^ì, ¼‚B âÀP’’ãbàúÿáê‰ë /î>e:P”%äÐ1/°(¾pêÃ×7ÏÏ3–(µR¿0¼=~*»þ0 3=½óZíÉÝìÀÔ/&Î ÷ 0 Ó¹Ž0Ãs`>¼r÷ëýËÙ>½ûÌ ¯(ÌÀ,ޱ…¨&¾ ϯŸŸ f>ÓÇ·'Û1Š2œ?ûÊøê¥g  xóü 0ïZ NCàœõê)0 3üý~üË>¾SG«?yò™AG[˜0¼yöü,@1“Ùý ζ ôñïçÁ÷_yÞ¼üL¸G¦0|¾ñêDÈ}½ŠÂý l·^½fÚ»ç¾Ô×Ïß~yu €¨Ó,g`•Óbк娾Á¡Ô^”eP+Ša`bçe¸Ñ¾ €¨åR°UÈlÈ1| ÆîœЀwÍhÀ`°‚I'TA„IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/editshred.png0000644000000000000000000000246311550446572023203 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÅIDATxÚbüÿÿ?Ã@€bb`@,ÈFýDuA ¹~1i†ÿÿÿPÓ"F&f–·/Ÿß|ýä~ñÿ sOÁÄÅÜ‚b-õÙžþ¦b ¿~309Œêÿ?«ÿ ˆËÆÊÀpüî7ÑÜʾ × ¦ €P &®n£.Æ TÌÀJ=ßÿ‡ºÑ\‰‹ARFNY €Pðÿßÿ¿¿þþGx‰X þC,ù‡äsphÀØ@qv M?~ù@€¬ €(N„0Ëÿ#ùfù¤èø`#€b¡†åÿ°XòMžù?ö4@L[΀ŷHìÿHÁÃȈ¹ÄBMŸÿGrXþªž_ÀŒýó/ªYÄBMŸ#[Kú ÿ@³â½ O?¡š@,´ð9ˆøõ1ÈrPÆbdÄžˆ…š>‡q@ÁüëÄ÷ XÔ#€b!¦ù—Ïÿ!%¸Ÿ@_ÿþ‡$U Jÿ°8 €˜ˆ)Å`)ø?Ÿƒ å`f`ôý7ÄrÇAÁ*˜€¬¬>6@²øã× ç®?[ùŸ A–³ÃðÜͧ ÷_|€‹,•ýŒ@úå›O n€u?Ð!,ˆÄúw]@€¥T`p2£Èý†Êýþ‡° n R¶û‡TŠâ8ê€bB÷=#Н¡þ…(¿€ô_Dyð©ÜGçÃê„ÿ¹[6 ¼ýÎÀðZT‚J2XÖùó”0_Ã|õ94þ!B䲯ñD@¡D¨ùü 5Náµ’PâM ,4Ðñ‡ˆ# €r<þC+ÿ#ûú$«!×pµÿ°§€bÁVæ3`‹[F$!9àZ=2ÈEö?¤zN0` öxâùÿÔ:Ešž°E@aDÜ´ …=Û!ctŸ£UÏÿñ´ PYIÀ ¬(ÿréÅ  ;ö€ìò„Ûi}è´¶Bqa7±šJSÜðŒþó/}„ëˆB ëòžBqÀßϯ»ýNWOAˆáù7F†_ŸYγ孌 ¯¿³0\yÏÄÀtу/, ¯~01\yqÀ ûÑW†« Áøð ÃÛŸþã/¬ €ìk.>ùÅðãý‹WÈv#rËh`Ì*¦>UP^GõÛË[˜Xظ„e~ûÈðýÝS^I5pU÷óãK†_@1^Iu°¾/Ïo2°rñ3°ó‰]ðëë;†_Ÿ^3ðJk2üøø è‘7 ¼²:,ŸžÝyúýé•’ÿççî‚Ù @ŒÝ; ïbDÙ)EÚEuIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/rotate_ccw.png0000644000000000000000000000314411550446574023361 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<öIDATxÚbüÿÿ?Ã@€bb`@î€p ºc+Ó 꼟 Ü<ìÿþûþýWPüXø 5õ/Ì‹@óþ230ü‡øõÿü¯(ʈ§A ´ù•¡ÔÐB¡5*Іõã—ï Sfíþðö«9+õB €XpXÎÌð›a¢‹·^vl¨ Ð3ÿ¤Ä…$¤ùu><þšÅÀö'Fà•½gøÃp¨ûÿƒ V¯ÿ`èö6Êô3ex÷é;ï¿xE8u¸t´e§21cI:ŒŒ Ÿ?|gxòèí»û^ßùòêû\ C£¯Cˆ½`L`*´sÕ싈¶bøôöï™Øy˜8ØY˜™p•LL ¹ÿ ?c8¼ÿÃáÝ7N|ûú+•…í Ã?ìi €0 Çw¥¨ÑS›ùÃ×™ ¡BTyÅÈÀ S6.&^AV†{w_3,Ÿ}ìå›ç_ÂXÙbs@a„å÷ÏïÜ»û†á?ë†_ÿþ2üøý—áן ˜þ2üaæ8ño`jùþý/Ç·¿žÝÿÆ &!Ào'.&-¸–áç_†ÿ˜Ù €0ðëçÿʵsÏßòì‡0ÐP å?€˜‘h<ÛO†?Ìßþ°@1ë†?l?à|fÞß "À$Ë tÈ /Ÿü``ç`cðŠÔfbbécøÍÄŒn@a¦8n`öû§Ç/ʳÃ'E[RJžŸáónÁ Û–ßüûàÊ›‹Ìl̉ëïÿÂ@O³0p2½ÄÂÇÇ.­k#)©e"Æðó3 ï/ÌÀ(ùÏÀ/õaËÂk ׎=÷ú¿æËvdû3°ƒ‰›åÒÇ·¿Ü×M¾²Ä%VEOÅ@˜áÇÏ¿ oŸ|{ýýõOGnæ_ ìŒÿ~ó:@€Á‰{!0¾X?¿ü&ýôÆÇÒg÷?§Ú)0üþÆÆðï;ÓÇ¿ ¦¢ 7O¾ Ú€â€ÂtÀ=`)øè.–ËßYÿym™ug††ùŸ_ßÿüõøÇ AÎO ¯9ëÁo þó k §ùT„ù7Ãï·äÙÒ.ízÉ(¡Ê“"£ tøWv†€~acàâ4A· €0pZư!Íúô¿!oðõý¯]€Aþ“q?á/ O€öþG3_C*—>“•2×ä›§ß'Š+ñ0ÿüËÊðûç?`Zø Ìl|èÖî¢dÁC Eß ÆmðBêFÉZÐ\ùÆÀÀÎöö·0ôÿfþ ÌELÿÿ1üû LÄ¿Ñt@±àÌÐ ñ@, ÔòG!Œ+ 櫃TA ðáú‰ÿ.‚@˃³0Ј¿1üû‹™ ˆOU´ˆ¹pA¿ !À Ä€˜ *þ—“UX~æÀôó÷?püùý‡áÿ?LCˆO±öˆ¢ï1¨ð%]DQÊÎÀ +úÿßïÿÀBìÃO`0ÝÄ 1   kSf(†^ åÆÒÀ0`dù÷ëÃw`°ÿ¦Æÿ˜AøƒY‰ Õ*v> å&²äLÀÁýóÏp`& –? À´ €¨çv``â_À- ¿€õȯ_ €|Æ€40þÁlÉõJ`¿™ Í/`jÿ÷”@Y(L} 4ðK. ê9TÓýZþD30þæŸÀDø÷#0þ30CäßF õjÁþ5@Eô_¦?2±ü`üÊðŸï.0YCáßP½€Qõr0Ž‘,Ž˜AEÒý¿÷yw|;(èÁ ò @Dþ¾àZn@Qê€ðø E>10ˆ mûûçÿoæèßd@µŸ4Š0°ÿÁp@1tß €¼g@î€pèIaøM :IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/kmixdocked_error.png0000644000000000000000000000506411550446572024563 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ÆIDATxÚbüÿÿ?Ã@€bb`@, BJJž………áß¿ ÿþc`ccc—b ÿNÍŒŒŒ`}Ì̬*@="f@ýó™˜*€!û…!ÀÈðçÏ%66Ö ššj^†"\\¥¿ÿÉ'Ö€bÂí;&&&F°/qáß¿ ,UPÓ:‚ALL”ÁÒÒ¨û.Ðaò@Ì@V0113|úôáãÇ÷ ?~|cøþý+ þñã×/_Xøøx&ÙÛÛXüúõ蘿@ñŸ rrÒ ""BŠ¿~ýò%pB €p8€‘áÛ·/ _¿~aøùóþ ´è;ÈõÙÙ©ÑÿþrÑ ¥üà4J?ššª @Xÿùó‹ ¬åL&`JbffGžèˆ_q•††ú wîÜbàc‘f䫼¼,++‹0ŠØÿýûË€ÞD4œ @¢á0T¾YYZZN(,Ì`|ôè1ÃçÏoÁ! °¸¹9”ÿüù-Òƒ ¾Døöí+ A¼PŸ3ƒõ·’‘‘ɪªAff†Û·oƒÓHŸ à//7(A <{öR (üKÙÄ‚7“!¥x`Ð JJJ/¬««P↠ÃÇÀ¡’'(`H€r+++ƒ°° Pî70#›ù˜ÀY¿c`úód@±“WAQÁÇ'8¥¡¡ÆFMM™áþýg ÒÒ ¯^½[Ž 89ÙÁb||àô Šn9û÷O òWN10þþÅJ¾DÐ þù󯾤¤(ÊÁÁ‚áÚµGÀ`ÿÅ *ÊËðîݸ¯aaÆ (sqq‚ÀûTàùöïw¥«§˜–ÃÊW€bBMýˆü J ß¿çøðá}F^^^Uh¨/í[Ožaæz9V†•Ñzz¦oÙzåõëb@ËSì€çOŸÜùúå»:¤ÌG/þ€J@pÂ3ˆÇ –(Øÿ3|:ì?Ãǯ®_9ÌÀa¢Å°ûð†ÇS¦ »ÇTÀÀ tDœ—Ÿ!Cw¬!0tTT‹ïE‹Ö,\ÈðâÇÙŽ`#ãè‰ÇŸ˜™ÙÈððü–å¿€ù˜ HÿfQn†woßAk<6PNùøñØ!"ÀÒP[MžAßÞM_ŸaùäÉ oß2Èùù1k1Þðp†Ìïߘ--‰RœX†3ü:vŒañâÅ {^¿n†L @ÁŠâ»«V-Ù!,,šŒç¿@ þ#¿ÿñ÷ÝûwÀø‹WAQ‹…ƒOX‰€¢èˆoÀì'Çðò%0uüÈ hkË ,&ư¢®Ž! 2ÎÎ À %2\é0|öûïßñ„œ ÁIl¹Tä‚øÈ­&P‹è?¤vbàÒ @7#c#OÂÛ/_V%뀲?þBóõ?H¾vçcgïþõ÷ï«/þd#ä@€„sËćwIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/color_fill.png0000644000000000000000000000412711550446572023353 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<éIDATxÚbüÿÿ?Ã@€bb`@,ÿ‘@ì.SS†= Ü¿~1ÀÂR ‰møãÇ “—ƒƒ#Ÿ‘‘ñ8CÌÒ¿ÿfPQQaPšõùóg˜Hÿ/ ÙŸ>}b ²Càß¿N_¿~Ýäááá¦?þ\ S%Õ€b!UÈþüIú|rdd$Obb"Çd·lÙ²‚ŸŸß¨ì±æ©!À ôi5ž™™É“ššÊ †7oÞ0ÄÆÆ2˜˜˜}ûömPž•Xˆ‰Ÿs~ÿþ}WKee%Khh(ÃÇ€2ÅÀÂÂÂPXXÈ ''T× -fff¼æ±út­””TBss3ƒ­­-Ð666NNN†ÜÜ\ #‹€ 0ä(>>>PzÁi0@t0Åj-ߢ££ãYUUÅ ­­ 6d!;;;ØçÀÆÿþe044;èó #<@)–ú±€Â™AZþýÿï ÞY2 ÒÒÒàì2ðÎ; »wï‡0áÅA–±²²2pss3èëës<~üx0Á6CëÐÑŸ‰õ#Pï Ñ/€øÈ€‚9@ˆ…€ø%¿ÅÚ¯?’ØÿÿŸèëëËceej a°,ÈpðàA†5kÖ00ÈËË3ððð€C@iÂËË M’Àt2”P¹æ'0½|²?ÅßÍØtL@±½Éàá1‘ABB˜áæÍ7ÿ®_ßüèZn`ÁìîÎ(..ÎÀËË jÁ ߃‚ZBB\Ð\¸pááÇ`y:ïA… (Š@‰Ä¦ vAAAv å¯_¿V¼{÷®10ÔÎãOsó«lóæi½ÅðëÕ+† 0\úÔ×ÏœÊÕÔÔtuuÁAŒ @¾ºvíË/ÁeÁõë×^¾| V r$(Ä@Q–„ߎ: TÇÄ€ò—Žž@,@_°±]½ÊðïˆÙgÏ2\u”§'ÃÓGÀ>¥ ËÐ+- À|ò©††Ðw À¸L`‡€ä@8|ø0;¿ ‚½ Ä´üÈÑÄœÿõ« ·¨¨ö`¹¼ðÁ o•‰ ôôôÀA ò (ÞÑ1,…ƒ,‚ùÔ ¢¢¢à4²TÞƒÌz†ñÕ«W–@‡^Šß„Õ Äœõó§#£/Ð@. «7?zôëÔýûÌÌÀøÕÔÔû–ø`£;–8AŽÏ………$%%ÁéBHH”(ÙŸ={æ Œ–ƒ@%OAúˆ9Xn}Âÿ÷/¿â“' ’wî¼büð¡úè—/¯^¿–ÕÖÒûd0º¥èBfƒÔƒ0H/(qЉ‰ÓÓ»w︞>}jtÄz Üg€bNa`øôãçO Y€é€ïÛ7nñ7oÖßTQi½ñî]Ô¯¯_yA!ËbBæP(‚ /Pšºÿ¾ÈÛ·oµ€ŽØ@ÌIÀ°øÎÀðœéÏŸD¿™µ#°*3zõªë‚žÞ±§wï±±²r€êtP¶Ã–ˆÅ ý „ 2 X©£„ €˜c@q,™¾208‹30(°ùŸø?³ÉwŽí¯ÅÄ^?ºsÇŸ°¼Oj( ‡H?¨îåš7nHs8ÐBP:à+Ð÷AÂÀ,ª:îÿû÷RáÉ“í÷TTÎÿ`bâyp(U.䆬¨~LkÀl ÊÞ›ˆ9ê ¾û‘ÁIATCݦR`ѳ’Xú½TP8,G•)XWII Œ x%Å÷ ²üöíÛ 6l• €9¬ €˜~@k…ßÀ"ü5Ä{Àܪ ~Ëšo@ZXÒ3ûO âL`rpûöíà6È %.|¤æØ3gÎ0lܸñï—/_Ú€žHÿ €˜@–|ƒDÐÇ›>?û â€Ï ù,DþCªÓÀ¼LÁ@ÁKݰB©9äèÑ£ ûöíûäç=S +QˆÙâ{0:à/0Gi—' k9Àò%0Á|Æ?óß¿o¥Ú%`ù N6Pá¬åÀ¾Ä†a­_ƒ/]ºô¨7˜÷!ëÄìÉ`üâî§ 1Àò¬ (ö \g û,ÑþCƒ‰‘ñ>ÐGÀÂĘ ™AE/¨–DvEÕ‘#G¬>€YÊb :àøñã Ä¶ßa@cnakø³ ø‹Š%€>ߤ";ì°ý ô-#4ø€¾9´Táýû÷ bäå ŠÔJ> ¬YÙ ”Òð5Ó[›p%ªSÁÂR,ÛO€Ú P•ûÀ¬Êpþüyƒú€é$¨ì>3ˆ…®Ý[ %QÀD¹˜C”@ÀÖ° e(FÃú6_XJê!ãß¿Œ„,Y òùû÷ïÿøñc2PèL €àøÇÀ`¤(ÇÀÏÀøÉÀ°c1 CØô³ ×öîcØ¿(ƒ!Ìõ«ƒ¼ê3;g÷¬~ÿúZ|4È=b(++Srãaö ÃZAIä?ƒš¾Þ©S¾¿~Êà¬v% ƒ¢Ž(ÃÇÕ÷þ-gçà`øŒ†ÿ øb!6 ªªª ‚‚‚È¡@pð³3ØÉÈ€RÈr fýÇà‘þ“áúÙ |¢Ì Ò¼ÀHJp2ðÊ 3p°^g¸{ñ*ƒ†…)Ãï¿ÁzpY ¨ÿtð¿ÿþ"; €àbÐá€ù”b€XâƒfÄ+ c„ahu0¯ð‹0(©ñ2œÜ}ŒALÓ„áÛ׿_"[Š" † # Ð6 Pò=@Áðí;Ãû?$ÙPRT#'”¬< ¢< ož=cdbøÎεÃBåÐbûˆnúÈ É÷É®ÿÔ ö8²«~exùô3‡˜ó·ÿ¾ùƒb)<ñ/ VVLÜ?þ2Ü|÷˜Ð Ffäà`„¸êûg†—Ï0Xùh0ˆügøÉƵf)#Ž´€È0@ÈåÀõ·o¡¾fBØ÷ã8ĘY¡ñŸ¾‹ ,ËW?þþþ‹j Ô!ð4Jä@3ذD@ÁTt÷ÕPP1ˆæ‚Ø÷ã°HPùÏÀ/ùO€ŽûÇðãýW`É(§$tä?p© µLÀ’L ä& gþaq@Á,.>Îpýó¨ F.9Hp°€Ê$ ã݆·GŸ3<»ûáÚmI^[†¿,Ü ?¾|FÄ5Øòÿˆ,‰”¸9!ÞDw@1!EõÃ_LgØþé"4З ‚ 's0ì?çÅÀ¤ËàW˜Íðï× Ü(•vÿ˜Aê™þC0#3@£Ý„ ;¿ÍyòãóqÁÿ =À†Xêy7¶2H¨Ë1üøôáϯŸ` áÙ 5 (¹ˆ £ºd`89g ÷—å$nþýýÇðåÃg†o¾2|ýò“áÇÏÿ@ü‚Aèï`þ 9XùƒÄ‚Qs10Ì»û”Aïý†|q&ˆ FhîceÜ<@ L0˜àÙá?#Šoa¡à3³(ºˆ=8 ¥ð{p°ÿƒ¸èïXJ|Fÿýý5„Æ€¥øEM”ÿxŽ@Ä‚µÕÂÀpãä^†?ª® ,ÌÀªƒ‰…, &`ñûç#š/‘|ÿ:ÃÀê¿ÿàâ=ˆGb×¥K ï%®(°<€Õ_ _¾ýËð‹ûJáÀÅçˆ,ñ’ ;–l@XÀÊÌЖXÈ Ê© ,ö_ ªPˆ 12ˆˆCà7#J#§zä:îï_ìi €°:˜¤¹Ùi&úç÷o†×ïþ2üá¦_1ª\ôâ9 ðó2`M„RÀª`ÅT¹bƒC©/#° ÿÏIé f•ˆ ƒ #0 ±Ä?Rmˆ*JØ "€‚;à=¨Qõ4Pðêµ» ›Ÿ\eˆR6 ˜˜¡¦123¼ûÌ‚ÀPøûç’ÏÐ"HÕ2TŒŸZO 9 €ààƒ†´Ê.-Î`(­dóüßß@AvH³Š‹ó?D 5åÿG* °´ ÿÃÌGiEܬHVÍžvî šlJ@öWPÈN,,Ì BÜÀ†%8= 7<ðaálìì Àf93²ˆ¹ú‹`+þùi½ƒ|Íôû Ã÷oL OŸ¼e8tô— ?°ú‡ÑãÁÕ‚5ËÏœ9ÃpõêÕíÈòÄSàT ñ=( 8€¢‹’ÓB틾|“bXÑÀË0{ÓÍ©§€Õ6¢eBùñ%oÚù&@ðØ ÄŽ@,é“€š%1óf1pòH°ù¼úÍͰgÓ­~ †¢STîœ#r±ih-Ì vF¦]ÀX|ÿûÿ_P£f!,EŽ.€bèî9@€iLg-¾ßÿIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/mouse.png0000644000000000000000000000375411550446574022366 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<~IDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €ÜÄ"ºz☘,Fvv†óï1Ì_°È¹™á#ÿ. ̼>B"’fR’rò||¼Ì,ÿ^¿zñþÃǯÞ¾{{þ÷×o‡˜Ž0°r=caå``ddføÿŸ¨ˆÿþc`øû„áß#¸å @,x÷¨éÏ¿8!1©|k;CWWwFkK7aaIfF†Û·o3<¸ûšSQASêÝ»—V·ïÞÈ>qêôóã'Ïìñäùf¶Ý,ìó˜€Ä ¹ÏàBv+ +#ã/P‘ÀÄ•¿ ¼À™SìêjÇðøñ.†wïv0ñ)jËö}Q3f­Ü{íòVΠÐÚ Ô«¤>Ù_ÀÖ#(Stgóòò‹ñWAAþGwî¾<=kÆÁ¤ÜÂé> ñ©`­ÿ¡ÁÂò(Ÿ®^=ÏððÞ'Y;a..n »¸¹Àl^^6 Ç?}üÉÐ7qÙïήM?¾~kaF 0Jþ}úÿ(ØL€;@Ϙ‘—……A„•A‘CãÑCÆDk›t“ìœ~†OŸØÙ ¼}}‹áæ•×ÀT¡Ì &&ÁÀÉÉÀÀ4“h!Ôœ@€ÄA!r Èõ{÷^z²qåãOXØ€¢–‘ñ=ÿ?Wì#sFPȃ|zæÐnÞ#ûwß°æä–bxðäûŸ ïŸexó\ˆAXPâCvˆå0‹xBæ66fâ çŸ1G”n¼wë^(óoP ü;Â@àgd„D;#$šõôMÍø…¥€ÑÌÀÌøèãÓ ܪ lÌ`Wþ¦£¿¡Èþõ‹áÇw þŠþ„Ò@l`(Å0wF»¿°˜h¸þù¶ €Àøù b93$ý‰‹ŠŠ±žºò•áÌõŸ ·nd°0Õ`ˆ‰e°²e`øþá7Ô ‡À0ÈŒïßøŒþee`°¶”c¨(-Ìc`bt‡å€ç‚ë×Á 2 øýû÷W†?ï¯2<ºû€áëgV`BºÍà`ÿ…ÁÍEŸáÀ>`°u23Cño`âf„D!$Cr0,”`ŽdF[H #ÃÚV­'ŽÞ² €À~þTô˜+Þ¿‡ÉÝÓ§N=yù惸ˆ&0n…Þ¾ýÂ0sÖ%†ªÚà Rr_\ܾ}¹‚AQàúúAê@bß ”~‚ý‚Y˜\@v4σ,z@úûW/¦NËúöùÛ{`‚âû’‹›•áô™— é™{~3¼`°°†8ú÷/;à'$ÞA–~ù‚ŠAb õ ¨ÒÕÖg”– Y @€ÒÃo¤•aïÓ×ý§MMxûñË#>>QpQÊÅÅ,Œ~2”aøøé1ƒ*°Lù 4ô×o„å?‘ñÉÐ…?ƒ‚œª9È*€BTFÿÑÁưçÕ³û³fÄ]~þê(ƒ¤”,¸Lgee¦üÿ ­§=e–8Ÿ >[Ž” @~þ„À>00<–ÂÏžý¦ 5„Zþ‡bDH\ùúù£ý¢ù9+._™Á ¢&ÌÿÀÌÎø˜¸fôŸgxঠ*õ€}÷ã'RVüñý»w ¯_20¾;è @ø€îˆÿ ˆÒæƒ3;c­³KPˆ«C2×/†û'ÿ1Ü;ñ•áë«  ìÀ¢›Á,\€A-–‰áÕS`|0þcøøþÃì¹/nÞ¾æôÿ÷ëDذ(`Ab£æK`{)ÃÈÄÒÛÞÚGXUÚŠã§ï—¼ ??°1Hj°1h~gxþî6þÛ6lXèû/YÌìÜWÿ|»Æ@Ä9W” :DHz°p³¸ËÈÉëKIËIòñ rÿøöç÷ó§¯Þ<|ôøÜO_—2°ñ®bfæø òÈÄ8Ð=#€ðV1@ ¸hÀ@î€pây‡S ëÓIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/view_fullscreen.png0000644000000000000000000000356711550446574024434 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< IDATxÚbüÿÿ?Ã@€bb`@, ‚‘19‡‹©Žƒ‰ûßÿÿAbà€a1Àˆ&†^ÿÐäaúå1ô12þýóáÏÏ¿“þÿŸ×@Œ (àãM{ÚØ/Å+/ÅðõÛ†¿ÿ€jþuý:çˆþÅPö¨²Zý™”2Á4H=HŽ…‘áÃÓ× æÎ{õëë q€‡7+—„Ž2Ãq öoCY bù‹0æ˜å‘,ÿ‹„Ajƒèÿ¨jÿmüÍ!ÈÀÄÎÁ ² €Àø÷éï—/Ù?AÂdà$_ü…5Îþ`#«ùuØ?¨ÏaòÌ@Ã~üšÍ2– € i€‰‰á×F†•k0|ÿø˜4ÿ32¡Däpd£æ˜ÿÈÌdd„`dµ@W€LüÇÂÆ -˶ˆ¢™áÃ׿ ÎR sdþ³²201Èù …@i†¿_¿1üûójþ”ÍÈÄÈÀÄÅ ÔÏö>##Ðù@Ç3ÿùŰpÏK†%×ŘÁjˆâr&†ßÀT",Âàª,ÌðéÐ~†‡óg Ãïÿ_ÞÝ~Ë`X×Ä lcOTÖúså"Ãóìf)v†?ìü ß?ýaà÷ b gÿ ” 0 nHª†øðÉšÍ ":Ï´â.1ü³žKQ‹ßÈ §… ßð? oÁfhé1ü3¶cøzw+ƒŒóq¯Ï ÷ׯƒ8(J0”d&Fxsp°0p³_gx<ó"»Bƒå´é ,  Űf9ÔG€â[º¥–á¿CÃÅ8¯30ñ PÂüω€‚†#8`€éÃÓ9¯~ ”1èt¶2@£ ›ßá4²cþ}ùç×…†r†Ÿ&} çú2üüý®ëßD" ˆ€Áñ÷?"eý{ýM'‘A¥«Gcó9²#þì_†ßß1¨Ö20éW3¼½÷ƒ’¡¡Ù” b@ArРε@4/›]Uès&"}ŽHA,þ}ùÏ Q_à |ò$ÃߟßÁz@QÀÀ ± € ¹èš¿ÿÙœS_§Ïa–‚ ú±&ãƒÓÔ!ÿþý;WÈÌì€éã?$ Q@Ðr€˜W̘>‡”¤ÿQr²ã`b~þbøËÌhA@,ˆ4@ÀêÿÈñÏõ9°âúûê p¹ÿ4ÈrHFØ F° @püùLjZ®¢åsD~‡øæK„o A H™K¤ÿýò™Á.ƒ”¬@(‰ð?#ñ>GÄ7–ÄM°, òÛv`üÿ{KÐ\@ð’ð/RxuêÃÏ÷PJ9dËiXჃr3°2?;X»€ËXe@f·¿ à„æºë3g1üýôƒÁaÅ"pVû-å£:=ü—†ÿ@)‹‡á°@úsæ(Ã× Œÿ! &h¼ åXðñ0°¾]Êp­¢”áßo  Ðÿÿ"û’ø »ïAYû?ËÆÎk} ¬òœ ~CBRC| @Ð(`f€ÖC6[´2åø¾ö1Ü)/cøJ ,Ì`_!'>Ôx‡ò!Þ&¼ Û›x60(æÉ2übãcøûû74 Á+#€bBI„Ð `üùáëmY)wUæË= ÷’RQò‰á?(>ÿ"Røß¿XâhÆo`1|µ¢’áÿµV¹T%†O_4¾•€ÿà-TX r"d„–Nò‘Á oÖüex~ Ø$0±cøuï#ß«—8ll˜þþלŒàv $¥3ÂÊ(`ÉáËåË ¿žßc`WŒd8¿›áÿç ìž6ÀÒ—‘\ºƒ²4<‚ðýëO†/Ÿ¿30ê›1ˆXBê`\r1ýgøóã;ç7ãhhý‡'Hhþ±å=§’ ƒÞŒyÀÔ,âÿü«ý j’ýùÍð X"2ü炇@Áê&^^v†ó÷Ø"zïCjÆÿ ðÒñ¼€´þ1@äÁ‚Â^32BÆ€h[üƒ•@33#ËÏÀ4ÆÇÉðÜvÀïŒÞ½yËÀ-/ÁðîË_°&X«Þ f€6¯‘ZÃ0þ?¤–ñDóÝŒÿà~Ó÷ð@`üúÇ0ñØÆƒùÀ¼É ODë¹UŒ¥õ‹Îÿ_j#01K£? AbÄ8ÐS€ðÎ)@ ¸ Æ ŒåÀ…IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/noatunback.png0000644000000000000000000000255411550446574023360 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<þIDATxÚbd0žùžA€þÿÝÌp.+ÈúË@ `<“H6qo`8›@L Ë·Oõa¨J6ZûS ÈW ‘åù@òžªpAuŠ1H$ˆ5ˆÄúðáë/¸Rf*[l$ðq³)4çZ2$ø¨38û &Ë@`¼ÿtÀoªûXd1;dE3d‡ë0ˆ °3üþÇÀðíB@!ð‹ªñ Šã[3y†êL+M9^fF†ŸP‹¿!y € FÁ—ßT±<HNá(Ïq`p3“bàÚðù'0šžd¦8Q.T$ PxžÀÅÉfhÌ¬Ë Ì ôÐÌûï2C— ÈG² €àøö›ìxe«G†”Hc1vpz:ÿâtðýjz xøò‹¬x.PP–ˆ‰´d°Ñaø ,=Î>g`øø·VtÏ<  ñÜÀ'À£àhÅàg¯N`çžC 'Þ¡Ù@`€âÿç‚ëƒâ™ÍÁÀJ—!×2| W^10¼üJ|àâ9 Øÿ¡OpOųœ¶CPˆ%ƒ–;í· 'ž’žl@ÁÄBÀ×õ xæ‘”°u5f°1”bxû Xˆß`(ä€÷hi €XpXìn3c7uv Êm·À ðäjI@¨`dàaЬYÆÌÆf,¦«Ë``©Ã  ÌV—_aæF2ðÿ?Ã@¡…“:3Ð ÁÁ ì¼¼ ÕÒñ'8 ¢Ð!0@LhÆ>ûûëÇç»»v1|~öŒáíwÜ©`9Zøþ‚8œÀ*’ ‘ô—á|v׊?\vlÑ:†KÛ00ýûÉÀÅÎ@F· €ÀLÄ7V"œ­X3D ªYO.]m{~ë•6°^Ðu4§bÈìH &˜ØYHdzéÎçXÿýö!ýÒþS×õ.cxzãÐpBää € `C¢ÁÅÂY ŒÌºßß¿iÛ»dûç 363|~ÿ™è!\ä€H  €à!ÀÆBf²>›þ‘áB~5߯†/î=Ù¼´c9þuÇþþž>~þGõ,@!¢€•ÂåRé]`¯Êáïçó/^žQ¿œáÄÞË ,̘Žà@² €ÈKøÀ…ü}@‡þøü!}÷šã&T-c¸yõNØÜlTôl Jߟ©¼ù¦mAï†Ý;>¼ù ñ,B!@AÊJÒ¡l JÀbýúù{‡ëó—3¬X|ØEÔíÄÌÓˆÚù÷ç —JÒ¬[4é êu»1°pÏæY†¿Ÿ³²@±0üþ¤ÂðñŠ3XÁÛã7AÍ6ZK¥»€¤"ƒV½'ãå jö@€.¯ÛA}nIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/actions/compfile.png0000644000000000000000000000262111550446572023022 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<#IDATxÚbüÿÿ?Ã@€btssc`dddؽ{7ƒ‹‹Kœ©©i?ŸI†õþüùóÿÌ™3‡>þ±k×® 1€b””d`àááïïïûïß¿ÿ„H ÿýûŒA†ƒðïß¿Áø×¯_`üóçO0þñãXþàÁƒÿŒŒ¦B„ˆåÅ‹`“¤ŽŽŽÈ70I€±q‰â#‹±°°0¨©©1033›ÂB €˜À y€¾ùt9Vȱ‰ƒì"L €˜À¤®˜º®TŸ¢[ŽÏ ¨ƒ9 €XÀä_°Å¸Ù9À\`aõ0.I¶Ÿc@ €X„ù!)YDP¤kÝr†•Ž1@Ó Ä~3˜k2Äyù20!0ù‘m9rHƒ@±0hƒÿïoF}ÉNÝ ,_~ÿÿÀˆ#FæÿŒ UkÛDü휾}ÿ†¯¸â[z€Fœ@, üï>p±°ñýU¨IŽaÐ`Sgø „È€—‹áþûG wž=``db$9þq‰@±0pü```ee`ecþóêç#6¶ ¿ ¹L B@'übü ÌFÀ4û2ËÑ£ €X€ÁËÀú›™‘á+Ó[†·À ÿÃð×, Ì ßþ|g8ôúÃíw×X¥XÀ®¢¤L@€‚ä–ß¿Y™ÿ}a~´òГÿþüûÍðèå†÷.0\xs—áá§/ |\ÜÀ,ÂÀÀÉÆÉðõÇW’ ®t@,ŒL …ÿYËüad{óë)ÃOæ`Ã_¼zÎðîã;6¦ß J" ïø™ZÆpùé]E}†`S_†_~‘UF ‡@±0³üî¶óVbÖ3’`øþó ÷ŸŸ€ùý0_7/ ¨¶aPÕúËpêц=‡~2XÝwc5óÇð±e²ˆéÃo³3'ï_þùç/ƒ˜¨0˜¹¹¹4;;0q²2ðqp2HIr2üûý‹Á\ÉŽa~ê`Ùõ‡¤¢½„…€bb`e<÷éËWçýû÷lß}™A›h9³3pr°3 3éÃ\XC¶f¯g–eøùûÙE3r8¯±0½fÜø¯àâò ×b`fK..NNNv†_ÿ2¬Ý|‰!@"ayêB £¾ýüFt$T( ãã_¦nv{Žp†Þi› ì7ûOŸ–-?˯ÓÄ0)¬œè~þþI¶å0€ÄÂpXèè@ªƒ¿Àüßè]Ç ´Cˆ¡gr=Ë6†>Ç9 &¡ ¾×”XŽ- ˆ…áÐGß!ÅÁŸ¿: Ï1›AGJ‹››ÁTÁ„áý·÷ °¢‘RËÑC € 6Ÿýƒ’:?ýøÄ`«bLé>}ÿDQ[[áƒÄ‚^SÁèo¿¾QÜ!Ôº€ÂêZ´Šp¥€Âp¹ )µ"²gZÑS acÁ E@€bAíà0’ärÚP;à])€BvÀ_P«Ô"æää$Ë„Ôspp0|ùò…Øc‚; €pg„ ¥¥¥íyyy±v*plr¸ÔOŸ>áû÷ï[`|€BïUJqKÁÛåÔç€x>Ðà €º{`ß—5öb´IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/0002755000000000000000000000000011550446574021430 5ustar jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/network_local.png0000644000000000000000000000425111550446574025001 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<;IDATxÚbüÿÿ?2pvvÖ³²²ž®££cøçÏ¿ß ÿÀâ0uê?”ÿŸáLÿ„0¦‡‘‘ñßß¿Œ‡Þ³fÍšŠoß¾ÝD¶ €XЀ¥¥UgQQ©#Ðâ?rþýód#ƒ 4•‰‰ʆÐ`6”cˆ + ƒ­­mÀõë׿>}:(ñf@a8@FFV“™áÀÁ K6žcúä/Ð,&¸%K™à€XÅ‘!Ç¡’ýæC\9ƒ¹±ƒ°°°&P•²ÃþüþËðÿÃëw_¤•ŒÃí¾~ÿ³fÃtÿAÏvvV†û¯2~ýÅðýço†ÿ@ :†¯?ZqG@á &` ~õ¤ ÌLPG0“г @Ï2üøôùo ç8ù‚ÇÀÎÑó› )áb€Â™@Ä—Ÿÿ¾|ú}¹ÿA–33"¢ž5|V X€!õˆÿ2Bð?˜Z””Šg@‚(ÍÌBŒP6+(BÙ̈tJõÿ –3þ†&Fhh1cɲ@ø :P™ ²‡™‚aŽap¢Êý9àÄ× ›™þAŠ &&¼VNüýÔühàO @–-ge)6ˆVpƒ‚èó?@ΠÚ? ô¥‹ ÒõÎ@ l)à/0U ós2¸j?b`àø ÌÏÀ¢h#84˜43$hAlP(C”ÿÔÍÀøÀZáÏÏ/ r ¿ÿbw@a8€……™åÐÅÊJ² Kå!µ0.™ •¨|€ÐL É2ÀØaóAlF`êeÍ/ï>cŠ…WXŒáõë7 y W†=zt—••ENP@©ª…„ ˆ ªÿAüÿ 6#¤8åòßÀϪ¦Aä&p[à7Ó`x0*!†÷ïß1¼|ùT«ýC¶ €0°pá‚¶¯_¿J)+«Èùò嬨ÈÌÌÂÄÅÅà tãÿÿÿPŠbü`dùòù;#¼²„8è!–cÇŽ¾½xñÒQ à;dûˆ½EÄ©äU ;­"‹ß¿ÿ€ôÅ`0³ññ ‰ÛL@ô¥À¡òóçÏß?¾} 4â÷pH[Cÿþ1Ÿ‚/^l*= Ä Ñ/˜}„-ü6Bn‡„„JUUUJ‚‚dÈ¿ DtDìX Bÿ‡‰³£Dþ/(=1|üø™!##Cè€ã@³¯¢[@6À UJ  Í;pbƒ7Á€Ió;°±òêÕG>>npqõ9ÐAŒ Ÿ>}@ÀļØr@a8àÇ ¿€õ?Ìÿþƒ;ƒ,úõë70…;–.@Í5`Ô÷ŸŸÖXÅZ" fáLjÒÖÃ@Žàà`cPR’Zø J 2ä°úfcû ´œè¡ïxÍ ¬%!ÈÅ,@®Û€aÈ G˜ÈbP(â$ÇÉÉ ­¿ðt ¡Á5+Îò €0l¹‚ –÷wìØe´èr‚%HE<<Ü,¬¬lŒ¿~þ6>¾üæ€? ÆrÂ9¥,oß¾ýr6F6k–ªÀrÀä&´Âã »@MC{|xxœèá#'æÏ›øòøÁÝ[€ú^ü‡mÒüû(þèèí@‡È Œxõê˜fcc»###3‡ÿa ~‹im!&uK–{²¯1èü¸Ê`Áùê/0máâæÞÌÁÎöh#$1ƒB“ýÇ (ø‰-#@Ùd!(^µ´´"%%¥cÂ_aê~ücûíö}‹´Ùg»ÿÂzÀzØjº~üo÷!åó?­ð±3íÀècÛ·oÏ´ƒîBi;#Ù @! --ñéÏŸÀÆjŸæ rÌß¿Rù? 7ëŽG ÿU€q¬˜ôæ_`…ù™¹@Ö×ä·Mœ ÷Ïà`gç`¸wï6Ú5«@ñüè €°ôŒþÀ]ùë×O† ®ËrVx¹ð‡‰‡Aáþ{©ÛÀxE50Á½»Épí¡1Ã{¶+ Ì??Aú„¬l oÞ¼%XPâÄ• à‚?~|eúô®»@ËÙa ñÛ_æ?nðk |dxý\þºøœaÑîµooï?ñ•ýßxyJJ>||^"€ÂH|||p€qÈ ÌF:@®RþVÔÂúœ ÀF’¨Ñì¹ý=ý‹á"°†¹ÂnÁK=+€%Ã5 þ€- DÛ­©3¦IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/ftp.png0000644000000000000000000000621611550446574022732 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< IDATxÚbüÿÿ?Ã@€bŒÞ? cþþe``ÒLÿX€ô¿?öß¿< ¬¸þÚrð3èò³*³ó°òýgüÿÿûçoï¿|ø~÷÷ç¿Wnþ:ÀÀÎx’áæï¯Ä8 €A!€×?~ñ30ýÎÕâ6s”75Ñ4`0Ògä•`àæàjùÇðþû†{ï1œ}v†áâí+¿/îpöóÙOËnþ[Ìð›á=>n0‚}í-¬ÌÜ寮dçÍ`ÏãÍ È ÁÀÈÀÄðïï&fFþ3|e¸ýÿ2Þ7¶ÛÍpfýÝK~¬fxÀ°—»€–ÿÿ[g)TkÃê+Å ý[h-##3D) Ã`ôüýÿ—áÇÏ ÿý˳1r0ü`úÁp’q?Ãöç+o8ÿíÚ‚G] Wþ·µýAw@±`8éßf66¦ÇlÉï@;Çß! ¼ï^ÿ ¶““…™…ƒ…ƒá×ß_ Ÿ¿f`d„†˜úÈÀ„¦Œö ,|Àd:ŸK@’«áXç ^†Kÿë€ ¾![@XÀXë%^`à Î`öÆ›õ?ëÏ€–01p³sƒÁÎÆÎðß}}ÇðëÏ/„À† êLê /ßú1¼ÒxË`Qü¯øDÇÍ_ ×€Ò¿`êˆ ªê ßÿùØÆŠÕ‰›r1è¿tF0ýxÏÀÌÎÂÀÏÏÏ ,(Ì *(Ê È-ÆÌÀøøýÃ矾üüÆ 6(T¾þüÊðâû #!}ÕÇV ‚¼ úé ¥ÀD‚ìP€‚8àÐßþòKkòöŠ:12JÝ3`á‘føÁò“Wˆ——Ÿ—•ƒ•á×ÿ_ ?ÿý*ýÆðõï†_>2|ûþŒ?}ùÆðñóW`¦ùÅð˜.¾|ýÆðåÛw†—Ÿ_3¸)¸1ü8'Ä `-ÉÂíÄ^ÉÀÊ  s@èa  èOTFi²˜#ˆ…л(¶žÑ+ØØØIPP+AX‡îJœ€Õ/üÿ>Ãíbí¦û]Ãó‘zDYtÒ¦hRÂ7ؤ@D.+çûÍ®T¸Ê‘åRR Þüëmmù„„Æ=æ4Ïr3›3aeว’~ýçU2à þ+üáí+F†íÒÛ¤r1Ø1;0p2q0üfüÍ‚˜ÿS9 Ã{Ï>|Îð÷Ï_†Ûwƒch90½zñá×Ï¿ ,LÌÀ´ÂÆpïås†E;W3œ»zžó5ƒQ ƒ ým¿÷Ë¿-j»@üa°Ñpä5¾~ò-Ÿ0/ƒ€î÷»n~¼Å`ÎgΠΩÎÀËÊËðhðõso^=ÿNñ Ä÷ÿÿo0ýùÃ/p6dff'ЧŸÞ29}ŽáÐÅS ß¾~æ[Q†ï×þ1¼¸ÂÄ ä"¡yvë=;†O ·ì6ff!FÆW'ÿ1(g30Ø~22<Âmo·1œc;Ç Æ«ÂÀûQ„áÖáÏ |Ü œìlÀ‚uÀrä0±~ÿù“áë÷oÀTÿŽáÆý >>`øøî ÐV`©ÊI÷À2æÑ¹? Š." b÷,X @`ðò0éñ*³0°ò03<Ùð‡AØì/¯ÜoV&†?¿~3¼øõ‚á݇· Lœ €>{°ñ '/ØçŒ 70þgø T÷X ýdÀR’‘ƒhç«ÿØ…~ºå0Šn}cÐód`fýw‡A € dWúüøû«¿þ}edx{‚_ó/ƒ¨ùOa­À Ô¿ úA+†áçߟ ϯ|†Ð?ÿ1üú,‰‘‹ XAŠÊ@wüùòŸèyQf†¯„¬øž_þLWÜ ì,üÀäÌ@`°ó±ð~{´èvQ`¼5¼òŸáÓM`É™üŸAX÷ßo€‰ *Ì Zñ< ÊŸ¸€ú˜–ÿ?3°p0¡D g|{üŸAH…ñ/3ƒŽ0³3ò 0‰ë7fp.à H"z‘•‰…¨‘ ZDÙÿö?Zû—á×û ¦˜ÿýføõ› è[&fF`9LýÊØ X1"¹áïÏÿ@Ÿ³0hEñ1°þà`¸µåÃ_`åêcÄ $ø˜þƒŠO&€;àLJßïYX™åX8† Î@3ü&žŸ€þƒ*`0C10”Aõÿ6`šúõ^Qýû zU^~N†OOþ3˜:)1ð°ð0èª)3¼ÿyƒáç·¿¿AJìæ/o~Ýee&B^F. ïaæ×• ¢†, ŠÞ@ß³€‹lPŠÕ€0üŸÿP=`}ÀÄ!ÌjŽ| ¢¢ü œ¿y¾¾Ö˜Ÿÿ0ðrp3pýãbxýòÃÿ÷ À,Âð €Àþ}ÿêÛe.¶ Q†Ï€S÷?`õÊŒWqu &FV`°ÿzú/¸ò\q@*?&6Fn±ßÀ¢ø/+°¥ÀÊÄ ¢ÄÁ ¨+ÄÀÏ,ÀÀËÆÃpùýK†½Ç/1°sÞdHdaxùíÐR†W ¿8þ=zyàýão?4õD~3ýaøÇò—AÃX’Á3I—AQYœû// //3„fâaàb^y`¢â–@( ÉΠ¨.Æ ) ÑÇÀ,W€ `,äåy®]ºõ‡á%Ã-ßã?¾œ:µõÉ…¤.3‹s—Ÿ0 ð08Ú2ücÿ¬Ý€ÌßÀ XÓC3&¤2¦~Í ,Ì`§oÄðîã'}y-†̯nìxúèÖË ´(þùíÍ©'K^T³°¶Pføò‰‘AEP‘áå—7 ìÀˆýÁ ¬T€©ñ70€âÙ èbB[[q`#…ØŒde`ÿÏÁÀtÀ[¦ï Šr ²òR .ŠŽ l‚_Jçüÿ{îÿy Ö @ü €iþãÛE;ç\N-™é¡wâÆS†Oï~2ÈðI3|úý™áûÿïàÖ(À‰A`„Bf`òg†/+Ðr6&6`AÃÉÀÅÌÅ ¨©Œ*`4üdP–’a˜r£á‚‡>3Úød-@!ð÷ϧg—­žyz]l‘-ÃGVI6INF.†ÿ€!Àò Ü€9œ!r#Šx™m f>YNi†]3L˜°ðÃy†í@·ïêþ ² €P›d_?í¾¸ðr»$gsw© ƒàO%†×L¯¾ýûÊð˜mA¥°`e² YÎl”ró07°¸åeågzâÄÏM =µÿÞ¯ú~÷›ÚîÀô¤UŒÚ¦cal3ÍÑ)TV Íil–#_ÀÍ·?ßÁiÔ6EÈb`Ùˆp°ýò=3?;¿õÝ\†Ì¾²¿§¾Û l&Κj¢Y@ 8ºfœ Â|­Š™z?çÜìùÿåÿóÿï€påãuÿ/|¸üÿú§ÿŸýŠý~÷ÿ°Àÿ¬u~ý6Äþ#À›ÿwþ7ŸÏûÏ—ÂùA€a'ÐÌ D· €°… “3[ƒ¹{’¡¾¹“ÃCæ ß~ýcxöù ƒ§2¸ ¹ÿõƒ:¿*ƒ*¿"ƒ¾°&ƒ?ö{f¬_Äpiù½û —€–ÿû!ŸC@ásT“&7k,Ÿ¡°¯š‚¶€ ;£ «0ß³K?`¼|üô‘áãK`¿èÅO†·¾þ¹{ðñ#†+ÿ.;J ÔJp·AY›ñDج–X™ìØÍ™øXØùÙøY@lŽüúùç÷¯ß?ÿÿôû5Û¿·€ITÈ\⇰Ԏ ±@D °t¶-@í¨Ã˜¡½ P£ Ô#Ö‹ ïpù¯Á±(¸òV®IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_yellow_open.png0000644000000000000000000000427611550446574026034 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<PIDATxÚbüÿÿ?Ã@€bhЀ; €Ü4à ÆoÑ ¬ÿ´30˜þecûÏÎ.Ã,$¢Äþçcûî÷³j/0¬­ÔaøÓfÂÀðñ Ƚœ@ÌÆÀðé+ï ìÿÿ1²s2q²0Èüdbg`gÿÏÆ!Ã*. ÌÁý]mÂúu…Çæíû…î€babbHbv6ÄbìÎÍÀÅÎÀÀýhòW&†ÎMF/ÜýüçÃN†ß < 4ÔþþcþÍÈ Å!Á,Ã.Î%Æ "&Ä$¬*Â,"-Ê#ÀÍÀÀt3ÐI ov00l9 ´k/ßAw@±°¨ó–2Fiq3°‚äï20üyÃÀðû/‡ŽšÀ±$Ñ©"ìßþKЉó Éð3H³0 10ð10òs00p1#Ð2 †Ï@ü‚ÿÙŒ?xž3H 2ÈE‘ tã`h˦¬Ì_W20|—j†3#P-£0Û*0¨º )0€´p‚b ˆ?ñ }@üÿ#Ãß×@a Ø e ?€l`dþ…4ÿÈfùÁ *Î4ŒAîk 1›5š30Ë·G¿o±ÿ¯Ì è ÔóbÉ!߀Áôó`t-`|ÄÀDÀŒ& :Æï7 L@= } Gü€°¿'%ÍÀ'ËÊ ÿø7 H±ƒ!Ð+@mÄòëÃC†o@C8€.þô0’Á†1}ñï/ÐÀ¯PK¾A|Åø ´`K¾C} u ˆýï$@ù %N61FV)öÿ’@°r3üÙ ‰1UÄôý Ãc†—"ìÌŒF ÅŒ@çýÿ±d0’…pY†Aôõ%0@|V&F!V1 ‰»ä€~ýÁÀûï;ƒ$P’ €X^½c¸§ðþƒÊo¨?ñ °Ï¿£Zr(þÃBêkPT0|XþdÐ=¬ Ì’Ì jDEf É2þa˜(ã]† €bi¸ÂpÛÓçß,?sB ‡1Ø!? lx¼Bù ÐaP<ƒ| Òó߿ߵ½ Cñ04ÿsÇ7VA?ï_:ÿÝtþ C@X¦Ìføûòƒ>@±x 1¼úwïÅ+¦ÿ_ä€áÂÀ ˜#`!Áôÿ Äù·¡¹”Ý@øÐçÿ@ÑLgøÐâ¿L@1 ›áÏŸo ?^sÐmÌ@áË»>ÞþÏð €X$Þyùö-ߟò_AãäkP9ä 0«}êþôá¿÷ Ae†3S+(JòLüÈÿ´ü7P T^…þ‹˜ÿ¼Ò`Û†@›®Ëó? ¸ß| ö#'ć ¼ÌLˆŸ_10<N_€:¹ (Æ”ceäÀ þ²”¤ÿAÄþƒÀñ9ÈÀ4ÀÀÆÅÀÈ)2˜€ÅÍÏ _2\ª~@,ûör½øÿ@ð°ôâ&L`Psëý«@|’W@¥Ðp\ƒ‚•ˆÁ^b&¨åŒÿQŠX€¸ÌÃÀ´(ç , W/1|>ñ‹áPä@±”ƒC€•áºö OeD!…Ð] ã.Ÿ:h)Ðr`á6Œf Ô‚¿Ì¸ðT0ññþød1(¶!¹¿ "hó_HÉÂ`šÇ̪œ@¬f­kÀ\µyÃ`˜ÿø.ÀðõËË¿{ž}{µá#Ã1 îg°ª €Å€éêÐ F­Í Û…šXä«îW@Gðmä•dŒÌùRø€jËŸ@ö; ýîÃ÷?ÿz÷ûÏË·ÿ¿ß}ÍðùÁe†/>2|xý—á#°øz÷ä7ÃÛÿ^ÃX§3œa€äP©Ç@ŒÈÍ£X.Ÿ™ K8Ó˜ùžãó=Ðeïÿ ¾ÿ ?>Mx÷÷çÝ·ÿ?=zÇðáÙ†OwÞ0¼ø™áÝÛ_ o¿þgø,'_ËÉç@] pýˆV“Áj³ßÈv#z-”‹!ÌK‰¡ðÝ_®—€eáW†wÏþ0¼ô“áíÿ /¿CRï+¨Ÿ ø+4NC+¿Ä¶Šˆ‡˜<KA ý†„a €¿¤X‚Ѐ÷ hÀ@î€pW X­‡š©&IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/file_broken.png0000644000000000000000000000417711550446574024424 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?Ã@€b1ììì”UUUg©©©Yýýû÷µ,`ddÓLLLŒ¿~ýb>vìØãÇW~üøñÈóÄ"@8..nñË—/ÿÓì۷ᅧŠÊ: ›D@ö<tÄÄÄ`Q‚L#cd1tyBêYYY xyyµ€ÂJ@ü €àøýû÷_ûß¿D[„®ŸZ`Ô‚ìÑ xáÉzœ¡kÅ!3Ðå,ll Ð8Ãj9L ;;;//333ŠZ˜YÈv€@1áò53±°0üÌåI“n¬XÅÀÌÁJMpy=@šáÖÉ“ »&NdxÿîÖ(Av4@± ;f È×?>|f8Ÿ“Æ prÇo ÇoÝb0¯©f`bøtØoß°ñð0œ^»–áu]ƒ<Ь=‡3X¶·3ÈÊË3|ÿükÔ€@a F Ï¿þÆp1=žAæî íy LjÊújŽ55½ÊÎÀ T󨬠 ?½r%ÃËÜ\W£… \€ñ}¸´”áრl@õ ó±9 €àEEEg@Ùä×ïßÿéÓ)ñÿŸ»1ÿÿ¿þÿÿo>ÿÿÿúÝÿoí9ÿ÷r0üßYQõÿó¯_ÿ¿ÿøñÿ;Píþ¹sÿ¯øÿ!5õÿÿ'Oþÿ÷îÿÿS§þ?‰ù?/6öÿ½Gþ¿}û(üîÿóçÏÿ«««ß= {3  ñùçÝ`œrÃVáåK`6ùÊÀ˜Ç`þñÑŽ6†ß¿2ØO˜Àp~Ö,†·ÙÙ Ž üyy À¸gxÿl¯€ÃO`|ýú•EØB €X0R?È!@¬Ú=áZRƒZS(ƒhúQ°áÜ© Ößþ0œœ:‘aÕé3 ¢çÎ280ed@,¥ô>-_ΰêñcåÊJ)II†ß?~0°€¢ )ñ‚@a¦ þûó'Ÿ’ƒÚü W¿ë3<ë+b`¸¶›áˆ§x¼ÂŒ““Ôe0sscNL)oÀ3ܽËðfÚ4†•÷ï3È–—3˜ÙÛ3üš‡^.À@±`Ëÿà‚éÛW>ií¥[.Å1|›PàSÄÀ$cbk{aqveeHò=ÐOÖ¬aØL€­­ &VV ?¾|'@t»@ €à!*¥PK8F`´cà•cÐY¼–ᾊ;ÃÍ“~]<ÈÀðé ëW  Œ øúüßÍ› ÷/fØ,'t»»Œ--qZŽÄ„­C®_À<Ì/! ;u>Ã¥ß O7Îgøuë"Ãÿþ¿xÁðè€ßÀà~¹aîׯd**L¬­á–£›‰^ý ¡òŸXÿúûŸá0Ñ)1=e`fúÏðdû*F&~†€îgdb`êeúÜXR^:䵉 ''ÃÏoß°óÈ &\i\ÈKÿŒ, çósxWu2(Ôñçû†/Ïž2|zô˜áëÓ§ €Ùì/0 (‹^½cÇv  ·Àa:â?Z„ Ä„-a€ë`éõç#Ã…œ ‰£³”€•çŸÿlÂLo,¬Àt䲂ÀìÅÔóTÇ 2Ø^½Êp º˜L^aÔè!@ÙL3Kû®d¥0È\˜Ë §Ì°Ê˜ÍV2|ùÃÀpLD”áÅÿ l  ­é~õ+‰Š28CæPc#à `a†$® Œ\Il wkK”,a×Zþâs6V ñ˜Ý¯›Û1˜îØÁð9=á0®Y¡úAÎøt„‚ˆƒ70N÷÷3|&H&P6Å’ 3 €00Ñý¼‡X c,2™ ¨ú°°»aåÌ`8yƒº¾ƒyCÃû´4†›ÀÜÂ2¿li`%õçùs`.ý®´°D„ `ú/ƒ\c/Ã…7š _žƒâh9Ðܯ@>÷d0Ÿ1‡AVAŽá+°àaª·mjbø ‰KPG°sÄß_¿³¥HTƒ°¼€Ußè ¬!ðXn èk3ÈL^Ãpñ‹çÇÀøÃUOãISDÅD~ )p¥´ˆXÔZSþû„†³oß2|Ö «¾æIIa°tueøi†aM„³(þ,h5U˜f®a¸ÙßÂð“‡Á¸°‚AHDá0Û!òo ¬ ¯+ž­ÀV‘¤¿?ƒ°@ú TûÚCoI@amÁØ¿?}dà•“dО0 hÈ?¦ß?~ÿ޵Á %z¡¡ êÀÄúXŸ|[3›g@{ ~üe.HNÁR®Ãø0‚,eéªý‡£Bfr0’ÒÇŸÈ>ÄVý"ûžÿüùÈ«[…LÃØØøÈŽAW®W€eˆý)G<€}¶3@lh¬H¾ã[°aëÈb:,r ‹9€•Uoo/¨‰ö äg@1"Å¡O»”””)PŒ š# v:‰ÀÎ)Ã?˜?~ü˜%7…íy@ÈQÀ²Aˆ¹iØ#ùü ?Úý Àm ™;Å8"ÝIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_sound.png0000644000000000000000000000625511550446574024627 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ?IDATxÚbüÿÿ?Ã@€bdˆ>aýùÅÀðˆÕ20|ùË`ÂÏÍ #)ÊðïªÿþýËÀÏÏŸìââÖñüùó»gÏžÙ{âÄñ]|||—¾|ùòH30333\¾|™A]]áæÍ› ööv wîÜa—W`xýúý{÷TUUnܸÁ@,¸\vëÖmyi †ÿÿÿ¢;€ËÙÙ¹811^äß¿"/_¾2¿sçnÉ¥K¯>|èÌ‹/ö?{öl'Péc €Âî&&†Oïß0ܼu“AMMáçÏŸ`aPt±°°êèèiB”11HJJ€0›­­µ~bb’>ЧɧN~}ùò¥SW¯^Y÷êÕ«“@‡Üÿóçï7FFL«ˆwä03<|ðAAAh)3Ør „……ÔÔT°jáââ`ÐÓÓaѯ_¿{?{öÜûÆ[oÏœ9u“——߯_?vüþýû,PéY @¸ôÝç/_€ñÌ ++ vÀŸ?¿Yôõ -77'0ž•@XØÓÓÃêåË×VW®\®FÕ»wïì>þÌFFÆÃÄBÈ PZPUUcøõë(AZi“šÒY€¶HK‹±£««£æÇ_4÷ìÙ›”ŸŸ•@L„4ƒŒáÓ§OàÔ/%%mª­­Å‰O=(WãËÙLLŒ ‚‚¼À¨UäríáPvÅËß¿¡ ½€‰,üãdž‡÷ï0°±23)«¨Øˆˆˆ€³æ¿¿ÿþƒÔÿÅ%ÿcPBƒ$¶ ¿~ÿeøýç4úþ‚ñß¿¸?}úô>|  jF†Ÿþ1i0±ñh1JË•ÿe¸ÂÍ(Ñzœáí…®ÿW–ìúÂÀÿŸ…KÆXOÓâ‹¿`ÿù—áÓÏ ¾þax÷ùÃûo¾ÿÍpçåO†÷?þ2¼ÿ Ì5ÿÿ0LˆbãçdøÔ*#¾~ýÉpêÔ±wß¿¿ @,À0³6’ž`*Ê''Ìϰÿì#†=‚÷^lÛíô…=Láζ°‡ÌÖÇdD¼Þ1Iñ¬<þ†áêãO Ï>þaÚËô$;+3ƒ /ƒ ƒ;ƒ® 7+/CÏŠ³ Ûžeˆt3aøÏÄ r>ãGOΟ?{ȹ @,b¼%Å*|lÀ¬öñ0øX ”r[uÊ ¦HÿÐŽ[¨ëšÆ "þ_fï >.¶ ²b‚ ºj âüÌ üLàl wP,þ†ð·ßÀ¨â¿À¨`çà`xúê ÃO`T2±1ƒ£æÆëÿïÝ»wÈy@,LŒÿØßebàÊqS«¤€ ÃÞ³̼ÌfLf¨›8CE‹Ÿ!Ç)AWW’áëw†Ÿ@ÃþXŒ†¯@‡£ŒA!ò 迠Ц0vNN†WÀh¥%6&`núŒÿŸ€Åö  ÞÓ‡Woî¸)ýbȱb`Öa`ˆ±da–fXüt-ƒ± Ã܆†W&§Â&1,Y³Ÿá°ºø,?ý€Xþ÷?4ýþ‡°ÿ‚‹k cþCB‚——“á50}|ÿöœÆß½{Ï,˜î•ÝâoÄòãÛ·'Ÿ¿übâÿ l<Œ Vòö +.õ0\u—AGH!Í'šá”Áy†¶ îÄ1dÅ2013S9Äb°ïA–ƒè¿þ`|bA>†ß™>|úÆÀ-ðŸáÁÃ{ W._ÿ-P|Ã÷¯½ùÅÀ Œ/þ ÔdªfÆðç) Ãk–Õg(oŸÌpëé}†àz;†M<³úæuƒ½ ÊPÈ–ÿþ‡ˆŠï@Çýš%ÀÇÍðé7 û_ÁY÷â¹Óß¼ùø€AØò;Ÿ @öôÞ«÷?Á¥Õ/ ¡_€A+&¦À öKIö/ƒ¥ŠC‡Ù"É³Ö ›ÚO3È»‰0leœÏ°{ß`–êùqô/¨ÏA4(èAlPJŸL¬œ Ï_føñõ=ÃùÇ¿ÙÙ<'pMcøýC €˜î¬yüäíïÏ¿ šüFƒ¿)Ãûÿný8Ï #+ÃP[ÄÐá°á÷2q†÷òOvÝYÃðí3ÐçLŸƒÒÈ×`ŸCÓ(A«v†7¿3¼zþ˜á—&‡j@˜,ã×[ ߟhƒöë{Oß¾åiF&PÜ©ðû-Ãk±G <`øLýjšê a äné1œz½›áîÓg _€ ò=P$ÿõÄ!¿ Ñ hââácxÿåÃÕ»Þ3 0üzû‘áûí÷€RAÂêý‹—o߃Rõ_h6ú4HRX™ç­ÃGùçÀ„w™áņ3žüåc0“Hgøvÿ%ÃÝ·¯Þ-þ Tÿj1(B=Â?r"âb Ÿ¾ýd8{ï Ão6!†/oýgxwåЈ…áç›O¯_‰¼x÷ù;0¼~ó(e‹‰H0Èÿ6`x-r…aû±= ÜÊÁ Ìœ, ,À ÕÖôgàá–`àQ;Vù€¨ÐD ÍO 1¼¹õ‹áÕÇ_ Lâì n{ÏðçÝM òwÄÄðó9Ã×·oŸ½ÿúÒ4üÇÈÌa —ß02¼å{ôÿù«^¼üÈðáý'`5Åt„;3;7ØÇ¿a>ÿ( âÿ&ÂW¯¿1\½÷‘áÕPÝÇÌaÇ (ø@, _óŸÌcP¨I°3€røò[†õ—†Ñd`z&ÈðUñ6íÏ> *3p|úÂÀË¿¸Ù%('¸¸eae†„Â?„ï*†ç/?3œ=ùظ`àeÿÎÀòõ3Ãï§Ç®@ ¢Ä j¤ß¼ó˜áæÓù ko¬døôÿ0>™þ~geøwAç-Ã×;'~ÿ·¦z†ŸÀ þÌälÀ–4ûçï ì ŸØÙØ€bvc •ì_ +.œ|Äï­È0sÅc†?,þ¾~ðùß·W Ë߀ @, jÓ€I]ÿÇÔ³3ôƒ¸J|"´yÕ¾1|eØþqòûO)ý?°¥~ŠáÇG`õÊ ¬tAE à þÁÌÅ XÆ_?˜€Å-Óß7àF'7í«ÏÔøxeù@y›‰W€áË…-/þ~Õ_A `"ü%Ä r(߲Ė¡A¹‚A„A”áýÂà,ìÀpžï"Ãéç/¾ó]cøùö1#›Ã?`ÐþbfFH>·jÙAè0~ °Æ»õ”Aþß7mU†c¯d¤D½ùÁðõÞÁ›ÐàÿÒ@À°úÉ`ÏgñDð Ã’Ÿ+Øøþ3þcx÷û=ÃÍÏ.¼Ö¬ ¿¥0|F« °^ÿÏô<0™`- hNr~),ï¿0DE¨3\VÚÒÀ„)/Äpþøž?ÿ߀³ßS˜z€baàdÔbàã6»^3,ù·ƒƒlâO`ûç7(g½ LhÀì<ýgøj30ð‡ì&fHb…È ´øôæc)>†Ã·2Ü|ø Xë|›ÿÿɾ‡ ¾^*ûs@±0|øyŸá1P+‹ Ã_ ¥_‘» Œ\@­˜ûo8ï1ð ºD˜ÿ310ýû nü¶–~þÄðóË[†?_ÞýÿõùÍÏwnßþíùÇÿŸž}`øõˆ?}`øûñ=àZðÿ‚Ù@, §þ,cyÍÀÌmÀÀÉ);áMX þøŽéƒðï`{Çðöñ9†ŸŸÿþóõÍ÷?Ÿ_~ùóùù‡ßn½üÿíå+†?ßÞ2üûùžáÿ×—@úP70öY˜ß¡ø ²ïA € ±'Ä`À`ÂÒÇ ÅkÍ ÌË.‰@û ` r‰ó5ÃCÝŒþ½þÿóék`J|Ãðç#Ð` k †}„f©wДýêC&Ø9 Dòafcàeð&`é,êþ5úà(Õ‚J®÷P ¾A}óÚ‡a²@€Ü™w:f¾IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_violet_open.png0000644000000000000000000000453611550446574026022 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ðIDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €ÃÃÛþÿcÒþûÁ”…•QŽƒU†O€_éïïÿŒG¬žué⎵ÚZN ü¾~þÀð˜h989ØÙؾûÂðóçöÿ 2±q ±±°Ê011ȳ°³È³±±Ê *³qð¨íß¹´îÔ©µóöýBw@±000%™ÛO26Vææâbgàââ`àâæbøòì?ó3~£KWö|þýç÷Îß¿þðüþóWã?#ƒÚß¿ÿ¤ÿüû/Å/",Ã/$ &$Ä/$"Ì'Ä¢ü|| Üœ\ œìì ü<< ß}eØ·kE(Ю½@|ÝÄ")'WàïÀÍø™áã[†Ï¯Þ~g``b™?zaž­Så¾Iˆ‰‰‹óò ð°ðrs3ðró2ððp3pq²1°½Áøáï†ß?ÞüÁÀðè×_ïþýæ`à‘Ú%Šì66nP@,ÿþ³Þ>ÀÌÀò•“—ƒ‹› è!Ÿ%†‘b~9ff`qÁÔŒ*†?¿ø/Ð2 …?>20|ŠýJþªùdÿÊý9èÃ÷÷l ÂbRÂ@­BðxgdbPW÷axòä4@±¼|þâ–JêWe vn†Ÿ?À¶üZð÷/H!3Ø ï/!ü…%[ û?3”f„D$Ø` ˜‰•áÍc†O/„E%ùØÙxäþúRù‡‡Gœ—WhÇ/€bùúåÓÃo¿¿3üúËÍðýË?ˆ¡ÿ¡¾ùÏæƒ,{È 1À,b3¡¶Cõ1@Š‚7 l>~aVvI ظ¹Eþ¨©y=ö@1}ÿúåñË×_Á†ÿcú4àÔrˆEÿ 6€ƒ¼ !xpÿGrð?¨CàÉE†¯ï€ `hòp 1²²r03³ýWW÷YÎûçÏOIPR –ÏßÝ{ýö3£,Âðÿ@Ó@¾[2ÇPŸÃèÿŒ_ƒi&HýúåéU`ð?```…Äg~y19Sef¡™‚‚J‚ì윒þü½uk{@±\¿¾ûþË—ñßp‚#41-……#„f`B`&fhð3BÒËÏ/ @9è0Q¾ ÿ†äŠ¿@qnV~uM~n nn&>>^†K—Žüýñã£>@±ˆ+½zúäÉ«¿Œ òàha‚Z ÍLÅȱè/0›}ûLý@ŸþøÉr?Yö;ýç;Dï åÿü¿@þ_ :®Ÿ\ Œ,ÿ¾|þÂÀÂÂÆðù3 Ãǧ>þúõé%@±ˆKh¼ýêÍÛŸÿÉ3À‚h1ˆff‡d§7ÀÄôê$Eúè÷oh̲L@ TÇÄ  ¯ÿà_ Ãþ̦L_YX9>½ÿ,E%è÷· ÏŸŸFÃ5€bùýçë‡ïß¿þõï7##8ƒò+73Ðâ¿ —01¼8ÇŽ6f–ÌÜ@eÐh[ÊÍ!Ù˜á'Ä€füÈÆÀÅÇÁðüÖw^`ÜgøðáÁu ªÄòáý6Nž_~ü`àeâçVF†K+~0œ›õ—á÷'6`ýÀÀÆÇÎç ß1~ƒ&D ÅLÀB‹‘’v ‰ÿÿ ‰.F úç§>2Ü縬G4À¡÷úõµÏß¾½¹Tþ €XîÜ=ôÛõ7ï¿1ðð10m¹¼öážï ìÌ l\„ñç "ÿ…˜¡–ü:€ŒLHÙ ÿøß—ÿ gY610J|cøùë0ý:àòCPðñ'€bÒÐðaà`|ðüÕ+6nF†—W2þŸÙþ]ýXþ¦…?@G}õ ¬Ÿ Ùë7þý #É3ë‚ ?w2ئ 1èjk2ü& ?žƒBà6Pö¨d &v`uúäù‹W¿™9.­ÿÈðíãO`ÐþFÆ(þ Æ`Çüø6üÏG$ ÌÞ#ðïËï¼¿Æ ð€AQVœxyù˜¾~½ÿýË—7·@Á 1€bù «?=zöìÙ×/ïîýÌvL@_ÿ†8$bÿƒ‹¸ÿ LŒ¢ñ7 ÿ?Ì LÀD Jˆ ¬ O zŸ¾`øât˜!ÜÏ„áîõÏ ’RR wï]c¸ÿij?~]?H=@±¼zuبøýþÍ[›7ïžøúõ #ÐŒHͦÿp‡üÚÌÀÉ Œk`výÍd3‚ÓÃH…Átè} ¾éª /ýV½ <Àø? ~PÐß„5NˆååË« úÏ­+×Oßty«"¢+Àðâô[`ʇxçÐRf éÿ€ã?`µÌÀ ,b!¾gee`ádaE°°c`–î¬â ·ÞœbøÀxáÈ9†çÏÞõþæý¯=ºòêLJǀ&?ƒy €€fpíùËÀÌÄ­åè•»=,¨Lîzëc†7¿0°³òÛ\`KX€vQ åÀZ‰ÿÃ_®o _Þ0|ý÷†áËÿ×ÿ¿þ}ýçó—ßß}|òùå£;¾¼ÿôáçoÿþýþîׯ/oýú , ÿ=Úyšþ€@ŒÈÍ#^YW¿‚%Î6)üïNbøò÷ ÷ÿo¾ÿÿlt¼cøôãÕÏOßž}úôñå‡/Ÿ_úðþùû¯ŸÞ½ûýóÇÛ¿ÿ|ø÷ÿ7Ì` ‚˜<@%Æw$üR?"@1¢·ÑxydÂdô ÿ0þàúüñÍçß>½ûýëÛû_??¿Ò/Éá4„&$þ Shi»ˆ‡¨^‚ú ÿ€â¿¤X‚ã@÷ hÀ;&4à w@€ñul5¸§IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_print2.png0000644000000000000000000000560711550446574024715 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< IDATxÚbüÿÿ?Ã@€b$GSkk«³¬¦éÚÿÿÿþºsí®—l~øðþ;w½Jÿ%Å,€"Ë“f-ÜçÅÅÊÀðêý†‡Ÿþ¿yýÚ“û·¯|õôÁ®W/žظqÓ}¨cð1@‘ì€ÚšjQC{ßÛ.æüèr@·0ÿfxóñ'ë¿€ì_ Ÿ¾ýeøñç?Ãów?¢ÄL4„~þ8H1=´ÿÇçOŸ® ƒÅ=]ÅE¡.Š|â"\ "À¤,ÀÇÎðèî²ÉçÍ.^ÿÍ*(¾++%ZÚñÞ~úÅðhÁ×~ýýTÉÈÀÊÌÄÀÁÎÌÀÅÉÁ &ÅÇ ÏÁÊÀ,(^zÇpîÚc=%>Pb`†ù' wíÞò莻ÄÂÂÎSiƧ ÈÂðò3(·^{ÎÀÀÎÊÈ  ­ÌøÆ¿g¢¼’ò×§œ¢|¿Å™>10psr1È ±i :fffH°þßCð·_ _¾ƒòÃû¯ÿ>™ÙY˜xñÖ+†KçNÞjy @, Œÿÿ^|ñá+0s]ÇËÎÀ /Ìn@ÚB†Ÿ30F€‡AàÁó¯ R¢Ü B\@ €†ÿ Šc`è3üù N  Àgøý’àþü…8ˆ‘á#Ð!Ÿ¾ýfàZþhÇ‘cÇþ¾{ûú¨ì –?_>ß6úamÊÆðî+$ñ<¹÷ˆáóóo ߀ªß ýõëÃk`°æb¸÷ÿ·  ƒ „88uÿýMX åƒÅÿAB™••áÛ_&`hübàÆÈ1'÷nzL wA †__o¾|û˜@øÀ>ûöõÃˇLT€©™%uó4Ã_ ·÷9ÏÀÊcÏÀÎÉ ö9Ì! –ƒÄ@¾zšèëß ¬ ?ÿd—Õ_®œÜ²ü †ÿ¿nÝ{ö•áßHáø ¨“——‹A-»‚õ7ÐÆXX¯3üÚ µì/4øÿÀ‚j9ÈQ D÷…á=Ѐ¾¸rþô¿OŸÜfà’ùÅðíÉ€:àÇÝG/?ýÂsù¯ß¿‘ Ÿÿàü  Ï,>þüù g„: ÉP>(‚hP´ü• l >&D`¼t•Çm¢ƒ ßÇùYÄÄðïËãç¯?}øKH@ƒÿýû‹aùï¿ ú/Ã_ þŒl`)Ox Gƒò88õñ¯¿H!d3³s€³íÓ§¯üˤ”-ÌÎü‘‡áÝY€bbx¹ûÝ«·__€R3+0'|ýöƒáû÷o`‡ûü8Èýü tÜ?`:ù ®z?-øÔ÷è³? 9ä_Ш€…È03ܺyáÕO6†??þ1¼?¿T¼ †·'þ}ýôòþž{ =e¸{ýƒµ‰ØÀ:Œ5 Ãÿ?À"õ÷/f6v†¯o3ì[ÒËÀ#¥ÌÀ-¦Â ¥nÂÀ 9h°ÿA²D³³â»·Œ ¯ïßdøÁ&ÌÀüî-ÃïG‡ƒ"@±¸:ÛÊHœÔ•degURf°ÖÓd¸óðã·?>ãô–ÿfÅ¿¿~1¼ýøƒA^I•!PW•áÕ«— ·nf8¿á ƒ²g6Ð"N†¿¡9Ùl ^aøp듘;×G×ÿ2|¹Ê oˆ…‰£<75ZÅÄÌ ˜~1<{ö„ù;Ó/À û,åX€ÉX„þf§Ÿlÿ>Åþó‹Å9dä5ÔµŒ¾-ÃpãÌkOpðÃÊ€¥ä«—ߎ½ÎÀÿï;³œ÷Ûë߃ôPö@±HJJº(*«2üøñ X12|þñ›á“ Ãì /¿²1s(° bø 4TÜþedbø/Å`ú÷;(l~þüÁ ­­Ãp|ÿ `ïɪª`–ƒòßÇ\gøÎ,Bÿ 01²2ü¸»û)PÙP9@,‚üü<à¢æ÷÷ ¯21ìÇÃpá:PÅgFp*gW±B äÁ? ©ÊDø9…»””8×ÇÎ]ÁÀËà ¬#889Ø88ï»Éàn$Àp‚M†áö­ç ¿?üÿûõ%Pð¿âOÄòãÇæ«W2ˆŠò3ˆkÂçßø6cagFH#Þ’d‚à÷Œ¼ þ|c&¼Wï¾0~·l _¹€± j6A†o¾0üx~›Á3J‹á$°ŠU‘ãexúŽ™áó͙ϡÁrÀO€†À÷×¼¼œB||ü gÎcØ·g °=ÀÃÀÂÌ®˜˜`Mœÿl jÝü¦´ï@žÈ ##ÏðýÓ†o@ËA…Îÿ€{uë>CA€ íOL âB¬@ß‹0ìÜušáûã`õ¨¬ –ß]geý¯.**´ç7ƒ€Chh(¸ÀapdñÍL„ß¾}eذa°þf¸yõ;0K1°0rÃóÛ/X¾eØ{‘áÞ“G ,¿>ÓÈÛ?ßoî|ÿÿûë› ˆ¿‚’@±¼{÷nã£Gw õ45!ØÖ˜µ¾ýæiˆ#@4ƒê¿ <<\ ¿Ñ#/¯ÀÀÃÍÊpõî#†×¯dþ3ØòëÇ«Û?>?½ñí÷‡GŸŸ¬}þ‘á÷Û ¿?~`ø÷ä@]·K †´™÷ €y€@VV¶NMMÃKGÇ\¥¼<Xpüú¬pþü× ù b9Ä!ll¬ /^¼`˜àîîÎðû÷oFFFZfbbÊü‰q322jiiæ|üøéáóçÏϾÿáÒÇÏ+*ª<øùóÇë Nÿ™ƒË€ba üû÷h¸®´´ì”¸¸;†oß¾‰?þÂìÅ‹ 7nÜúzÿþýÇÏž½|øêÕó Ïž=ÙË,€"É Pøùó'?;;G©»»gQ||<§¸¸HŒƒƒ“AEE…AMMÁÉÉûË—ïœÖ¸~ý:Ð×Úb3 €ˆvÀß¿QñËF^^¡'""ÊÜÖÖ,öþý'Ó üÏÀÂÂÌðáÃW†Û·Ÿ3¼}û^‚@B —ˆ(Ó[£‹‹oNxx$‹Ї਀¥ &&F0~ðàÃÝ»ÏâLÀPa9ë8ÁàÄB„Ï­$%¥&DFÆ™š›[‚䇟‘Tüg`ffFÃ_†G^2¼zõ L ììì@þ‚‡.@ !!ÑUSÓ`*,, Òw þüûä[ïA–úô•áéÓWÀ„øèk6p4°²²1á ‚*¸¸¸¹dd$xxx€l†¿‚ƒÿçÏß`ß¿yó•áåË÷`µœœì@1Çu+Ø‘ø@t0~ÿýùóÌæææcPœÿøñ›áôéë@Ÿ¿úšl93}¢ €"¨d(Î7m:Âpõê=°ïA¾âädÇ/(¸a–³°°€ùÌÌŒàPaBi €ˆÈŒ`ÃAàúõ‡@¿fPPbPR’û……n1ÌRPúÉØ„¢ €˜ˆ)|þüùö9;;+ƒ€/0gü— @)ï°¬Ã(Àï€b"¶èÅ=;;0î³â_ Àu4ș྇±A4(*@1¶œìsPŠþúõØRR1@-f€²!Y ìJÁ4 ~ï=<̉ñ ûwŸ€–ÿG¬€Y ¢!lD(r@•ÿþÎv àûäD ³œê{ÍÊÊLÐt€b!&‚ò=(áýþýl1¤-“GD̰B @>8 áL DD]ð\ú13³Á$ €Õ ¡¡åààæšo [·nÖ À| 4—ùD„þ3<{öhà/p‚|J„ ì‹ i)ñðp3<|ø˜aÙ²%?·lYsäýûW«€’Op™@Šw~~.píjx@Bƒœ+@¡)hþƒ $ff†C‡Ž2,Z4çÙéÓGvÿþýc=Pò Àe>@±.ŠÙؤ¤Ä@48XÿüVBÿ˜À–ƒ¢% Çýøñ“aûö ÿW¯^|õîÝ«kZ·ñU þŽÏ|€"è€W¯^Ýݳg¯®‰‰ƒ¸¸('‡0ÃÍ7—€­`ƒƒ¿AþaƵ_·m[{ìÇ7 _oâÄrÄH¨U,((¬ÄÈȧ®®éeddªáâèÄË®ú—AN^Žáï=>†]{÷kÅÃvîܰíÓ§sZŽñ;,µ*Vóˆ  • (O)±Ž¸˜´šŠŽ…¥¥µŸ ?ÿ¯_¿‰ôîŸU«–LúôésPÍ[P!ÄÍÍ L°œÀrCŒáÊ•+8@Ä6Jñ ¾ùòÕÓ@,úâõƒ¤ªªÚj11Y†£G¿€*¤¿°ì¦¦¦Î §§®¤nß¾ƒ×`€"è///†ï߿ÊØÿçÎûüùãûÏ2ŠÊçõ-˜¹þž>÷ÿ×_°åÿ455tttÁ9†ZpáDÐ|||Àrî?#¤qÁÀ`fiýŸŸù×?'þ×òÒWg2üæËÏ'Xöñþ¼Ã.Φªª ¬´¾0Ràì ¤ñ¶Šˆ •vËÉÉ ÿå;P3±þgÿøŠ!Œq¶Š€Ê[ /ƒ¿œ£‡rä.4kNN–ߌn¨5ŵzõê@EuÐhÄDКšÚæ¡¡QÜ?~ü€³Þ¿»7Øs›¢7ÐE ŸŽ1¨+|â“ LÖa\ ÿÿëP!¶ÿA .Pix›ùDÐOŸ¾`Ú»÷0¤E2;ËÃ' –¯?0p½šû“›á×}†Wß1œÞš…í/¸l††°ðúÌ& €:àðá}[öîÝaÌF µÿÿ"ïçŸÌŠ¢o¤D4O±1ü ûÄpþȶ¾beù÷‡^Œ³°Ý¿ï¨s…Ë|€"X Æ¿.¨’ƒ&&fÒadÐædÐýËÈÀÅl›ÜýÁðú)Ãi Ü ”Æ0|@YhÏ læ ò½omu™OIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_green_open.png0000644000000000000000000000457411550446574025622 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< IDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €"XþÿÑf`üoÊÈÊ ÇÃÎ%#*$¬ôõïWÆ—{ÞÍb¸È°–A›ùƒ3×?@-ÿ8l6 ¾o¿ø/;PH“Aˆ…A†‘Až…ƒIž—[FL\D™‘‡QíÖú‡uÿŽÿÔü ÝÄÂÀô?)ÈÕc’¯±·—0ƒ00ƒ(¿Ëï/byS]|ø™áÏß ¿þò0üaÐZ Æðï¯4P¯”€8ŸŒŒ¸˜Œˆ”œ°‚ˆŒˆ¬¨¸ ƒ0Ÿƒ —ƒ”°$Ù7{’·”‡mÞ ÔsÝÄ¢®!WÚÝÂÍÁ*ÊðŠá%çߟnýzÄðó?ƒº¡ºÀç¤OSÕÔ¿ÉIÊˆË ÉòK H³ˆ Š3ˆ Š2ˆˆ2p1p3ò003°â?Ћ¿~€É_àfâab`äùÅðMÅ ÄÂÌȺ÷#Ðqßø¸™8¸¹Ø™ØÆ±2š19ñ)Èðˆù\PKþâ/Ão þóïÃo ~Ïøhõg þ–ÿûÿ/˜þ ¤¿q|fàçþÂðM)â˜4•þ?~É@,¯¿»eÄ`ª,-¢Êðùç' #ßÿÀ†°s°3°]úé0®?€-`dd„c ÿ ˆ‘á?#ÄÿáÀø,÷êç †OL?D¥øù^²¾–ºšhý.F>n`ÒûË@,Ÿ?üxøåû†Ÿœ?¾ýûÆÀÄ4ŽbÁ/Æ_ ¿ÿü†dF&°ã@dÌ'pO1"8Lÿ™€¾ÿÍðèÛcnva1>V`àI HŽ? ªòÀ´ü¤‰ €˜~|ùóøþ§» l@Ÿ²±²1°°Ó%3ÄÿÑà?p,ÿ‡;ÆG¦Aľÿã>ç¿áÀÆ (ÆËŒQ–ÿ ò² ?yÿ~ÿ' 4… €XÞÿ½÷øÝcf … ˜% ˜/ÁAÎ ê¿@bƒêoarŒÐ``ü¡ýÿÅðèÇ#†—?_Cá篿 bR Œ*"¢‚3¹eÙù„Y%~g½y÷@±0\ý}ÿÁ“çßÿ1þáüä8 D™þ‚iP4€03#3Üb˜CþûÉðèã×?_3|øóœŽ~ÿûÍð˜~ø¹4Åtl½Euxy@!ÂÁ°kö«¿7?ýÖ AÖWï¿xÔ ÿ˜€‘|ò-(M°0²0°K)HÊþ ¶”^@¾áß@øãß°… Ä Êßÿ~:êÃ÷ÿ?X9€Q Å_1°1³0¼}ù“áæÞÏþÿz €…2憂ðÑR‹Éèÿÿ‹±é !¤j¡m¨Çö¦ËÝå»ÇÑTfœ´>¯£¥jŠ_št+« ­„öš„C¥Y|ˆ%D'Ër2I —ÜG¦voQ‘©›Á¬'Dɱ 7ænS‘¢þ@, ˜>¼}õåõßß¾gúð8ÎA†ƒ,Ýøj#íï·ÀñÎÏÊÏÀËÊËÀÃÌÃÀÅÌŽ÷ÿÌÿÁ–‚R>€Ò (øAøùÿ'ÐßøÙ¸9¸>}øÈ ,ÉÎpÿ0µ½þr¨ü@±0|üÇðþÕ—¾}dâ‘bøt1Ãæ›V?_ÍðXÈð°ò0ð±òCå׿_ ßE èE 22AÒÄ¿ÿÀGÏ_ –wïÿb¸{ü?ƒ‚ Pÿ¯ß ÏÎÿøÌðëÛ% òWÄÂp÷=Ã?VÞëOÞ?ee`ÿÏΰõùV†i÷¦1p±q1p²q‚ëŸo¿!²#Ä6&6pT€ç_&x¢'À¿À”,G~þúÅprãC†7_Ä>þgøôðÇ›Ÿ•^âOÄ ,¢Yþ=xüâ!ƒ­ªÃÅ·—æÝ,v!ðïß¿ðBäsP(€rÈ÷ „ wÔÀ„ J”ÿƒ™ýÃ… O¼Ì­.JÞfxsÿÃë; Ÿî~¾ TzcÄ,o™÷瓇_ÿfabbÝüx3ÃÛïo„8…–CÁ`éõè{& ïÿ³Á.+™à…(þ³ÿexpâ=ƒì9Q6†WO^3p2ò3|¸ Œã/?o‚¤ €X@‰ç/Ó£‡wß}}óç•À©×§ØÙ€5ðDyð’%™™™Á48 €Y™‰R.!¬(…ë?†ÏÏ~1ü¿ÆÉà™`ʰ÷ËNME†›ç10°‹bd߃,†9ÄùäˆßŒ öB-—VÀ²ã#ó¿|Ýβdú' '­ÊpæÙK†Ï·?ƒ‚þ&¬q@Ì _ËËßÿ¾°qZÊ[³é>e½Ëðúýg&f¨þC,Ò ‚ê#Ї@ÌÌ~L¬ÿu#;+7'ƒ0'ƒ7/çcÌ O/üaxÌY—·¿dx½óÃ¥íþ¾»ùìåÿç¯7Ýyhôgù¬$X å?«–l€Æv¯ ¹=w.1¼üð…‹‡Xy+)`RVTܬà\ŠÿÿßX~cñç`ÖzûïÿŸ·ÿüxýûû×Wß?¿»÷õï??ÓÖG`j|Çðóç[†¿¿_-z´ó 4€Úw Ĉ’ʸ|”Â5—˜äpò?ýøŽá×Kf†ßoUë{&†_ï@–ýùùûÍO¿ÞýüðóýÏOßÞ~ÿïów ¿¿¦ÐÀÄ´äÈ’—@üˆ¿1€2ƒ›á7²•ĈÑLåãT*düóëçû_Ÿÿ}ûõîÿï_ï%È[†À*Žáÿ+h þMH ü§  D"@1â“5:¡†~CÂ? ø/)–àÄ8Ð}C€ðŽ @ ¸hÀ`Lä}Äc{½IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_midi.png0000644000000000000000000000567111550446574024422 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< KIDATxÚbüÿÿ?Ã@€bdßÍÀÀÊÆÀðçÃß¿ ÿYdÿ_e0ú½‡á?T 2ø TÃÏÏŸìââÖñüùó»gÏžÙ{âÄñ]|||—¾|ùòH30333\¾|™A]]áæÍ› ööv wîÜa—W`xýúý{÷TUUnܸÁ@,Núÿ‹á1‹1ƒæß3 ¼ÿß1üa`Aw—³³sqbb¼È¿ÿD^¾|e~çÎÝ’K—.^?|øÐ™/^ìöìÙN Ò7 ÇÄ‚]ø7Ãf/›_k8þgø %Pt±°°êèèi‚øLLL ’’ Ìfkk­Ÿ˜˜¤ôiò©S§__¾|éÔÕ«WÖ½zõê$Ð!÷ÿüùû‘Ó&€Âဿ ßXÄŽßff°—øÂÀÂɶècaa¡55¬º¸¸8ôôt@Xôë×ïÞÏž=÷¾qãÖÛ3gNÝäååß÷ë׿ÿ> Túd ®¤ÁÀÄÈðùÃ[†ç /d•Àøóç7‹¾¾¡ƒ€€Á åææƳ {zzX½|ùÚêÊ•ËÕÀ¨ºq÷îÝçÏŸÙÀÈÈx €X$Q†[·n3¨j2]Œÿ–†††Z¤¦t -ÒÒ¢@ìÄèêê¨ùñãWÍÝ»w'd'~02üþõáÓ§O@ßÿa’’6ÓÖÖâ§”«ñål&`È ò0(**ñÕÙ’€ºþ00nþñß`üRïßa`eefTVV¶*ùÎŽÿ@jþƒâòD?ƒ$±ýcøõû/Ão Yèû ÆÿBâþܹ3??~üð € Qðó0ÝiÃJ›“CKˆCîÛo†Ÿ9„&ewaàÿÏÊÎ%c¬¯í ñÅ_°7ÿþþÇðæË?†·_~3¼ûò‡áÍç¿ Þÿb¸ýòÇ>~ÿÏÀúÿC„4ƒ?Ð_ÿÁeÄׯ¿Nœ8ööû÷ï·ˆ…á?c …Žø\=AiA6i6†»ï ÿ¦ë|¸¹)ì!³å FQ·L’¼«O¾axòú+Ãûïÿ€–ügx÷èËŒ ì, œ@,ÌËΠ,Ïà ÎÇÊ &ÀÅбü,Ãöƒg"ÝMþ1²‚œÏðäÉS†óçÏÞr_eE„† +3ëÏÀÒã;ÇÀ`df¦~5Ù~s‹Ë«0pI²Ê|-ÊÀõñƒœ(ƒ®,ƒ/3ƒ'0à˜€ÏŽ„_ÀÀùþ˜Ï~1ÏÊÎtð†ß00±1ƒ£æúõkÀÒðÞ% ç@±01ýçÜu‹‰o|À™—ƒAHs#§ÜKœA(<\E„ë?ÃÿŸ_ä$øÀ16Š-üú’d@Iä€_@—ü:â0…±sr2¼~ÿ›áÇ lL ¿~ýa8sæä§ÏŸ?ß•–ÄòþÕÛ».ò¿tŒeؾýg°a ƒX€¡ÂDï߯9#Ãk LGà´ú–f¡TZ‚Ó.D?ˆ¦# ýaøþí3ÐsÞ`8{ö40Œî‚”˯_ÿ:÷ßv†¯`в¿jlð`˜ ðs!,þµ˜Bÿ:„ \§ý†À7 äexü‰áãço ÜÀòëáÃû —/¿ Ô ÄtÚ£‡o~ƒ<ÊÀÆøŸV^ƒ &r†ŸÀ ûûÿ/3++Ø÷`_B-ý ©?Ðàÿ ͽ dùo äçaøø›…á퇯Àlû—áÒ…3Ÿ^¿þxŸAÐü+¯2@11|zqïÕ‡  ÐÇúèV`¡ÈwC} ò1È"˜zÿûoˆ<(´@æ2±r2¼xû™á×× ç~ceqÃf\4…áÏ%€bb¸·éÑÓw¾þaù ôÀ,õ¯@¡Œvp J’˜á?ÐúˈHý r,„@¹‰˜Þ¼ÿÆðòņ‡\ÚœªÁ1ò,?ï3|ª@L ¿?=»õäóÓïÿÀY˜ªÿƒ üdÿù\Úqp±-ø–ûµðËïÿ@ÌÀð(ð˜u¿CÝÏ?‹ÿ@C Ü< ïŠoÜÈðö??Ãß÷Ÿ¾ÝÞ*Þ ÷ûÊ×fŠÅîgføøñ ƒ˜¸þ ú_ ""¢ ïß¾–^L B ÌLÌ Ÿ¾|føðჀ°(Ã÷?õÄGa!!E#GǨ wYÀø ª@G ‹‰2|z~áܽw ¿Ù5~=ºóŸáí%PB|@L ¿NkÊ0Ñ×d¸qùÃ¬É ’Â\ Oï^e˜7µ›ã?Ã×wÏfLhgزv1ƒ‡½9Ã+§Ú*sÍ_?ÃÐR–ÁðàØF†»·®Cè4Mü%b„EÞƒçÆËŸ LÌœ núÈðû ¸ PeÄÊ'( ¬¡Á©_BRš—Ò®—¶ÿ€MFv [Š“‹‡APH¬NDLœAès[ÌÜÀPû ްåPú?ІŸ~1\»ÿ‘áåwPRfcøýô¨¸ÄßTýµN@I111†oß¾ÀªW Ü5>¸¸^1ÀZ0ÀFмàއ‡‡AFF†á×ÏŸ@C€éhØ×ÐtJSï€‰ïø‘‡ _>pKÚŸ Ìß¿2ü~rä Pö6( ¸:."" ¤¤ ´ôØÀúÜg••ª40ÙØØÔÔÔÀl>>^U «€‰X-¿þôƒáã7`Öý ) yú؆HV ‡˜~¾zðåß× Ë_Ì ˜@¾WSSûF öï_? NIx}q+ƒ¶¶60(ÿ3ðóñ3hii€óì?`þ|òîÿÇï˜þþ`à†ÒͯÌä¸$ÕþËf~†/Wv¿døûå(Ó€Ì &Xk—••…˜ßÿó=¨Õbÿ²A9€¨æ¬ÙÂÀ¬`@|F nN¨#Ã7f~†@_¾ef¸p÷=Û‡÷ Ʀò ç_00H‰}ÿ‹ƒáëýCw õÀoy¿~3˜‚-RTT`ðñõgEi)77W†Ÿ?1ˆ ‹w77U`°ƒ:"ÀÖ¯P0ä~ãþ?¸øõ“™áûó/ ù!ê ×¾22hH£EQ˜áòšCÿ½ºthÐSX; €Àøóë0õK‚1Ãßï :: v'30a}gÐ×Ó·±þƒõÿŸï òr2àˆÏË+à '§Àðêù 'þ20ýcf`†ÊãOŒ%¸®¾ef¸òð%ƒë7†;·^0ü{rè ï׀†¿ƒ9 € !ð÷;¸/ðï×'HSøïx³ø?‚ Ž‚¿rÀ’‘‰ =¿€ìß Ÿn^gøýâÝÿw7¯þÚñãíןž|`øþXªƒóï‡w _¯j<jÂ@ 01ÿ‡XÂÄÆˆb–¾!¦#ØñŒ¿?þy½!÷00n9oþ|æÝŸO@… †&ºP>Èo·o^ÇðáÅ-`Ùÿ‹ô6?3ÃçÏ_Þ¾{ôÕÇÀ¤µ(ü’Aë+œ €@Ηâd Ö„æŠÿdõ²!ùz-„ZN0ö$ñ½1;KIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/file_important.png0000644000000000000000000000343211550446574025152 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<¬IDATxÚbüÿÿ?Ã@€b1ììì”UUUg©©©Yýýû÷µ,`ddÓLLLŒ¿~ýb>vìØãÇW~üøñÈóÄ"@8..nñË—/ÿÓì۷ᅧŠÊ: ›D@ö<tÄÄÄ`Q‚L#cd1tyBêYYY xyyµ€ÂJ@ü €àøýû÷_ûß¿D[„®ŸZ`Ô‚ìÑ xáÉ zœ¡‡ºe¸|IŒZXz@– \¾Æë; #+ 3;˜ÿçëW‚¡†ÍL &t [†,†l ;;ÃÏ×o®”3ÜŸ=›‘‰ §Ïñ‰Á@÷ #33HèFM5ƒàÿß oNcøÁÌÄ žœÂð÷ý{P¾#˜0‘@LØâg¼ òýƒ… ?`PïìeÐËÉcx8¡ŸáýÝ{ ÌìàèÁ—xÑC €˜°…NW³Ñ·W¯žÏžÁ ‘–ÊÀðô¯˜ƒ¢š ÃåÞ&.P‰ƒ× tÇFà ïoww1Èé3ð«k3ü}ó˜“ß0è8¹0ü:ráÞîÝ ,\\ xC9ˆ _@ÖÀÌÍÍðîü†o‡ö3(ù00¼ûÀÀdgÇð_C“ùço55†kû~ýú‘p¥+ &\ùÅõ@ÿ Ûm- ê^ ,lœ ÿ¤$Ž^¹Âp›Xž 1(IJ3ðÝ»ÍpaáV>>p(àË 0@p€J)l!ð(Îôý“ X_?g4¶``Zú’ŸŸÁÑÊŠ¡¡µ•ÁË“áÇO3 #ΟÇðþÙsfvvœ–#G@1a«ÁC™ƒƒáÛ‹ &ObÐ [Ä ®ÎÀ t 0Kr±s²¸8ƒ…ƒ00*Ô^>g86¡èe¡r€ XÈܘ4‰A”“…_D”Ῠ(°aàåePTTdPTP€àåÅÀÀËÇ`ÈÎÁðnår†{'N‚$¡ €p§Pq ´üݵë _öífÿûœáÃò ´ÔášA5›Ì’’ ïƒü®?À Êü‡áü”É @å¸à w6ægF`¾¿ÖÕÅ Ïþáÿ½û ?½þˆŠÃ}àììÌlÄ@Ò¨XŽaønjÉÀùé ÿý»έYËÀÆÃƒ·. œQÀÔøhóækçD¾¾cø&§Ìð/<á×ç/À¬ö‹á0WØÛÛƒC¤÷'¨BbçbÏ+`øøó?ƒâßß ×§Ocx,¸˜€éWÖ\ÀÔðX®ß<™Ažõ;ÃO¯¾d•3|eãbøöý;Ã?`è<|öŒAÏȘ¡°´ ÌÿtÄW {ö@†ßß¾3ð^¾Àplî\V`‚Eö r F:ÀÄs{ê4Á÷O¸¿`øÌÀÉðó÷†?·®0ücZLáL@õ‹ûºD€‰òÅ•KÀÌñ“áçÏ_ ?™Yþró2¼–G’œL —æÍa¸ãê ¯¥ÅðjèÑ @µ!(Þ¿¿yËðlå2 ~ â—ÿX™ÿ3ð·ä3übfeøý÷?Ã7``ýûÏÈ Lñ?~þe¸ûýà(Ñýþóèû \l@‡þa`{þ‚á8°ò’¦%l €Â PÁ,hØ$¥.œ; ÌJü@Ãÿ1üûó‡á°Õöû¨iäÿû ÿ,¨€üÿÿÀbÿ00ˆ€%'¸òüÃðh¦šœ¼!ƒžÃ ’˜uL§MgxtøÃÏ?À9â¤\j‡°AjA#ˆ düƒÉý‡˜÷èH]`™¡ddÄð˜HY ‰9  ¶:ú/0•ƒÊsõ°PÌšÌùæ?Ø1Ù—!÷ h9(‘c« ˆWAª|þ€Z8A /ÿÕbÂZìþ‡8[™@È!Àˆ¯UKH_‹2èmL x9ðçÏF\Ý*dÆÆÆGv º:pÅL[ öohv€‚‡°Ïvˆ MLL¾ B}|ýlr ‹9€5koo/Ãׯ_?ü ’ F˜" 9žv)))S 4¡ìt €S†?~0=~üø=0An -Úó €¢T»pÓ°Gòù ~ ´û@€øŒœþœ¹€IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_cyan_open.png0000644000000000000000000000455711550446574025455 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< IDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €2 ~þû§ýãÏSff9V6^>^% ãû»g}:ul­°¥ÍQ'O†_Ÿ>2üjbagc`gecøýí+ÃïßÙýþ+ø‰Qˆ…™Eæÿß¿ò@sä9æpñó+ÿåàP{¿{[ÝûC{çµþBw@±üúϤah0ÉMO›[€‹ƒ“‹ƒ‹áí¯¿ Œ>>ñùÏï?;üþÍóëÏ_ Fµ¿þJÿgú+ÅÎÇ'Ã%!!&ÈÇ+$#À/"& *ÀÇÃÀÇÅÉÀÃÍÁ ÈÏ˰âþS†M»¶‡íÚ ÄwÐ@,Ìââ¥áÞÜÂlž~þÌðêç{†¯o~301³2ð©( (ä—N•’’ú&-!..%(À/ÎÏÇ"ÌËÍÀÏÅÅÀÏÍÉÀËÉÎÀÉÆÊÀŒÌ¿ÿÿ2|ûóŒü†ã_†ïŒ L‚2@»DQÀÃËÀðï@±ücd`Ýqÿƒ3ƒ'ƒ0+pð1p1³0˜˜I1ð;Ú*r°1ð031°21‚-ùó÷/Ão þõç7ï¿>ÿÎðhØ_`‘òçÿ? Ø? ä-ÿ ´‹YTLÈ‚—8L@×úåÔQ€bùõöÝ­(YUe[Q!†Ï¿~ƒåÿüƒÂÀÊÂð…™áïßß ïQò÷È 8à üVûÿÿ?xjþ €eAô—ß8™™˜EDø˜¹¸åÿ|ûÊ2žA\’AJ˜"~2ËŸïß~2¾-ürЧªþ} .%ý[ȵl9ÔýLÿÒ ô? Y¿b扲230ñ ° tƒˆøÏ  Á¦ÓŸŸ?_}õŽ‘ è8 Á²ü##88Áƒ,€Z Ú?@‹þ€ùúL,qÈ' å?þþcàfF/#»ÇPèð= 6€bùÿùÓ½ïß3üg‚Äß?°! `K qö° ÿÿ%þACá/ÔA¿ÿügøúû78!™ ì@q~~&Cs±™ rŠ‚ ì’À¬*ÊÀÈX@,_O½ÿ.(äû׿ÿ8a†€} xx¼B¢€Èf„¦ˆ@Á Ä tóç/°xçSበÿì350 cXÀ’z ëˆ%l. € ¼|v$`¾‰‹kó”ï©Ã/ÙEfmˆ·5RÜÝ+€XxUTß|÷þí×_¿åAAøâWX¡ ñη ÷¿~&Ò_`Ÿ2ÅØrÜÌŒ @š } 2‚õ-:ìÐrPHüø)9€eùñh9 ÃïOŸ.»€ƒ*H†aaNð0õÿ/ðAž=9DÁi§8ÌzȱiHšÚ$²ÇÖ#>h-/}* b}†óBï7ŒAP‘½+ ¢fSœÏhÎ%Qh>PWÞìIî,$GÆ·¸ØFÁçà`NL¿bùùü Ã?vŽï¿ÿ`áçbøóû0ï¯yò‚aÉã× ?€¹‚“XÒÅ€Å68X™ ™÷lÿQcd§PT€Bñ'È@ùï@ÕŒ@³ÙÞ¥yHº{ç3Ãë—€¬WÄòîèAvfÖë?}fPà'#ƇÏæÜ| v0þ ôæGÆà _ƒ,ÿ ~VhðƒÀ …Ÿ@G€B”^˜nßf–¦€Qødƫʮñ'€bñ `øÍÉõàæËW žJÒ 7^~dXzí>¤¸e9`i*?3²}ÇfÿZü˜o9³"Å?,³‚-`qþæú†\u†ë/yîÞ{ÄðïãG†ÿ7¯Ý*»r/@±° 3üÿõëÉ»·ïÿgddÝyï)×o߸¹€&ý…D,È` õõ?Èÿ~'ÐPº%TPùÊxN¦ô·1xƒ]LJ”áÈ㇠¬\Ü ¿Ÿ=ýÎðæÕ-PðƒÔË?`°üÿýûÑ÷÷￾üúCàô“WxúýVò‚ËpÎúìû?f`ü2s0'02‚£ èx€”þŠþò‰Áðý;; †¯^2ˆñ1üû•áï¹3Ïþÿvü õÄòùÚE†_¿ÿ¼ÿldôæÙ篿¿}É ˜@Þ‚š - YþƒÙÀ¶ °šeføŒ&f&HðƒBà?Ô½÷ï3$šê3\æ}P)+ ÄÏÀóå&ÃË[7@AÖ8 –/W/+À÷ž^ýè™Ê/`cè|$ËFþý¡ÿ*} ã˜YÀŽþ #ŽafM6PHùL3È}þİãê †‡¯_+´ß_¿ýýxõÚ+†û·ŽM}«™ˆ‘ذ6£Øøµ¸âR¶´±—ûûð10#ÿF2°0–bÀj™… ØðàÆ)'È2P ,;¾~e`øòéÿÿÏÀ†ÓÛ·ß¼|þù÷Ó§~}üøáû ÷¿{÷÷ó§·@üšáï`Àpš@e@1"7øTÔ}¸¢“–¼50âÿ,­Ø€Õ4sl?€9úÓÇŸÿÞ¾þôçíÛÞ¿ÿôóõË÷?ß½}÷ûÛ··À´ôáïï¯ÿýþ²ä%b`jü”ºí Fô6’j›†v῟?¸€eõç_¿¼ûûõËû?Ÿ>¾¡/ÿýûû š‚?B…Æ)ÈðŸÐâ€(@Œ8ÄäX jè7$üŠÿ’b >@ŒÝ7 ï˜Ѐ; €Ü9ÓX•_~¾IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_tar.png0000644000000000000000000000612211550446574024256 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< äIDATxÚbüÿÿ?Ã@€bdˆ9ÄÀð÷ÿf`øó‡‘“A–ñƒÑ¯Ý ÿ¡JÁß¿øùù“]\Ü:ž?~÷ìÙ3{Oœ8¾‹ïÒ—/_Þifff†Ë—/3¨««3ܼy“ÁÎÎŽáîÝ; J ¯_¿²ï2¨ªª2ܸqƒ €X0œôÿÃc6cÍ¿§xÿ½cøÃÀ‚î.ggçâÄÄx‘ÿþ‰¼|ùÊüλ%—.]¼~øð¡3/^¼ØÿìÙ³@¥o@Ž%ˆ»ðo†#,> 6?Ö0püÿÆðK èbaa1ÐÑÑÓñ™˜˜$%%@˜ÍÖÖZ?11IÿÎ;ɧN~}ùò¥SW¯^Y÷êÕ«“ÿþý¹ÿçÏßoŒŒ˜6ücøÆ"Épü1+ƒ½ØN°å@3 ª©©`ÕÅÅÅÁ §§¢_¿~÷~öì¹÷·Þž={ú&/ïÉ}¿ÿÚñû÷ïs@¥ßAf@±à &†ÏÞ2<ÿû‚AVYì f6cccg‚AËÍÍ Œg%ööö°zóæÕ­[·ªÎ;÷èÖ­›ÇÏœ91Ÿ‘‘ñ@±àO¢Œ @M Jz ?þ&.& ==uRS:0¦ÄÄ„€Ø‚ÉÊÊ\áãǯ »wïñ-(ÈJ &Bøõë?ÃÇÁ©_JJÆ\[[‹ —òÿàtÁ¸ÃÈ (ÈÌ <@®-@!ÒŠ—¿@üç„ L4?ÂO?`àâdgRSS·fø”ûT¢Áê Vƒ3,(¡ÛÿÀPûÃðûÏ_°ÙÀDÆÿBâþÌ™S?ß¿ÿ € Qð뿳)#;³ /»œ€ —Ü×_Œ¿ß²‹LÊnþòŸ÷‡Œ©¡– 8`˜þ10³Æ×>ÿüÇðæó_†Ço2<ÿð›áù§? ¯¿üeø,R¾ýbdøóëC{ƒ´Ø_ÀhdøòåÉÇÞþøñã&@±0üùín-?ÇËP„ƒ›“…Ÿ›•A˜—áÉG†’¿¯nnüøÑü€$ƒLЭïâÜ—w=cxôúÐb`¢¦TFF&Vf`ödbàå`aàáfÐe›!*ÈÁжä,ÃŽgb¼Ìþ3±€ÓýÇΟ?{ȹ@,"<Åé^Ê,@—½üÌÀðhñµ× @Cä•Ň-X,&-ýWDŠ[êÚ`¤é(i B|¬ œlL ,Œ L ôôáw` òý ýˆÙ88ž¿ûÆô-3787]¿~íÿýû÷/ð €Xþÿûüÿ#7ÐB '9”¹ŒÁ0@œ/:P†‹—ß¿3Ȉó‚“ʨ Œf†¯¿ Iç7£ü7PÍ_ øo yì\œ /ßübøñý;0]üÆÿÉ_¿~½ tÀ[€bùðúÝm•_zúRì ï¿AJR ƒ™A zÿá؇o¾Ó'Ђ¿°4 Å õ¡iÄ•À€ô7 yy8Þܦ‰oß?ûwïN:yü  €˜~~ûúäó·? ¿€Šu}:ä#`îcøÄƒ|øŸ•l8›Á,úÉ0 G!óÿBCéÛO^†·ß™>~þÔÏÈðàþ=†ë×._Z ÄÄðíÓ£GÀÌ ô)3ЗŒ¬Œ ÿÁÿûû+†_7·1|¿½XQã—•á $xa–þåÚÿР‡æà_!¾©àãføô‡•áÍû/ ÿµí™³§>¾~ó탰õ>U€baxûìÎË@r5£àçýã ¿oodàþtšA\˜á÷Ïo oÙë»´£ª£¸ÃH þç7$Ø3 ÒÀÏ¿„øJ,@µÌlÀ„øæ3ƒê—· —_2sp…¬Ëø÷ù›õCy™ÄÂñvÇçw>¼9|Eàç½C ‚DÕD´s€AÏÉÀôò»» ¯¯dx}2áÃ_Q†ß’ö ÿ½ÞSÇ÷o¨¯ý8 Pa%nv†×ÀzåÙÓÇ 9TÙ•Ý<ØoÏ­—eøþT €˜×$~+6f?æ Ãó„IIW‡ABÓŠ]€áÛ‹Ç /ïaøõì.ó¿¿ <¢ ÊÚ B\ßXmaøuz.ç¿| „ Àq ÎÐhù„˜?}Ë úç504ß1ì{+ A†—Û[Ï2|{¼ €XxÙ}lÂË™ÙdTþºÁð÷Ó¦ß_89dÅ€é”.>20þüÌ *Ž ‚Æ âçV1l={’á­b<ëHi Ë  Yÿ€Žcøôø2ÃÙoþ²ë3|xãÃû+ rà1@±|ûõÿ×ÿ+‹îÉ20ò+1°È10ðuÿ¼ ôÖ ›ÔÀEÈÿÊÀðî*ÓM Ì/Î0üfö…XòQü…âßÐÐa!†W×~ º_ Œ’l o6µ>Þ•Äò‡•á?°‚û,c`¸À´XãªØëPOPIl0y€ññáϳc ƒ@ø'@±üùÏÌ🗟“˜b€ª‰…áÙ†óËœ[Äåò‹} Àâ‘Xƒ²ˆÕ³Ì× ¿þdxñæ?ÛoVV6Hûõ"@ÍÉGÀJåêÅ— ï¿ 1ðp~e`ùòñÿïg'¯@ ¢Äntrñu# Tœ*þ@eé`ÅÀ 4‘_ Ë 0J¸¸9>1¼ÿÉÆpë°´ûóù?;''+;P#°øýÍpåìc†Ì†îyþ²}føûêî§__Þ5ZAÑ@,ÿC€‡h1¨ôflþô1Ч@Ÿý†°"8€ ì€ÿ€• Ã`ã³ãÿ? LŸiäÃ'`± j²1\¿üœÁGWˆá'?ÐÁìœ LÜ‚ Ÿn¬yÎðÿ¨ür@±€â‘ è;Æ¿•³ üX5ó/Ø |¨!ŒŠÿì¼Àøgg?†Ðæ% ?Ð? ÀŠ•áúû :´¤Îý*/-ÂpçÙg†ï÷ß=H•Â@,@!¬Ó­HHIsÀO`ͬJ€Ù‘Iè.¤†ç`… 柈,?¾ÿdàâÐ( †cÀ(ÒÆàY†SŽýbx{íPÉS˜Z€ÖäÌÀZh(°Öõ¿¿üäk`°ƒÊR ›è`Ü‚s#Ð-OÀ•ÀP 1Bž ö¨}|ý!ƒ¶3ÚƒÏ>ÿÈpáÏg†çO€‰ùñŽÛ \*ûs@±\{øñÈÎYÛÕt%ÕeX$ÄÀ5Óo`vÆ(wüŠÁÀÎðçÛ'†gW1œÙqŽáÕ†_?0üøø˜á÷×7ÿÿ|yûëçÇçß><½ññà·7¾¾ýÀðïÓ†ŸÞ3ü~ûšáß{PðŸd€T`@Œ|œÌbÿÿ…˜ªZ›È›Ø¹è èI³0:„-PÃ…áÝ£· öc8rð—Y¾]ÿ úí#÷û_¼bøöì߯Àbîç{†¿_^ãò 4•„&¶ïPü Šá1@°Î0é0ˆ9¢"êaú*îÏy<¼¹~³þeØ·y÷§<;ïÝå'Ÿÿ]úÇÀôbøß÷ Ò ŠAƒRÄ(ý—˜>@aöÖÙø€‰Î‚‹ñ­š0çy`± üþûßßþ2Ë`PB-[ð–Ȳ)+càwþIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_red_open.png0000644000000000000000000000424611550446574025270 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<8IDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €»Aƒ60)š211ʱòñÊðŠŠ*1|ùʸúù‹YÛÖº00ü ªûÕÄ Ä¬@üˆ00°õ r00±10Èüc`gec‘gåå•Uæeø§¶øæÝº5ÿþÏ*ÿ…î€bA’A°ß$eoonv~^nNN^.†wïøó*vÝ¿ÿùÃN æ®Ô£¤¥®–à—á—‘ã“•â“‘á“‘åaàâãa`ãåeàføvùÃòÜêP†Ÿ¿÷õÞAw@±Èjª”Úgp3~ÏÀðú ÃK ?¿~ú‹ƒAOU^ óó穲*òßDeeÄydåøy¤¥XxDEx„…¸XyyØ€~eç_@~êý ›ïßÞ¼bàøó‹A„]èQdð1Ð# ÄÂÈÈÀÊ|p;à—þ Õ='Í g.y [†|>!fI 83+D篟@ÿÃhÁ`¼}ËÀðhñ¿¿ áôFñÏ_ ¬ß0Èðp 3|ú"„œð¢€øË‹×oo}u SæVTúü8A0üù6”¤äÌ·þŠÿ‚Xðˆÿýƒ`dâFˆéÿÿA,g†ÈË7@½Ÿ¤…øxŸ½–ÿÌ4hŠ4b Wˆåóç¯|üÂÀ téÿÏŸ€ý†Ø"¨o ‚„Á–ÿ…âGÙPŸƒŠŽ‡/ÀV ò³ÃTè6  "@®€$~€búúã×ãï÷AQÃ4¨ú/Ð;AÿG%þ‹]rÿ¡¹õ˜m¾€CFP€˜s@)%h40,y( d²Ë;†{_?Æ10 aúˆḋpßaáÿE …ÿ É ’ wž10<&jVfp:b°c`pa`˜ ÌF‚¼¬L’ÿÿý]ù÷@±ì``¸÷àÑw ë9ÿüfUNŒ¡>Yðê PT€ƒ~ xY J߀éçÐÒçÀDùåD• ß~2ð 0p±é˜ð°ëððr0ðq°0¼óúïÛ¿ôˆE ¨íÙÃǯþü–ÿt#0þþ-fDv(]€J Ø`Ü~¦•/_!‰ä㯠ԟÐÄJ¿ÿÂ£Š‹™á?Ã}Æ¿ b¬, l_3ìÿùç#0ÿ -†÷o^¼xûÿûWyÆÿ| Ä,Œ„øX><FÓk ï>-þñ ÌÀ4ÃÄ¡™4#"‘ÂÒÉÏß lÀlÂÈÉÉð˜e¹ÙYž¿ûÊph"ЄkÄôÇoÞ¾þ ÌÛÌ ÍÀPû”•áᜀ Œû30Þ}1”ˆYY!ìºÿÐèú‰pz€:šY ‘CH€áݳ bÀPºõýà †ë@Õˆå>äùðéÁ¯¸¹x€Ñ Œ +ï9Àð×^f`³ðpKFvˆ/a¾c„ú 6#¬øpÈ@ðéÞ†Gž+ F†¿À4qáÏ¿ÏÀ z (õ €Xv*—¿ÿ¯ú˜GS›‘•‘á×¾ ¿–¯a`(èþ c‚ @Áæ¤hødŸ?u–Aâó†G@1¦ï¿Îþÿÿü ·SÅ›'À8æä`ø}ç>Ã×Uëþ üĆ€Bå88cÇ BƒÄàäÅ‹ Š~~ Z¶¶@¡ oýa8ÇÀp(u”¥ˆI ’£ž¼yôä70…~ß½—áÏû ÿ€>û´d1Ì€ìÿÈA¶ ôíí;w~IK3(hk3°=#4óÙ†ïOÅ(øA –’éÑ‹‡O¾«`çQt8-€Cô?3Aƒ—h33#rð#GýþÓ'†û@‡ØE Þû÷¸äåxµæ–?ží¼ ~r€b9qÀ{Ë7ïÞü~ùJàχO LÀðèSEÿiœKþÃ*1A4ØbF°cÁŽ% `v¼ ´T?5•T[-æ¶^ò¹?@AÖ8 °@uÃí›·O¿;wB…KFŒáó}`QÊ i­,búôÿŸ¿ ÿ¾fbf 80D€!ÅÈÂ)/€Žf`ggÓ+wï3<†Àÿ½{¿|ÉðhƇïßÿžþòå0ò}KËÄÈ ­™´ÊdÅ·g{ÚË}8x–áçë \\ l\ ,ÀlÉt=3ýŸX>ñèÛwÀFÇ;`›àõ¯_ÿßþúýçùŸßùöùÞû€‰í°ÈúÄï€aýˆ_óÌs Ug 9œ­ˆ9g©30ø”*Ê,‰2Óåÿþì50ÅþfxÄŸ~ÿax¬T^þüùóɯߟ^üúýáõÏ_Ÿž~ÿñþí¿ÿÙ[`4~–¯ÿ@,y ÄÀFPŠá;†&9 Fô6š*C˜'Gá7F®7?}þø÷ß;`=þþ#¸iÁðò?$õ¾‚Zð Š¿Bãô7´ñ—ØV1@1â5X¤ †~CÂ? ø/)–àÄ8Ð}C€ðŽ @ ¸hÀ`³FívyAr˜IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/trashcan_full.png0000644000000000000000000000543411550446574024767 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ®IDATxÚbüÿÿ?Ã@€bb`@,茉Çþ320€œ£¿ça``6`dþgÂÁÌ ÌÉÆ,ËÁÁ.ÆÂÂÄýïïÿÿ¿þüúãë·W?¾öóëû[ ×לa0¹Ìp{Õ'†w×1,Eu€bÁé4š?¥˜Säe…ü „t$ùY¹ØXXXXþÿcdøóç?PɆ¿@öo û믿 Ÿ¾þbx`îôíîÝ×?üý±‘‰sÛsqY@ŒèiÿXŠ UEËý̤y9^¼ÿÃpûéW†×ï¿1|øô‹áÓ—Ÿ ÿ~ýb`üó‹áÿßß ,@M¬, |Ü RRâ <‚ o¿ýc8uöâÛ—Çæö2Ü\4‘áïoè!@,X‡•™…uB¬³b–¶(Ù{?6Ÿ{ÃðæÃ7†??ÿ€}Êðåƒ"Ç †ŸX^|ãÆ#Ä!¿~0üúñ“áï~^n-=Mk3áK"’m—·ó¨3\ìËÚðÙ:€ÂŒ)‘òY–¢ Ž|e¸ùô#ЇÌÀ`þÿûï—» 1¦Ì îú ^|bØ|ü)ÃÞ ïž|à`øÎÀÎÀÂÌÄðèÈw/^1yø˜áÞ{ ænî ?3ão½:{—áùÁ. %?a¶†$9ÂÍÕE6œÿÊðæÎYcž¯ ¿™Ù>~ýËÀÉð†!ÁSÁÓF‹áçï JRü y\ ^&®¹Æ°å"?0ú€ ÷Ðü߀ ˜…áÙÍÛ ¸xT-mî‹iºÿ~~p%К[0ûÃ|\,bŒ Ì ¯?übøóŸ‰ýç+†ly9)F&Iq`¢&¾ÿ?>~üÆðæÍN`Ât7cãûTÃL ÀPøÏÍðëÏ?†Ç?1|þð¨˜X830ˆ ; €0Àö—Qœû?ƒ‰ÃÆWÊ çße`gccbøüå;Ãå«×€ô%EEnnn6 ÜÇdEØôTUøùùØÙÙ$Å…žºÃ°éØ;M]#†w_3üøùÝN€Âp›ï-N†ï¿.Ÿbf`fúÏÀÃÉΚ·?b`ddfE O|nne†G2ð 3ÐŽ?Þ}üÎ0eÃseëHNqQ†³õÿÃHq„á€@ELÀÂGM”A˜“ˆ­ÎÿÁÀô”‘Aé+ƒ´´,;ë`üÂÀÁÉÉÀ ´‘ù/ƒœ´0übxöáÃÓïâ ^‰1|——šõŸáâ³û@ÏŸ‘ÃØ*ca(††¶vhÄSx¯íeœ¬ UZÁöcpÕ)kÉ‹ùà –ÞÓ Û? Br˜f Qk>ÑZAç œUL¬³`=w¯±_I,Š$l5`‰7ûRÈ3‚K¾¿ó l娡ÀDÎðX«Š23èC_]‚˜ÕØžfgøüí?0[}úåÃÝ׿¾£Š“ƒ…‰UÂÿY¿2üùýX’ÿfxóå7Ã_pyþkI@ØÀŠkF æeú L1œ ?þóÐ `ÀËLÍ??3¼÷†A–‡…á÷÷Ï ¯¿C„_á'‹0È™¾£âМÀ’‘‰ñ'Ð8fHÑ΀„­.`)9€‹œ¨~ÿ Ð' ?>`xðøÃf.n]e~†GÏ_3üÚñâû7†OX~þøt0Èyïß&Ôú Ö(Å(ñüÚÈÄÑŠ–¿þˇo <ÂÀìÇÎð˜Ïï=yÉÀöÿ'Ø¡LÀÐøò‘…ƒd@iWa¶cq@1a«A ‘ ÇŒH©Äüüù °ú ŒF†oß¿ùŸQô‡A‹…A5¬@‡¼VTŸ¿ýaøöå3°¼ø ÿ`Œ+ˆ[] ² —¿þB²$ã?HÀý L‘Ÿ¿|c`û÷•AŒó?Ã_¬Àú‡hÐ6Æ¿ ?U2°òbbbfø l/¼¶^ýà'Ê¿XB €°åÆ¿~ Äí úþ‹ û.¼e`–”¢œ„xØ~|ʱr1°0q2|Zôäõ`¡õ èp6Nv`ð³1psýþñ®¶/@1aKÿ P6|ùá;°Ùõ\<û•áñóÀšö'?0‡³Ø?`Ó ØüD¯Óg·Ï›¿ãƒ¢0åSöÏ?r•á+7Ã7L wž}a8qÿÃìÀü¬éXØ…Äø…¤89y@‰˜¨éó— ïÿr2|Öªÿî\æ×3×Ñ¥„™ nÏ›¹a!›>cl¬­–ƒ˜ +ÐÇ@03€;ÃË_À¶ß.¶?L O?þgäùÁÀÇÁÄÀÉ ,¸€Åõo`‚ûÊÌÆðé? 0W|føxñÔ¿ÿç§aøñxÈÈÖf¿Mü ¢NBfÑiñÁRÁvR —_32LÜó €€iƒ Xi²ó:¨“ÂÔÃÊÊ úÀ,ùØAùÉðôý†wï1|¿¼õ5Ãý•G~>Û4w'¿@¶ €p9€ù‹Ç’AÐ$”_ÝÞEAÇR…]TŠ…ÄLœ¼Àxå¦k` ê!ýeøñíÃç>½}Ãðéñß?ïzÊðâð†o·A}½Ã@ó.ñ'ôŽ @ás [ Ê ¬"& Ür ìüRLœü̬ÜÀ0+°¢aü÷ûçß?]¥ï¿0ü|ýŠá°•úï×  >¾Äï‘k"d;ˆÀ00ðB17¤Ý %HU2ä/´Ã¬¾@Û/¬ÝN$; pE(#ÚèÕIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/chardevice.png0000644000000000000000000000427611550446574024242 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<PIDATxÚbüÿÿ?Ã@€bb`@,0†»»; K¡¡¡a77à¯_¿ÿýû÷—áß¿ÿ ÿÿÿcøû÷˜ý÷ï_P¨AhˆD¦‡‘éÕ«OOœ82ííÛ·s€?±9 ccŒ ÁÎÈÏî9hÁ×î3ôV´\GFÐÖÂM¦Ü™G¶‘CUqwþlFãe]z‡ÖÀ j…RŒœ/bL„°Ÿ³µ}õo]]Ý$FF&†Í›73œ8qìCFF˜ F@åƒ|ÏÊÊÂàååÅ`llÆÁ°iÓº˜{÷îlJ_G×@pðòòò€,abbd˜:u*Ë/TTT€!BRœ²²²2œ|[ r ÈR\‰äH¹ðŸ_a @Xòñ;wîÞ½ ¶¤Œà’ccccP|ƒ‚äPXÀ¢‘EŽÀã€bBVŒœïoß¾ ¶TXXìK`6e`àãã³yxxÀàää„cPîaDàô7(þ€õ›ˆY1ȵȎÕÑÑa J»wïføñãØç K`Å1Èq Paf†âƒBäff&†¯ß™нDþ2¦$Íýñû_†wÈ &l¹d >|˜áÙ³g  à(ùƒ|¢þüÎðñãx\½váÑ‹o šŒ{rò~±„ „jŠ2øìŒ4–ËP¯Ö4J@ _úøø€ÙàÔŠ`…ÍãÿÁ>…Ƚ{÷$$¤ÚÛ'ÕðƒùûžgXßîÆP–úœAè¡û,¬2l ®×X6'š1|X{‰\: R1.ïAî…È· `ßµk???ƒ‚d!Ì (¸ÿÐrI†3æ1¨««sÍk)%u7µ¿ Z¬›¸8¾­ùÁPUûñɦ —ç$0‡Xk3Ú²1ý)–0/ˆ Q‰üƒG(®A©”Ý Ùé¸HÅ/r¡ ïß¿3Ìš5“AUUáó—À8ÿË øl'ƒîïNQ #w}f˜?ƒ—aâŽqæ ÿ’ó%›¹ô…£=5bA¥>@± æHª@ 2ppp€1È÷ –AQ´gÏ^†¤¤$ †‡_ˈ/@‡ÿdP}´ˆUá ÃϽL [÷ê1|N-c(¿²Ü¨Àu¿ƒ  ÃÑ/ ’¿Ý6® ¤b–Tƒ|šŸŸÏ /j‘Œràýû<=½À|>>N†§O~0|cüÍðÁ†A`Ï9†íç.º¦2hrÜgpw¹Â$¨ÇÇÄpâÃüò÷ŸÞü¨ €à¸uëÖ½?Éñòò‹ààô‰–ÿàZ :°Šä†÷ï?}ü‰A^^¬Ÿ››X6ð1||ý”á6«:Ãk– Œ4¸381,dûÌÀpž™aVã·¿ù7ÿìÚ°¨í1@ÁpðàÁI&t›ÇÄÄs‚BâÏŸ¿Ðªô?Ø!°&,­¼zõ œX¹¹¹ Mµÿ â‚`‡½âäcxáÉÀ÷‡™Aÿû21`N¸ÇÂpbÃ.'¦ßv¾gøùí¨Î ¸>~ü¸~„þìU«V¤ ~ !m>¸ÏA©„ È×ò?|ÿþó¥¹¹µ0Ó²ý–tÀ6$0m°!Âðã§0þ`xõñÃ_Z zG29ÉÃpÖ2ÁAEŽñÜÝ«ú÷ÜZû €Xãÿ‹€Ùê0)‰£ªy:@-8 žýþýÇp`´™qppƒC æ!!A £Õþü¿Íp÷‡<úÃ& —ÕL¸%ù$8ØdååPÅ<@± Y*î@1.P Äû€ØãîÝ['ÏŸ¿lâí-Ãôóço`öý Ì–?i„˜k¸”äT^qq3ÜñŽf`þù•(ÉÀ,žÙXY ÒDc 2šòÇ8ˆ»ß¾}e>þB&ss3pùúõ;пå¨ù ´ï?¯(0‡0üúñ:÷î=¶´¿êÿ2 €Èí˜Ìâp`£üè¾}»^Μ9èc6°q_¾|Züß¾ýVç_ž?ý,!9í%°Å½ûï£G÷N‚ˆ ™¥…@|ñóç÷šóæÍÍfÛ0??_p]ðüù å?ÁQj¯|–ŽÏž=f¸páè¯Ó§ïÿöíË* Þ ƒˆV ¡8¤F!))ùR§,`)Ê'-- n ¯?›g ›Û /žz{åÊé_¿~YÔ°ˆßƒt•iÍsƒ›°°x   /°oÀlÂ}}÷îÕ£7o^žÕð@|ˆ¿Â45ë> ±¨tõS Ñõ ”çøzË €º{`·LÎCåIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/zip.png0000644000000000000000000000107511550446574022741 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÏIDATxÚb`Àf20èw30(3Ð.ËÙ|a`Фµˆ ›å"üü|}8xií€b°œ‡ç€÷¤Il Ì Æ´v@1¡XÎÁqÀ;=]€ýãG†'Oèˆn90νíìØ_¼``b6:9 €Xà–30°Ÿ>ÍÀ (–ùò…. – ¿îîd`Pc|ÿž—áý{a ;}@1"±Ù üâï´t@ 8 G4à €Ѐ#€p@ŽhÀ@ 8 G4à €Ѐ#€p@Žˆ‘Ö,a`èg`0xd¿G?áß ˆ…Öww7péïw`xü˜ŒàççÏ ›ëë?ïýô) €hî€÷×®10€Úš ÀÊÊðóûw†Í“'ƒ-ŸÁÀ° €hﯡøùëÃæM›>ï}ñl9H €hŽ€­îýÿ•”þÿâÕ¼¼Ÿ2Ü刘lyÿ_ÍÀ€Õr€b¢ƒ#lf`ø¼—k°ÍÊj¸,€YPqÕñŒå4IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_grey.png0000644000000000000000000000544011550446574024440 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ²IDATxÚbüÿÿ?Ã@€b Ndøóç7ÿaøû÷/;;;Ã÷ïo˜˜þbh©áãHrssë}öìù­sçÎî>uêännî Ÿ>}ú ÀðóçO°9²²² GŽa044d¸wïƒŠŠ ÃÓ§O`è^âoŒŒŒvÎ`fffxøð!0¨T–²€-ùFDD$@UU«v==mùùó—ç“'O=oß¾óè KG>õë×Ï}ÀPÙTúõï_HÈN€|÷ýû†çÏŸƒãä fv##c~~>‚‰‹AYY„y=<\­ß¼I¶¾qãf!0Í<¾uëæá3gN-FÝ~€b!dÐÍ›7~ýú   rR»ˆˆƒ9ƒ••¹ìçÏ_£öï?••– @JHÀÔ Ž+mm-N\j‘s4–膆,??7ƒ¸¸$0J­ˆ ª¿ ,ÊŽ¿~ýÓ J€?fàææbQW×°ªûÏŠÃÿPË¥0 ’ÿôé30!ËýùóŠ!qúôÉï?¾ÿ@ `þõë·++«!4//¯Ð11‘ŸïÞ½î¼{÷úF Eÿ€òòúúzŽ‹Á†}ûöáë×o@‹¾0|þühÙW ÿ+Ã÷ßôw†ï?=Ê &*ö (‡}øðáäÉão~üøy €X€>OðôtŸaiiÂJ\¼¼ÜÀ‚†˜ ?Baæ£G÷¿31qŸøý›)üëןœ;vG ÈàÏŸ¿ åââ``æA~~q1qn^nAaa†ys0Ø€Á×ל°AåÊÇ.\8{ȹ@,²²2¹aa~,ÿÿÿ»úÝ»·À”ÿèRV` #š””½\QQþŸ€??;(*äåe€–r-áb`ae‡#0 €iæ/Ãï?à4ï''7ÐÌà*ÿÿgb¸råÒ¿î_:à1@Ê@†¢¬àæÁœ‹Wz§ND‡ÚfhŠùÁüx/£Hë1&¥¬}ÈæÜly¿êȶuÊoÆ Q70‚Ëáö…tü÷¨“à6a¸ÎD̨hRJ!ìO)õP€û@,¯^½¼+&&d())ŒÃïÐ 1Œ……œý>~üv(Žÿl`„$\pªÿfðÿ?#ÿÓ É/@Ëxxy¾‚ÓÊw`AÅ w gÏž¹Ôyˆ0!=%¤Ÿ?C+¥¿`C@Æ‚ƒ” ̪@2þ[UÂð\?ü‡””ÿ!Ž)û ™O_¾0sÍ/ ÙŸ9¤æÞ½;ÿÅ4(øA!ð €€øòä*`åN¡ ¨ù †Á ¨ÈÆõ¿!ÿCø"ÿÀ¡t(€Áóó÷†_>ÓÂo`ðÞ»÷€žû þŸÞ¿û˜öØø‰ €˜Þ¾}}ÿÇ@‹™¡ùâH;ÇÀ(`ge‡ú¿ÿ@û¤çÿ!¡ö9PòÇï_ >}Zþ%@\œ oÞ¼æžÀèüÄ‘Ÿ_•gee· ˜“tˆéÁƒÛÞ¾}÷VÙü' PÇCX(±±±Ã-`€;Žl8ˆ rÈO`âùG`ýób9¤Â:€“d1°@{À %¥ÀîçÆýôé3?~(‹°°è[`…óh ¬dƒÿß¿ úü8G€‹V Eþ‚²Ù?p0ÿúöÏ_ˆƒ´’ L y¿€j…¾~øÌÿ÷i‰›áþýÛ ·n]½ 4ñ9@±HIɼ:àÝÏŸ?àu>Ä!ÍÌÌLÞKµoß‚-e³ÿвì0hù Ž´… È= ü/.!ÍpíņgÏ>C@X\øŒ’+ r €X~ÿþõØŠy*³!éà/Ø×ó B„…˜5AŽcd‚fE&xVüÿšNþAè_P(1¿ 0çoŸ0z%þ1\»vá-0šo x@,߀ïß¿{ö˜j„À®gš~ëÖ# ~ ö ËW`.ab`ã`aàáæÆ)' 0Z@¥%¨teûÿ`ÙâHâüÏÀÁÎŰõäA†ã×.3X)ë³ûw†»woƒÊ€û º €X€Å"ƒ¶6ãcPù."" TÀÈpýú} +ïƒãT22‚‹Y`~þÏðîçW`±ûÿ!!,XÙ9€¡Ãc†Ä?4W°³²3œ½q…áúík L@ÇþºîÕ«çŸ>} ~P]𠀘tu 899ž½yó˜ÚÙÀåöÍ›Àe8NA9ã/$Xÿ‚Ò=Ø0FF6 cÿ2|üð™áõ‹ Ï=dxóì Ãç÷ï~þ¥'&†W@öé«çj“R€Y‘‡ ˜Ü¿ó ˜.n¼™@,|||Àâöç­W¯^ÿV*,  •Ь( T&0‚#Ò`bU@ ´ !V°øÀïËPaÉÀÉÁŰñì[~~v`ÀLG7o^}-Aå>@ÓÀPytÀ«÷@—‰¾~ý\»R18§3þCkå0‚!(Ÿÿƒåh‘• eÀ ßwტ´8ƒ¹†>°úÊ (/ÇðôÁC†Gï߀Æ?Ø`€byýú¨nÿðúõËß¾ýÕZâ’•˜™a¡Àu #ÄÿQš]ÿ¡yŸè€Gïž3üç`dH&ð/ ¼\ \À6Âþ+翽ÿðþPù ˜>€byòä 8ªoß¾qåÙ³§ºÀzŸáõë·ÀŠgH r8ØÁcgWPt@ªoŸÊfdX|d+ƒ˜° CÿòE Ï^=gøþåËOÿ¾}öä"°°UDa F!!ahÕËbàåå³%::CúúõGÀª÷ ¸ç Á ÜÀƪ°Áûýû°EôŽUö/`ïÛ“çO?^½÷ãŸ?>ü†ì¿ßÞýúñãÍŸß¿^Túâ—0JÛUTT4$22v¡‹K(7|ýúèý Œ?|x÷X“}¶š>‚”¯Aõå˧÷À¶Ý;`öØ„{ Œ†g@£^ñ' þMl0 Ê¿‘í ŒÆ³¸¸x¬²²J°¢àøðáýÇïß¿‚,&Ðï FäK¨ë_Cƒñ#’E¿ð_bû „­õÊk @, *©|ñ ÉI±06ôÁ¬¥ñIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/pipe.png0000644000000000000000000000313011550446574023066 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<êIDATxÚbüÿÿ?Ã@€bb`@î€bAá™1âTø÷Ã? EX`ef`¸ÄÄÆùÀáÕÿ ÿ~gøóç7ï_?ô/†oß¾Èhié®{ðàα7o^Öu}†™‹z€¢Y|ÿþMÊÄÄbõÊ•+LûúúòYYÙû€Âèꈅ–ûöUÒÜÜjݬYÓÍ•”dDDB?~•ÒÜ\ÅñãÇ÷< ’÷0µÄD}˿ɘ™Y®Ÿ1d¹ãG¯nÞ¼ÏàääÍ‘QÃÊÊÚ TÆ S@LÔµü»¸©©ùšéÓ'›«ª‚,Éðüù;†¿2<{ö€áóç·À¸ÿgTª Ó@,TŒsc“µ“&÷š)(H3<|ø’áåË Ÿ>}cøòå-Æ K–/_vëÏŸ¿›£ €(¿ ¤ýý‡¸‘‘ñš »Í¥Á>ñbù§Oo€–¯`X¶léu`YT¾ ˆŸÀôù!ðŸAìÿ†tá¿8½LtÜ:û•¤á>ÿüù+Ðò· [¶¬fX±bé¿ÿ,êZ Ä÷‘ ²ÌÂb,V3z³ØÉqÿchr‘áÓG†¯9^¿xÇðéó†Þ0lß¾hù²ëÀrdù ~€n@±ásIæŸ k˜B¬Ê*˜Øç×30tº3| šÃðŽAœáÛÇ× »wobX¹rùÍ?¾-†úü6㈤4ðÿƒ8Ë/†•Ì‘@ËKÊ8J~10Ä3°êÞfXËðåÖq†Í{w2,[¾äúׯŸçµ-⻸Ì R|Îò—aS£ CÐbN >Þæ= Ùßu¬ìx¾aà]QÂpì*ó/Ÿ?.Âçs & çàÀÌÒ½Xmʪ€–W-¿ÃÀðõßf C¾Ê1p»›3¨è¿g°ùðêP×! ¾GÈ_„wP%‘ê&/NVW¾?@A†/À\ô ¨øûc ýáÏ 8;Е¬ ßY~üþ*éØˆ X€BqÀCÏ †Ÿ?A5ن߿1üýû›áþøý§»¶¬“óÃ- Ló•ZÐc?€ÁþåÐò÷˹0Ü[w†aýŒ_ÿþc¸ *‰q@¡8@SZX¢ýW¥°*õóçÏ26ú2ëS ³L~ÿËf`îrc`Ù¾€ÁÚX ÉABhù §–¶þü;÷Ãþ§Âæ:1 ”4,, ø/ÿþ]BQQnuVVœ‰¢8Ãs †«Aó^ž–gø²ÅÜÀÈÿáÞæÓ K›~þ›ÿá00R€®cØ\÷ã„3üúõKZQQ~CZZ„‰¬¬8¨:ex,dÞ3Š3Ü2®cXUÁ øè 0ÎÁÁ>÷'Ã>¨å[ø±™ €Xp[.·:))jùkHÅòù;çwÏŽÞÆpâ‘à]Í#¯¾ýøÉÀ ‹+Ï Yn')–ƒ@±`Zþ[RAAf}LŒŸ©¬¬Ó'¯€–¿W,oß>g¸pá,ÖÕ+¯ß½{sÉI†ƒ@-¬@üˆoìÈ €XPÓÀ?999镱±Þ¦RR"@ŸC*–¿1¼{÷‚áâÅs ëÖ­»u÷îµ…ÐB極)@¡8@BBtCD„»¡¤¤Ðç `÷ùåËÖ¯_wýÖ­‹ ²}%¡ŽX@(¹àúõ+Çž?´ð#ØrÏA–_»vX§¯»qãÆ…EÔ´ˆ¹gÄÆÆÁëâÜ—ššž"$$nFݼyaíڵׯ\9…³J%¯J‡Ø @` ƒã„…ßÇ'vñŒ+þ·µMüohhJ\À €A™šíG˜„á`ee´´t™¤¯ouÈ-bEj·žavV@ë±,-ú0;ˆq {Ç4àS€Y拾ALþIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/services.png0000644000000000000000000000413311550446574023760 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<íIDATxÚbüÿÿ?Ã@€b9ÆÈÈr þÄ?ø+3Ðø‡ÁI@ ÷Ù·o§ê~ýªêyEÈ2n ΆèeøÄk€ €˜ü‡ €,ÿ Uˆ 3±±U9¯_­cìæš¤ÏÀâ$äst €Ðù`˹€˜ˆÙ°`vˆCÍD,- E\T"ÂT¼Â²ø,7b'¨ã‘@1áÒÀŒ#~C¢ÊVÖωbŽº Fê †¸Ì9Úìè €ð:[(ÅÙ8ƒ$ÝÌÀ)‡UJœÁÐÛU@’Á(ÀƒÍ¬8 –Áâ{ &|Á’ü õ5 ÿb`5Ö1áU—„FÖ?Ew#=# GÝ `ô0ˆCôaMØÄDLVùuÈ_Hð»H{[±1²‚´r€±×a0URÖfa`PG¶- ‰ÐÐü‡Ãl€ÂëX®`GŠn.Þ qMˆ=ÿANceàccÐ7TÚn 0°„ZüDTüƒ!°ŒÐÐQÖçSúü/пÿ?%ÁÆÈ9k3h'4ÄÁ)Þmø@1Á|Šÿƒ?0(%½D˜þCðï#Óö¿ÿ R.Ê FüÂÚ@ïkBKZ ýÃaå/@±ÝïÂÂÁ›ÅÆÊÎöïÿÿAãœþücã6–ñS&Š¿²óß/ˆ³~³2p…õÜ­óÖèäádËæÑ? ñÿ -gûûõã¦ÿ&ã%¡ r3KôÙ”8þ~ý”Á¿(Á¦¾dâdcàS~ÇÀÄj u1h€¦¹¿‡>¿bføþ(·îÓÿ  "Ÿ™Xô³r 0j^Ç¿vW@±Üyûñªä¡úü>Æ@ÀXþ) LWBØûVDþû]h:Ðâ¿ÏPcò8¯Ø{^YV4}ÿ!aøè•¿wÁ%Å“Ýg.Ÿ>ûyâļ—áÿ‰?'ŸJJí{¬+`.ÄÀ$~òТß@ú0±@ðoá Ã@‰ï3âϰúËŽP ×L°ß€ûwèŽÏ ‡›.2ôeïÿ´øý·íï6,ÏòSlJžG™m¶˜@,0ÿjü#ŒDhÌ‘ @Ùˆÿ})`ŠÆ'‹¦Ï±T]ÀRHJE’åïý‡ K· 9: A$Îoˆ¥ @üÒÄQWQ³äU–i_€¦²²¢;#4Ÿ£F#ËOm'iÃݬê»Áy7 –¥Ø“ÌAŽüÞÚÂLœÀÄ÷M µB¥v å¿A‰©Î¹ç×?Y`K‰Ïh÷‡·j@‘¸@Lø*f.;1s`õò ˆÙD!Ê’À"˜ XZò21|½v•áÏ/`âбI@äÙ€ø¿(¯3ƒŽº˜¤<¤ŠÆÕÄÄ­ÀÑ1(; š«ÚñêkW& ïÙ€…°$ Îðïφ;ý»f_ý¾+õàŸ¯Wó;P—,Ĭ@=\ ZΪLÊ 6°* æÜMo/y_µDa7`ãã°nà¦î¯ ¿/î`8Y|aòº¯&30¬¾ýâß–/”ÅØqòC‚GâfVnο 7×Þæ>óçça`¨ÞÇæ€;=Gë~Vö•<;-N]`ƒš Xý<ÇðzÆ\†ME·~ÕÜýwd;ÃB`YöèˆãßNÛÿYÿÆi1íŸ Ì Àæ!³+׆÷ÇŸðyüæ&0QŸÁ– ˆhæ©ãªr¯ÿ<œì¹müÿÿ\ðÿ;A,ÿÞ‹ëÕ@%¡@,†ÖëQ :j…Ãï÷ Ôÿÿÿ8¬÷B…ï`=³ ¨D[°b@Á'x/°bºëüÿÿ·Šÿ_§©ÿß'Éð×X&¥š ‰ŠWïK!©‰™áá¹höÿÿ§ýw$ë9ÿK`>rƦ €˜©”á¾ I²nš*ÿ]~Þϰ¶åù÷úO øBhwî Ž&>8ç~– —þ3œ|}ù¯ïÉsJìnœøÎrôûÓ E1J­@ŒÖX Àä& LJÀâKméOÒ @I¨ŒÅ€]—<`”y\f`xz‹a6Pxºã_¹ *$¡…âhØTÀ-\9¡f¼CW`›2×DúhyIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/desktop.png0000644000000000000000000000526611550446574023616 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< HIDATxÚbüÿÿ?Ã@€bb`€Å)·bζ@bVb`ZJ¶JE‰@Q^|‚â?’Ýè2ã ”À¯ÄI« qàµä„Ö)X fÎ_ßÐS¨‰áÓÜÐ@L_RÁ$ëyíÕ¹ÞJ¿ˆ…&ÞbY$@îýtØïv"®&ˆkØq¿<ñ©è=#“ñß»wâ~ÿ~@´‚ßÿ-ÙŒ¿¬ª¬àŽ÷0b`6e43±gnÊò•ð‚ÿÿƒDÅEV­/‹³+]ŵøLN|_Î lu€Mã (êô€Š•ˆzQ🙕á§!Ã߯ ÿ8^30ˆ<`ú¸ ¥ÖAÙOÕŸa≠wî20åax»íò'†Ï" €(s( ÿgdøÅî'Êü"RGø3¯±=Ë£·¿.\?û&°„K$T;ˆaɽe ·ÿßb`ý)Èp³çÏŸGŸìbøÿg-Є{DžþýcgøõW—™‹3Í–ï†G‚Ñ>Y—à› "RÀÌp[‹Ák‰"ƒ]1—Hžc6ÃêëNþ:ÁÀÆÀÏpwòß?ß÷ÞÝÍðÿÇR )'AÙ €XHòí¿²@‹9…ø£äÅÕ„™">1k(0p)ãœåCåí› ÏMxzüKö>?Äpèó!æÿ ÷gþû÷iÃÃã ÿ¾-š¶ˆ¿ƒŒ "|ËÂð—Á”‘™1VHR"P]CRBUC€AQôƒ®;ƒ‰V1;°,øÿ…¡½¯aÙßà Ó+ËÎ>;ǰêá*†ÿ¿ÿ2¼^ÏúÿÃòW'~~ »øÌx€bÁ™‘ÿ13üúéÇÂÉ*¥(é©¡)Ê *ÏÆ 'ËÆ )ÎÁ`®!ÃÀÆÎ×±bûY†IßN1t—å2Üyr›aÞ¥y ?~ex»Ÿ‡áÇFö ß߃‚}3¿G¶ €XP²Ð?`Ñ÷ƒ]ŸáßÏ41QgA]%Yi /™\tDÔÄy¤Dx˜YØPœ»ûèI†ìu… MUÉ Ÿ_~dè9ÞËðñë[†Ÿ—8´þ0Ü–ùÅÿåUÍ`Ü¿D÷*@ÁÀ ,µ¹Ø~§YÜqJ°ÝËøù¥ Ã#MG†P#.#e Ff6¬aõ÷߆Å;72Ň00}cdhÙÝÊðòÃs†¿×™ôy ¢sÖ®¿(tâÁÞp†·Ûµ|@Ö@‚èϯ\)]³•KS9oŸÛÇráÀ'c;c59¬–ÃjÑSW¯1ˆóñ2$èú1ôlèfxvïÃß«ÿü¥2|#>ý``0²ÐaàÖ f`“òB7 €Ààæãwâd°ØÁÀÆõ—áÂ)[†wj! kŽÝaøöýö uÀ‘ t”%¤ù¸z-"D>2(ÿvchMÊc0ûÌpåÌI†ßß3¨èér1HøeµH#›@`°³ó‹û±¬``à&Î ‡3ðÉs1<ü%Ȱzï9,¹ñ0™2Ù/†gÏ2\¹{›aíÆõ ›·¼dðOghÉcxúô1ƒ Ëwþ¯WnÜyÄàÄ}ŠÁ\šÕœ[?Z]@ðáÝó3§?‹æ·ì o®Ë3œâbàfkE =†µ§_2¼~÷)Wþûž XmßzôVï?˰xÏ}W†x/?†ŸÀjøç¯ÿ ®z" ß^>bp[Áí¸›™YÜ7“‰Mf@174404T¼¸Í.ÉÄvø± ÃIaO OùXõý³{׬õ”€–ÿ†À?p]ÃÄtÀãG |ì\ ɾ .Æ \œ ßü6þ€ÓÈŸ¿øD~ÞaP›Ç ¦ûŠáÞ-M‘Ûï…~0|¿s”†’?ŸÙwçä®õÓ_¥0üÒÏ·-AE0”UÎ<þÁpúê=°¯ÿýc€n¬¦ÁЖÉàdeÍ )#ËÀÃÇÌ¢,`‡‚0#Ð_ì„®0ˆIýfàZ%§®ÌÀ¤ËÀÂc² € øû“áéšîY{ž`ÐøÏð÷?¤qÄl)i0¬1|ýþ“““‹Aè%%UEyyE%U-U1uÁ= šÀ@gü¥ÂðB5AÞÄH„AØ< Ô D{àÛÍËÏÏoŸºaß}å ÌLˆª]^Ašá=#?Ãî“רØXÁ‰„ÿƒ" tñXäþ† ##?0$$D…„„ä¾îcàæ¦k\ ûžÄ2üggàæfN`{A €P‹â—›§Ïßhîg-¥l)#Èpõ-¤ÙŠ M†ÕGv3©Ê0p°²2üýûl1¨ úû÷/˜ÍÎÊÌÀÁÆÌðþó†C×^1º÷—ÁçÉ!†?© 8ãr›0¼yþžáÎåËÿ>\|2 €AÁ Š+H´N62;(«bJO?â«ì ÿ¸Åøy8Ù®œ¾Ä Ïÿ‘!ÉËœáÅ›Oà–&+3 cØ`½óâ=Ãá›oŽ?þÏðŽEЉS˜‡íÛÿ o^}axsãÃLJßý¿µü Ç«³ì T€‡§ÃÄ}«2$Ì­~U3<àÓaxõÓ‘á%—5Ã[nY†3Ç2ÔãY„áïŸ_ _¼f8ÿàÃéçŒ gŸ¯;¿(8T>¿ÿÆðêņ·×O|ÿycÇ#†w¯3¼¿ j âó  €0RÞþ¦‰SÖöžÈÈÎ=”|¿½—dxýÙžáà}†{ŸEœÌ öÝúÂpò;ÃkF1†ÿ\¢ ìœ<À,øŸáí³ oîßdørçèÛÿ÷v\ax{á,ß/'€&ßâÇÐú\”v°ñ²36/ŸUå˜ÊYÀð“w»0µ‰åÞ00\]ËÏ0ù|.Ãaµ~a†ÀÜñåãW†÷Ïž2|¼{úëŸ[Ûî2¼¾p™áã­³@ ¢ô¿b€4ÔQ@awˆYkÇN=t Rëúõk ïïmgàÿ¿ŸáôK†ÿÂQ¢Æðý;ÇW/Þ>¸Åðãî¡— ··\axíÃïϧ&\â@ü_{ €p;,{¦·WÅfD9Š1TìFÜ=`¸? Bè뫇 ¯øôïÁᇠώ^zÄø¿c€ô¯€Âß$»½xBëj¿ì ~±2|øø–áËÓ; ßoî~Âpwû†w×¾ý æÛ@üT¦’Ú¾ ü!âÆ® R6% l,’ }bxzâÃçÇ  ¾[P‚úKnË €;¤‘êñ· " ˆ¿P£?`g±î¡vá`üIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_grey_open.png0000644000000000000000000000430111550446574025454 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<SIDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €ýübþýû« L‹¦¬¬¬rlll2‚‚Jþüeÿùógç¯_¿x€´PÐBiVÖÿR¢¢"@K„ÄDDD„@HTTX”Ÿ_h7ƒ€€Ãóç¯öîÝ Ô·ˆï ; €X””Jãâ¸ÿ}øè£_ ¯^½a`ffaPSÓ M˜ª¤¢ôMRBJh ¿° ?//sqrCƒhÔ†ßþ1üþýˆñ_†ï?@fd:JÈEv(A¡ @,LLŒ¬·o? ý+0øXXØ€`bps³epWàççe`§F†¿–üùÍŒ"°e_¿}cøûïØ00þ÷¥¤ö/PLTTL¨Y ¦¦f ·oßb –/žß’–UÈ÷ ðh H3 3P10:¾Ò XTnŠ.X¢™€þƒ–gÿ j@ú>ý 4ó7ƒ„„»ü¯_?AAõd0}0\¿þ‡ €˜>þòðÈÿ2üúõì+å ƒA¾Æ=ß¿!¾†Àˆ­‡üƒøâ0 Õà+êùÃðáÓ'pè ±²±qH%ØøøøŒMÁv€@1}ûöõñë×ïÁq v`”@ƒ‰lé?°M¨B„ r>D @ÎÛ÷ï~üüæ 2s˜Ðüÿzzz@OþâýõëØAÄòå˧{oß¾[þl4ÿÂćø ÏРGDT-ýþó‡áýÇ _¾}z†‰á0A‚‚[]]ÛA\\t¦””Œ //¿$0G‰ž={¶ €X®]»xÿÅ‹—ßpþƒØ÷$=@¼’/(dÁÎa„„4 @– Ÿ¿|aø Œ¶ÿÿÁêýøÉÌß ¶¶Ž:††f: l.**Ìš[þË}€b¦ÐWOž<~Œùÿþ#9à?ŒÊÀÈaøÇøœV~üø öCrÄo°@ñÖÿ”[þƒR$àãعë÷ïŸ ¯_¿Š Ícf8sæøÇ?~¾ `¼ýúõ[`b“‡û   9äÃ‡Ï ïßføúý4Qþg%F&&ˆã i‡œHA ˜(ø 4ã÷ï <ÀB dÖ‡÷ïùŸ˜3ž1CþТkÄò÷ïŸ?¾ 2¸ ì 4ññã†;wž2¼{÷ÔÿXÙ˜Á…HŽ™hÝ?p~ƒ8ú/$ü%hYŠPˆ±8;'8m‹ˆ2<~üXB>¿Ôð €XÞ¿ *6€²"''7¤tæÿ»wŸ2ܼù¼ÿ€… ¤Lùd04­0ò?4-02¢¤ŸÿCÍÈÂpëÑ#†-—Î2XJ)Íû,€®‚K@寈åúõ+ ,xýýûÀ2œ”wî:ì/ý{à¢÷ &c`p>xùò¸~÷îÕ+w ©V@ pÑ Põ÷7” ,óÿü†ˆAŠg 8Pìï`H223l>q!ÈÉ‘ÁÙÜ‚áí×O ïß½e¸ÿöm å÷@å?@1²<É¿Aq{ûöc†oß~Ù¿ÿ‘å?x 2üÏßàè… ˜†ã¿`G‚þè•‹ B< N†f zG@ˆáõ›ßß¿w ü ‹ˆ ”H€ñòèÙ³'Àzå0q@ %Á0KA>ƒ…Ä€ø‚A>ÿ ûÌ°Ì O_¿fxøñ9CvH8Ãû_”d¤þ£óò¥³Ï€ž¸ ~ˆåÉ“GÀlñóý›7¯ß|þüUà° 9R€¢á8ž!lFpT€iÆÐ(bDIàÆû‘[2ÂB˜ÿ³3übþÍ *!ÌðúÃk†÷nƒ‚þ&¬q@,?Ñnß¾yúáÃ*‚  ôlÑ€$*@…Ñ0R_@jIÍÊÊ ¥þfffàâ`cØqöÃãwÏ6<ÀððÙS†??¾2|ûòñïË;w€M×Ç€ö=ƒUÍÄJx `Z¨º=>>KîÆÇÀ2à3¸ÑÀÎÎ Î ,,,@K@ìÿ`Ç+`æÃçÏ>}úðÿÓ§>|x÷ýíÛWŸ¯Ý¿ûáÓçÏþüøù'ï~þø,è~¾Òs g 9\l#róHDDØ'88r‰·wÿ‡Ÿ€Žx¶äÛ·Ï`‹€ü|ÿþͧ÷À< ”ûôöí›÷Ÿ>}z,ÄÞÓÉ`Úx Œ:%/ø#âïHT=þF¶ €ÑÛhÂÂ"a**Ê…Àf×` ¬®ßËì÷Àè[`ƒå%4õ¾‚Zð Š¿BãdøOh¹H  Fb zA jè7$üŠÿ’b >@ŒÝ7 ï˜Ѐ; €ÜÑÅåÁòZIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_games.png0000644000000000000000000000626511550446574024574 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< GIDATxÚbüÿÿ?Ã@€LÊ1 Â0@ѯ4C¹ƒBਧè±<гé–-!Q¸d¨Jêâà›ß†é€÷ > ÖŽÝ6°oWÖ_ù×Z£ïå4އc­õ>ÏîìÜí$eï—åùPJ!„À{Ï0 ı֒RBkM)…œ3ÆB| ¦›~1<`2`Ðøw†çÿ;†¿ ¨J~þüÉeoïP›šš, <ñ—/_ ,¼téÒ­ƒœ~þüù—/_ì*}ùïß_‚!@,Ø ‡½lþ¬eàø÷…áïH(€¢‹‰‰IÍÂÂ\ ¬(,!!¬VVÚ Ú·oßI8uêÔÛ+W.ºråêúW¯^ÿû÷ïý¿ÿ|edÄ´ €X°»ëÃ7VI†cwYìE¿00s €-¿°«ººV]l ººZ ,üýûϧO_xÞºuëéS'®ñòòíÿû÷÷Žß¿Ÿ*ý2 ˆgØ012|ùø–áÅß— ÒŠüùów*‚‚ƒ–““ƒAEE„ÜÜܬ€!auíÚÕªóçÏß¼{÷ήóçÏl`dd< @,ø“(#Ð ªÚ†`ËŽÐ666U!5¥³m‘’bF''{¿jìÞ½;©  ; €˜ðêdbbøüó?0¹BBBzúúzbø´€r5¾œÍ YAAEE% × €X0tþýN@ܤÿÀÔüÿÿ?YY9oaaa°0(f"$§2 ÊþÇðë÷0Ÿ…™‰áï_Y >#3úôé>|ø@üú+Íð—I‹•E‡››I‹Ÿ—Cþç?V†·œ¢Ó²¯ÿ7ø'ÅÈ'ln¨éÌÁÁúÃÀÌôŸáÇ¿ ücøôýÃÛÏÞ}ûÇðøÃ/†Û/~2¼ÿö—áÃ÷ÿ ß¿ÿd˜-Í /ÂÃðè9fff†¯_2œ:uìÝ÷ïßo СNbKB­%%¥Y„¹Yø¹YÞgbÈç,0{xmSÃ?ΟYå­ò©K¬>ù†áÚãO O>üaøöX.Š•™A€‡A¨O„—AG™›‡ƒ•Ÿ—‹¡cù†=‡Î1D{™2ügdEãGOΟ?{ȹ @,À¬“Z¨,)%ÄÁðô=ÃÃ/ Ÿß˜:$eeø?„Ìœ.&-ó‹_”Sfï+aŽ÷?äDœ•Ù$øY8™€Ç ûÀPþŒ½ï¿!ø/0ø…x^¼Æðãûf6fpÔܸqý?°ðº ä< 6†_\î01p00ðôƒ0O#§ÔUˆA*,T— X.|úÄ !& B ¯ƒb hÉ/ˆ…ß~@’Îoþ •êÿ€àåçexûô/ØìL ¿~ýa8sæÄ§/_¾Ü:à-@±|úðé±…ÔOm6†/@ƒX€>ÿób3ˆ´ðý§ ÿþ23|ü±à4Í‚Êp’ýÁ¡ø4-ªeçàF'0-|ûÎÀÊÉÏðîÝ N?? †ï_ýýó ˜n¹¾ý—?`þ€,ãoÿ2ðp²ÅÿÃ,„YþbéŸÿh¡Ä óøx8î}ùÏðéówAF†‡ï3\¾|ü ø@L žÝ{ðú'È£ ¬ŒÀ²ˆ!bØ/ i¿~ÿb`Æ #¤ìdFÕ&ˆE¿¡–‚‚ü74@ü¯@Ëÿåù¸9Þ~gdxûñ 0ÿ2\8wòÓ›×ï3[~càSa †§‡>yþÜ  %œß@/þ €BáÇ? ll¬@Güa¸yù"ï_ØyùDdT¸xy µø¨@þI€0Ç€Ó'+'Ãóן”¿¼c8ÿø7›çâx†?Lº?–Ã÷—¯¼üöê+4aÁ|õ Œ€aüå󆛗1Ès|cpÐæi¶ï 7l`¸{ó8Dþ@Õÿ„¦~þÐPa:€•“áõ‡o o_¿dx­šâ&Ëøõ–Ã÷'Ä ÿþùóï?þÔT„e£?°8ó÷?îœØËãcÏð—…\'¨iª1³âú-»¾üå`”’cøõ‘áÑt#М<< ¿½`¸ýø)Ã[!ÆwŸ¾ßÙuÀáÏû¯_¿{õîË?H>þÊ>ÀxÆ÷O +nž?Á )+Ä «¤È°õ؆u;o1<~÷ˆáì¿‹ †ÚJ ×Oî玠ø)˜~ACäˆÀ´ ,&ÊðñËO† ·Ÿ0üadøôèÖ†wW®ð €X~}`øòöÝÓwŸ3Hó³ƒj†7O->ÆÀÉÎÆ`§%Áll0¼}ñšÁB–UG˜?2(0+1ˆÊ 1°¿Åð˜Àx€¾å‚H¹Àcaxwç70!~c`cgøtëà†ßo¯­z@L —{^]yúú0± £Oß¾0ß0A’á%Cœ§1ƒ½½5Ão`D~9{œAiÓ">–W J‡4¸€²Ã?†ŸÀ`§?t¢aüÿÀ(xýú+Ã廞|FÉ6†ßOO<Z~ˆ¿ ƒ€ÐÙ\ÏÞóé翜;ÁäíÀàâìöÍ`‚j0.m#†ÏÜÀøcaøþSá ÃÃ{W^}úÉÀÉÌ ®aeÔ÷ÿ€ièý‡ çO?gøð‰—X³|ÿ tÀÑ«@Ëï€Ê€bf7,gøû‡‘›—ãWœÀ+&O[]=}= ÿ€Á÷ÖføÍÌÆð_L X^°ãZŽá>°¡²vû†Ç¢Ž ¿Ø€ñ Ì)ß‘ÿXþþÿ˜@ô?†Ã{o1„ÚË2\ºÿ˜€Ùûë·ÏŸÎ-Ù,åöÚ¸Äâ&xŒIHCÊ'3TžÙÜD\[ýû)Š@P=Ê ¿üÊ£âë7†ƒ{v0l>}—á…r8¢ÃPjÿû‹ XÜ2ý}Ô÷Ÿ“‹›áÞí7 ¶*@ŸË›t,Àøe—`øzcß †_¯-ø ò@±ðð ¤WWf”2ýggX14ƒ™­&'78ø¿~ý ÿÀJˆáÁíë ¶íbØûFœá‡~)— ÐmÐö0Û«¶Ì|À¨øÇpÿásÞïô=NkY) !†gŸ~3|}pô6Põ=HiÏ@,NN6@ƒ¦·îb`þÍÆððÚ{6vSm åß•°Düõ›áøÁí ‹v_e¸!èÏÀ¦kÊÀŒßŸ_À­6° @ñëÈüfßÏ?0”Æi1\ÃÊ@ï* 3\Zsäï¿×—Aí»§°†@±ˆˆ©¼{ó‘áßOF`±ÉN9o|`Ð2'3 ó‡wV¯ßưñ¶(Ã{é"v!!†ÿ_þ2üÖ”L,ŒàT*í@íPH;E ϯ>fPçcØûíG/øþ}exxÿ%ÿÇŸ3üþ ,>>À@,÷î=zêæn¯*¡ÌÅðüæw. ïŤøÕ(;áýG¦,=Äp¬0Z€¡ ª¦‚ÿÀÊô˜ôÿýaøóMß?1üüðâÿ·÷/~½}üà×Ëïüûøì÷§¯~¾}ÅðØÆÿñ”úO€ÌIJsçîM^^ÎÅÑi. Gö^bà6£Ìì´¾}ù°jdž³¬ñ |b2 Œ?Ÿ2üþø˜U_2üxÿô÷ïoo¾ÿýòê럯Ï?ýùtïù¿ÏÏ^3üúü”ï½gøûýÃÿ¿¯A¨¿@ñGäV2@1²³sÊ……Åo¬ª.1ÐPW ~6uV­\ó¿rÂŽ/¾ |düñâã¿ï?}òŽáÇó§ ?_=zf0¿•jДýÜ·ƒ$²? °¤#¤KÅelnîÐeoog"&&Î~ëæÛ¶m¸y؃¬ |…b/>A-úmÃÿ#·{`‡òkëíIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/socket.png0000644000000000000000000000567011550446574023434 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< JIDATxÚbüÿÿ?Ã@€bb`@,0càÉÀðï7à fdf`øýá?÷ïz l,î|ܬÆ"¢Ü¼¼œ¢ÿ~ÿùóþÝ×—ï^½¿ùíÅÍ“ Vìaàà¼Áðñ"Q–ƒB €XðªøŒžŸ¿ Ùù¸Êm­äܼmdM”¹䄨x¹˜þöþ˹›/~˜¿ö9fÛ>÷—ŽìÛÄðã{ÃÏ[7ˆq@1ÂÒFücdcúÇoe,]ŸªÆí®ËÍ uî_ fF$Ÿ1PÃ÷ ŽdX¸äèË[û—62¼\;‡áÿÏßøB €°;àÇONvö9ÉaºQ©žÒ ÒþüùÇÀ”ædcÆï?ÿ¾ýú ¦a‰‰…‘á7 Ãñg ó–^cØ>ÚT†Çsª~}Âå€BFp°3²s°ögÅ™Fù› 2pÿûÁðüÃ?°43#Ç/ €Þÿöë?Ðr £˜‚â ó >&/_M¶‚ì­SÞþù÷beD"üý Çß ,ÿò‚2HjI0X†æå0p™$ãÊq„ü÷˜à~)Z™Éµ©*ò3ˆ0~ZñŸA‡AF˜“A›•• l@ãâço Åß~2|úú“áݧo Ÿ¾üdø ´øË· ¯?~gäa`f~Ë f­Í¬`› ŒKl „€Ù[€«TKCŒkëþ“ üœL | |Üì ¿€1ð@?ÿ@t¼†ÊݧïÄùX€!ÃÄÀÁÊÈ Àà À >}føúõ+÷¿Ød8qŸ«‹°y,P7º‘~ÿUÒS—xôô1ào®~æcþ zv ÇÁ)”Fî=ÿÈpñÖ3°Ÿ?b`††û÷¿¾ÅX ô'0mì;uƒaÑ®+ Ÿ¿ü`0P‘c2 õ}´{ï\ )§‘@p°r±{ÈK±I^¿y‹ÁÄØ˜áÕOv†Ý÷Tdù„¹Ùìö†k·ï3€2#Ðâ@ÈŸ>¾»îË·ï _|dØ{â Ãû¯!‰ú÷/†Û—2h›J=:¨êÄðë6¨”ú³ €àäã0ff#n)%yF ÌO E7f?ÿ ŒO†ãç1œ>~šANJ”••ìï?ÓÀ«wŸ>{ÃðáÇVVpÉÀÌÌÂð*/Üe0öµg`äW5ûÿú¶PòÌ^€‚;€S‹ƒƒ“áæÙ ÏïÝbP×5bÐ3ÒeàcøôhÐ!¢jz /]aØ»ê; +°”þ)1!ÁÌ’,¬, âÒŠ ß…ÄÅ¥îß½Åðñ/°ÔüÁÀÊ+.õë5ƒ0²î~A‰'·.2|ûò•á'0(_>yÌpåÌI†à„I!†OÀ\ÌÃÉÛÏpÍÔœ“‹ƒáÜ™ çÏ_``ggGÁpAö—áù£‡ B² ,¢ Å’À¸ÅÀÈ',¸ù€aÏ‹œî&ÆÿÀâ…™ƒh ¨˜bøòñ3ÃŽµì==¤d$~|f``gegÐ6Ög`çÕ¿®\¹ÉðŸ øÇð2 J zŽÎ Ïo2”¿Íf¸¥¢É°ž/Ÿá/¸†c`Gv@Áðíë’B\²¬ìÜà`—|l\ ¯Ÿ¿f¸wÿŸ¸$0+Å€%5Ów`¢ý4I@˜IXT?:Á`ñö"'0»<þËÆÀfPÎ`ÂôŒ!ƒ5Ïå1ƒÚ&¡OÅÌ/P½ðÙwÀ§wïñ(Šë²ÀÌ.é~~ÿÁ ¯­Ç ``,á ƒ7°ÄeøÊ&È øô Cùß3 ¡)~ l?~2¼yþ’áÀžN5®' Âá/¾Ÿàb8ò=›á'0|ñÞ–•Qöò¿ÿ§>üWò /ˆÞ¼{›‡‡›—ÌŒÌ "’ Zú: ÜlŒàrTý‚ #`‰Ëð˜,÷Ï1”\ZÂádÇÀÎ ÙçoD³3„æ³3è'}cøz…¡t¶5ÃlH†ó·ßýàºÍ¿Ë“i²‹(çƒì ¸¾_Ù¸ïåû¿¿¤Å,3ƒ¦–*Ct¢?ƒšŠ P• '0¡íàã%F`­øçƒÞ¼"†ˆŸ_€!L3oÞ0üøñ—á§3°p—áÛ3N†K³Ôî=e¹½ŸAãâFÆ©™wµ92™Äu™2€V‚²#@!Šâ‡¹p÷¤±¾*¿ƒ‹ƒ.ƒ 706øØ ä~ -,˜ø/îeÐ6‚À)êõ+PªülA]ç{Ãðå++ÃÙa¶ç å&ê öÛ:J,[™„‚X™Ÿœ`c8ú”o„@Zá€ïO¾=;ºxÚÇïÌ ¶¦* ¿¾ÿbàù ƒC‚'60ˆµ}fqù ¸\à&À}R w[„8ž 3¨3ýùÎSÏÀ ôŸáþÖß©½?íûògÈË k¥2bx¸qÍšu{öJK‹2üÖr<¬ÿøAŽ‚–óuq=»ÏÀÉÌÄðA\œáÿµkÀøÎðOª¯ÅŸÈ2¨ s žÿ yO|¾0<ÛÍÆPÐðéÞŽ/mÛÄoAÖjýçÓïûšKWm8õØHWœA„‡è …lH¡À f`Ë Tüdø& ÍÝ»ÙØþs²0€Ê%¶?Ì ·„ß1ürûÁðêÃÍ Âÿø1úi0+³‘ðõæù»ksê'yÿüíoY`Á)ÈŒ0 VH@1ˆÓ‹˜°Ñü ˆ?*(0üýöéÄ fA†ÿÀha¶l¸Ÿp3ÜXÀÈp®…•AžIÁ_IZh„!ra@ØûïOmº¾091·võÝÍÀF&?ÐÒ¯_ÿ3\ºóƒáí»ßÀÏ>[†—À´Äôý;Ã/`H¼×Ñaøÿô)ó… ¬Â ¹ÙÄÿ±1Îgü,À L½²\\Œ@¨J~˜U„h”22b:„UÜ”A! ÜÒ/ÞWWW‰…“áí'FFV¾¿/ô* <ÿ}f`’–c`‘`àú\àÕ+fQQ†ÀPù lâýyûžáÿŸ_ <@G­9ž!ùúõ%Àj9¨BÙ @ø" lrÞìjÞ’êfÆR *Bâ¢ÌŒ¼B œ['1„lme0gø+(ÄÀ( ÀÀrį_ \À´Á( ,¾9©–™™áò ù<=ðçO?ÐÆÙ Âd7@ãX{hƒ&›¤.»0ÐËœ| QÏuS˜ÿšék;V†¿¬¬à2–˜6ùùX€Ž8LuG>ßûû÷R Ôb ¾ i•ÿg b€1@ L  mÀT-hÁÀPàÍȘ ÇÆÆ& ô-HÁ`(<ûó‡á0DÖÿûwØ Ú´iPê*(¿ÁúDްn`fñ•a`ðfHE` ó+ËÀòñÃ#†[_ŽÕ[1 w¡)xÇ €¨åX4Z;âÐÖ/¨î¶¥>@K½¯ØzF`”ÚF³fÿ´IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_open.png0000644000000000000000000000437411550446574024440 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ŽIDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €"v10ücÑføûÏ”ù¿';“Œ?§Ò×?,ŒïŽÎœÅpyîZí˜? †¹ __10üêâàd``gg`øþ…áçv†ÿ9…Ø9d˜þÈ3²0Ëó°ÍäVþÃÆ«öøÀÌ:†SæuþBw@±0ügJr1“™äk$ÂÍÏÃÊÀÃÉÌÀÇÉÆðö;C9›Ñ£Ë+>3üþ½“á÷_†ßÿ5þ3¨1üù+ÍÀüOŠ‹ŸWF”_TLJCHA„SDZ”STˆƒ‡ h+ƒ Ãá‡ú÷3„óÚ^ }wÐ@,Ò‚¥ùþ*ÜÌLŒ Ï>20<üôèkyÏ‹§JÉJ~“’—‘á—dcáccæagàçegà:˜hІŸÀÐùü‚¿ýúê0þ°0°òŠÉ¹¢(`êùÇ@,ÿþÿeÝyƒ‘‡™A² â|ÀPªã.ÈÀ  ÄÍÈÀ”%˜A†i ‰ß30|ø´ø30fþ10üâ?@ùß@ü Ê*a`–*BD<3“nÃÿkˆåÓ«··|Õ)눳1|ù‘ÿÔøh  ØÖï@ñ ÿúôÿ lF¨¹ " ”Dþ0@ÄA!ñ(É-(É÷…]Xžáç[°4¯ #¿&Ãÿ¿ßˆåÛׯ¿~ûôÃçÿ€1Áðh$È@âß?ˆa ô?¨åpGüƒ8 ,ÿ ü @o³=ÀÃ'Àú’]Hè6n…?ŒZÅ@¿ÁŽ ¦ÿß¿>¾ñòX!3€±è74ýC Rþ‹$÷!þJƒ|r3ؼŒ ¬< ŒÜÿTKþÿaäýûû‡$Ð 6€baøôúÞ£W?Àÿ†úì7°~ø …¨Aþæ[$>,4`Ž9æë/H‚< !>~^fe?N}±™¬b:‚lÜ’ÿ³Š¾½ÊX@, 7ßò*øûÏ œ¿šþÂÂr"øaQð*÷ï"áÁ,þñ‚"§`Hsss0zëH+Ië0sp1° 0~yý ¤ò?Pã°X˜ÿ3<øÀÈpð!ãO¬ÆÅÆÀÀ ,@eÂfDiöœšGÛ_ˆ'~²3+ °”fgøõù%ŸÃ—·Oþ½ºx¨ô@±0|¸ÆðûÁ»/¿„¹ØÁ‰‡hɾ›ÿöÜùÇðèrn`A,]Á¡^hžG.˜ ÕÚ?hùŠ.P(üJ~~÷áí“÷ÀRóØïO¯føzçPù+€ba¸³Hs^ôö¸x•®þcX}˜*¹€% ׆ÿ¿~2A,c&¨/4¨¬bêaü‹(ŒÀû IC¿€Œ{0ðó3üøòX0q2üzr® ×€ø@11hÃTþÁýgo€QÅpïÅ?† §þ00m`ò˜ŠþÆ ýó7"¥ƒ1ÿí7¤H†ch ’…ÔÕ3÷b¬EŒ e¾ º?@‰ßJÝÅ@±0pHUþ~òìÅÇßÌÀzcÿ¥? ?þgàçg[/gŒÿ@¯ý–­ÿ€ñÏò’𘠥58`AŽ gÜ|Á`È÷‹AVC”aÿ£g \BÀÒøÃ«ï¿ßß¿ ~r€baøû”b½|þöë»Ï W€ñ.°¾þ‰] ý´Ì tú Ø|Ê³Ì eŒ œN€üøö+ïûW ¡‘š '€µ«š,+ÃÍk ﯭzÆðûýePðƒ@, ¯€JŽ÷_½yýžAà˧ÿ ÌÀñïO¨‘ÿ€í&pêú²è=˜€–üÕÀDªp@!²Dÿ:þÓÍÇ %þ ×±2ðÍ–æa`üòá˽  ¿ kœ Ã˃à ðÞ€Óû®}PáåçaøðîÐ &pû´ü/ÐRï™YAî²ÿC…è˜ÿŠ%̬ÊÏï>eøÿñÆ£ÿî=½ÂÀòëÃïÏÿ¾¿}üÃÛ3Ç€JžÁ" €€•°òÿL5,âZü6ÍÛu\#äîßøËðíë_v6`ƒƒ™‰X°²1*ºòÿŸ_ ?¿~bøýõ=ï¯ïþÿùúîÏïO/¾ÿúðèó·w>üýúöÃþ]òóÝ[†?ï€ñë9ÐÎ3ÐÊ$ ĈÒ>â7ö¶©Y"gäÅt00Þ3ü¡}bøóý#Ãï/¯~þùüèÓŸ//€¼úôûÓ“÷ÿ¿½|Çðçë[† …߀–üYòˆí+`ÆgøŽ„A-ŽßÈV#F3•× ŒUÒ¬áï®?__þÿóÃ;†ß߃}ñû=Ð࿯ )ø#4!ðWhœ‚ ÿ -‰ĈCLˆ¥ †~CÂ? ø/)–àÄ8Ð}C€ðŽ @ ¸hÀ`kåü–ixëIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/link.png0000644000000000000000000000154711550446574023100 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ùIDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €Ü4à w@ ¸hÀ@î€pЀ; €Ü4à w@1†„„ˆ011EþýûWÈçfffæaaaáÑ@qn æ²yÿüù#xàÀ¾ôÛ?©å€bZ¬($$Ôž””Ä-))Éðïß? €3-cNNN†cÇŽ1ìÜ¹Ó ¨g#_¡–ˆåàÁƒg*¥¥¥[³³³y………±*üþý;Ã?XLjF@1½{÷îÿ½{÷&/[¶lÅ‚ ~ýú…U!PÃÏŸ?A’¿©é€bqqqaøüù³•WLL 0®Á¾;###ØA@Ÿ3¼}û–á7õü¥¦ˆ…‡‡GJ^^~jaa¡40-0¼yó†˜.Þ¿¦AŽ¥ƒOŸ>ÑÄÄô]°¯¯¯¸¸8ÃË—/Á–‚èK—.1°±±1€Å>|øRÿ‹Ú QQÑPccc†/_¾€ƒûîÝ» K–,ù·uëÖ'@°—””ˆ»ºº2|ûöÿTu@±ðññ©rssƒ-þü9ÃòåËAø0dVåŸ566VC^ PËÿQÓ*X@PB;}ú4Ðçìu@¹•@|˜n¶µµMååå5ò¿ñj: €X^½zõ ü" G\¹r âû€øTÍI #’8Ⱦ ÄŸ©é€bºsçΞóçÏ3°²²‚²(ˆ|ÄÈ}6£ºx ¿§¦ˆ ˜èÖ/\¸ð( A-Š£’¥ÂÔN„.lØÙÙóòòþ¯Zµê?°H~÷À§]ÔÂ3T ΖŠÿ544@A_Ä|ôp@1"…„P ÈÔâÃ@¼ˆ?árµ@€ðî•)‚HúîIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_important.png0000644000000000000000000000621611550446574025511 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< IDATxÚbüÿÿ?Ã@€bdßÍÀÀÊÆÀðçÃß¿ ÿYdÿ_e0ú½‡á?T 2ø TÃÏÏŸìââÖñüùó»gÏžÙ{âÄñ]|||—¾|ùòH30333\¾|™A]]áæÍ› ööv wîÜa—W`xýúý{÷TUUnܸÁ@,Núÿ‹á1‹1ƒæß3 ¼ÿß1üa`Aw—³³sqbb¼È¿ÿD^¾|e~çÎÝ’K—.^?|øÐ™/^ìöìÙN Ò7 ÇÄ‚]ø7Ãf/›_k8þgø %Pt±°°êèèi‚øLLL ’’ Ìfkk­Ÿ˜˜¤ôiò©S§__¾|éÔÕ«WÖ½zõê$Ð!÷ÿüùû‘Ó&€Âဿ ßXÄŽßff°—øÂÀÂɶècaa¡55¬º¸¸8ôôt@Xôë×ïÞÏž=÷¾qãÖÛ3gNÝäååß÷ë׿ÿ> Túd ®¤ÁÀÄÈðùÃ[†ç /d•Àøóç7‹¾¾¡ƒ€€Á åææƳ {zzX½|ùÚêÊ•ËÕÀ¨ºq÷îÝçÏŸÙÀÈÈx €X$Q†[·n3¨j2]Œÿ–†††Z¤¦t -ÒÒ¢@ìÄèêê¨ùñãWÍÝ»w'd'~02üþõáÓ§O@ßÿa’’6ÓÖÖâ§”«ñål&`È ò0(**ñÕÙ’€ºþ00nþñß`üRïßa`eefTVV¶*ùÎŽÿ@jþƒâòD?ƒ$±ýcøõû/Ão Yèû ÆÿBâþܹ3??~üð € Qðó0ÝiÃJ›“CKˆCîÛo†Ÿ9„&ewaàÿÏÊÎ%c¬¯í ñÅ_°7ÿþþÇðæË?†·_~3¼ûò‡áÍç¿ Þÿb¸ýòÇ>~ÿÏÀúÿC„4ƒ?Ð_ÿÁeÄׯ¿Nœ8ööû÷ï·ˆ…á?c …Žø\=AiA6i6†»ï ÿ¦ë|¸¹)ì!³å FQ·L’¼«O¾axòú+Ãûïÿ€–ügx÷èËŒ ì, œ@,ÌËΠ,Ïà ÎÇÊ &ÀÅбü,Ãöƒg"ÝMþ1²‚œÏðäÉS†óçÏÞr_eE„† +3ëÏÀÒã;ÇÀ`df¦~5Ù~s‹Ë«0pI²Ê|-ÊÀõñƒœ(ƒ®,ƒ/3ƒ'0à˜€ÏŽ„_ÀÀùþ˜Ï~1ÏÊÎtð†ß00±1ƒ£æúõkÀÒðÞ% ç@±01ýçÜu‹‰o|À™—ƒAHs#§ÜKœA(<\E„ë?ÃÿŸ_ä$øÀ16Š-üú’d@Iä€_@—ü:â0…±sr2¼~ÿ›áÇ lL ¿~ýa8sæä§ÏŸ?ß•–ÄòþÕÛ».ò¿tŒeؾýg°a ƒX€¡ÂDï߯9#Ãk LGà´ú–f¡TZ‚Ó.D?ˆ¦# ýaøþí3ÐsÞ`8{ö40Œî‚”˯_ÿ:÷ßv†¯`в¿jlð`˜ ðs!,þµ˜Bÿ:„ \§ý†À7 äexü‰áãço ÜÀòëáÃû —/¿ Ô ÄtÚ£‡o~ƒ<ÊÀÆøŸV^ƒ ödÿýe`faûìK¨¥¿¡!õü¿¡¹Dƒ,ÿ Ä‚ü< ³0¼ýð˜mÿ2\ºpæÓë×ï3šeàUf &†O/î½úðƒÚàøû¡A–ÿaÄÌÄÀÊà .@þüX ö1̲¿‹`ñ¿ÿ†D(´@æ2±r2¼xû™á×× ç~ceqÃf\4…áÏ%€bb¸µêÑÓ·¿¿‚Ìb°Ï€ ñÛúµ +S>^<Íð˜ þ0 Ûoh€ƒý?"õƒ0ØñPyPnbæ„7ï¿1¼|ñ„á!—6§jpŒ<ËÏûÆ ßŸêƒæ«{Oß¾,ˆÿ-ÿráƒè¶y .º ¿ûkž?~ÁÀÌ ±l0}|þ LTÀlûˆ?s( ýü±ø4d@¡ÀÁÍÃðXXݸÿáí~†¿ï?3|»½ T¼ &qË/^¼}ÿå'"õ 1æe34ÃC¸]|ŒdEΛÉpá Ãõ×ÀÔÄ÷Þ30<ûÄÀðdùOˆÏAÑÊ–?Aæ@Cê'0:„ÅD>sÁ¹{¯~³ 2|~tç?ÃÛK „ø €˜þ|øðêõ‡Wo¾ü‡$ÀáëÖ ò¿_2ðjë3ü¿}›AÃÞžAøÔn†ó'®3Ó+ÃçßP aÑõjñ_Ôtô æa†·ÀSð¨ÿA„°Š'¾ãG2<øÀÍðñ/Ãßï_~?9rhùmPn `"´:“ûÅÛ¯_þ¿zË z|#ƒœ¹%ƒ¸Ãá+WJ23Þêè00HÉ18qþcP?ºˆáÁ'f†G¿î~dÖ|ßî>zÉððÙ†@Ë>K c@Ùo` <}ìC¤‹«€ÃofA`€?øòïë å¯@å @Ü$¿ûè#Ã?¶å , …Ä”ÄDD„øùDÄ€|7WF†èç‡ØO®fø l~câaøÀ$ÂðšAŒáÉwN†û¯0Ü~üŽá΃ç ÏÞ~a8x䃙ƒ¤š Ã`YÀÌ#ÏðíÁé— ¿Üà Ão`½Ëøõúµ;>sßÊÀwóÃoH¥#lû)((€œÈÀ`aÁðNWAìÛóÓó>>}Á¬îÁñþýÈ1Ü _Y„>°ˆ0¼cf¸p÷=Û‡÷ Ʀò ç_Pèû_ _ﺭ~ƒŒ fmf6Á/¾x¾>•ìÅýLè'SZ1;'¸Ù Â&&&àòA\ŒáñŠÕ ÒÀ’ô“ Ã{E[¦ˆò\ŽëPñåþs†œ e†ëÀM€€yõÌá³ÿÜZ¸žáïO`oˆá ÈÄ”ûê0CÞ«ÃÒŸäÿ}ýÈð3¥”á;/¸ ø Øÿïß~«Sv#3ö°`´;·€á×½ëàD÷è—ÿ@ËAE/0á½¼ù„A[‚‹áê[f†‹^2\8rŸáέ ÿžzÂðëã5 ½ï` A€baü÷›CB^ºFêß'ÖŠz ?Ì€nûÄÀ%,Äpæê5†i³ç0˜ØÙ1ðñð0|&ÜiY /Ö¯g0{y‹áÔ‘© O}»Ø€ùíÛg`/êë{†_Ÿßüw÷Ö¯ßß~ý÷éɆï/?2üøø‘áï‡w _¯ÚyÔ„9 €g°°fÛZiL~q“á30žŒ­€yTƒ€0 ¸aùX ÿfì_À0þñù+û}ûx~þd¸Ì)ÄÐ#êôâã?Æ'ÿ>@þ_`€•á/ËOÿï®> Ls@Å*.  ÿÃ׌ F9^VÖdffV `šñ?´† ˜€ò!ÅõHãŸéÓÿß^ÿgØ´aPø9Ýs€ÒµÚÔ-\ IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/exec.png0000644000000000000000000000417011550446574023062 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< IDATxÚbüÿÿ?Ã@€bb`@î€bAæÌ`ddø¤Yø;TŒˆA~…Ò€ø³CÕýƒŠb`F¨mÏÅÅåpíû÷e;þÿŸ5À¢ €XÈqõ¨¥¿˜ØÈwbcf6SWVÖPÖÖVWRSc`z¦}êTQ†ÏŸ•žÅe@‘ä ¥\?T´ ›•˜””™‚¶¶²´º:£´¬,ƒ0Óë× =bø ÄÊ ü ¶.B !_$З®@¾¹¨„„Œ³“¶‚Œ¿¸ˆ0ÏÀùý;ÿgÏ~^¾Ìðíñc†_ïÞ1üûñƒÄòŒBŸ?À 4ç=6{Ã@gŠ-Öƽ ¨¨¥¤®®¡”­°¤…ƒ¸‘1—˜ÓÕk ‹2ü¾z•áë«W €þýõ‹áß n`Ðÿgaó•99Ä€!vŸA—ÕÌÌm &&Á2ööj&¦ B:Ú Bšš`©¿ 8ÿõ—áë/ óþ32°Ý½ ±d!33Ã&&pˆýûûì¿¿3ˆå´ÙØTÏýú¥ ÅÛØ@(øÃÍíäfàûô ˜oÿ) 75l%/@¡ùòÖýû—ß^8ÏÀÌtÀ?ˆï!ð"?2ü—’bø§ Èð˜þÿûñù—Ï ÿÞ³á‡À膒®>wnƒ’¡ 70X àBw@¡$Â}ˆ:õîÔéIuÐ`û^B€B‚ XksÈŽ­ ÿ€ ”>þÉÊ}¡ÃÀ¬¡ÅÀ¤ŒvUuviI…®Nóg4Ÿ30 ø‚l'@¡8€ˆß20ìztèP«za+#8~ÿÿÿ ±”Ý€ÿŠ3üùÅð_F†áŸ“+Ã?=Mmf …Œ|ü \ LœÀt,¤~=Í haÍ ÈÆ®rã×O ó#Û @(à…Ú—oŸ={ËâÁCmn`Vûóã7°`á§þÿŸ€eÚƒ‡ Œ§O20ž?ËðÿɆÿ¦10*)20|ü Žw†¯_!QÆÿÁå/¯œƒ¦šºÂÁ+—ô€©ë$¢e` @kÀŸ>9÷æÊ5m Ÿ?g`¼t‘éÒ†ÿwï0ü{ò”á/0žÿ-ûûýÿ ç$$þÿM/ÿ‘rΰ#X¹yäµtع¯\Ò:€RqB@¡8 ê´ÿÿ~;{f¬:ÐpÆ7þ¾{ .ÙþÁ0Þ‰ôë†ÿ'k  >Fh:ù¯ja¥9#3™UËt_10#; €P0šä€E‚ë‰coÿrrƒÓ;;¸¨¥ø¿@Ãþ²0-ü=u’ è@Nn`yý)uþ_`i*ejÁ ""ª~îÍk ÐXê ”l¨Ë)²ä€EÂýwﯾûö Xæ0B,„–xÈ (1þ}xŸáßC yÌLP߃r ²#€F¯´ ƒš¢²0BÛ<`@(àâÏÀÏ¿/¼yó† „Ø YòùÃ?`ð• \2" /F°ãAœ€¹GR×€Q”Á(ɳ €PpŠAÍ—g Ç^«Z¸‘0rñ JìªfU`yÀıøPî 0_úÀðèÅs†ë—/Ë6P•ˆ"0;%  ±¡°÷æÛ·¯ô¿c„U0Pü Ê†T;ÍðhÉ/~A†OÞ1|Züíý†¯/ž2¼æ WÀôòÞݿ޿} ,îgƒÙ@(¸€ZJ¾±ûüùìÛ|ÉÀpó¤MpˆÂ, D¢¶ÿþüûwü5Ðb \´ø&ÆOÀºà+bÿíŸß ºÛž11~½õüÙ“ÿÿ?xÇÀpŠ·€æ€ê÷§@ bømPÃ@¡8à š€m¨ÃfïßÿäãcåˆÏÀ¢õ+þÄoµàÓ?¾Ýú÷ï%Pß“—/žÝ–õ7 ”Í^ñGhù†³û@(8Œ& lÏ]}óéÓëϞ)¿ûò…áÕÿïüùóêÆ¿€qùè;Àšå*Pé] ~ ©JÀ•Íb[ÚĈÜ7¥^ôºÁ™!XÂG>!0ânM¿¾ °wP “Ü·€Ú @x€J*ÐÂã R Túd ®¤ÁÀÄÈðùÃ[†ç /d•Àøóç7‹¾¾¡ƒ€€Á åææƳ {zzX½|ùÚêÊ•ËÕÀ¨ºq÷îÝçÏŸÙÀÈÈx €X$Q†[·n3¨j2]Œÿ–†††Z¤¦t -ÒÒ¢@ìÄèêê¨ùñãWÍÝ»w'd'~02üþõáÓ§O@ßÿa’’6ÓÖÖâ§”«ñål&`È ò0(**ñÕÙ’€ºþ00nþñß`üRïßa`eefTVV¶*ùÎŽÿ@jþƒâòD?ƒ$±ýcøõû/Ão Yèû ÆÿBâþܹ3??~üð € Qðó0ÝiÃJ›“CKˆCîÛo†Ÿ9„&ewaàÿÏÊÎ%c¬¯í ñÅ_°7ÿþþÇðæË?†·_~3¼ûò‡áÍç¿ Þÿb¸ýòÇ>~ÿÏÀúÿC„4ƒ?Ð_ÿÁeÄׯ¿Nœ8ööû÷ï·ˆ…á?c …Žø\=AiA6i6†»ï ÿ¦ë|¸¹)ì!³å FQ·L’¼«O¾axòú+Ãûïÿ€–ügx÷èËŒ ì, œ@,ÌËΠ,Ïà ÎÇÊ &ÀÅбü,Ãöƒg"ÝMþ1²‚œÏðäÉS†óçÏÞr_eE„† +3ëÏÀÒã;ÇÀ`df¦~5Ù~s‹Ë«0pI²Ê|-ÊÀõñƒœ(ƒ®,ƒ/3ƒ'0à˜€ÏŽ„_ÀÀùþ˜Ï~1ÏÊÎtð†ß00±1ƒ£æúõkÀÒðÞ% ç@±01ýçÜu‹‰o|À™—ƒAHs#§ÜKœA(<\E„ë?ÃÿŸ_ä$øÀ16Š-üú’d@Iä€_@—ü:â0…±sr2¼~ÿ›áÇ lL ¿~ýa8sæä§ÏŸ?ß•–ÄòþÕÛ».ò¿tŒeؾýg°a ƒX€¡ÂDï߯9#Ãk LGà´ú–f¡TZ‚Ó.D?ˆ¦# ýaøþí3ÐsÞ`8{ö40Œî‚”˯_ÿ:÷ßv†¯`в¿jlð`˜ ðs!,þµ˜Bÿ:„ \§ý†À7 äexü‰áãço ÜÀòëáÃû —/¿ Ô ÄtÚ£‡o~ƒ<ÊÀÆøŸV^ƒ &r†ŸÀ ûûÿ/3++Ø÷`_B-ý ©?Ðàÿ ͽ dùo äçaøø›…á퇯Àlû—áÒ…3Ÿ^¿þxŸAÐü+¯2@11|zqïÕ‡  ÐÇß ò È’@V Ã!€ùfÙ_ˆE0‡€øßC¢ Z s™X9^¼ýÌðëë†ó¿±²¸Îa3.šÂðç‡@11ÜZõèéÛß_A fño A4ˆÿX³²±ƒƒf1Ì·¿¡¡ñû?"õƒ0Ìñ yPnbæ„7ï¿1¼|ñ„á!—6§jpŒ<ËÏûÆ ßŸêƒ€Î«;O?¼ü ŠS /ÿ332üc‚¤E ÒŽ“”}Á ˜åm Ã€r_ŒOÀtò˜u?s( ýü±ø4d@¡ÀÁÍÃðXXݸÿáí~†¿ï?3|»½ T¼ #ÙOîÝzûž0Ã×Ï?¾|ýÄÀÌÅÇð™Xý6G€éãÏW†ÏÀüöæ$xý†¿ "–‹WOP\"ÿÿš>Àªeøôüù{ï~³k2üztç?ÃÛK „ø €Xô„žúéI~º}„áóçÀh  °Èdµ¿>¾ÁðžO˜9¾}û ˆ ‚lðæÙÍûÏDíÒD…Õ_hE‰" ax{÷7ë?˜Ä8>Ü:ü‘á÷p9@,ÀÐ6÷rsd’•“g¸{÷.ÃË—/Á–óó°38s›aó †(ñ/ ×Ï`ÈÎ.=#Ã/a†×y¸~¼d`ú³’áÊã» r*à ÿ -Àié(ó>0žnßÿÈðXÚ12°1ü~zTÜâïÄòèįÀBâ;°¨ùðë×oÀš•áç÷ï B¼ü zRÿô´u€u ƒ€°ÐGŒ w¿døû郈”00¿32ü6Í~ü…ø\™BJ7ï€‰ïø‘‡ _>pKÚŸ Ìß¿2ü~rä Pö6(ˆZ"5˜@- ‹ÁX߈ÁÅèf #T€ŽûÌVì j²â ¯^þa`eüËÀ´üÙ« lO?3°Õ±³³10³@*ÙÀDqú؆H†ë3üfþÀðçÕƒ/ÿ¾¾Yþ ¤ €X°´A€Ƴ (0þeøôÚëׯΞ¹lVË2()Ë›[B ì\ ß¾¾·?2ò1<ùÆÉÀø˜€ÿÛ@‡qñò2ܼñšÁLŽ‹AR ˜Hiˆ™‡ŸáË•ÝÀàûrT ƒì &ÌÍp022²€S:;+Ãá#G R.š †?¿A L¨ úá?0ùÿú,Pü¯,B XDÞ1 3\¸ûžíÃ{cSy†ó/¤Ä¥*Ã×û‡î@ëP03Ž–a0–àb¸ú–™áÊ× b¬ßîÜzÁðïÉ¡' ¿>^Zóf@±`‹P.øô郀€0Kr«Tn`wL\а±qëôŸ^3ðqkO`©ùñ ÷û¯þ||Îðëó›ÿïîÞúµãûÛ¯ÿ>=ùÀðý%°pù̃Þ1|½vhÅ PA ³ €X€>fbcc¦^v°ÅÀž˜feýÇðîÝc åjÀ°¥ò˜É¿|þ ÌÏxy8„€Ñ •Ç»'Üûó£ýÃ7¯þ|{ÏÀøاû L¡?Ÿ€  þ Mt¡|8 `{ÿÝÇÁ©ØÙdxûö-¸ËrÈ_`;áñ£û@‹ÄDDE¾|ù ¬Pž3pr²:¨ ¯€¹ãრÿ_Ú,æŠV¨ï~!áøšñÄlf+ppp$[«ê@G0‚¢Öe¥P"üLxLLÌ`.¦!OƯ߾ýøòùó6 {¨d#µÓ``ÁlèªI"IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_print.png0000644000000000000000000000622211550446574024625 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< $IDATxÚbüÿÿ?Ã@€bdßÍÀÀÊÆÀðçÃß¿ ÿYdÿ_e0ú½‡á?T 2ø TÃÏÏŸìââÖñüùó»gÏžÙ{âÄñ]|||—¾|ùòH30333\¾|™A]]áæÍ› ööv wîÜa—W`xýúý{÷TUUnܸÁ@,Núÿ‹á1‹1ƒæß3 ¼ÿß1üa`Aw—³³sqbb¼È¿ÿD^¾|e~çÎÝ’K—.^?|øÐ™/^ìöìÙN Ò7 ÇÄ‚]ø7Ãf/›_k8þgø %Pt±°°êèèi‚øLLL ’’ Ìfkk­Ÿ˜˜¤ôiò©S§__¾|éÔÕ«WÖ½zõê$Ð!÷ÿüùû‘Ó&€Âဿ ßXÄŽßff°—øÂÀÂɶècaa¡55¬º¸¸8ôôt@Xôë×ïÞÏž=÷¾qãÖÛ3gNÝäååß÷ë׿ÿ> Túd ®¤ÁÀÄÈðùÃ[†ç /d•Àøóç7‹¾¾¡ƒ€€Á åææƳ {zzX½|ùÚêÊ•ËÕÀ¨ºq÷îÝçÏŸÙÀÈÈx €X$Q†[·n3¨j2]Œÿ–†††Z¤¦t -ÒÒ¢@ìÄèêê¨ùñãWÍÝ»w'd'~02üþõáÓ§O@ßÿa’’6ÓÖÖâ§”«ñål&`È ò0(**ñÕÙ’€ºþ00nþñß`üRïßa`eefTVV¶*ùÎŽÿ@jþƒâòD?ƒ$±ýcøõû/Ão Yèû ÆÿBâþܹ3??~üð € Qðó0ÝiÃJ›“CKˆCîÛo†Ÿ9„&ewaàÿÏÊÎ%c¬¯í ñÅ_°7ÿþþÇðæË?†·_~3¼ûò‡áÍç¿ Þÿb¸ýòÇ>~ÿÏÀúÿC„4ƒ?Ð_ÿÁeÄׯ¿Nœ8ööû÷ï·ˆ…á?c …Žø\=AiA6i6†»ï ÿ¦ë|¸¹)ì!³å FQ·L’¼«O¾axòú+Ãûïÿ€–ügx÷èËŒ ì, œ@,ÌËΠ,Ïà ÎÇÊ &ÀÅбü,Ãöƒg"ÝMþ1²‚œÏðäÉS†óçÏÞr_eE„† +3ëÏÀÒã;ÇÀ`df¦~5Ù~s‹Ë«0pI²Ê|-ÊÀõñƒœ(ƒ®,ƒ/3ƒ'0à˜€ÏŽ„_ÀÀùþ˜Ï~1ÏÊÎtð†ß00±1ƒ£æúõkÀÒðÞ% ç@±01ýçÜu‹‰o|Àèa æ²+|$„""UD¸€¦þúÎ +Îޱï?†C-ù ”úú’d@Iä€_@—üÊÿ¦0vNN†×ï3üøñƒ‰ƒáׯ? gΜüôùóç› Ò €XÞ¿z{×Eþ—ޱ ;Ã7`uÀ Ôô ˜â¿þüÃÀ ô #ÃûwÀ aÝ[ ÍLÌÀDƶð?,Ý‚,üM» Ç€h`:bàá:àцïß~00s00|xÿáìÙÓÀ0f¸ R@,?¾~yüèÜÿÙÁA÷ûçO†»—.20ƒŠ ´Œ ÿþüf`&žÏ@×}øòAZK‡A@Xl!Èò?P€00áƒë4P}baA^†Çß™>~þÆÀ ,¿>¼ÏpùÒùË@ËA!ð €X€N{ôðÍo39`10|üúAA’‹ÁÌH•á¬9h 0ìÞ}’áíÛw ¼"ÂÀÄõí ãƒhå¿XŸ‡áão†·¾2HHýe¸tá̧ׯ?Þg4ÿÊðç @11|zqïÕ‡ @³Áñ÷ä%` dfeg`çà``b6†ß@±¿Ì¬ Ì,ÌKa–ý…XÒûÊÿ ú?œ 6—‰•“áÅÛÏ ¿¾~`8ÿð+‹ëÜ6ã¢) ~(íUž¾ýý”pÀ ži\”Mø ü ´á'¨Pz X@‚æcû?"õƒ£ñ/$Z@ò ÜÄ Ì oÞcxùâ ÃC.mNÕày–Ÿ÷¾?Õ &!ÍW÷ž¾{*ñþ3Að_hMrÌ/ 7ý”j€•f¿ÿ32“#°ü–@ ̺Ÿ€4°|–i‹ÿ@C Ü< ïŠoÜÈðö??Ãß÷Ÿ¾ÝÞ*Þƒ˜ÝûÇÏÞ¿}ôâ=ÃÝ›7öo^ÎðõãkhüÇý ƒþ+#P1ý÷ç†}[Ö2?ºóŸáí%PB|@,2¬—¾ð>¿ÿñø†³ ¢ÀJB[šf¬ o€%܇/?~“3¨&üóãÃw C€YÐUWšáÇû ®¾dxÂ!Ï ì.bÿÁrÅ?¤(baa†·w3¼úø“IŒ“áíÃ~¿—Ä¢ÉvÖÈÏ5Ì$2&Ø4dgxõê%Ãéûn¿øÁÀÁŠ``beøÇÁÌðò3Ã7nImyYI)†ß?¾1,[¾€áÞ¥c І¶à ÿ -À‰ó(£è°~šùXÚ12ôÓ rà¨L –ÿ̼FfVüœ\\@ß~gø ŒÄ?b’ oع^~ùÏð·ÀT.Ý€ÅíOe‰Ÿ÷¾|b`dag060f¸vêÃ][¦ÿ2àÔ@å ï€‰ïø‘‡ _>pKÚŸ Ìß¿2ü~rä Pö6(–ˆ…UØÌ–çÀ„õïóO?¶àa¸zèÄOŒ” ‚Œ ÷Ï/N#]3~v†Œl RÒâ _Þžc¸÷ð °ÄÃÀÎÆ̪,ð\tú؆H†ë3üfþÀðçÕƒ/ÿ¾¾Yþ ¤ €X€‰ŒåîÝç ll| ¢ü, ?ñ1¬;ÊÁðó;´E+‹˜ üL ¯•x8€ÁùêÕ7†çOß 3çï ì  çï/`éý—‹——áæ×ÀŽ‹ARMá?°,`æágøre÷K†¿_n€Ša±Äl,üyûö#°éõ„á;ƒ4°Êì7þÁð›‰á°ýú Ò”åfýÏ Èù˜%Y0œ<ÿ›á¨Îl- ùïÌ<À è>F`lÌߺû’ÿÃ{cOC†£/¤ÄžÛ _ﺭ~ƒÌ –ß¿½áädf–c8}ö8æ Ë$E…À©ØêµMÁà0$Þ žÿ ;_½eðôe05³aøýåÃ7fpéÇnŽ­ÿËÌðýù†üu†k_4¤uƒ¢0Ãå5‡þþ{¬hžÂÚaÄòúõë[À@`–g¸~ƒAEU!<<˜}þ‚›]àæ8´N–ÀJ‰…aýúuÀZŽƒANF‚áÞÍß Ÿ…-` ,©ž^{Â`,ÁÅpõ-3Õ‡/ÄX¿1ܹõ‚áß“CO~}¼4êÌÄrïÞÝ£/ž¹eii©&&&Í—Æ ««®·ÿþýnŒ‚hc@¥ °¡ÀÀn`|ûü’áðùÛÀHñdøwï9×O¯~}~óÿÝÝ[¿v|ûõß§'¾¿üÈðã#0~xÇðõÚ æ F ÌÄê݈ˆûûmÙŽŽ>Ö­­5¼ŒÀºÿ÷ï?`K!ø?´A F.NV†–öþë÷œ{õòã§ï¿™>þýôè=Ã`5ùçÛ;Æß@úó+†?Ÿ€  þ Mt¡|xŸ €X@=”W¯^oùòå×óôtíõ_¿þäýùó'$ÀE1ÈrpÃã¤u r++7ƒ¸¨ÓÝsë÷®âçPK@”~!áøšñï­±³sr+)©E333Ù-â÷‘ø06Œ:’éÁƒ;ûüåÈqJ*0 §Å%÷²IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_home.png0000644000000000000000000000516411550446574024425 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< IDATxÚbüÿÿ?Ã@€bb`@î€pcÁÿ  #3ƒù×OfÆÿÿÿc`2þþÿÿ÷÷Ÿß¿A<0þÏLGÿþüû÷Ä%)FFã÷Ÿ¿¿Žÿø1éàÜl tQ‘¿¤äyygÄèé‹‹ 22¼{ôˆáPœ“…áëÏ ,ÌŒ lL@'üýÍÀÀÌÂðó÷?†_?1p±11| 1þc`êøþ›‰ãî‹ ×?~÷™a6³4˜ –ÿe``ààX¨/'g|îä !†ÿ~~ûÉð÷çO†ïŸ¿‚Õ2ñûÛ' ƒ…áÏßÿ ÿÿýe`eeaøñý 37ƒ83Û‡/? oþý³è‰×è &6 à G°01šÉËû½¾û€A@™Uê§4#3çïþ3³1íbøú‡‰á37ᅩ Lì\@yf†_aÇÁÃðèºOÀúùï?ƒ0;C°¿š CÐxt8‚ÞA_FfïÇÏÌÿÿ|eˆ,ÓeÔfcøvö Ã¯ïŒ @;XÙ¹þþø ´¬éç÷ï ¬ÀPùóë05010øÿ÷OFv`ìCãÛWq ~f6­Ë?þüÀÀpšÌÀ €˜˜¡¼ï BÒµØ9X¿¾}Íà¯ÁÀ/ËÇÀÄÍÏÀeËÎÀ Lv  æaþÁÀÊÔL”‚ìÀšrýaaàbªý÷á0˜xX~3üüÏÂðè8NÆ_ _þ0íYVÖÀôpýï߃@Õ¯@ p9Ì qÖrrñ|Ÿ1ˆÊñ2$ê …732°3p¹Ë2ð20ˆ²p0üüóA€‹™ ìCQ^`°Ó=ëÿ_ B|\ ¿€¾çfúÍÀÉÎÊðç÷!n 9Xøÿ0D)Èj˜12Ò?Èn€bÖf`ÐÖ“‘Yìðû7ÏŸwo$M¥„œ€¾¥H L¬À¸fa`àcø'ÂÌð÷È3†Ÿ ƒÿýaøõ˜8x~~ùÈ*%˜ ðëûW Œl\`=¿¾}a`áâcø¤ÿ€r/'0:DÙ¸5¯|þü˜N³ ÓRvvýo¯_3|F­¨™ƒ¡$@yä #þƒQQ”áç»/ œÀ¨øÊÌ‚@CÙ€ÁòûÏpÁÃÌÁ ûLœÀœÂ ´ø+§ Ãß¿L@〡(( 1†Ÿ¾Y\úöí"@13ÿÿÿýàׯ?öÿÿÿòPÖ2ÈPHFEh!0i±-g†:äFVmq†ß§2|{ôá;#30àY¾¿ÿ Lt ?¾übøñû?Ã?Pzàdcàáe`&RavÑ? Wß|d8øîßïÓï?þzûñãí_¿ÞËq† @gE‡!C<s30 ÍŠ€JafpJg`%`<óó1°Eê00Ì>ÂÀ*ÁÃÀ)ÎËÀñX°³!ëo {ÿ3ðpý¦wÀ4ñƒé'° ü÷ìó3W&Þf8 ú# B ˜øï ´Œ~ô#ƒ ÃF`I 7`ÉÄ¡¡• âÿ¸œäÕÿ3°ü~ÃÀÄË,•>20¼}TÆ1í÷_†¿1Üxü‰áõ)Aæ¯ zZ@x_Ëšw~00ÌÙ ÄÿˆVy±8Њ¿À²˜ˆÞÿÅpèí3~-~aV^ c€åÃ/Pa Ã, Å/önØÏp÷¥óï_ þ– "R’@G¾gxvî*ÃTV†óö~ çzô¸·2ü&hfˆ¿Bs?@bl¹4¤0—ë ì¼ Ç~Ûûøö^eàÿwè Y`èÞ€bÁl#À¬ù€M `…óè:Ã[ì ¿n±10™CŠfHÕ áÿϾÛÄðOæ9Ÿ­ÄÀ‚IRß‚ARþ°ÑŒY`0”'h €XQ[C,l<À`‚ì àæ0.þ`x!ÌËÀ ,Í !ÀVýŸ…!69š!h°>¨Jb`&ãä‡$8`t}æú? F /0vAu¬Å„×6ìû+#'Âü—÷/ÃnH…øè!`ó ÿ 0Bš/LÀ¨à”¶€¦¢ŸÐ¤ `‘Ë Ì Ü¯~=ùÁðáÚ†‡GÎ2ܽùÔâú…ì€bÙ„";vnº»bÏ…p=m1sG&Žfÿnó«`|3Ëz`òWÑäùª ê{`pý{ÏðöÒ%†[{1<8yŠáƵÛ?.Þ{úâæ÷Ÿß10<–‹g ÁĈ­¡ ÄR@¿[K~ºBŒÿÌÿ+\“g˜”3…ÁÐÈèP )mBeør÷ë‹g®ìÞÇpñØ™ïW®ßûpãÏ¿‡ÏE-°x¨êßâ—@ tØeĈ¯Éjè]£¬œØ}lM |ÙÕ>ÚrÛ7€¥Åm¨…Oø-ÔB¬Ír€b$²ÿ 9`˜i00ø¨ 0k¿üô÷ïà πúí A”ã_A-üMŒÁÄHFOŠZxK†ÏÐ ýW’{ºÄ8нc€ð¾!@€ìU ÞÌ|-HIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/camera.png0000644000000000000000000000353711550446574023374 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ñIDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €X@DBBÃÏŸ?µÿýû' J”,,,¬Ñ¢¢¢®lll|Ÿ>}züæÍ›…?~< RTÇR 6Œ,ŽÌGVÄŒ@ü‡™™ùО·vSjmm]###à ܬ Tì–ÿPˆbee2þ10213üùóŒa–Íc`ddóAâðŒ˜˜™€bÿ9räæ7üìyyùÆÐÐPN>>>&&&†oß¾1¼{÷ŽáóçÏ ÿþ…”cÑììì woßb8°/ƒ   ƒ…µ;Ãç/_øfüúõ ¨†¨ŸŸ‡•‰‘ˆþücbøúヰ/£¬¬¬f~~~@4˜¼`ƒðhЋ/Þ¿öÈ ’a ®òî% î½ ·¬gàæ»tˆÃôé“bbãƒ"?¼ÇpûáS} †÷ÿØž~cfxþáë“» æÜ7Áv@ôå?å ßÁ0È"¥ qdËAAÿîÝ+Æÿ]ÿÌÀðþ7ƒ¬´,Ãå«×Ž=Ê`bb ^65†Ÿ , Ç/ÝaøòýÐnnN_ïØE¸€{NNÄBJŠ9äÕ«— ||¢ íeÙ ËVOfPõc01·eÐ76gÐÕÓc044føôù+Ãï_¿äÄÅÄù¿3|ýü‘áÆ   œ\ ?~ý¥-€"Ú PùòècV))eV6V†ÖÆFpˆü¦>O//†?~ñ/p¢û´ƒ™…OPœAYÍ€áñ³ ÚÚÚ ß~‚› @$…À§OŸ”• ~ÿù tц/_ÿ3ppü:â?Ãû·ož?ýv(7?ЧüÀ¨…ä¢?ÿ0Š2¼yó‚áõë× \\\p3ˆ…Xßûö‡ü@Ÿs ý.Ã@iâÿ¿ï ÏŸ=†Îo :6 ¥¿ø9ƒˆˆ0ƒ„¤,þùý›AL\†áÅó{ \7 €˜ˆuÀ?xyEþMd„ˆÓÄ?`Ny 66v!†{÷1|üôƒAHH˜VÞ2¼yýT¨Uÿ:š““XN@Ì‚€"2 @Ì`Þæ‚NPßÿþõœ&øù… òÓöîÝ t$/C[ûW†'oåDaÞ“ll ß¿ë€"*@–ƒ `–zÿ ©¤ÿׯ â’ —¯œ[ Âkúô~!a!`±2üøùnH+ ÃïßÀ¡ DAeÄ1”=™P”àòŒÑCQ`bb„F(þ!.‡TZì ¯^>c037gðõ [ *š‹K*ÀY”pÙÙ9áyäë?~ƒ³.L €Xˆõ-È?~Æ!Ø  ,ÆÅÅËðõëG`Éøš¡§wCZz0Îå„ÃÕ+ç„Àøþý'Ø Š6a>pZ€"*@®åää–o 4ÿ3üV.""Ò ?¾}fÅ b¢ÂÀäù‡á0M°+'E% `|C¢€‰‘‰áû·/ÀtÁÀÀÎÁ7 €Xˆu7ÃË—/~ýü ,|¸!‰ Œ¬ ²rjÀ ÇðXÁ°²23(«¨³¢8з@ËÿCÀ ö—/,€Ü ¢KB&~~>`ֺŠ¡e‚”Cþ2üc`c•a”be%nP*ÿ ,Ž!(å³Ë„çÀhûÉ ,, Î)0@L¤8€››ØùËpïîpBBd¯ÿà Tuÿ–xFÄ—¬ll Ÿ?½gxô胒’<îa €˜ ©“ –/ñP–ZðáêÕÓ@Ë~‚"° rU r~òä>ÃíÛ—TUUQR?T-#@±@Ûx 'ƒÚè `[¬¤Ö€Ñ22²À`üÄpãúYQI)i9A¨ÿ€qÿáÍ«W OŸ=– p³Àõ(Ä€žÚó €ÀØ·oßD`Z¡¨¨v¨Ij±|ÿþdÈ¡/Á ݼy˜¿³8Š@ùüÓ§àl+$$ ¬¦y€!pE?ȃÀ6á—gÏží FhKˆØŒ†¨eüf Œ†2”`$¤Ì`‚:PÔBi°¡@ÏÝÚµ €ºo@Þ1 w@ ¸ R) Û 5%ÏIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_locked.png0000644000000000000000000000602411550446574024732 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ¦IDATxÚbüÿÿ?Ã@€bdˆ9ÄÀð÷ÿf`øó‡‘“A–ñƒÑ¯Ý ÿ¡JÁß¿øùù“]\Ü:ž?~÷ìÙ3{Oœ8¾‹ïÒ—/_Þifff†Ë—/3¨««3ܼy“ÁÎÎŽáîÝ; J ¯_¿²ï2¨ªª2ܸqƒ €X0œôÿÃc6cÍ¿§xÿ½cøÃÀ‚î.ggçâÄÄx‘ÿþ‰¼|ùÊüλ%—.]¼~øð¡3/^¼ØÿìÙ³@¥o@Ž%ˆ»ðo†#,> 6?Ö0püÿÆðK èbaa1ÐÑÑÓñ™˜˜$%%@˜ÍÖÖZ?11IÿÎ;ɧN~}ùò¥SW¯^Y÷êÕ«“ÿþý¹ÿçÏßoŒŒ˜6ücøÆ"Épü1+ƒ½ØN°å@3 ª©©`ÕÅÅÅÁ §§¢_¿~÷~öì¹÷·Þž={ú&/ïÉ}¿ÿÚñû÷ïs@¥ßAf@±à &†ÏÞ2<ÿû‚AVYì f6cccg‚AËÍÍ Œg%ööö°zóæÕ­[·ªÎ;÷èÖ­›ÇÏœ91Ÿ‘‘ñ@±àO¢Œ @M Jz ?þ&.& ==uRS:0¦ÄÄ„€Ø‚ÉÊÊ\áãǯ »wïñ-(ÈJ &Bøõë?ÃÇÁ©_JJÆ\[[‹ —òÿàtÁ¸ÃÈ (ÈÌ <@®-@!ÒŠ—¿@üç„ L4?ÂO?`àâdgRSS·fø”ûT¢Áê Vƒ3,(¡ÛÿÀPûÃðûÏ_°ÙÀDÆÿBâþÌ™S?ß¿ÿ € Qð뿳)#;³ /»œ€ —Ü×_Œ¿ß²‹LÊnþòŸ÷‡Œ©¡– 8`˜þ10³Æ×>ÿüÇðæó_†Ço2<ÿð›áù§? ¯¿üeø,R¾ýbdøóëC{ƒ´Ø_ÀhdøòåÉÇÞþøñã&@±0üùín-?ÇËP„ƒ›“…Ÿ›•A˜—áÉG†’¿¯nnüøÑü€$ƒLЭïâÜ—w=cxôúÐb`¢¦TFF&Vf`ödbàå`aàáfÐe›!*ÈÁжä,ÃŽgb¼Ìþ3±€ÓýÇΟ?{ȹ@,"<Åé^Ê,@—½üÌÀðhñµ× @Cä•Ň-X,&-ýWDŠ[êÚ`¤é(i B|¬ œlL ,Œ L ôôáw` òý ýˆÙ88ž¿ûÆô-3787]¿~íÿýû÷/ð €Xþÿûüÿ#7ÐB '9”¹ŒÁ0@œ/:P†‹—ß¿3Ȉó‚“ʨ Œf†¯¿ Iç7£ü7PÍ_ øo yì\œ /ßübøñý;0]üÆÿÉ_¿~½ tÀ[€bùðúÝm•_zúRì ï¿AJR ƒ™A zÿá؇o¾Ó'Ђ¿°4 Å õ¡iÄ•À€ô7 yy8Þܦ‰oß?ûwïN:yü  €˜~~ûúäó·? ¿€Šu}:䣟!AøñЇ@¯²²±Ã-û³è?$À…Ìÿ ¥o?DxÞ~gbøøùÐŒ îßc¸~íò% 1 ø@L ß>=zLÁ¬@Ÿ23Br0¤˜øL^ £Øÿ10ñð0°ñ°‚-3Èw öX®ý zhþõâ{>n†OXÞ¼ÿÂðXÛž9{êãë7ßž1[ÿgàSe †÷Oî¾z*倀.ø´ü͵; Ngøùü0$þ20KK009;3(È héOÔââ7" €B”ÿBC‰˜¶˜Ù€ ñÍgÕ/o.¿dæà Y—ñïó7ë‡ò2ˆ…áÞ†ÇßÄúÇÍÀ÷îú†7“Z.ždP|ââ@ƒþ2¼9úŒáᬆ[öž rYe ‚¢ ¾@| îßP_ÿúq,$@¡ÂJÜì ¯õʳ§s¨²+»y°ßž[/Ëðý© @±0j½¾÷ñÿë{{Žñ½KapÐPd(Êe`•‡i êÀ$m}ã:Õ…‹¶ïßÁ :u%ƒ°š0ö–ý…Æý?¨ƒ`â ¸xy>}}Ápýþc†÷Œ² Œ¯?0ü¸·÷.Pê5@128/ã–gÿ¼gúƒ)Nš* ì¶ö–°òA®8ùó÷o†×[71Ì~û‹áwÇ!)IPû’v¹á4+þþNe ×n>f¼—áçï· {¾¿ùñïÙ<‰ >ö‹÷Õ©?ô=ûn+Í Ì§Àð:wGM©aDù…‚ïžb˜½¬Ÿµ ‹äS$%aÑM¤ ,$"ÂðêÚo`A÷‹Q’áã­ƒÀ¦ÖÇ r €X|_Õ3TU6dxô”áÕåk@ß02°pq1°pp00S&8Ûâ?`Aôç0+ù²b" ªçv2ÜyÅ *¯Àðÿ7¢\€%>X40³*³ wïd`ä¦ôl ž• ü €X~³³; 00 €ª\V`JgÔÐ`ø´è0yƒŠÍ? Ëø/ÿè ¦S§þ?yÌ ÈÎÎpèÄ~†ßüñ œÀ0`ecƒDø?D€š“€•ÊÕ‹/ÞbàáüÊÀòåãÿßÏN^Dÿˆ…™ƒCçÀôÄ “•ÅÀÄð‹’µ~Š4`þë×/†?À4ñ••¡´”aþ|A6f†¯>2¼{ÏÀÀóí=ËÀt;0­°±²3°°2‹ßß WÎ>fÈ Qaèž÷˜á/Ûg†¿¯î~ú÷õå-P£mÄòØ.ú ôÍ/p±ÄoˆCêvF`ÕËÆ Pú0@Éó?вßÿY¾kÃß,â@͘>e`øð XlƒÚ‡l ×/?gðÑbøÉÏÍÀÈÎÉÀÄ-ÈðéÆšç ÿ€JÁo »ˆåÓ÷ïOM!!†ïÇŽ1üúô0¾ÿB¡Àv 8@¥¨Ìúø10õ?fã`øÌ ,@ñÿÚ¼dágø `ÅÊpýÆ}Ž? ZR g~•—a¸óì3Ã÷û‡@‰ï¤Ja –]?våâú.§£ÃùqÅ †OK—‚}Žè¹@²!Ð\0fFŽ6Ã÷¿>H˜0p|…$<äVØï?ø€84JƒáØ;`õ- “`8uàØ/†·×.•<…© `j8qøÒ¥qÞÞž¼ –/323£d=xY n.n†7ÀVáÎÿ6 „”!iA3A*NpmúøúCmf†5Ÿ3<|þ‘áÂŸÏ ÏŸwÜføûãPÙG˜±ö °™kÙbd´ÙÝÉIø÷ƒ ¿JfÔrœÀn×A.†öã϶9Me`ægøõñ-ïÏï~}óÿÏ—·¿~~|þíÃÓÿ{ó‘áëÛ ÿ>}`øùá=Ãï·¯þ½¿ôÔPCf,@ÁÃZ!®ÜÐpª§—70Þÿ‚òüHÃLpÌÀñɯ ýöü™Ëdÿí¯ô·ïn¿ÿýáî«ÿßž¿bøóõ-°–zÏð÷Ë+`þyM塉í;ƒbxÐrg‰QŒÁ͇‡§ÆÍÌÌT[G‡]h)¨àylD?wî׺óçïûýgÿ_F¦ËÀÒ ˜@ø-ƒ EÈ(ý—˜>@aôÖ€¯l ¸ð02êòppˆ Ö?~zå9Ð  †¨¬~µè“  ŸAžGp˜=IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_violet.png0000644000000000000000000000600311550446574024770 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< •IDATxÚbüÿÿ?Ã@€bŒŽîcøû÷7ß?¿€ôVVv.Nn†÷ïO2ügxT„¢áïß¿ ||Innn½Ïž=¿uîÜÙݧNÜÃÍÍ}áÓ§O~þüÉÀÎÎÎ ++ËpäÈCCC†{÷î1¨¨¨0<}ú”áÁƒ@¶2ÃÍ›·ˆ—Ëþ3ˆÉw ŒŒŒèàrvv.IHˆø÷ïŸÙË—¯ÌîÞ½[zñâ¥k‡<ûâÅówïÞÛÆÊÊòî÷ïß @5xC €°:€™™‰áÍ›W ïÞÝbÐÒÒûì(`t±°°šèëëk‚øLLL ’’ ÌfccmœœdpëÖäK—.½¹zõêé7®íÜ÷çÏŸë@ü Ý3 @8C€™™TA¥´”l9È7"""ªªªXõpp°3èéiƒ°ÈÏŸ¿<Ÿ|øÎpòäñ7?~ü¼ @,ÿýO°s±šal¢ÆÂÃËÉÀÇÍÁÀÃÇÉðúÚ?†¯·˜g>|rù;‡ú‰DÃ?ààܽçÃÇß¾ÿúËðíëO Oÿ3°S?(Ññóñ2 ‰1ðÈp0ðrq1r1Ì]¼áÀc >¾Îà„ t>ÃÇ.\8{ȹ@,¢Rb¹î.6,>±0|{ÆÀðä+0¸¾ƒå;ƒâÑİ®åòz2ÿx8øÿþf`å`PS—aàábcàæbe`eaf`üÏ .°@e0É0 U†ß@üXrpò2¼ÿð†áû·ï ì\ÀèøÇpåʥܿtÀc€“] @P…ºt‰åÅlÊN,²o6à/ep#g¼ùÆÀL-ß¾A,†WHyè?(á1AñÊÿô”‹•‡á)0|ýúXPñK×w gÏž¹TrˆË÷¯_ùþ“h6Ã÷¯ÁqöÍ J¢ÀèÏo~^^°¡ Тý$ó0€”À,…Ψþ¼Ö$@ð‹‰0Ó!0G|¦q`¥tçÿµkW@Á Äôõ맯ß}kf. !ÿ A-ú oPh°q°Ä0 Uƒô`ßòè›7÷¡Œn6~ yLÀÚõ#8ž={êÓ»wŸ_Šˆh²qs‹1ÓÛ7Oîüø…™ì ËÁmYòû×6`¢`Fܨ0þ ƒý7`4>¿ L_¡°cåàVn€Ùô°LùÆáìÜž§¦æ¹ìÏŸïºÄôàþéG¯ß~~ÿÿC ‡X*‚Ù€Y \æüÇ3A| •Yß¾~ÈÀðâÐÑŸAæÅéç?0øÙع>~ø´üPµ8»¡¡÷»ww~þü¬@,B‚²oŸ>{õh† (O3ËJ°eÐÒë/°Àáâe&B’EnbøñÔ¿Bø¿€Áý÷74$~Að?PvüÈÀÀË+Ìðíû]†;wîÍàbxûöËáÄð €X$$4ßテ“7#¸x…±@ï±ýf`ø˜Ÿ_ŸÖ¡o!ú ÿAe +3ÇÈ m°üdÏ@‡ý²£°²,Ãó—ž>ûô—*óg7þ|úôô ¨ –_>}}õìùó¯ÀœÀ ,©þü$oöÿ /N³0\Û,x>1°q³1;3;Ð&v …À²‚Rÿÿ@£ã$èAƒ‚äPˆñ³‰2Ü–ÏŸ–˜Ì /_^zûïßï@ÝïˆåÐ[ïÞ¾~öéëWQ&`Âù ´„‘áü¢ çfMÿÅËÀÆ÷]ò'§Ì^q.A6`IÈÂÁÊÀø˜]™  ó?4QþF(ÙWŽ]e¸vÿ°PÇÿ€¸ *(@±Ü¼µ—Aù?óã_¾0H 30Sàé¹_NÍZl ²pMÿÅÎðûÃ_`|ãýÅÀÂÿ“Yè#‡00øXØyØXÙ9€ÑÀ ɦ ¾g:æÞ«{ 7ÿ¦&`\13¿þûîÝPðƒê‚ÿÄ¢ªâl ó={ûî »œ<Ã3?Î.ûÌ–ÀÈeùŒoFh‰ÌŠ?™Áôßßl ÿ?ó2|yñ›á+Ð6Ž/ L\Ø8ÑÄÅ,38±2|ùôáæßý áIv ³¦nF/°<¸÷éçÏO·À-^  `ÂúuëÅËw€ñÊraõ{†ï_~ë&`± \†++ÃÿïÌà`gÆ1ãOV¦oÀh`âdø Tð…ñÃ_æ¯ÀD ¬xX8.³íb°Îcøú•è(>`M¸ç °Œ•‚ßAFË·ooÙè÷­¯ß¾ÿüŽAôéù¯ÀJ˜€–3‚ËFFxç?#¨p:à°‘ú›‘Xc‚s´løÏÅÀø—‹ÿ×ÿf.øÈ &hÄðàþ7ii†[·^ ¤7 ñ.kˆåýûûÀVϯ¯^¿zñéíoÑoÀV #Äb`ƒÔ7¬ò˜Ìÿm:\¼2‚¼ýZ"rÏ_Pl13|byÇÀtÁÎÙ˜áæ¥/Àæ—(0ß 0¼zµçÛ§OÏ/U¾€UbÄòêõ pÝrëÊ+÷=ßé ¨ó2¼¾øXwCйÿàºáÓ?%¤ÿ Ì@ÌÄÄÊÀÌÆÌÀÂÍÌÀÄÉÈÀ*t¦Ð‚ —l6j^3lXõ Xè|¶~€ú_½ºth¨"ús@1òòJ-abâ0°qMÚèY$}½éÃçG߀¹€‡زa6X¸YØE4°ÀÀÿáçW†¯ ¯¾þ{Ëðåÿ+†/^ýúüãÅ·7o||þàîÇøýû뇿¿¿ûùóË›?@õ#¨ô;Ä/a ”® ¯BˆghéB;½8®wg?0|czìA¼eøtð·ÿo>ÿxõûã÷g?}zññóÇן>¼ööë§÷ïÿøñîߟ_ïÿþû 4ø°]Åð ˆA­‹oÐÄÃ?@ md;£¯Äϧ+«¤Ÿ÷ëïW %¿ÿôþ÷¯¯ïýøüæ÷Ïo/¡® ÆHýB‰í/#¶¦;+±$¤2…ûâ’/þ’b >`Èõ}.m$IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/trashcan_empty.png0000644000000000000000000000427411550446574025164 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<NIDATxÚbüÿÿ?Ã@€bb`@,èŒ G@¡Â ”úuâ·oü Œ,úŒÌÿŒ9X”¹X™e98ØÅ˜™™¸þýý÷ï×ÏŸ_|ýúêçÏ~~~w“áÆšÓ &Wn¯üÂÀ%ÆÀðôŠÈ¡@,8RôçŸ,+cš¢¼ˆ¯¢¶¼ '++Ðqÿþ22üùûŸá÷Ÿÿ ÿ3‚é¯?ÿ0|úö›áÁSç¯wî\»òéïÏ ¯//šö —5ĈžÀ!ð÷0*Í4E ¼M¤øø¸8ž¿ÿÍp÷é7†Wï¿1|üøáÇŸ ¿~þbø÷ë7ÿ? Ì@½\¬, ‚üÜ ’Òâ \| ¯¿þa8}êÌ«×Çft0Ü^: ¨ä'zfüÿÇÁÆÎ6#ÁM%Þ\M˜áÔÝ ëO½fx÷á;ßß@ËþübøÿçÃ? ûÿï_ ôŸ_@è??~0üþ ´ãï_~^}-wG±³â2}×·ò©2\^ ´á+²u„éFæÜX¥x%a†y‡>2Vdû# p0ÿÿ/ÍÇÀ 'Ç LL¢ Ç/¿`x÷ù'ÐPüvÄÿ¿@ ¡²ôŒYÄ ”úœ‰APR†AÛÌ–á???í‡÷ ®b@Év„á€ÿþƒ“†8ƒ87/ƒ0/'ý§î=|ÃðúÕ;†ï?þ0üøþƒá0µƒã‹'?ƒ„ ƒ¤‚˜Ãk`(Ü{~Ÿá'(Z1Ò<@a)ˆþS:0-pAœêªÍÂðQQ„á&0a>yó›áÃÇŸ Ÿ?}aøòù+ÃoÀùûh1 ;';7 ''Ã?6†Oþ2ÜýüŽáÃçÏÀ‚ ¨hù,Õ@a) ¨˜Õ„Ñ,MDž}dcx÷•áÅg^†ûï€Ù ˆê~Õ A†ï@ö»ßÿ>ÿøÎðíû7†_À¨bf&é?ŒpÇRñ ¶"R ÌIÄ ¿@¡”â†T×?«Pf þáÿüˆƒ,b& F°.F4ß¡€bÂé¨VfF„¾@Ÿ^{Å ˆ8L ¬Z±D@1aÚÿbÔáLP,@þ‡ ?‚J;r*ÞÿX£ €˜°©ƒ?¬6†i{ú ìŽ#Ëh €0 gˆ#ÀLhzød¿úJå »ÿa Öö8 5üƒ:dçw`9¬êmˆÈ,V <0@€ÍhTý#=k.`BäFxzø Êr@oÀ‚è¨0ÉOh6üóŸ èf†Œ,@ÇÓ>#jâÇ“g‹ ÌPCØ¥÷åGŸ–ï{ ,†ÿƒ£æ?°*\˜™fb†Ít8˜þå€bÁ–`ÙðÕç_ DYõ#ÃýÀÖÐÛ B<ì`Ë@Å. ùHC âÚÿÀÐù÷ã78õ23![û«[.`d:ë5°:^}ô1°ú®U%.P‚…™l1 °DÑlÀ`geaóÙXXØX!˜•‰…ã3Ï6`(1aÍ‚ @!ÀÌøÿ¨ä{ùá'çŸþÁ  !à YLqÌLaòŒ°Pø®Q€iâ°MÁÄÀ lb~cúXÔÔ@¸ýøËÇ'ï~I³²01ü¦º¿Ð” .Ó¡AÍŠw …`ÌaƒÅ¡¥Öÿ ëA ØL²™!lų¨(CÍ+„·Ï^±x×#9qp<ÿø )š9X –0Ã08áÅ€¨ÔT;ˆF+(z˜XÁùöó¯ï ïœÿÇðîìu í ÌDxcÚäeóþê2ü‹uÔW`æcaàbšÃiûƒB„… R:€ 8 P(ýš ¬¾Û’/Þ¾eøtöÐ?†‹ÓN0ü|¾¨ñ1²u„Ù/G³ ƒ˜S‘˜EtjB°¸¿­Ãé§Œ Óöb`ÕxÀPafC°Y ‰ˆY9˜þ÷X@¼zû†áÍË ß.n|Åð`õA†_¯6 Þ Ê\Èv€¯ƒ i˜ ¦³¼¶…›¨4 °áÁÄÎËÀltüg`66@-µ¿ ß¿~gøòé=Ãçw¯>=¼þëǽCO^¹Ìðý.°§Ãpˆ¯ñgôŽ @ás ›¨ J ¬"& Ür† ì‚’Lœ|̬œ\ŒL̬À~ã¿ß?ÿüûùå'Ã÷_~¾~ÍðýÑ`kõ(Bø4Þÿcë1@N/ 6?Ö0püÿÆðK èbaa1ÐÑÑÓñ™˜˜$%%@˜ÍÖÖZ?11IÿÎ;ɧN~}ùò¥SW¯^Y÷êÕ«“ÿþý¹ÿçÏßoŒŒ˜6ücøÆ"Épü1+ƒ½ØN°å@3 ª©©`ÕÅÅÅÁ §§¢_¿~÷~öì¹÷·Þž={ú&/ïÉ}¿ÿÚñû÷ïs@¥ßAf@±à &†ÏÞ2<ÿû‚AVYì f6cccg‚AËÍÍ Œg%ööö°zóæÕ­[·ªÎ;÷èÖ­›ÇÏœ91Ÿ‘‘ñ@±àO¢Œ @M Jz ?þ&.& ==uRS:0¦ÄÄ„€Ø‚ÉÊÊ\áãǯ »wïñ-(ÈJ &Bøõë?ÃÇÁ©_JJÆ\[[‹ —òÿàtÁ¸ÃÈ (ÈÌ <@®-@!ÒŠ—¿@üç„ L4?ÂO?`àâdgRSS·fø”ûT¢Áê Vƒ3,(¡ÛÿÀPûÃðûÏ_°ÙÀDÆÿBâþÌ™S?ß¿ÿ € Qð뿳)#;³ /»œ€ —Ü×_Œ¿ß²‹LÊnþòŸ÷‡Œ©¡– 8`˜þ10³Æ×>ÿüÇðæó_†Ço2<ÿð›áù§? ¯¿üeø,R¾ýbdøóëC{ƒ´Ø_ÀhdøòåÉÇÞþøñã&@±0üùín-?ÇËP„ƒ›“…Ÿ›•A˜—áÉG†’¿¯nnüøÑü€$ƒLЭïâÜ—w=cxôúÐb`¢¦TFF&Vf`ödbàå`aàáfÐe›!*ÈÁжä,ÃŽgb¼Ìþ3±€ÓýÇΟ?{ȹ@,"<Åé^Ê,@—½üÌÀðhñµ× @Cä•Ň-X,&-ýWDŠ[êÚ`¤é(i B|¬ œlL ,Œ L ôôáw` òý ýˆÙ88ž¿ûÆô-3787]¿~íÿýû÷/ð €Xþÿûüÿ#7ÐB '9”¹ŒÁ0@œ/:P†‹—ß¿3Ȉó‚“ʨ Œf†¯¿ Iç7£ü7PÍ_ øo yì\œ /ßübøñý;0]üÆÿÉ_¿~½ tÀ[€bùðúÝm•_zúRì ï¿AJR ƒ™A zÿá؇o¾Ó'Ђ¿°4 Å õ¡iÄ•À€ô7 yy8Þܦ‰oß?ûwïN:yü  €˜~~ûúäó·? ¿€Šu}:ä#`ÚáÇ@]ÍÊÆ·dù_(%,£þ!ñÿBCéÛO^†·ß™>~þÔÏÈðàþ=†ë×._Z ÄÄðíÓ£GÀÌ ô)3#"?ƒ2 È`PýšÊ J,  ¦NPN€†Æ?ˆoÁAÍÁ¿þB|’àãføô‡•áÍû/ ÿµí™³§>¾~ó탰õ>U€baxÿäî«÷?©¨è꿌ÿBœ¬ ™EøXØž?Íððö†»7o1èš;0È©¨3üú RƒH?ÿBâ_hhÌef&Ä7ŸT¿¼e¸ü’™ƒ+d]Æ¿Ï߬ÊË †{?~“ð ä|E +$$~ ùôí õ³gÞ>¾Á ÊÃÆðñÍs†»×¯0˜ê2œØ·…A\Al9È÷ _ƒ<ð)$@⌠€cç`x ¬Wž=}Ìð˜C•]Ù̓ýöÜzY†ïOUˆ…AÔäÕýWß^2°3ð}FÚÛÇOܹÁpûÊY†?_ß18[3ܽu‚ARSƒÁÖÄ€a÷Öõ Ÿ¾ÿeP4ugx÷š è_h¢üýáP¬rñò2|úú‚áúýÇ ïe_`øqoï] Ôk€bf`báùþëØÏ'§$^ß=ÇpzïyAfkM†£{61(È+2\»÷”áÀE ëÿK0ÈÙD0(Û‡2ÈêÛƒš™áÇ_H\ÃrV„¥‹¯@E¬ooKË· wY´¾>ñïóñ¾M ÿ~î eþ×Uy>úÇNœ`ðËÌexóô>êõ[tM¾*0L¹!Î`äZÇ৪ÌÀÊ,X€Aú”ê^ûŽ|D£ 9wüþ‹!†W×~ º_ Œ’À¨¼uØÔúxTË×oß_10É‹× …ù Ÿ>ePÓ·`øŒŽï?8ø9Þ3Ü=¸ŒáÅ០|¼< ?~þbà.ß~übÐrK`–”VLˆr–ø`ÑÀ̪Ì>2ܽÿ‘‘‡(ÉÆðçÙ1P9Â?ˆX4ªùøxûòòò1”–3èéê1ð°ýgÈŒexsu7C‚›6ƒƒŽ4Ãç'WJÒ#>=¼Â`®)ÅðûÍ}†ó¯ØxÅ•‰ï/0D˜Á òR¶eÛ'Ï>2œ;ñ”áõ» ÿ9€5&«Øÿw‡úvýÿõqPÅ{€bµr€M'//f syxxYŽƒÞ|‚"Àò€›O˜ÿù€yŸ œb lÀBiç‘‹ oe½~± 1|xÿr_ùï'0nþþgg¥oÀ2äìÑ{ É¾Ê '€ #°²úûéçOç—l:ó ¨ PõtâéÓ'›}}ýR99¹À P³ú÷ï? (0hu?0L-,¬€õùo°'+#âg~qˆ0|a& Æÿ˜€Ž`øð XlƒÚ‡l ×/?gðÑbøÉÏÍÀÈÎÉÀÄ-ÈðéÆšç ÿ€JÁo t@àö++ë¯ïÀʆ‰‰™¹) lDÂÙ¿@%H Xš1K+PcäÇ/H½Ïøj ?Ã?çØõ÷t8þ0(hI1œ}¬Y¥Eî<ûÌðýþ!Pâ»I¾ o‚Z+ _jË3x€Ó?`Rÿª3~BÊnäVØïÀ Ä¡Q ÇÞ«oi ˜¬Ã©Ç~1¼½v¨ä)L-@¡8àÐGÿþp#°! `‚¶x@Y‘Úðµï@èãë´E˜Ö|ÎððùG† >3<ld<Þq›áïk@eaæ "¸qÈô‹Ö^Çí` ì Ÿ?}D/~~|Íðûë›ÿ¾¼ýõóãóožÞøxðÛ› _ß~`ø÷éÃÏï~¿}Íðï=(øO‚{>P@,Cé˜òA˜°8¹9~|öçÑŽ²Œÿ?=ýÿõé+`¹ý–áïÏ÷ ¿¼¦˜' ®Ô§ ÄöŠ¿Á Øß¾}ÿ{üøvvÂuÇ@9áñí3/ÅÛl`8ì ¿‚ZJ ô_bú Äõ•6ÐÐH -ýÿ?#!MÀ¬ÉøçÏPBZĠͲ@€×–9 §ãIIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_cyan.png0000644000000000000000000000602111550446574024420 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< £IDATxÚbüÿÿ?Ã@€TË1 Â0Ð/  ”àÌr‰Ĺ«ÇðD:f±`qmÁÁÔµd‘ÔüVW··<¶­ø” ó›@TPK¬„ÀæqÇzzafì/ªJî­µÇaxöm{=5Íå,„¸¥”F)%rÎàœC)çŒ1ðÞCk#B?ïÐu=¾ˆ—Ëž²r2ˆüþÎðÓ\ÎÎÎ% ñÿþý3{ùò•ÙÝ»wK/^¼tíСƒg_¼x~àîÝ{ÛXYYÞýþý›¨oV0311¼{ó†áÖã» êÚÚ`(ºXXXMôõõ5A|& :II f³±±6HNN2¸uëNò¥K—Þ\½zõô×ö îûóçÏu þƈæ !ÀÈÀÂÌÌðàáEUU ¥,`ËA¾ PŠaì zzÚ ,òóç/Ï'OžzÞ¾}ç3ÐA—Ž=|êׯŸû€¡²¨ôëß¿ œQòÝ×?ž?ŽK€šÙŒŒøùù&.vv6eeEæõðpµ~ó&ÙúÆ›…À4óøÖ­›‡Ïœ9µuûˆ…A7oÞdPTTdøõë33³…9©]DD€ÁÆÆœÁÊÊ\öóç¯Qû÷ÈÊJK ‚%$`êGƒŒŒŒ•¶¶'.µÿá0q…,??7ƒ¸¸$0J­ˆ ëÀ þŒcP6ûýç7à  øôÑ#n.Nuu !!! šÿ  8ü¤þ#§ˆÅ üÿ߆_¾2|þö¬æÏŸ¿P ‰ûÓ§O~ÿøñý'€bªeþùûÑ/F&CV.i>nn%ANÞŸ¿^<ëüréÜÆÌ,ÿØØØåôtÁ¹”}üñŒß-z÷õÃ[ ~þå Çï@±ïßž}úÌÀðë'Co /ƒ¤°Ã ™™™>|øÎpòäñ7?~ü¼ @,¿þýK02·˜a¡§ÉÂÏËÅ ÇËÍ ÌÍÉp hX3 óÌ/÷î|)¥pâ9ø£ŒœKOœexùñÃ'`šxûí;ïXXY€ùž—¨WˆŸA™[‚Á†›˜X«¬`Øuè0C¸§;0ü™Ááôðác† ÎÞrî ³°H®«‹9 /óO _ξ{ËðýåoF-uQñÒêåÒ2RÿD88øï±°1ˆ³01(*Ë1ˆrq21Èb §™þr 0ê~ñ/`©úéÏO†ßœ /?|bøþí'+07ýc¸råÒ¿î_:à1@±üùóûß‘GO´¹Ø8™Y$Xx¸¹Y„Ù8œÕøü<X€†}ÿü…AJTèþà¸üõïÃo`þþû‹áןÿ þƒð?p0ÿ²ÿÙß>:òÍÓ ¿€YšèïÀ¨9sæä‡oß¾ß:à-@±üúðþn¸Œ’¡›´8Û¯?€ÆC4ƒ ÿÇ LŒ¿ÞüÀÀ LHŸþFÿá)豈‰üG°A!Â?Žäåãex}ûÃׯßX8yÞ½{Çpöì™{@Íwø@1ýùñãñG`¢yûëÃG O?-ø”ù *ˆ€†~fC`b–r`‹A–€*P… Kþ‚ r,þáÿúûŸ? ?ýf`xLˆŸ€!Òwÿîíÿ×®^?(þÓÿ?˜þÉ_ Å€ùè/ƒ‚ô'¸BùÏÀŒë?ÿ B,9-?Pî7ƒÓÁ?†/Àhú¤ùùxÞÅßøÈðXãž=wúÓÛ¯__2h”$@1ýzõâþ+ ë@Ù‡ÿ!¾øó˜gAåÐõ,¬l`þ…Êýýóõ`K¡b Ë¿ ŠB:P4CïГ?>½g8óõ+CUkƒ›Ï2`ÐêÓ+—=ùðéýw FPPþcˆ¿~þb`cc¦ˆ8(AE 8øAìs`Hý…Dÿ§!`ÅØ%è?Nv†@O>~ò០;ƒ…%7ÃÝ[ ß+ Ÿ¬üÛ{/_¾yÿç Øç@Ãÿ€ãX ƒBá÷.!6`é‰ûoÿ@Y dá_°ü_ †Ô”„Š–Ÿ Ëø'PŒ™ ˆùø>}ÿÆpáþ]†§@Ï0¼zÉÀpåÂm Ïˆ…WMãýç·oß½¹Ü x',``ZÂLï>úòá38= žÿ à¼Ï,FYAE)#¤… (D~þYþìP{„GT”áãÍ; ^¿g`—f`xpÿ°|¿*ˆåï×Ï_ÿ¿ÿü-0›ðr±ë€ ƒœùòƒáÈã— bÏß1ðƒ‘—lÌ l@9öÿ ‚ZPË‘ð ”v€õÄPVŠrs“ï_®KP)†×ß2üüq¨ì=@±ü~ÿžá77ß³À¢—› hЇÀ„³üþ †åO_Ûˆ, Ì¿ä¿~ezUè c¸v6 Z& åŒàÊìïD®ùþ¨P&àŸ¯^1Ü|ñ‚á)È•ÀœÆtãò] cïƒÜ €£ªYƒ³ZZR~^ÈÉ›:x'¯A{@$‰åD‰Y×罹™oæ“k]Aey¿1×…H~:‹¦C©'ÀWL/ Ã%MP+{­”\'ÒwGÌZHM‚qïÄZ™ÒÝ?q$†~„7ÎX8g(¥s˜ºµôÛ_ð~ˆEÈÕ‡á//ß³Wïß1pªÉ1þ‘aãíÇÀˆeÕ©À0þ .÷¾ & oAâ¿>ÿ tÌK <ÐA_ß3p-ä`fa`:„…XhéÀ„÷X ÆÙY2ô¾|Ž(æg?ýùôñóT– ‡¨Ã_¿n=ûþ0ZY¶Üy,¯u8°Fúð%ÌÏÀŠ”½~ÉO`åÃĬ@_2s±20ƒœXC2}úÊÀòç+0ä>=|ȧ¡Æðؼg:ˆ™‹Ÿáß®­Oþÿý*¿ƒ@,€µßßßn=÷îýã/?D¯½zÏmA š5  `d³oÀ€ùt);0w°3r#¸}jñþZú‡™—á0j¾ß¾Ã(ÀÏÀ)ÂÏpõÕ 1q†/?1ü¾y”øîCÓ,@±|xØìúóáÇ/}ù&ú˜ÀÁÿûÔòÿ¨T åÿóá7PVed„¶„ÁîüÇÈÄðïÃgg ù6†: {Ÿ?e¶3>Û Ì‡Oûõìñ ²°V@±|¾~\­}òäÊžçot{4 ß¾¡ú”ß@Í/P3 ä8 Oþ11üVßÿ€m*P?‚„¡Z8ïßaàæ”åGN2¼þðžXá1|zóîï¿‹§. PEôæ€bä6¹³ñð°Elù`i-ýï0ãX1;0ñ³+;+'°Râ:‚ ˜]YÕ3رÀFë¿OýzûöÛ§O>þ~öìã÷/Ÿ?üýúåÃÿoßÞýùüéÍ¿¯Ÿ_-•~Ç€ø%Ì„ÒvåS× áŒI^øNGë°Ð`ö¹~ÿ¦t`}¬”˜?}üýÿíë¿ß¾ùøûÝ»O?^¾xûëýû÷¾}÷ïç¯÷¿{ù÷÷¯g@£^1¨VÿMl0üTÂ#Û @g^u­XuÍ< Ë9þüðñÿ—Ïïÿ}ýòþ÷§Oo~úøXƒ\ÿŒ‘,ú…„ÿÛ_ l­wPSX^2H‚J*$_|CòÅ_R,Á X1ý8–î¹IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_yellow.png0000644000000000000000000000600011550446574024776 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ’IDATxÚbüÿÿ?Ã@€TË1 Â0@Ñï U‚%»t2x†ÞCâ <‘ŽY,Z\Û!dI'É"¡MÐÕí-o–÷ðaœ`J°XÁz Ç׎[Þ0'ÿ…”e)u]Ÿ†áÙ·íýÜ4׋âBxK)‰1RUUaŒAkµ¥Þ{œs?o麞¯bÁå2g¦[ 'ÿÉ1°1þGw—³³sIBB¼À¿ÿÌ^¾|ev÷îÝÒ‹/];tèàÙ/ž¸{÷Þ6VV–w¿ÿfªÁ„ÝL ÏÞ|b¸õòƒ‘¶ØG Š.V}}}M°2&&II f³±±6HNN2¸uëNò¥K—Þ\½zõô×ö îûóçÏu þÆÈȈa@á ff†‡2è¨*-e[òˆˆH€ªª*V=ì zzÚ ,òóç/Ï'OžzÞ¾}ç3ÐA—Ž=|êׯŸû€¡²¨ôëß¿ ܆ÂÿŸž?ŽK€šÙŒŒøùù&.vv6eeEæõðpµ~ó&ÙúÆ›…À4óøÖ­›‡Ïœ9µuûˆ…A7oÞdPTTdøõë0T˜- 4ÈIí"" 66æ VV沟?Ú¿ÿ@@VVZ2@1ÒJHÀÔÍŒC+mm-N¼þC1L6 üüÜ ââ’\À(µ ¸þ£ä?0+2€ðo(@ ðþã§ ì\Ü,êê6BBB ÿþþfY þVŠŠ¡˜¥úÀðçË' R þñ_0 §OŸüþñãûOÄŒZfÆ_ F, †Lü,ÒŒüÂJ„u|Å?ý,xõ¬sÂu†"ÿ¿üãde•WÓ7riþLÍŒ Û¾½c`üöžñË[Ư ü’ñÇsƟùŸŸ0üûõ‡á“ïBv)Æ€ÑÈÄðáÃw†“'¿ùñãçM€b:.Ãßj£© · #ËçÏ õ¿–ÌÜ{ïé÷<®‡'~2ˆ…kü¼Îùwßæ/Ϙ¿g`úöhèF.VF ^!~†ÿr¢ \’ ÿùôþñck]Ãý#;dÝ£8™AqÃÌ].\8{ȹ@,ÿäùs™C„XØÖK™ ¿~00|*daà3T=˶\H•óß'~a~^žó Àb`Öb`à4› À¢ˆ1@‚ä'0ú¿ÂM/ì ,|¿˜î=cøòí 'ÿÿL W®\ú÷àÁýK@…ˆå÷ß/ÿX?F’0âM}ð_’E†ÉS—A(”WàÈÀ/?…z€üÿHÒï ü_ÀlúŒ€ø˜ÿè Ÿ‹™ùë+†o?~3ð°²2|ÿþáÌ™“¾}û~¨ù-@±|ú÷.×ß~C! Ãß@S$0þú„ ˜’þ~føñá5  (%10üût$ÐÇL¿ ÉŽ’üÀ–1üÖP6Püÿ ÿy¹Ø¼`øðõÃ?`T½{÷ŽáìÙ3÷€Šï‚\€e2Ö„è¡£“þÿg©“º88ƒBñŠNMšô®÷š6áÄo©Aü‰©²¦sàr¡d‹œn~A[ÓÁ¤ß4VäŸi¬$Äè Øc•‡³Þ£ =:9œ%ƒe[Ë8OŠ_ È+€˜¾}fxÀðá!ÐGl àefÆ¿PK~0üùýhè?VV`Þúÿj1ÿYþÿ7ÜÿÿCBåÿ_ Åßže=>`â{ ôß[†ïþ3\>uê÷Û·/³…ØÌ¸ˆéÒK†û À f`Uß00nAøÎÀÆ ~¦¿‹ÿÃ|ŠcH¡ñÿBä?0Ôþ}†&°¬ÿÿ‘á/;+÷?†¿ï^0¼þøAøÛIŽ U y– Ë>ýdÐ ¦Ù÷1¼¹ÿžèâ ÅÀ„¿~ÿb`cgZ Kíÿ€–þ&8 åÿ€â¾-~Ãðïë{paöÿ30'€Ê9ž¿ Lß1น täÿßÀiå(ü‡„Öÿ¿ PFß?¨å, D, ¬ÂÀPxýØ9à-õ”á<ÃÆë ·ŸK˜ÃûÏß½ãÿóÈgƒø×ÀTþë‘ @‡0|Êÿ&$P.%8& … G£æ?8•@‹tF `‚ýà t0- )i!Ö ¯>¾½È  ÂÀðrßCŸ®€Ê€b¹ó‡á«öÃ_Ïù¿³ “$û þÍÀþñ9÷{o>sò3°°3£”V0ÚŒàšdõ¿Ô¼üÿTåþ‚Bè¿@÷çC`z¸ÉÀ ôÓ¥“ o_10Üjz@,W€öI¾fx&þé-°š4QÀ Ê;—ÜbdaŽ ?˜Y¾Cƒ…‹›•“ƒ™ XÀ€\TËr¸Áò\‚P°s1°øÈðçòf‹÷ ‚Àô9ù.¸ ¸Šg€bÉæÆ¹Œ 5?C@Do@'^FÒ­ËÀRŒ‡èv`ˆ°ƒrãg c€yú÷ÿì L,ÜÀáf`f9ˆ XѰ} ´ü/¨,†;'Ó¥G Œçî2ˆ0¾f&Øï÷þî ~P]𠀘Ö[WfÌ Ï^…˜pÞ=:à4!ñ ˜ê5¸ŽýËl¤r0𕉰}aàczÎÀöóÃÏ7w>=½ÏðåÙS†?o•°ØFÃÿ7¿8Nže`HdâùÇ  jk^eøôè/Ã- å rœ €X ¸€áð‹áÖßOþ03“.Èò¯Àxáå&¤ßòá7¬ÑÀ Nå ö(dX+ó_NN—?3|ûù•áû‡÷ ¿êþsð3ðî¾ÌÀjaÄÀ pš‹÷/ƒ.0V_bxòR ‚R3@±\øÎq·”^¾xÏüã…(óÀ f„X*›@lXçDƒâ–…âpýð¢ù\@rkà¬ì ¿-g`Еˆ·x•åØo0Ü9ùðÛÑÏ À fxk‰Ë‚×`íÿjϾ¾"øj¯.ƒ80øs@J– @Ë8ŽbVÁ? ó вwÀ”ýî'ÃÇ÷¿=ËðíÖS†ï2|| ÕW?><ÿÃðîñ/†7ÿ1¼ª•~Ç€ø%Ì„ÒUIæb™žÈ°5Ž…‹á П€Áþè»ÏÀzïã_†×oÿþ¾÷öÿÇGo>>}ÏðéÖ+†·¿0¼û‹áPÉ{``¾Æè3 Q¯ u:´y„À?I £¯ÏËë¬Ê÷ö'0*?¾úÊðþé†÷~}ñ—áåwˆë_Cƒñ#’E¿ð_bû Ĉ½gÈ Ä’Ðzæ‹oH¾øKŠ%ø@€"®?=`ÀIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_html.png0000644000000000000000000000632611550446574024442 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< hIDATxÚbüÿÿ?Ã@€bdˆ9ÄÀð÷ÿf`øó‡‘“A–ñƒÑ¯Ý ÿ¡JÁß¿øùù“]\Ü:ž?~÷ìÙ3{Oœ8¾‹ïÒ—/_Þifff†Ë—/3¨««3ܼy“ÁÎÎŽáîÝ; J ¯_¿²ï2¨ªª2ܸqƒ €X0œôÿÃc6cÍ¿§xÿ½cøÃÀ‚î.ggçâÄÄx‘ÿþ‰¼|ùÊüλ%—.]¼~øð¡3/^¼ØÿìÙ³@¥o@Ž%ˆ»ðo†#,> 6?Ö0püÿÆðK èbaa1ÐÑÑÓñ™˜˜$%%@˜ÍÖÖZ?11IÿÎ;ɧN~}ùò¥SW¯^Y÷êÕ«“ÿþý¹ÿçÏßoŒŒ˜6ücøÆ"Épü1+ƒ½ØN°å@3 ª©©`ÕÅÅÅÁ §§¢_¿~÷~öì¹÷·Þž={ú&/ïÉ}¿ÿÚñû÷ïs@¥ßAf@±à &†ÏÞ2<ÿû‚AVYì f6cccg‚AËÍÍ Œg%ööö°zóæÕ­[·ªÎ;÷èÖ­›ÇÏœ91Ÿ‘‘ñ@±àO¢Œ @M Jz ?þ&.& ==uRS:0¦ÄÄ„€Ø‚ÉÊÊ\áãǯ »wïñ-(ÈJ &Bøõë?ÃÇÁ©_JJÆ\[[‹ —òÿàtÁ¸ÃÈ (ÈÌ <@®-@!ÒŠ—¿@üç„ L4?ÂO?`àâdgRSS·fø”ûT¢Áê Vƒ3,(¡ÛÿÀPûÃðûÏ_°ÙÀDÆÿBâþÌ™S?ß¿ÿ € Qð뿳)#;³ /»œ€ —Ü×_Œ¿ß²‹LÊnþòŸ÷‡Œ©¡– 8`˜þ10³Æ×>ÿüÇðæó_†Ço2<ÿð›áù§? ¯¿üeø,R¾ýbdøóëC{ƒ´Ø_ÀhdøòåÉÇÞþøñã&@±0üùín-?ÇËP„ƒ›“…Ÿ›•A˜—áÉG†’¿¯nnüøÑü€$ƒLЭïâÜ—w=cxôúÐb`¢¦TFF&Vf`ödbàå`aàáfÐe›!*ÈÁжä,ÃŽgb¼Ìþ3±€ÓýÇΟ?{ȹ@,"<Åé^Ê,@—½üÌÀðhñµ× @Cä•Ň-X,&-ýWDŠ[êÚ`¤é(i B|¬ œlL ,Œ L ôôáw` òý ýˆÙ88ž¿ûÆô-3787]¿~íÿýû÷/ð €Xþÿûüÿ#7ÐB '9”¹ŒÁ0@œ/:P†‹—ß¿3Ȉó‚“ʨ Œf†¯¿ Iç7£ü7PÍ_ øo yì\œ /ßübøñý;0]üÆÿÉ_¿~½ tÀ[€bùðúÝm•_zúRì ï¿A²d0+8!¾ÿð˜zß|¦O aiŠAIð/4 ƒø øþt /'ÛûÀ4ñí;°@ãgx÷îéS'T ÓÏo_Ÿ|þö‡áPño .P‚R>Ð f`ú—‹ œ\ìpKÿÃ,úÉ0 G!óÿBCéÛO^†·ß™>~þt #Ãû÷®_»| h$(þ ÷OS°•7+#3û†»÷¾0Üyð™áýç_ ¿€5$ ã=mIU`bcføö j!Ä× ß‚ñšƒý…ø$&ÀÇÍðé+Û÷_$¥þ0œ9{êãë7ßž1[Sñ+€baxÿäî«÷?øø)âÎ7†%‹¯1¼xýAE…—A h!+;Ãí¿æ-»ÎÀÉúŸ!8P…AMC’áóWHí rÈoDøù’ÿBC‰˜¶˜Ù€ ñÍgÕ/o.¿dæà Y—ñïó7ë‡ò2ˆ…áÎúÇo¾§}:wö_ë„K ¶Î eŪ B\ÀègGÀo!†ŸeVìùÀ0qþ-» ή@ËÁ>þ õõ¯?ÀB” A‰›ƒá5°^yöô1ÃcUve7öÛsëe¾?U yÃWû÷Ýzùx×¾€qs`©õãÃóüàbóÍçWàF (=†;s0Ë 3L˜|üŒ ÆÖ Ÿ¾Aâü/4îÁ!òáP¡ÈÅËËðéë †ë÷3¼g”e`|ýáǽ½wR¯ˆ…á¯þ§§îÒ¯e0Q}Åðí‹ ƒ·(0;²1|üþ†áõ§wÀT,f)òÃ-á? N>oÖn¦aaQ)Q†ÿuÁ_Xzø À„(,&Æðéñe†³ß2üe×gøþðÆ?†÷W@åÀc€bb¸ñÓDÍ„CïÞ·[@M– Ò@CØ€Åé/†ó·o2|øð˜…Xc²0\»õšáØñE ¬O.ž} ô冟иe]H è§ -$"Âðêóo†[¯102=vë$°©õñ¨ !Q^/v‰¬?9ÖÝcc0a`æúÁpùÌ: ÅØX8©€˜è¾0Ü|ò”áÀ©c ¯^e0´7føò͘¯?3ððóÁ$,ñÁ¢h°2ûÈp÷þGF`(þccøóì¨áŸÄ""#dú›ùýKOÿø0|ù¡ÅÀËÂÁpæÊ;†;W7ƒk¶oÀ|÷éëg&n&`ŠÓucøøãÛ—÷ wî¾¶¸‘Í ‰phZ?¨9ùX©\½ø’áýw!ί ,_>þÿýìähAô €˜eÕÂJ¾‰»qe%ÃÓGû8y司U„¥ dT]>ÿþÀðøå> _4 ‚Tµ”å~¼çgxý‡á/ +ÇŸ¾óßO`aó÷?Ð1ÌŒÀ‚è7ÃÙ£÷’}•N+F`eõ÷Ó‡OŸÎ/ÙL)Aõ0@1}ýôý°ä–`øÃöœáÙó} ß‘úXx°óK1ˆÊ™2pk7FÞo Êzž ¶vù ¼\¿lô¬ØX¹¾±ò3¼efxù_˜áég&†{Ï?1ÜzüšáÁ‹ ûÜapÕbøÉÏÍÀÈÎÉÀÄ-ÇðåÞñç ÿ€JÁo „ @L_~½ÊÁ,ÀÀ,ô“AUÓ‘ÁƼ˜‡ Xú1€S·€€<³À> )‹LaŽ? ÇïMe¸ñhÃg`ËÈÍËðX^ÿËÂð•…Ÿá3›Ãv1†³7Þ3(Õ*hI1Ü}¬Y¥E¾}õ÷ß=HAÊ@Ì_¿ðpjY‡ŠéÿgˆµšÆÀlƒ*$PíÈÅ ,Ëyøxxù¬4£Dä€ÑúŒAHà;Ãâ 2ð+*ëFpœƒ+* þüù'çÛ7 )!j gÞ33hIë†?Nï?úëßÝ%«>Û €úS˜GA½egð+KU`µ+Âðñ$*P"äVÍÀXb`öä„$y8‹0<Pb•— †'¨Ü9þöÙ[ Ú"Œ <Âì Ÿdàüó™áù“× OŽÏ»ÊðlS#PÙH Î@Ю‚¦ƒµwÓº s<…ùx^¿‡ø”Ÿ…!¸ä:@X_ðÓbZãY†Ýwþ3Hhh}ö‘á×çw ¿¿¾ùÿçËÛ_??>ÿöáéÿ¿½ùÈðõ톟>0üüðžá÷Û× ÿÞßúj¨!kŠR_Šιrò¤)|œ Àlóë /“ 0132Hp 2ˆ2ñ1Ü}ñ‡¡´ýÀ¿õëv~åeûúïË‹÷¿ßß~õÿÛóW ¾‹¹Ÿïþ~–Ý¿ž€ºf@üÔß¡øÃÛÍĈÒQeqâàó¯Ôq7µ·ùÍõ_äÃoÆŸ b?”~_ÿ»kÃÎçî­8ÂÀðò8Pý ~*Í d0°àeø¥ÿÓg ,½5&`¤Šº02Šéqòòˆã€ýû—Ï¿ÿÿyl)¾½,;ÎCß m•”tÏ €tYŸ O°IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_cool.png0000644000000000000000000000614511550446574024431 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ÷IDATxÚbüÿÿ?Ã@€bdˆ9ÄÀð÷ÿf`øó‡‘“A–ñƒÑ¯Ý ÿ¡JÁß¿øùù“]\Ü:ž?~÷ìÙ3{Oœ8¾‹ïÒ—/_Þifff†Ë—/3¨««3ܼy“ÁÎÎŽáîÝ; J ¯_¿²ï2¨ªª2ܸqƒ €X0œôÿÃc6cÍ¿§xÿ½cøÃÀ‚î.ggçâÄÄx‘ÿþ‰¼|ùÊüλ%—.]¼~øð¡3/^¼ØÿìÙ³@¥o@Ž%ˆ»ðo†#,> 6?Ö0püÿÆðK èbaa1ÐÑÑÓñ™˜˜$%%@˜ÍÖÖZ?11IÿÎ;ɧN~}ùò¥SW¯^Y÷êÕ«“ÿþý¹ÿçÏßoŒŒ˜6ücøÆ"Épü1+ƒ½ØN°å@3 ª©©`ÕÅÅÅÁ §§¢_¿~÷~öì¹÷·Þž={ú&/ïÉ}¿ÿÚñû÷ïs@¥ßAf@±à &†ÏÞ2<ÿû‚AVYì f6cccg‚AËÍÍ Œg%ööö°zóæÕ­[·ªÎ;÷èÖ­›ÇÏœ91Ÿ‘‘ñ@±àO¢Œ @M Jz ?þ&.& ==uRS:0¦ÄÄ„€Ø‚ÉÊÊ\áãǯ »wïñ-(ÈJ &Bøõë?ÃÇÁ©_JJÆ\[[‹ —òÿàtÁ¸ÃÈ (ÈÌ <@®-@!ÒŠ—¿@üç„ L4?ÂO?`àâdgRSS·fø”ûT¢Áê Vƒ3,(¡ÛÿÀPûÃðûÏ_°ÙÀDÆÿBâþÌ™S?ß¿ÿ € Qð뿳)#;³ /»œ€ —Ü×_Œ¿ß²‹LÊnþòŸ÷‡Œ©¡– 8`˜þ10³Æ×>ÿüÇðæó_†Ço2<ÿð›áù§? ¯¿üeø,R¾ýbdøóëC{ƒ´Ø_ÀhdøòåÉÇÞþøñã&@±0üùín-?ÇËP„ƒ›“…Ÿ›•A˜—áÉG†’¿¯nnüøÑü€$ƒLЭïâÜ—w=cxôúÐb`¢¦TFF&Vf`ödbàå`aàáfÐe›!*ÈÁжä,ÃŽgb¼Ìþ3±€ÓýÇΟ?{ȹ@,"<Åé^Ê,@—½üÌÀðhñµ× @Cä•Ň-X,&-ýWDŠ[êÚ`¤é(i B|¬ œlL ,Œ L ôôáw` òý ýˆÙ88ž¿ûÆô-3787]¿~íÿýû÷/ð €Xþÿûüÿ#7ÐB '9”¹ŒÁ0@œ/:P†‹—ß¿3Ȉó‚“ʨ Œf†¯¿ Iç7£ü7PÍ_ øo yì\œ /ßübøñý;0]üÆÿÉ_¿~½ tÀ[€bùðúÝm•_zúRì ï¿AJR ƒ™A zÿá؇o¾Ó'Ђ¿°4 Å õ¡iÄ•À€ô7 yy8Þܦ‰oß?ûwïN:yü  €˜~~ûúäó·? ¿€Šu}:ÿ+ ôÃ7 Ÿ~C beg‡[ðfÑH†9 ™ÿJß~20ˆð2¼ýÎÄðñó7 ~F†÷ï1\¿vùÐxPü &†oŸ=¦`V O™Ù‡™Ÿl@¾¾gøøä.Ç7~||ËÀÄÉÊðTH#,ý˵ÿ¡AÍÁ¿þB R#ÀÇÍðé+Û÷_þkÛ3gO}|ýæÛ3aëÿ |ª ÄÂðþÉÝWï2°-ý÷‡‘áõÕ oÏe`ût‘_@ŒX2~xÂðŒ[Ã<‹K×+Àì…(.~3 ÒÀÏ¿„øJ,À´ÅÌLˆo>3¨~yËpù%3WȺŒŸ¿Yÿ8”— @, ÷Ö?~ú1õÓßø®.ícà{ÑÍ`æàÄ i\ÆÀÆ«.Œþ~¹ÁðöÜ|†û^œIb`ókcàädøûê{¨¯ý8 Pa%nv†×ÀzåÙÓÇ 9TÙ•Ý<ØoÏ­—eøþT €€Öèõ‡_œ=Oþw7ƒMu&0 „‚Ò_—S̬ ’ny ’æb Ì`8³ø1ç°e Ì\| ¿ Žø ûPÁ*¹xy>}}Ápýþc†÷Œ² Œ¯?0ü¸·÷.Pê5@1s¦ü‘}²9$Bc’¬e¶1Ã?^+`"» ,`åŸñs ~Lõ÷þ²‹0ª~`à¹uá• /e]E2ħ°Ä‡œaéâë¿ ¬ooKË· wY´¾>ñïóñ¾M ÿ~î –rŽ>qqÙŸ¦@C~¼dèŸ2›AI•‡!8XZÆCÀÆ /î^{Ëý•AÖ“ÁlÑT†wÂ~¨30ýAT'¡æ(axuí7° ûÅÀ(ÉÆðñÖA`Sëã P9@,¿þ0¹›Ù~Qd”ú÷Ά ÀæÂK`IèãÍÆÀÎÁÉs@|îÔ†kÀñ·g`P& 9µ¯ Ü÷w2|V2fàD.þ¡F3¨2ûÈp÷þGFf $ßgÇ@åÿ fv1%`D²ãJ Xt+[~nVQH{…˜¤?3ð~dàæÿËÀ-J Â@Gp];ÅpýéQPS áÿ!ÒþX©\½ø’áýw!ί ,_>þÿýìähAô €X˜Yþ ± þ+çfÈÎe‘ÖZâ›ÀEÒ†ðð§ oœŸ0H* ¬3XD€øÿ†;¯3¼ÿòXÌþa`c†''+;ÐŒÀâ÷7Õ³2CTºç=føËö™áï«»Ÿþ}}y ÔhE@± ‹ßÁ­V`Ê0˜˜¨Ù2À ÒÀ’‡áX­¼<ƒbã!#ûpòøö—á 3?°ÈfþLŸ¿Ýú XlƒÚ‡l ×/?gðÑbøÉÏ ÔÃÉÀÄ-ÈðéÆšç ÿ€JÁo [ˆåËgÆ»Ÿß±0H0ð0ÿÆàîÎÍ`c túõw ‹·¸3ì’¨¶˜ÁÑ vPŠ6_ºÇ ÏÇÄpçÕw†+1ÜêcçÃÏÏï~}óÿÏ—·¿~~|þíÃÓÿ{ó‘áëÛ ÿ>}`øù¨àík†ïoÚPCï«hs'9‰L Ë7“·¶døôEˆáÓ'p¥ÌÀÇûˆŸ2| Túd ®¤ÁÀÄÈðùÃ[†ç /d•Àøóç7‹¾¾¡ƒ€€Á åææƳ {zzX½|ùÚêÊ•ËÕÀ¨ºq÷îÝçÏŸÙÀÈÈx €X$Q†[·n3¨j2]Œÿ–†††Z¤¦t -ÒÒ¢@ìÄèêê¨ùñãWÍÝ»w'd'~02üþõáÓ§O@ßÿa’’6ÓÖÖâ§”«ñål&`È ò0(**ñÕÙ’€ºþ00nþñß`üRïßa`eefTVV¶*ùÎŽÿ@jþƒâòD?ƒ$±ýcøõû/Ão Yèû ÆÿBâþܹ3??~üð € Qðó0ÝiÃJ›“CKˆCîÛo†Ÿ9„&ewaàÿÏÊÎ%c¬¯í ñÅ_°7ÿþþÇðæË?†·_~3¼ûò‡áÍç¿ Þÿb¸ýòÇ>~ÿÏÀúÿC„4ƒ?Ð_ÿÁeÄׯ¿Nœ8ööû÷ï·ˆ…á?c …Žø\=AiA6i6†»ï ÿ¦ë|¸¹)ì!³å FQ·L’¼«O¾axòú+Ãûïÿ€–ügx÷èËŒ ì, œ@,ÌËΠ,Ïà ÎÇÊ &ÀÅбü,Ãöƒg"ÝMþ1²‚œÏðäÉS†óçÏÞr_eE„† +3ëÏÀÒã;ÇÀ`df¦~5Ù~s‹Ë«0pI²Ê|-ÊÀõñƒœ(ƒ®,ƒ/3ƒ'0à˜€ÏŽ„_ÀÀùþ˜Ï~1ÏÊÎtð†ß00±1ƒ£æúõkÀÒðÞ% ç@±01ýçÜu‹‰o|À™—ƒAHs#§ÜKœA(<\E„ë?ÃÿŸ_ä$øÀ16Š-üú’d@Iä€_@—ü:â0…±sr2¼~ÿ›áÇ lL ¿~ýa8sæä§ÏŸ?ß•–ÄòþÕÛ».ò¿tŒeؾýg°a ƒX€¡ÂDï߯9#Ãk LGà´ú–f¡TZ‚Ó.D?ˆ¦# ýaøþí3ÐsÞ`8{ö40Œî‚”˯_ÿ:÷ßv†¯`в¿jlð`˜ ðs!,þµ˜Bÿ:„ \§ý†À7 äexü‰áãço ÜÀòëáÃû —/¿ Ô ÄtÚ£‡o~ƒ<ÊÀÆøŸV^ƒ &r†ŸÀ ûûÿ/3++Ø÷`_B-ý ©?Ðàÿ ͽ dùo äçaøø›…á퇯Àlû—áÒ…3Ÿ^¿þxŸAÐü+¯2@11|zqïÕ‡  Ðǃ|²äÐ,,¬ÀB‘î°a–ý…Xsˆÿý7$ª@¡2—‰•“áÅÛÏ ¿¾~`8ÿð+‹ëÜ6ã¢) ~(íUž¾ýý”pþ½ÿŸ…‘á0þe„:Xrðr10ãï?P˜ãà¾ý ßÿ©„aŽɃr30'¼yÿáå‹' ¹´9UƒcäY~Þ7føþT €X„4_Ý}öáÕ/6YÅŸ¿2|~rèú? Œâr œÀRï;¨¤{þ„áÝûWÀ%ÈÀ%£ÄÀÌÂÌðã+$üúƒˆ‚?HéhÈ0s7Ãû/¯nÜÈðö¿ÓûÏ ßnï•AÊéíÃ'/_™~B‘÷òi)1f`–yw÷>ÃM>qŽ/d98¾ýüÉpûÍ'†g–a ¼–Î L?!í%FHµräôrÈ?`t‹‰2|z~áܽw ¿Ù5~=ºóŸáí%PB|@,š_öü7¸ðõ¯­š9ƒrY>0ÕAL|ýšÁféVY-6O/Pe4ñƒí“G ûç/d8ðé#¯KÄŒˆŠèß´(baa†·w3¼úø“IŒ“áíÃ~¿—ÄâõaoXfT¬¥²‡70œ^¼„˜ÆÆÆÀÉSƒ*°¨(utufø ³™^üg¸´ lÀ¢’á+Ô7ß¡ió/!Kð€„<\§¸IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_txt.png0000644000000000000000000000640111550446574024307 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< “IDATxÚbüÿÿ?Ã@€bdßÍÀÀÊÆÀðçÃß¿ ÿYdÿ_e0ú½‡á?T 2ø TÃÏÏŸìââÖñüùó»gÏžÙ{âÄñ]|||—¾|ùòH30333\¾|™A]]áæÍ› ööv wîÜa—W`xýúý{÷TUUnܸÁ@,Núÿ‹á1‹1ƒæß3 ¼ÿß1üa`Aw—³³sqbb¼È¿ÿD^¾|e~çÎÝ’K—.^?|øÐ™/^ìöìÙN Ò7 ÇÄ‚]ø7Ãf/›_k8þgø %Pt±°°êèèi‚øLLL ’’ Ìfkk­Ÿ˜˜¤ôiò©S§__¾|éÔÕ«WÖ½zõê$Ð!÷ÿüùû‘Ó&€Âဿ ßXÄŽßff°—øÂÀÂɶècaa¡55¬º¸¸8ôôt@Xôë×ïÞÏž=÷¾qãÖÛ3gNÝäååß÷ë׿ÿ> Túd ®¤ÁÀÄÈðùÃ[†ç /d•Àøóç7‹¾¾¡ƒ€€Á åææƳ {zzX½|ùÚêÊ•ËÕÀ¨ºq÷îÝçÏŸÙÀÈÈx €X$Q†[·n3¨j2]Œÿ–†††Z¤¦t -ÒÒ¢@ìÄèêê¨ùñãWÍÝ»w'd'~02üþõáÓ§O@ßÿa’’6ÓÖÖâ§”«ñål&`È ò0(**ñÕÙ’€ºþ00nþñß`üRïßa`eefTVV¶*ùÎŽÿ@jþƒâòD?ƒ$±ýcøõû/Ão Yèû ÆÿBâþܹ3??~üð € Qðó0ÝiÃJ›“CKˆCîÛo†Ÿ9„&ewaàÿÏÊÎ%c¬¯í ñÅ_°7ÿþþÇðæË?†·_~3¼ûò‡áÍç¿ Þÿb¸ýòÇ>~ÿÏÀúÿC„4ƒ?Ð_ÿÁeÄׯ¿Nœ8ööû÷ï·ˆ…á?c …Žø\=AiA6i6†»ï ÿ¦ë|¸¹)ì!³å FQ·L’¼«O¼axòöçßÌ ï¿ýexóé'Ð ì¬ œì, ¼ì Êò< â|¬ b\ ËÏ2l?x†!ÒÝ„á#+Èù Ož~þÎ0Þg¸|éüe å ø@L@§=zøæ7È£ lŒÿ`å5(³€×Ï_¿˜88^Þ~ÆðëL*ƒ{¬9¿/Ðu;€ÅÐ]qu• ¯ï݃ý?ˆ¾oÀÐø Ä‚ü< ³0¼ýð˜mÿ2\ºpæÓë×ï3šeàUf &†O/î½úðƒÚ `F˜ùTüabexÿü çýi ná² ¬b) W]¶ŸA€™áÁ½ÿ Ç~f2¨8¸3üú Ñ 0†?œ 6—‰•“áÅÛÏ ¿¾~`8ÿð+‹ëÜ6ã¢) ~(íUž¾ý y¸Å¿ÕÈõšß<ûÈði_ƒG—l&ç@ËmA†·3¬ÞæË íS¬°X€Ñ Î`Çÿ‡„(71s›÷ß^¾xÂðK›S58Fžåç}c†ïOuˆ‰AHóÕ½§o_‚ìÔ× )øã§ ö”3…¼gÐ,ûA åë€Ù…•á㫟 W;1p¸µ3°ðs2¼faPÚùù¢dÈ Pààæax,¬nÜÈðö??Ã_ âo·wÊ÷ÄÄ nùñÅ‹·ï¿ü„ÄÈ€?ÀZıµ™Á×ý:ƒ°N50%kÑß«Àyõ;0yÏŸoÄðÕ¬…U„Ÿá݈ÏAÑ÷hñÏìòÌO £„ÅD>ƒçÜ½× ¿Ù>?ºóŸáí%PB|@L >|xõúë7_þƒ &Pxºkƒ«ñvY‹r Àm Ä2`„‚R׆%3ä)u0*KÉ÷`‹ÿ¢¦£_0‹0¼:úÆËŸ LÌœ núÈðû ¸ †Ÿ¯¾¼~ú˜ç$ùÙ€éšáÁŽå ¶Š³Ôœ«€¦Ëäos€¾ÿtȆå³Îµ2(è©2üúm1Bk@PVåP}NKÿ@ ˜•?ë‡ûþK;F6†ßOO€Ê{@ü €X>Ýæ_±Ço>|gcgx°}ƒ¹Ìc¿ö€!ÒEaÁúÇ ¿™?0üyõàË¿¯/@–¿© fnPyt÷ØöCÿ\ô'3Y†³š8° lc`x{쥳'ت´1¼7÷gàfµŸ@ϲ0³0üeäaøÄÌÀ"Žñûw¦/Àâö?° Éø—‹——áæ× fr\ ’j‚ ÿe3?×+»_2üýrT ƒ@à4Œø«BO¯~2-s`dÐa`¸ÚÅÀðü8bïKز+ øA• 0|ÿ²2‚ƒ™Òt–žÀ°fâÒÜ@_ÿ†ü†[w_2ðkLcOC†£À”dxl/|½è´ø r@±Ø~Ý lvýúâ–ñ—UXÄîˆý1p¹þì1Cîùj†kÚ% Àöûë?f åÿAå= #°a´œ Òv„µ¸ÿþüafø,=óCÔ®}edЦ_Ea†Ëkýý÷êÒE ²§°v@±¨sþ$¬¾Æ–úÂ~23üç3f`å¸Âðåé'†ÊsÉ Ç¥ª@M*`ùÊ´ôß_ Å Ë™™€)œì&$ÌÄOo>a0–àb¸ú–™áÊ× b¬ßîÜzÁðïÉ¡' ¿>ÔáÌÄòØã‘–uá•àg`ùý‚á ŸчodØ#ÜÄÀÍÂÉðT¯r°0°m`ú0fæ3F`“ë0þ¿}ùÈðçë{†_Ÿßüw÷Ö¯ßß~ý÷éɆï/?2üø̃Þ1|½v¨í¨s@±°°³J?ÿùÓpîÌE rìÿ6_`g¸ÂUÌðTÎAŒXö°ü·ÿü|Çð X—ÿùñ™á÷·÷ ¿??ÿñûÓ£O¿¼úøû˳¿?>yÏðã-°/÷íÐe@úó+†?Ÿ€  þ Mt¡|8 666çOoߨ̙²øî7oÏü—¶úmÃômÓ¿w÷žýüõùå÷ŸŸ|þ÷ùÉ›ÿ?^¿Hï~¾yÍð÷ãK`Œ“Ã[¨Á¡}µÌð?|Íx€b”Ðyóõ«Ó×ß¿A.<l¸ó‘¸ ÿo’ ÿ~|dø÷hÁ¿7Ðx{Ä_¡¾ù Ê¿„,Á  ‚ЋÑIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_green.png0000644000000000000000000000611611550446574024573 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< àIDATxÚbüÿÿ?Ã@€bdˆgg`øý‚ÿÃÁÈÀÀÎÈ`òÖ˜Aæ¿Ã? DÿþeàãHrssë}öìù­sçÎî>uêännî Ÿ>}ú ÀðóçOvvvYYY†#GŽ02Ü»wAEE…áéÓ§ <²•nÞ¼Å@,¸\v‹ñƒüY†ÿŒÿÑÀåìì\’/ðïß?³—/_™Ý½{·ôâÅK×:xöÅ‹çîÞ½·••åÝïß¿€jð†@aw33ç7n¾¹Å ¦¥ö€¢‹……ÕD___Ägbbb””a6kƒää$ƒ[·î$_ºtéÍÕ«WO߸qm¿  à¾?þ\âoŒŒŒVÎ``fdxøà!ƒ‚ŠÐR°å ߈ˆˆ¨ªªbÕÂÁÁΠ§§ Â"?þò|òä©çíÛw>téèÑç~ýú¹*ûJ¿þý €bf0`Ä=ƒB›èJV&† ¿nÿ`àååeàçç;àׯ_ìöö-vv¶’„ 3ƒ (®Ù­­­ä\]=,µ´t£•bØäÇ÷_Ÿ={ú €p;à=sÿ?ÃçÏŸÔÔÔÀ‰lBBB äååXIMí\\ rr2 ¦¦¦ü66vº22rA¸ @,„4‚0uƒ£AFFÆJ[[‹—Úÿp‚Kt3@Ò 0D¹ÄÅ%¹€Qj @LpP€<ùHÿú É–@J€O?eàáâfQW×°†Æ0þÿ=OC,á@ù·ŸÞ3¼ÿò,÷çÏ? þ ¦Aàôé“ß?~|ÿ €€©‹™á×#FC.NVi~>A%!!aRŸ~>~ý´“áÃÆ/ÿ¿ücae•7Ö7r„$F†¿¿ÿ3¼þþ–á÷÷ o¾¼â· o¿¾fxóýÃÇ_ÞÅŸ~Æðëdž)S¤E¤þüûÌ`L >|g8yòø›?~Þ  þ%DÌ0óaçgç•fã–d¸ùõCà߈™¯î½üþýá ±ð«?op^Ý{“áÕç— _~bxûí Ãïÿ¿¸¹8¸9¹$EäåD¸uDø$¤ø%J–ä3lÙ¿!Þ7þÿÁáôðác† ÎÞr¢LnUh 3› ûßoüzÉpùý†ÿ,ÿ´Ì4E¹óx—k(+þçÁ÷ˆA‰G–ÁVÓAˆSŒA„M”ƒ•“…• ˜vYÀÑÿ?䯿¾2übàâcgxñè%Ão?˜9˜¹‰‰áÊ•Kÿ<¸ ¨ü1@±ãêßá÷‡Ø‹2°2°0°þg–Äì ¼Ì¼ Ý.Ý Â‚ÿÙ€Aú‰A†Wìƒß kþÿeA`YÄ?€ùœ„þýÆ30q€óé+ÃÛÏï~þøÅÀÆÂÎðãûw†3gN~øöíûM ’·Äòöéû»úÿM UEtÞ~Îï ƒÿ1+0-þcxóá%0{þgøø÷38™ƒÂRR>øåƒê¸7¿Þ1ð ð3ÜøöŠáë× ,œì ïÞ½c8{öÌ= ’»@ü Se EÁ×F¤ âþgÒöJ)¥ý¾4ÁæÍäÉÍ“ñ.Yxò2 lj)e@ˆöè¡*•'|;ûµG_‚ù\%ìåXHƒ¦n±¦ §L$0=iÝ=øé€§*X„b+ÁQþÿù]Š¢D¨C©¤=ž;îò6Þ¶6]ï4û”œuA ÖˆªŽô ÅÄ‹¨„ú—±02£zU˜aãé°'¬ôK‘:dèG„öÆîdŠ µötÎo0FBk|ˆ‰áå¯û/?¼f`ef…ù‚AѪ þ&6f&¨ø?¨:`Têƒñíï7†§?Ÿ2|ÿ÷˜@ba`çfcxþæÃ×Oßî}¹Æ¡Yª’'h.»Œáç_]€bb¸÷ÿÑ“7Oßÿcü6j<ÄŒÿ~þþÉÀÁÎ^8,þAÁ b,êdøþ÷ÃË߯žüxtÄw†¿ÀÄøë/P†‰™“ ˜ŽÞ3¦Cmo‘¬ºÔ´´™¡&_ìÔW’Žf5ˆH¬–€€ ÖY» "ÿÿþAÂÅÅAœ»â±DqÃL;Ó6£‡S×ãú*\ä¿(7!J oÚRŠÈ¡ZJXï¾a/ó@x¡q•a2VÔÛ“ùIPûu`'ˆm½dlÁÿ¢o€Ô£ÎO™ ™baøËüõÉÃÏß}ÏÀÁ L0 W321° ¿òó ÃÁÇ8_s2p±s3p³ó0p²p2°1p3 8ËAœ!ÁY P…Â/ ~1¿¨Ã½ß˜~lÛ<>,·þÜjz@,ÀâŠáãë¯ÏÞ}úÀ +, ŠPf†uÏÖ1¬~±œøó3ˆ|aeeäbàçàgàbåe`gåúèw` ÷âH@¢äF`ÝyjÿS†k×n1¨š¾gø÷™á˽ 2à>¨®Àa¹£At4Á Ö‚¥Wr; ­ÅBQ´ˆû…]o˜å¨W:^õ˶"9¡cÐF6dˆDDK,³˜ùŒÝ7$ÚyGBq"(¨.óÅŸõ‹~ç‰'4Õˆ¼,p0ƒ„¤4­¼í`~×ï'€XT„€ÕÛÿg/_¾aàÖãd8óú,ÃêG«؆1 ƒ6DÀ ìóOpƒå/ë_†ï@ø Xx±þ¦€¯l ¬ÿ€X'°£Šè(6 Ã¿¾ùÍpñèU†„$7†i‰ø?Ëë??S÷- ‘ï@æ °&Ö™·¿xñ‡™‰eý£ Ÿ€j8à–à Z`ƒ0(g°1±KMPt1rc`F01üÿ)Ù%çÕ­oœÍîóßf`áaaøl¼¾úæ 0CƒJÁï 3ˆ˜—@ ãÖ“/ß¿ú÷\ôò»+àø\ Œè-žÿàJçóp–d¶žA –ÔB•œ¬ÿÁÅ8û†+>1hóé1°ëÿbxñ탢¢ Ã㛾?úrÿàb €X€Õ°ìüõáųw/^|"úáÇ`Qüî{XkD3ÿg'J¦LÀæØ‘°¦öp£ ˜}­Åÿ0ðc0VfØ÷uƒ€Ãþ çOÝüÆðùë Ò0O ÃëàÙ­s/¯\ytQW\˜“áÁ‹ <œLðZ‘ Rô2‚[4 bèk f¶n˜YiXLs°²2ps;°À:ºèÊEG>=ûÏðèà †O>ÿexõþ"Ð¥ Šè#ÌÄÈÀË ­ÂX d}T¶¸·Iï¾u™áí—À–,+0‰°Ð``ãaá``ÿÏn3üÿÂÌðã°Æ|,ùÞ›ìoÿüúùæ×·ÏO¿}|s÷ëÇÿ?€Aùó÷`ÁðŽ(Ãðï÷k % Òï¿„9 €Pc™K0D-Ak¡~ ×Ówïþ¼eÎÄð÷°jgøñæïïßo~~üõöÇÇï~~úöêÛÛ_~¾6ßÇ{`!4øß3 I¯€ø¨n‚&6þn4!€Âl<ó Åò( æýûõ—ãçÛ_ÿ}ûõþÿŸßïÍc /~-ørýkh0~D²èþKl €°µÞA‘¯Ä ÞÏO$_|CòÅ_R,Á À?Áö›*£IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_orange.png0000644000000000000000000000572611550446574024754 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< hIDATxÚbüÿÿ?Ã@€büªÁÀðã/ß?@ t ;ƒ0 C­˜ ÃY~iÖÿÿP4üýû—O ÉÍÍ­÷Ù³ç·Î;»ûÔ©“{¸¹¹/|úô郀€ÃÏŸ?ØÙÙdeeŽ9Â`hhÈpïÞ=†§OŸ2õë×Ï}ÀPÙTúõï_HÈN0ðÿëg†çÏŸƒãä fv##c~~>‚‰‹˜˜”•A˜×ÃÃÕúÍ›dë7nÓÌã[·n>sæÔ"`Ôí Bݼy“AQQ‘áׯ_ÀPa¶000Ð 'µ‹ˆ0ØØ˜3XY™Ë~þü5jÿþYYiÉDР„LÝàh‘‘±ÒÖÖâÄ©9½2âY&~~nqqI.`”ZL#(·ýfÅÿ¿|Pšû ÑJ€÷Y‡››E]]ÃFHHˆáßßÿ @¨¨Ž3"a`îùýþÃ_ ãA±ýçÏ? þ ¦Aàôé“ß?~|ÿ €@!ÀÌø“Áˆ…ÁI€]šY@P黨€ŽÏ§O?s¿?ëœü‘a£È÷/ÿ¸XYåÕ Aš0ƒlÚþá ç÷ ŒïßAØß00~|ÅÀøõãg ø›g ß~þbøU:ƒSBšñï`421|øðáäÉão~üøy €X€>Oà‰ñÁâáÉÂ($ÌÀ ÎÀ ¤_ße¨MK¹w÷ëïYOžøùL4\íù5Οˮ1ü{ÿ‚ùÇ' eo˜þüd`äæb`âbg`e`”—š! ga& †§ wncÐŽˆgàÇ#0w=f¸páì ç@±üW•ÍeÍMd‡ùg OÞ<``xú•AÀJMt×rUù_$%ùùþÞg`–a`ÓÔc`ä:’_¨˜]˜3ñ¿_ ÿþüõ“áßï ŒßŸ2°ò°0ü~ý‚áÛ·Ÿ Ì@µÿþ31\¹ré߃÷/ð €X~üûýçÖ !@ÌÍÀÀÌb¬ÀL-ÈÀšâÌ YÄ/ð‹‘‰ñËgfQ`èü–Û¿¿‹Ä@ ¤‚bÿ0›þ¦# 'þý–€lÿ/ÿ{o¾ÿøÍÀ ,ˆ¾ÿÎpæÌÉß¾}¿ Ôø €X¾>þpWDÌÃAÞo!©¨™á0%²Óè¯o ?>¼g`aÆûG`@ýYøl)Ãÿ¿Ð¤rÀ?°Þÿaìÿ ÿ¿}``àê{ÍðõÛw`ÙðîÝ;†³gÏÜjº JNh(—aˆFA=àýϤ® µHÄ©Õ]²š™—!­¿ã©è³EU^LN…4H“'Α|¹_ìÖÏfáºKI­•ˆ$GŒ"öÓH7ìs mÇ®óºü…€<ˆéÛg†ÿ^<ú–Rþ‚â’ñÔðß €qùÈfee*ÿbñ°¥P-…Ào Ã¿¾Ö_fA~ö_¾½}Ãð˜5/ž:ñ‰åíÛ—á@u€&ÓåÏ ÷ÿ¿z ±üï/þÿ^(€ÀÆ zPE ~pýÇ3Hì8þÿB‚ý÷W†Ÿ_CóPì?¸äaãdaøþò9Û/ßø\á8j$‘W&Ê»ì3ƒ.@1-üÅðˆñéã÷ ÌðÿÄbpb9æ7°þ Vˆ¥`GAâd)Èà8©Fß¿//þ}zæÏoHd* ÃÙyØ~¿yËðôñCEÞçìªÜûþüxÈÀ @,6À”øéÑý7‚ÿ¾ 2 `iµè3`h€J/66.HÑ J\€QÊÀÄùèÛÿ û÷ œþƒ,üÏ­9AÙ"@ýœ"| ÿ>~`xv÷ƒÆÿÏ _ï³1ì|ÿõ6ÐÄçÄâËÂðþã—ï¿„ï/x<ÿ5×X@EÄ'`Áô”áû{H>¼ Tò-À þÏÀÄðZªƒC¨XTƒØ¿ÿ`à–gøö=ÇÛO€ê\óç,ÃP9€…jI„‚£™) ûŸ§ ´(¡U‰‹>P‹hôu€Ç›¿ 5N7¯ ¸j4‹Ì !kפQï¾…a…¬uÐ ã«*yNYJk‹à9„Â?û DÝìÇÁ:&:áF¶˜€Gé@, ¼ úæÛ3†7@!HUY7÷20ÞÚÍ 4ë+/à þÊ.ÀÀÂÍÇÀÊÉÃÀÌÎ t ;Ã&`43ƒ’8=0üƒ8ÿ@AFn6†_;.0üþøû÷øß àÕÿˆe2TüËðìëË— Ü@Ãîwm'0[²@ÊP!n2ÛŠÀ‚X@~gàÖÙ~}b&†oÿ€©œ•èXVn°ƒ8ø~¾þÂðkßÙ’TÁŠFY`à>|òþÓ3†[@ߌ uHÍzëû㧸ο¾X@KD.>HÖcDj\@"T~1€Ò+°Ðb¦Næß`Eß~Ëú/o€æ‚žƒáë†' B.Q ŒÌ—8¹ÿ1¨ ž|òR ~ @,×ÁfÞÒyüô=Ã×7¢ /!ŒWpG©¥Ã kñ€â–œHÁ GXKHq0+P ëý7ØÅxt€üç×¥¾œ{ÍpðËÏÐø·Lˆeÿ°¹\¿y¬ŽE¾†$BXÐÚK ÐÔ ,Ï!¹„ Rf€ðÉq¬L ¿¾g`ú¦Ì ”eÅÀðh%°A¨¬\0œº{ãÛy† @…/`M4€bÙiÇýË»ðàŠÆõ«ºÌ"À,óXš±Ã Hq NæÌL ی̶(@!Æ,-YA¥;ÇÀº…[€áݤ _¿døúåÛçŸÿ.d`¸Œ,PEôæ€b4a„4ÿdþ3´i‹oÑk´–f¸s X5 `<2p&3Ð``c`²ÿé¿@K¿Û|/0|yû“áýûß ï?þüõòïo·_ýxÿé§ïþÿÿðÒP{ôî›çÀ¢ h¨ô;Ä/a ”¶«?CHŸµâB¥T-.†÷¯þ¼ù¬Å~1|¤ßÿbxùþ×|üå×ÇçŸ}º÷ùÇÛçÿÿ›ž ï€M“÷ÀŒúò °S4ê}Àð šØ`ø¢¹ „Ñxöa`ˆµäÎ{ÿç?Ç«/??¾ùÿè†÷ _M~ùâú×Ð`üˆdÑ/$ü—Øþ@ak½ƒ"Zˆ%¡ t˜/¾!ùâ/)–àO€V‚ÂøIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_orange_open.png0000644000000000000000000000423111550446574025763 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<+IDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €ß)30°ýeÐþÍÀ`ú—AŽ‹K†EDD‰íç7ÆÎ+of5¾cX["Äð§[ˆáÅPšåäd`àba`øø“áÇöÿ9X„¸˜d~²0È3p2É3ròʰJŠ(ópþUë;ò°®äÙÿù@û~¡; €X˜’XBÝ'q:ùr3ñ 00ð00ò10|yËPRRl4yÓ£Ï~3ìdøÉÀÃð›Aƒ‘Aíï_éŸl Râ<2RbbŒ’ÒBÌ’ò",RR¢\"B Lü@3ø®ºúÞ)†ÿǺBþîÚwÝÄ¢%WÊ^^ÄÍÀ4úã3†ï€^ý fNSÏ?OS“ùöSVZ\XRžŸQ\Š…AX”IX€ äPnv6 Qÿ€vƒè× þÌÀðhÆÏ§ Ìß$øXe€’¢Èâ?@ @,Xþ³2\ßä]Ì.´˜ŸE(ÅÉÀ\ ϯÀ $ 4ˆ¢dÉo á¿¿ñw†¯¯>ãâÿoþ÷ˆÿ@Ù@q¦o Ê@~Á,gâÉ,L 3þþg –O>Þâ—ôVfÕúèzF%@ÍÑÅL£À¸føò è@%@±¿A  ø3¸<û©±¿¼‡†¤Ÿ4Ãù§Óþèí0ÆýW ˆéÇÇ/ÿZüï;"èþ}É4ä/Pì;ÌrÿA‚lɈOa¾9,öŸžÂ#ÊÃ*ÁÀ ä°i2‚|I ¿Óׯÿÿ~›•ˆÁ ʘL@ÿAB´ >ƒóCù¿øÐЩý𘾂mááfF®0‰ÿŸ æß ¼?~ÿ•üÏ🠀X^~a¸÷÷ù#&¦ÿ gü‹æH>û îÄ~#¢÷ÀüÈðjŸ00|{4 Û¿þ0°Iñ1Dó1:dñòÍ”ãçüÏÏ!Éùý(ÓŧÄÒõ…á¾ëÇß>á„øî/œfød!Lì$ˆA!Šçÿ EÝ÷wDùë;$9€¢ìP0C¸”§©’/ÐQ‚ì v<þûúÂ}€bqd`xõþþ“WÂɃS-H'Ø2˜¡ñÎȱ”~~Zò ’@iDÿý ÁÿÀ0ÿ Í¿ÇÍÄÉÁð€j˜XÁƾúâãC†—ÄâÎÆðþã³—o…¿‘Ë€S:4˜˜ ¾øŒÏ@åß ©’HAù‰ ¢Œ™¡ÉŠb1Ì€ŽæfbøÇÊÌðïÓO&`qÉðþ;Ãîgm¸@,Ï™>p¿úðšáÇ7ˆïÿBãŸèä÷@Kï``x÷°„ÊÄÌ,Ðlÿ Øÿ¡!¢`–Sÿx9þ}:@”‡áåÝw 'þü½Tù €XNÕp½ýü@ëã{!`!ôó'Ä’›ûníd'v`iÇÊ)B@Aü–ÿC0¸ZcBø&r0qÿ¼÷’áÍé <ŠÀòè7#ùÇï>_f`¸Tý €XÚæóüc¸îòü1ƒ˜$Xo}}~50×KG6„a ÐÂ5ÿÁ*ÆáòH!ÀŠÑß Ö=¬J¾üb`ûþaßÛï  ½ÄŸˆiP¿Þ/†_Ÿ>€”éoî10\ØMtLƒ`øÏ_HœÂðïߘø×/ ’gþËðfÃ]^÷X^u†?¾1|{ñ™áЇ¯À‚‡á(ˆEå?8vŸ|¿÷ô773°Àý7`*çâ‡$FF¤ª \£á4@>‡=##"„@¹€‘áó‘' ÿØM¸Íx~]ÚÇÅÍpýÍ×ï÷ÿ3Ü?H5@1½šÌP¾ÝV_?00<½ 4Œ’¨Àø/*¿±„ÿ R˜ýzöžáËA‘D ÷v0°*ËX¯?xõ XR\f[ËÀ@,«þÝü^ûÙ‡7 ^ 0|û IáȾÿÏ M` r”Rý‡Æ=L#4î¡óáÀgÁØ|æïûÀyŸCZšáõÇK Çß}ýMXã €XÖükÿ“zõîi 'U˜Å)õé  \\*¢ÁÅ34Á*4fH¾eU&H‘ Êš  ,ÊÎðmß#†_wþ1|Þ¸†áå½ _¿s0|þúçïá·__[%Ç€ ŸÁb €…!NQúÏ 5OSl»Q‹½ÃýSÀ0fKn`.àæ}f6H6dòÿé¿@ ¿þgøóê'×w?>¼ÿýÿÃÇß^~øùýþûŸ<ýôáåÏ߀&|]ï^20¼ÚøXÒ<ZušÀ@!'1OŸ>cÙ%™úü _1üzý›áë›_ ßßé÷¿^¿ÿõóþçߟž|ûùáŗߟîþùþéÿï€)ç-07&Ýן!–ídr@¥Ûw$üR¢!@1¢·Ñ\Âø8 ?ýcäzõõ×ç×ÿÿ¾úâ=ÐÔ·Àˆyù ’z_A-øÅ_¡q 2ü'´µB FbÀzA jè7$üŠÿ’b >@ŒÝ7 ï˜Ѐ; €Ü`ú±FoíNIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_download.png0000644000000000000000000000603011550446574025275 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ªIDATxÚbüÿÿ?Ã@€bdˆ>ÈÀð÷ß?@è6&“/kdþßeøÇÀŒ¢áïß¿ ||Innn½Ïž=¿uîÜÙݧNÜÃÍÍ}áÓ§O~þüÉÀÎÎÎ ++ËpäÈCCC†{÷î1¨¨¨0téèÑç~ýú¹*ûJ¿ÂB €pFÈŸüexþü9ƒœœØr /8MLLùùù&.vv6eeEæõðpµ~û6ÅúÖ­[…—/_~|ûö­§OŸ\ T¶ €XtóæMEEEpâ¹90ø5ÈIíÂÂü ––¦ ,ûõëOÙÝ»÷ú”@L„4‚0uƒ|Ï ##c¡¥¥ÅK-(G“«¹¹ÙÄÅ%8@‰ €˜Àñ Òô÷ÿâßÿÁ4€àÓÇx¸8XÔÕ5l…„„€ÑñŸá?H-(ÿÿƒðŸ‘„ÁN;øíçŸ ï¿üKÿùóŠ!æ£àûÇï? 8üe0ade·åæaVçåf“ããç’ý,æüçÙ«È.†ëË—~ùÏó•CÑÄ@Çœúÿÿaøñë/ÃÇÿ>~ÿËðöÓ†÷ßþ2<ùð‹áÖËŸ ï¾þcøöûç_Œ þ`˜)Á +ÆÇðXÎ0ƒÒÖço ÇyýãÇÏ›ÄÂðçjˆ³êä` fnv&^NVV†§_òþLxvïÈ»‡ì^GÄxïc?´é Ãý—_0 d``ecfäegàfcåá`ÐSæfàšÁ,ˆøyYZaØqè,CœÃ&V`11<|ø˜áâÅów€~¹ @,R¢Üé!v²Ìÿþ%>30|~Ì#À‚‘6 ŠòB,É‹—ÈÉHü“áÿÇÿ·ƒ/+ƒ»©ƒ8Ðp!n&`&# ¡ H9è°@ýÄ?€f¼û -.†çïŸ0|ÿþƒ™˜Fþ2\½zùßÇ.µ<@#£Ap#"&…¦‘>È'øe‰/°´ÁÆh87ˆÅqÍ2³—‹Ä{œlA)Y䣵€5@×;ÔÆYõ\8ö×T¸’D>QäË#þ¯ó•H;儼Rk,‹ 2Xdñ<áý°…pL,°¾ˆåãë÷wÜ•~ɰ3¼üÄNDÀ4Æðó/¸@[öþÃwVf o¿@ %#PúÓÿ!U þq($ùx¸÷—h! §Ã›7oΜ9 ~þ@L¿¾üâão @ýcï~ ¦/†/?€b¿þ0°ãdø?X†ùõ9’¥ÿBôØ ‡:@TˆŸáíw&†Ÿ¾ƒŸ‘áÞÝ›ÿnÞ¸r hÌ ûˆ‰á맇Oßýdàú– ê#˜ÁÀ„4R¡01³2üþ ¿Ð Yjh°ÿ†ŠB”@l>N†ÏY^¿ûÂð÷Ï/†3çÎ}~û郸+/—4@11`šàâ€D ÈB~!Y ÃàtñQ¬s ;0!¾ýÌðýÓ†Ëo¸¹øvqg®ºÐ €X¾¿yúäÕ·÷À¢GpÓ©- 'ïjbc€/¿€!ÀÁÊÌÀ ̬Œl ^†Q ²*ðæ(~ý‡8 dùohˆÀB è~ 8Þ~üÂðäñ#†§œÊ¬òFÆ 7§¯à`øùB €X¤œß<{õåõÑçœì`ˆu –ù,ð2”(ALvv†³÷Î3ô¬­d¨‰]Æð—•è6HTüGJ”ÐËÀÊÀÍÏÏðñëS†Ëw?0|dRa`xöŠá烷€ÊŸ°üòþõÛ¯ïn>ûÈ ¢$ÇPä”Êðƒá'Ð÷°BBó1p3TÐ`H:ÓÍpùÙW>!F03"TÂrÀhôü:RTLœá#ÐñOß¾cøÇ.ÀðùÞÕ? ®_•ÄÂðûý·×/^>ÿü“XÀ2\ûyƒá¨A©e€¾6Õþx¬:X€>e‚T €,c@uÀßÿˆ„ Nˆ@Ç>;ÿ“áõ×? ŒR¬ _îž|Ãðï+¨ø@À4ðšáûÇOß;Û†W¿^1ü…-rûX¹¾1|Êýeøðñ+'°àb†#¬BGäÒÀäÄpõÊ †'w>1pK¹ÿÀÒÿÉ¡ÛÐrà'@±0¼˜Íð—‰÷ɳ·ö ¥þ0¼þõXÿ…[Î Löÿ€‰àô»+ ûnÖL 7ÞËÿ¿ß¸¿3p(';³0AjwC~rо7^1¼}ö ÷RÀPùÈÀúñÍßß//]*»r6@±0‹2üûðýÙƒû_%3¼úó ì& ¯™™ž³Î±'×nxÉðéÃ'Þº ßþqƒšì ÌÀÐbylÿ?3°²2°ìg¦zNV†o0<»õ’!;\¡~ò†ÿœ ߟßùøÿûKP¼9 €XXyRصŽÖ<ü{…“ ¯þÃî×ÿ_@K3Üxû\õ²±°2ðsó1|gÀpéZ"Ãÿß_$¤õ1ÀNŒ¿€+Æ€êÿ1ܾøœ!ÉYŽáá6N^†œÂ _ÎÎzŒ P)øä€ba¸þñ“‹R,0¿ 0\|{Øg`øøó+°xþÆÀ¬™€Y˜.ÿ½ÈæúáëÓã ŒG¹ÅäÀyža8þ±p0k]†«î0x«p3°K [T Jr" 篿døþøÄuhðƒ[&ÄÄðøÝ–¯ËŸ¥<œÎûó5ƒ/ÃÏ?þ2þ† ÐÀtLŸ ‚ˆ™˜9_b`=¦É ¤´’WÞXÍËýŸ lÁ1¼6&”8þ3XÛ)3\~ÍÀ lÊ p2|ºuöëß÷·@õÀ ˜“ÒíùýçêÏßQºïî3éh*°0((H1|ùýè`y,"A)›ý×˟þî3aQžÂÀ%©Îl1€2¨`ªaò™yïé…+ <,Ž]zÆpéØE†ÓûOÿ¹~îü÷Ÿ÷ÖSñ£u@Ó®Á €=vY5v“–mÂr” \.3ðÙÿe¸óñ10þÿ‹Ú7{Þ;À ¡^ÎÀÂÅÉð÷ÇG†?ß?2üþüæÿ·wÏ~ÿüüúׯ/¯üzÿäËïOß0üxûŠáÇ»× ¿€øïû7Àx%:`ü3œâ×0kµ«Âoì&`Ѹ‚ï‰ Ÿö ‘oÀêØÖ[ú‹áÃNÍ¿<|vßþÿýðíϧ‡ÿ|º÷êïç'/~~~Ëðï'°ˆûùáÿ·@‹€˜á 4•[Àâ’à@¥(ÅüE¶ €0ûJüú~L¢Î•ÿ>Ÿàðý üï3Û§÷#øP/Ðÿ>‚J0 ~jÑ@-õÝ~C1J²$ˆ‡˜K1°rji†ßßÏéCPŸýC€—pi^L-¶IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_image.png0000644000000000000000000000607011550446574024554 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ÊIDATxÚbüÿÿ?Ã@€bdßÍÀÀÊÆÀðçÃß¿ ÿYdÿ_e0ú½‡á?T 2ø TÃÏÏŸìââÖñüùó»gÏžÙ{âÄñ]|||—¾|ùòH30333\¾|™A]]áæÍ› ööv wîÜa—W`xýúý{÷TUUnܸÁ@,Núÿ‹á1‹1ƒæß3 ¼ÿß1üa`Aw—³³sqbb¼È¿ÿD^¾|e~çÎÝ’K—.^?|øÐ™/^ìöìÙN Ò7 ÇÄ‚]ø7Ãf/›_k8þgø %Pt±°°êèèi‚øLLL ’’ Ìfkk­Ÿ˜˜¤ôiò©S§__¾|éÔÕ«WÖ½zõê$Ð!÷ÿüùû‘Ó&€Âဿ ßXÄŽßff°—øÂÀÂɶècaa¡55¬º¸¸8ôôt@Xôë×ïÞÏž=÷¾qãÖÛ3gNÝäååß÷ë׿ÿ> Túd ®¤ÁÀÄÈðùÃ[†ç /d•Àøóç7‹¾¾¡ƒ€€Á åææƳ {zzX½|ùÚêÊ•ËÕÀ¨ºq÷îÝçÏŸÙÀÈÈx €X$Q†[·n3¨j2]Œÿ–†††Z¤¦t -ÒÒ¢@ìÄèêê¨ùñãWÍÝ»w'd'~02üþõáÓ§O@ßÿa’’6ÓÖÖâ§”«ñål&`È ò0(**ñÕÙ’€ºþ00nþñß`üRïßa`eefTVV¶*ùÎŽÿ@jþƒâòD?ƒ$±ýcøõû/Ão Yèû ÆÿBâþܹ3??~üð € Qðó0ÝiÃJ›“CKˆCîÛo†Ÿ9„&ewaàÿÏÊÎ%c¬¯í ñÅ_°7ÿþþÇðæË?†·_~3¼ûò‡áÍç¿ Þÿb¸ýòÇ>~ÿÏÀúÿC„4ƒ?Ð_ÿÁeÄׯ¿Nœ8ööû÷ï·ˆ…á?c …Žø\=AiA6i6†»ï ÿ¦ë|¸¹)ì!³å FQ·L’¼«O¾axòú+Ãûïÿ€–ügx÷èËŒ ì, œ@,ÌËΠ,Ïà ÎÇÊ &ÀÅбü,Ãöƒg"ÝMþ1²‚œÏðäÉS†óçÏÞr_eE„† +3ëÏÀÒã;ÇÀ`df¦~5Ù~s‹Ë«0pI²Ê|-ÊÀõñƒœ(ƒ®,ƒ/3ƒ'0à˜€ÏŽ„_ÀÀùþ˜Ï~1ÏÊÎtð†ß00±1ƒ£æúõkÀÒðÞ% ç@±01ýçÜu‹‰o|À™—ƒAHs#§ÜKœA(<\E„ë?ÃÿŸ_ä$øÀ16Š-üú’d@Iä€_@—ü:â0…±sr2¼~ÿ›áÇ lL ¿~ýa8sæä§ÏŸ?ß•–ÄòþÕÛ».ò¿tŒeؾýÅ/Ä0AÌÀP…Äû÷_€qÎÈðHÓ8­þ‡¥Y(•–à´ËѢ鈇è€G¾ûÁÀ ô܇÷Ξ= c†» %Äôãë÷GÀäÄÀ´¥ À´Nù¿ùdÖQ߀˜XÊ12A¢DÿƒY²ê&|p >aA^†·ß™>~þÎ0Þg¸|éüe vPü ÆoOŸ=wAø;ÃçŸÀ,ÌC¾ýÃò#8ëüüþ…á» ?30xþmafã`‘ªe†øú?Ä1¿ÿ!èoÀ(ø Ä‚ü< ³0¼ýð•ABê/Ã¥ g>½~ýñ>ƒ ùW†?oˆÅƒ{¿°.‡8ÿÏ œÀ2à?´æh`~fsÙ@õX:3‚pó†7J Ê:úÀÿÐ(…À÷ߨE0˜X9^¼ýÌ úõÃù‡ßXY\çÆ0ÿeÓúu´¨ €˜yXy=Ý]„¤Á ¬ËY ™ˆy€Žà:œ@qKD`ùÁÄ ¢¢Í ¬Ëu?Ü÷¿ÿ#R?ƒr($@QÆ Ì oÞcxùâ ÃC.mNÕày–Ÿ÷¾?Õ `ìÿûúñCÍ‚s O¹4„þËnP<~ûúŸáÓ»ÿ _þgxûŒ™á°Q1£õ ƒ–*7ïL Ÿ€‰öÛwˆÏÿ@CV‚B ôÂÁÍÃðþË+†÷2¼ý/ÁÀôþ3÷ۻ@åÀ{€—„ÿÿýaVS`Ô0dàÛ? ï†?ÃÀð˜fÙiöÞw^ÖÇÀ ýÇð˜#Ø?õþf€¿ÿÿ#åo¨Cþå…ÅD>=¿ÆpîÞ;†ßìš ¿Ýúè(!> H©ÍÈ ÌëÀÖƒ;°^gýÏð˜ y€)øóó?Ã×À²Aà7°(e—í?ÿ@ÊÆÿÐj€‘5ÿ@",Q ‹0¼½û›áÕÇŸ Lbœ nþÈðû ¸  q`ÜlŒ B@ß[‰ÿcaøÆððÕï, Þ½eà`fbàdà–T0üƒÅ1´‚YÊÿÿ ‰$Ï,}?óòíûþK;F6†ßOO€Ê{@ü €XþC]ÎÃÇÎÀò®Ï3ˆhk2<>‘áÐö“@ßfx oNÃz–×9¨ž5Ÿ˜_~eà`ÉÁÉÀÂioýƒ¦€¥3Ã;`â;~ä!×ÜÀ’ö'ó÷¯ ¿Ÿ¹”½ R@, ÛÁåõ¥ƒ —v0¸`ñ*†9ó'3œ9ÁÐÕŸáþ¦VÞw" ¿o-ú¸˜¬^üfgøþ‘…ãïgÆO l,Àb—‹J,JöÐìÓÇ0Dº(0,Xÿ˜á7ó†?¯|ù÷õÈòW 5Äò È·odØ¿óƒ3ƒghÃËWÞ?½Á°þÚ†Ÿ~3|?»„áà LÀF*0²€YX­2²3ü`bg`&JÆïߘ¾‹[`(²0þeàâåe¸yã5ƒ™ƒ¤š Ã`YÀÌÃÏðåÊî— ¿Ü•,  ¬!ñþÓ°«ß½û˰oÍr¤6Ì/ ´ÄÁEÕ/`83µ°€Û-À°fâÒÜ@_ÿ†ü†[w_2ðxÏ`ìiÈpôƒ”¸ Ãs`{áëýCw õÀoyÄK½ ÖÖÖ@C˜¡-Hbc‚Æ-ˆü l–iik1¼| ì/üæ×· ’°÷ cþüaføL7ù!ê ×¾22hH•* 3\^sèï¿W—.•=…y €ÀU‘ © À&¨ÝLéì`‹A¾ýþýØQ?~|û”X)=|ò ØâVÑàJ\ƒÂ0°iÀðôæc .†«o™®<|É Æúáέ ÿžzÂðëã5P@Àæ2V†h°:¿BýÿÅpvÜ\[­mµ Å ~ÁÝ»+ÿÁa­Ë󉈡L0¥ØH‘˨”5 †Ü约ÍL¨R‚㋈™õ—3ýd·¤ç‰ú[ùç\¸WÁðü8°ÜwKü ¼ˆXá0²±ò7 ¨Õ ô 8+|.$$ÊÀ LL?þWL 5,À~$°î~yzÛ/Çö~døöüÓï/Ï>üþøä=÷À¸ùöŽñ7þüŠáßÏ' Âˆ?CÝG(ˆØCù÷òå3°¯A>óïß¿€>ÿ Œ`‰øã+¬ý÷ïOpƒôë— ß.öíþöåËh|~‚²è;4åÂð?|Íx€b1âããúJšT,B«aY a#zÉÀþ 0Ç}ûóøñãƒÀ¶Â*äø$N Kï<}=IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/www.png0000644000000000000000000000610511550446574022762 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ×IDATxÚbüÿÿ?Ã@€bŒ, Ü@ô(ÀÈÀÀ ÄL¬ ÿA|&†¿yþ3Y3p1ÙòðséòŠð(sðqò=ðÿÛ§oï?}ü|÷Ç×OW>8ÀÀÆz’áëÖ¯Ä8 €A!€×?ðR:’Áv^ê¦ÆÆR úê¼ Âì \, øñÛo†‡/~2œ»ù…áüù¿Oì;uöÃC˾m_ÌÀðé=>n=Íð‡Ñ[\I¤+$ÛR+8H•ÁL™¬î7Ã_ ff`²™ázɧߘŽÜøË°iã]†ýö\zwkU5Ã[p9 €°;’,ꜣÌj¢òÍYu™­bd`bdK²±°1üùûè? ß}gøûïPö+Ã&v†›Ÿøö^øÆ°iÁÉoç·Mébø¼¾ä%t †“þÿcfecí Ês)ÌÔbÐxÃÀüí Ãë dðƒ•l9; ;ÃÏ??¾üø 0F¨w 3Њlo´ù˜sL¸D$›vÏcäeø´¾hÁ7dëÕQëR`%Ä À|‰á÷wF†W@‹™ÁÏ!Œs›hņ÷ßÞ1ü:‚”HÑýÄR¬_8Ÿ1ooJý‚© „Å@üï—GŒ]¢ïÉÇþÿ•`øð›™A€[ŠCˆS€ ˜8Yö±£þÝ×÷ ¯¿¼; ÿ™ÇÈÄÌð˜(tD…®=Û ïäÂ`ö±ªôÔò›WþÞ[s@AœŠ÷ßùåUd{•DY>ígæ–`øó_”A˜W—AG™Uá÷_F†ŸÀøëïÿ ï>bøöý'úò…á#ÿó#0=p2|þú•áË·ï ¯?}epR°dxö|ƒ¾», j|%#—6ÌÄ„0¦LTkµ—'2¼zx›ŸßˆAX@›‰E€á;Ð}ßÉçÿb ý ß<f½G b¼J âüêÀLÃ Ì–Ò Üœò@‡-ÿòƒáóç ?š¿ÿdax{ç2íWË\ÃãuX5bFp€l ¨þòªj+3)~cxÿ‚‰áÌ+M†S¯ø¾cêÔÇ Ëýƒàkî2œ½všáû×? ×ï_c¸|û,÷oü¿ ]cøðþÐbPªef¸÷ä9C㜉 gÎÝ`8r ƒª!?ƒ–¯ÐREÍM„ÿmŒ\U/^?Ì È§Ë -kÏpü)ÃÝ7 zb ‚ | Ì¢ÀÀÊL o>~d8töÃá g¾}ý Ì·Ò Ÿn?exòüƒ–¥—æ‘˳íþ>» @`°±±ØpH²3>ºv‹Á. “˜ þ}ý˜a?f`¸þè\!–ïïNßÏ À'ÀÀÉÎÉÀÄÌNp€¹äûÏŸ _¿cxùöÃû÷¿†æû7 ÿÿƒŽ‘ XvSíoN†;7O3¨¨$20p)[2|~¶ €Àà`×U‘a`¿ÏÎpáàdm 5fPÞg`xtÈG`Šfgf8þü?ÃåMS8¹À>fæ`IL|¿~ÿü.œ@®g:PNÏ…áùý# <ü’ ß¿¼aøþú5㇧Œuâ˜y$eÿ~f °DE”^¿»ÊðèÁ.†?_?2ܽ¶œABÁ†AEÇŸAVÁžlÐ\&`Ý`ç]Âðýï7†ûwö3pr 1üþýÿï€rÀ¬ÈÅÄÀÎ)šÿþýÅðýÇc6^yM{†w/¯1ˆy1Ü¿»›ƒë¯ÿ×ç <vïûÀìÉô•KXèß OnaxþdÐÂi ʶ ?€Qý è6`IèèÓÎ`öå7;ÃåóëŽjF#¢(—†ì oÞœ`WòFÓ+»tV–ÿ ‚ ¢¢" r” 8ˆRúþÿÏÆÎÂÀô ( ÙÜü@_üf8q¸”áó—UF`n|@ß-L ì(,eÈÀÁÇ.æáE2Ð!¿ePÒôbptíb`úóáèÑf†_??2:2ó‹‚Ì)f °~|ýúž…‰UŽ… R"ŠIV†?>0|ýúX¸€ ñ$ã?ˆ<¨L`ã’càªyôXüÏŸ/ ì¼ æVåÀÒ““áųK Ži ÜÀzÌ@M“áõóŸÀZX‡S @ËOï>ÜeûÇŒ/f#X8A>üÌÆïUÌ-ª˜ª‹P r#'P X3²ÿaà”`06Êa‘a`&È7Î3|ú~Ÿ›‹X”:èÿ/ï¾€êu€›ûæÍËË\?e„„…YA)h:ÛN>a%9' *6`Úbg†Ð zT°Cƒ(À/¨ÈÀÈö¨X[òð2È+83h+{3ð},ÌÍ ,²¯2¬>œË0qs4Ãù»;ž<þÎÀðíÙ+ Õ_ì€ÿöx{‹ñ‡žªÃ/–¯ Ù¾1kF2${o`ÐJìL‚ˆˆ¹X!˜й€®ÐWOa`†ÂO¦· b¢ª šòÎ ÂÀñ‹ƒå7 04ÿsü†ÎOe1]†Kç¯ýaøyëÐê÷- o:´åô…¼‹cüÄ9ÕüŒ³Yœ—Xœ«\`Xƒû(èÿ›-ꃒîy…5t”ÂþüûÌ`£š ¬d8&_~X€)1¸h{1¼úv•ÁPQ‡áç{y†ËÇ:ƒà2ÈuÀ›o/Ÿo^zo£…“×OL@¼ ¯€±Ä luýúô70ÉÿïÐøÿÏ€hƒ°‹dýZ`cÒ’E(”8X2( J2Ø()38ª2pqq0TøÿçñÞó@e@é €Z­_°ù’5W&3ï;`=“AØ&,A$Ì¡…°P (Š€iƒŸ "ÏTç¡îÅ ÉÇNC抒 ÇN20œØ0ë!Ãÿ'>Ù @6!<ï»›Û·­Kœ$Ȭ팄Ý>A P€¢á/4 @¹ ‚’… âspbe”0Ü,``8tó'CLÒÜoN”ÎÿT ¶« Í "Æ¥Ê+ª¡¹oº%/Ѐ7Ÿ!Õ16€ €¶à‘ÀJ @” ÄäE`ý”¼æß½•{þݵ€÷‚¤ €°ôŒ€ÖºuÙúïþåõïÿ߀ ž~úÿÿþûÿÿñÍ×ÿÿ_âË/!øÚ+ÿæˆÚwßÿÿÿùç?¸þ㿲Ç*`1©´hvó [@ 8ºfÀXulÕ°Xþsž·ÿ}øÿñÿê‡[þ_yûðÿí÷ïþ¿þò÷ÿg EÏ?ÿüÿýçÿÿ~ýûŸÿþÿß·öÅa“)ß‘,D· €Ð¢P!„ݯ<06\ß<œ‘ážØF†Œ€‡ ŠŠ üÌü ÷¿>`PçWaPPe0ä7eûkΰûÔ'†i³O2œÜ¶ð>çM@Ë¿nšwTð [@ølš ª±‚¢>¾Z–vÚBZÿ…Ô1°J»~\?€ ‰áÃ»ß 33|¹ÏÇðþÚŸ?7Ïì~ôïÍ~`6{tß·áqŽˆ€;¤ 'aÇÀ lÎÌ*¡ÀÎ+ÈÏÊÆÁÌŒ¿~~ûýóÛ›Ïÿ~=Íðï °„û*d.ñC þŒÏ`€"ÖHÑÂÀÄB ê0fHŸÜÙõˆ?ñ;\>F΂â¦~ãIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/file_temporary.png0000644000000000000000000000436411550446574025164 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<†IDATxÚbüÿÿ?Ã@€b1ììì”UUUg©©©Yýýû÷µ,`ddÓLLLŒ¿~ýb>vìØãÇW~üøñÈóÄ"@8..nñË—/ÿÓì۷ᅧŠÊ: ›D@ö<tÄÄÄ`Q‚L#cd1tyBêYYY xyyµ€ÂJ@ü €àøýû÷_ûß¿x-*#"íüŠýƒ'^G£dˆÁ’ &ô8Cûß¿ÿ L@mìL ,Ì þþcøñëÃï?˜ÿ3ð°32°23€Õ¡ë…;šåˆ—¯aŠ@âÌ@}l@ >~þÅpüò†—_þ1°°²0ügdb`ªût'Ó_Yav†_À°üýçFt › „ád‚ÄXY™À>ÝtôóïÌ ‚< ¢Ì , ~~Æ+#Ðëï¾32ìºó…éò7.)N†/ßÿà  ¼!À´üíÇŸ ‹¼eàdfeøþìÃgÆŸ \lL Ÿ?¾eàæágøûŸ…áïFAa†?âR ?apRÿÆ`¦)tÄ_œ!Ä‚-îÁ)–…‰áý§Ÿ ³¶¿fSdøõêÃÛOŒ´ù•¤€ò, ¯ß03Ó Ë¾Ìð‘Y†AE]žaë¥û ~½d°Ðgøòí7J:Cm€ÂŒ`úòÝ/X„%^ÜyÃ`!ýÁØV™”WØØ9€ #ƒ”ŒÃÿ 22ñ2x¸ª3¼}ý“aÍÑ» ’êJ ›O_†Ú{Q>†_¿þ` €b `¼32\¸öžáÑw†G¾0¨°?ep°‘eàâåúX€…ƒƒEÌ@6˜/ ÀÏÀÃ+À §(Â`ÆÂðèÊCFq†­G_2°1ÿc@.ôC €˜0ƒå?8ï9õžáåo>±oØ_2¬ßt˜áý»÷ llÌ ÌÌLÅ- 0ÊØÙY<`´23hò`x÷ùÃWì ¾êcgQôl@!À Ìs¯_}e¸÷‘ƒáé›ï Öêœ î^N òò’ {öœ`Ø»÷8ÃçÏ_¶ XŠf`Y $"ÎàfL7¿0<ø&Êp˜3ØX ÅŠˆa¤ ùäÞýO W_°303}eP”Ò,l ffº ººj 'O^bX¿~/ƒº–2ƒš¬$DZà ¯5´^ýøÇðøÁiiqCC-1nA¶O ×þp3¼|ó ˜~ÀŽÄ‚­ûðñÃÛ\ ¬_>¼ÿÀÀ'ÄLB œœì ¦ ïÞ}d8rê2á]þ¾}àöŸ›AXDAKK‰AFF‚áçÏ_ ¯Ÿ=aøÿ š¿>Ë‹¿À"˜‘•½ú li€˜Å~ýeb`æ``x("ÍðîÇO†ßß~Sú†/_¾-þöÞ3Ü»wáÂÙç Ïþð1œ{ÃÇ ÷ûƒ·“(Ã×ïÿÀE;¶¶@ᬎAYÇדáõ§Ï ›Î 0DØ[1ü{}ãÒK† €ÑÄÁðìÙc`¡ÃðŸ™áÙÓ /Ÿe`WTaØv…—áÇõ‹ Mñ< ¬ÜÀtõk£gm_€ŽHôaaà;ø‘aÙnCu+ñÏÀ*ú3Ã`Yðå++ߟ_˜éã¯(ÃÓÿÊ Ûö ¯?j’8„¾Û ´ ‰2Ì4@,¸šb0…Ÿ @;&3µ¯ ëNþ`˜wƒO@„AZŒ™‹ƒXÜþcx,é?þÎ Ìx—!Íàƒ‘ßÿlÀèXkŽa«Œk Gǧo ÂBŒ ¹¾ž¿þÌpåᆗ@‹¿¾ÿÇÀõÿ/ƒÿ†µ¿ *r, Ìì _¿,ú‹Ñ Ãæ€b!Ô…µ€¥+óñ21ØêÁ|Ä Ä#þº¿€Yøï×àœ„Í,ll€BFbÚü K ê!YaŒ½_€²0@ðllÙ2âêV!Ó6*ÝgÈâ°øgÖÕ 6¨o`Ÿí š˜˜SîwœÑAL?›Èb`ÖÛÛËðõë×O ?ƒäˆ¦¨@އ‡§]JJÊ(ÆHNb¨‚úñãÓãÇßKÝM@¡E@{²@” «17 {ä Ÿ?âÇ@»ÿŠ^<„¤¬ïIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_man.png0000644000000000000000000000632411550446574024247 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< fIDATxÚbüÿÿ?Ã@€bdßÍÀÀÊÆÀðçÃß¿ ÿYdÿ_e0ú½‡á?T 2ø TÃÏÏŸìââÖñüùó»gÏžÙ{âÄñ]|||—¾|ùòH30333\¾|™A]]áæÍ› ööv wîÜa—W`xýúý{÷TUUnܸÁ@,Núÿ‹á1‹1ƒæß3 ¼ÿß1üa`Aw—³³sqbb¼È¿ÿD^¾|e~çÎÝ’K—.^?|øÐ™/^ìöìÙN Ò7 ÇÄ‚]ø7Ãf/›_k8þgø %Pt±°°êèèi‚øLLL ’’ Ìfkk­Ÿ˜˜¤ôiò©S§__¾|éÔÕ«WÖ½zõê$Ð!÷ÿüùû‘Ó&€Âဿ ßXÄŽßff°—øÂÀÂɶècaa¡55¬º¸¸8ôôt@Xôë×ïÞÏž=÷¾qãÖÛ3gNÝäååß÷ë׿ÿ> Túd ®¤ÁÀÄÈðùÃ[†ç /d•Àøóç7‹¾¾¡ƒ€€Á åææƳ {zzX½|ùÚêÊ•ËÕÀ¨ºq÷îÝçÏŸÙÀÈÈx €X$Q†[·n3¨j2]Œÿ–†††Z¤¦t -ÒÒ¢@ìÄèêê¨ùñãWÍÝ»w'd'~02üþõáÓ§O@ßÿa’’6ÓÖÖâ§”«ñål&`È ò0(**ñÕÙ’€ºþ00nþñß`üRïßa`eefTVV¶*ùÎŽÿ@jþƒâòD?ƒ$±ýcøõû/Ão Yèû ÆÿBâþܹ3??~üð € Qðó0ÝiÃJ›“CKˆCîÛo†Ÿ9„&ewaàÿÏÊÎ%c¬¯í ñÅ_°7ÿþþÇðæË?†·_~3¼ûò‡áÍç¿ Þÿb¸ýòÇ>~ÿÏÀúÿC„4ƒ?Ð_ÿÁeÄׯ¿Nœ8ööû÷ï·ˆ…á?c …Žø\=AiA6i6†»ï ÿ¦ë|¸¹)ì!³å FQ·L’¼«O¾axòú+Ãûïÿ€–ügx÷èËŒ ì, œ@,ÌËΠ,Ïà ÎÇÊ &ÀÅбü,Ãöƒg"ÝMþ1²‚œÏðäÉS†óçÏÞr_eE„† +3ëÏÀÒã;ÇÀ`df¦~5Ù~s‹Ë«0pI²Ê|-ÊÀõñƒœ(ƒ®,ƒ/3ƒ'0à˜€ÏŽ„_ÀÀùþ˜Ï~1ÏÊÎtð†ß00±1ƒ£æúõkÀÒðÞ% ç@±01ýçÜu‹‰o|À™—ƒAHs#§ÜKœA(<\E„ë?ÃÿŸ_ä$øÀ16Š-üú’d@Iä€_@—ü:â0…±sr2¼~ÿ›áÇ lL ¿~ýa8sæä§ÏŸ?ß•–ÄòþÕÛ».ò¿tŒeؾýg°a ƒX€¡ÂDï߯9#Ãk LGà´ú–f¡TZ‚Ó.D?ˆ¦# ýaøþí3ÐsÞ`8{ö40Œî‚”˯_ÿ:÷Ð@W3Á bW `ƒ¿ÃTP‘û@l1„þu>¸Nû4 dž° /ÃãïL ?cà–_Þg¸|éüe VPüÀ2•¤±`=*â|„ÿ¿{? 豈K­ S— –!Ì1dKpÃ8U%'³gSÙ•—öÍ”’_6÷á¹ÝAtvæ'•èTˆöK\¯~%¢,2¬’bZÄÂðþÙí«×î1èýÏðüõ{†ÿœ" Šú œ\|@Ãÿs(0µ?»Ïðé+0!}zËð—]ˆARÓ‚WP˜¯EÆhÈBàûoHT¢ ‹L¬œ /Þ~fPýúáüÃo¬,®sc˜ÿ²iý:ZT@ÌJò¢^ÃÃ;·¸Ä”˜ÙØ –Bƒ˜õ†°CCè?Ð7o?aPdÿÌ Äõ—aÕ}nVÛç¶pÿ¾»þ,@±DÛ‰:ò‹‰1qJ0|˜ÐÀ`¬'Í ›ŸÇÀÊÉ© þÿfx{ï&á’b†O>Œ ¼¶> ¬{1<{ü€ALY›˜»àQð© …( QÉÁÍÃðþË+†÷2¼ý/ÁÀôþ3÷ۻ@åÀ{€bbäàåòžá~A4ƒúÉ= ê_˜€ÁÆ…h  ÁÏÿl¹x›³®-šÅðƒ—áéÇ O>10¼ýÆÀðé'$ïs8[þ¥ ¨C~£CXL”á0œ»÷šá7» ÃçGwþ3¼½Jˆˆù×fÑß¡æ1Iþfdø¹t1‹ª Ã[1†·÷¯3°MýÏðãø i-}†ß_®3Ü’Ôg`”³¶äØáY– aéà÷?fh†.1<¦ƒ¼: o.ÿøëöªÕ@‰cÄòüÐãJ®f7õ×mÐúTUËÀxþÃá¶Z†­ÛN2¼þ#Ì ÿý CÄù“ ‚òª ì•U ŽºJ §¦na`0áΩƒàåÂ_h6…9‚ ˜£>|Ö÷?2ü–vŒ l ¿Ÿž•÷€ø;@±00()š[+1ð 0ðM™ÌpßL—aé¢ ‡Ôûþ °3\|lK§ÌÙ$dØ~}acüÌpèòm)Iv`1ÌÆÁÉÀÂÄ/#þ@%°tfx÷þÃñ#¾|à–´?˜¿eøýäÈ ìmr€bù-À!Ç),Â+dîþgc8  ÔÌÎÀ¬á¾H›0œf `Hbü,ªÀ-h>6`…òîÃW^6ö?Ÿ8˜Xìr1°³³10³@*ÙÀ`9}ìC¤‹Âõ~3`øóêÁ—__€,R@,Ÿ~üüùãû7x)'&-LUïÁ‰‡…•…á×—/ ¢ÿ?0°qAKB`©ùñû/†œ ßÙ¾3‰ ± Œß¿30}·ÿmHÆ¿ \¼¼ 7o¼f0“ãbTdø, ˜yø¾\Ùý’áï— bd@1íøñÿöÓ³gÁ®axõŠAëØQ†Ä³ ÌW÷0|{ö„AëІ˜ÃsO_‚´—¿}a¸úš‘áÃÏ_|ÿýÃ7&n†¯,B XDÞ1 3\¸ûžíÃ{cSy†ó/¤Äê9¾Þ?tZü™@,â~þ¯NÞ¾þJ¥»]Œ¹½›˜±kJó|M>1¼z½—ÁÐMžA¸‹á•³+³¯?Ã]/c†‡ÀÒXÃA[?ŒˆîË`Æÿó‡™áûó/ ù!ê ×¾22hH )Ea†Ëkýý÷êÒE ²§° uõ f^…õmµ¿]?üee6¹¸ÃcŒ´µáÑòõÐ †ß§N1\ݲ‘a߯ æ¾Ñ €Åó/QEf&P i’áéÍ' Æ\ Wß23\yø’AŒõÃ[/þ=9ô„á×Çk@#ßÁÌ )!~óË7o^;ññï½þûúìãï/Ï>üþ,O¼öå¾½c`ü ¤?¿bø÷ó ¨ÑÄŸ¡‰î#”ÄÈÁÁ!ž——»FCSÕìÙ›/XYÙå×o¾Áòüþû¿lÿÞýüüíë7ß-Sáo@/³ý|ü{ÊŒ…'îß¿³š—ßA þµè;¨GÂÿð5ãœvØÙÙ5cùùx”ÿdøðõ7XúÏŸ¿P 1÷ôé“ß?~|ÿ €@!ÀÌðë¿»!7£´ »’€«Îg~·ŸÏ^]îd¸µjã—ÿ<ÿXØ8äõµÁé“è ao¾ýeøðýÛO¿Þ|ùÄ^}ŠýøÇðîë?†§3üz`F”$ƒ´/Ð_ÿÑÈÄðáÃw†“'¿ùñãçM€baøû?ÁÛNy†›‘(‹0+ƒ ˆ¾÷ž!ówáÌWŽÈîqBì?wøõobœWv=gxùñÃÇŸÿÞ|ýËð Xvq²³0p±(/;ƒ´0ƒ 4C¡nÁY†mÎ2ÄùX0ügb—}>f¸páì ç@±H‰pçÆ¹*²üýËÄðöã'À<Ìö¬@µ**Š¢I‹—ËÉHü“áÿËÿàƒ8+ƒ®?ƒÐan& :&`3Ìeø ÝïÀÿñH ×g_€¡ÅÎÉðüý7†ïß¿ÙÜÀÜôáÊ•Kÿ<¸ è€ÇÄòû÷χï02ˆ“Ðl –âb`òÝÃÄø¹Åÿÿaøñõƒ˜0ä~-ùù‚¿ÿ&—ÿdrÀ¦î7°gçädxóú7ÃÏ?ؘ9~ræÌÉß¾}¿ tÀ[€bùøúÃ]oÕ_†¦rì o¿“ÔH•ð h8¨þôÉûßXqÇüb08éý‡b4þHúýó |<œ ¯ïÿeøöõ;°š`x÷îÃÙ³gîµÜâÄôëû×Çï¾üføøô?þ-üÏðh9P/Ãw e_€üŸÀˆfccüj˜þÈ4`¾†f P(¢RDˆ˜X ïóWpavÿÞíÿ×®]?(þÃ×/¿ùÅÀÆJÝ òâ#á Ã~ƒâ(õË?È–Cƒü4ØÁ4ÔA?|'@!ÉÏËÅðù/+Û÷_þ]xæÌ™Ooßþ~É áÊÆÀ«Â@L ïnßõþ0{0€Sô/$Á†ýúÍÀÊÆN½ q˜å ß‚} õ5Lß/¨å°¢d.(!¾xó™áûç7 —ß°rðÅnÏã4Ì\Æðë‹.@11<ØþèÑ›_ïB ƒú☿üAŠ_pÐ#%¼_°ù ‚ÿüCȃJ> Þ|øÁðäÉC†'œêìŠvÖÜÿ_Ÿ6^( ƒÎÛ{ÏÞ½ùú[AìCF¨ ƒÿƒí0þÙÀQŽÛ¿Ë@qü ê{pâû:$ËAæ1ÀÍÇ,Ÿ1\¹û˜á£ã‹× ?îí¿ Tþ €X$­Þ¿zñú°lô VƒRÈ¿ßàò˜Fž|d`–¬`9PÁ *É‚aÕ,„`Q4‚AT\ŒáÓýó ÏÞ½eøËaÌðõÞµ? ®^•ÄÂðóå×7¯Ÿ¿¡<,ÀRè|O™ÿ3Ü}ÏÆpù1#ƒ ÷g`õ *íØX€‘ ²„A¾YΫ ¢é÷?DŽà`xqé7ÃëϘ%Y>ß=ý–áß×@-áÛc†ï…ž½z[ˆ ìr&`ÂÙ{í?ÃnPaÉ*ÈÀÃñ‹A˜í;:†…‡“-¬l,@‡@\ªËþ#•àD ¤™é÷ö­7 ob`5l€¹éÉaPpT× ÃÍùÀ27íñëäE >Ùvþö+Àáef`c';Ãk Ö9 Oÿbàúø“‡ñ;°ô† '+Ð1œÀ¬ ‰‹ÐÜ*ÈnÝ~Ãðìþ'†wÿĸþ|b`ýøîïïç@ÁòÞ€baPÍúRâÙ«·ï8´øîÞýǰóüVFpd‚Ìàªä¿Au-ÐKÿ˜Ø~0ð0|&f fÿø•á#б¬ l lÀTÏÆÎÌðèÐûWŸ3äDª14LyÀðŸƒáû‹;Ÿþ{u hè;É O9P^»õôå§?@óYöžû,›þ3ðñ3-‡¶.@á JvÀþt(˜ÿƒþ/+°îgeøÁÌ qäÏï LÀ:ƒñ?°èfge¸}á C”•ÃsFv6NnF.!†o«»_ Rð;Èh€¦G ütëÉËOï_}b½óø/ËF†?¿ –‚[ÿ¡î`„d7`Ðþ78À”€["\@9.P{èó{ ö¬  ¢ W9HQN˜ ß­;vÿà– @±0¼?*;?¼}áñâÍGÑ/Ÿ€¢À„ó÷çpª§l ÅÿÑÁ ªˆþ@ªÚAÑÂM„ŒÐbäæ/o¾2(²üapsWe8úŠACŒá#°pdÛîo ï®_ªzk¢ ë£àtóð΃+gî}ÒåÖ^>üÈMÚ _3j30%ó?PtC€8LÐl nßùàÊm!Q&†Yko1¼~óžáÀ— oŸ?ÿËðdÓE†ÿ@ÑG˜ˆ‘W h Ð[ÌÂüæE[´ƒ¥ï_ÿËðãç?v`–cãbf`ÖT¬ÀÏÊÆ,Ûÿ÷XÀüdøõõÃï¯ïEú[†ß_Þüúýéå·Ÿïî}üúöÑG†>0üâßß1üz÷†áï»×@WƒJ¿c@üæ€Bm»ò›‡ˆ9Ö-”Öóàúüá7Ãß߀QŸ~ÿüÈðçó‹ß>?ùøçË3 ~õé÷ÇGoÿýžáÏ×w ¼gøûhðÏg@“€ÏŠÌoÐÄÃ?@ md+³ñÌoË&ešÇðûÇﯯ>þÿñá=Ão þ ôÅïw@ þ\ÿŒ‘,ú…„ÿÛ_ l­wPT*±$¨¤BòÅ7$_ü%Å| ÀütL¢õD…IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_font.png0000644000000000000000000000637411550446574024447 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ŽIDATxÚbüÿÿ?Ã@€bdßÍÀÀÊÆÀðçÃß¿ ÿYdÿ_e0ú½‡á?T 2ø TÃÏÏŸìââÖñüùó»gÏžÙ{âÄñ]|||—¾|ùòH30333\¾|™A]]áæÍ› ööv wîÜa—W`xýúý{÷TUUnܸÁ@,Núÿ‹á1‹1ƒæß3 ¼ÿß1üa`Aw—³³sqbb¼È¿ÿD^¾|e~çÎÝ’K—.^?|øÐ™/^ìöìÙN Ò7 ÇÄ‚]ø7Ãf/›_k8þgø %Pt±°°êèèi‚øLLL ’’ Ìfkk­Ÿ˜˜¤ôiò©S§__¾|éÔÕ«WÖ½zõê$Ð!÷ÿüùû‘Ó&€Âဿ ßXÄŽßff°—øÂÀÂɶècaa¡55¬º¸¸8ôôt@Xôë×ïÞÏž=÷¾qãÖÛ3gNÝäååß÷ë׿ÿ> Túd ®¤ÁÀÄÈðùÃ[†ç /d•Àøóç7‹¾¾¡ƒ€€Á åææƳ {zzX½|ùÚêÊ•ËÕÀ¨ºq÷îÝçÏŸÙÀÈÈx €X$Q†[·n3¨j2]Œÿ–†††Z¤¦t -ÒÒ¢@ìÄèêê¨ùñãWÍÝ»w'd'~02üþõáÓ§O@ßÿa’’6ÓÖÖâ§”«ñål&`È ò0(**ñÕÙ’€ºþ00nþñß`üRïßa`eefTVV¶*ùÎŽÿ@jþƒâòD?ƒ$±ýcøõû/Ão Yèû ÆÿBâþܹ3??~üð € Qðó0ÝiÃJ›“CKˆCîÛo†Ÿ9„&ewaàÿÏÊÎ%c¬¯í ñÅ_°7ÿþþÇðæË?†·_~3¼ûò‡áÍç¿ Þÿb¸ýòÇ>~ÿÏÀúÿC„4ƒ?Ð_ÿÁeÄׯ¿Nœ8ööû÷ï·ˆ…á?c …Žø\=AiA6i6†»ï ÿ¦ë|¸¹)ì!³å FQ·L’¼«O¾axòú+Ãûïÿ€–ügx÷èËŒ ì, œ@,ÌËΠ,Ïà ÎÇÊ &ÀÅбü,Ãöƒg"ÝMþ1²‚œÏðäÉS†óçÏÞr_eE„† +3ëÏÀÒã;ÇÀ`df¦~5Ù~s‹Ë«0pI²Ê|-ÊÀõñƒœ(ƒ®,ƒ/3ƒ'0à˜€ÏŽ„_ÀÀùþ˜Ï~1ÏÊÎtð†ß00±1ƒ£æúõkÀÒðÞ% ç@±01ýçÜu‹‰o|À™—ƒAHs#§ÜKœA(<\E„ë?ÃÿŸ_ä$øÀ16Š-üú’d@Iä€_@—ü:â0…±sr2¼~ÿ›áÇ lL ¿~ýa8sæä§ÏŸ?ß•–ÄòþÕÛ».ò¿tŒeؾýg°a ƒX€¡ÂDï߯9#Ãk LGà´ú–f¡TZ‚Ó.D?ˆ¦# ýaøþí3ÐsÞ`8{ö40Œî‚”˯_ÿ:÷ßv†¯`в¿jlð`˜ ðs!,þµ˜Bÿ:„ \§ý†À7 äexü‰áãço ÜÀòëáÃû —/¿ Ô ÄtÚ£‡o~ƒ<ÊÀÆøŸV^ƒ &r†ŸÀ ûûÿ/3++Ø÷`_B-ý ©?Ðàÿ ͽ dùo äçaøø›…á퇯Àlû—áÒ…3Ÿ^¿þxŸAÐü+¯2@11|zqïÕ‡  ÐÇß ò È’@V Ã!€ùfÙ_ˆE0‡€øßC¢ Z s™X9^¼ýÌðëë†ó¿±²¸Îa3.šÂðç‡@11ÜZõèéÛß_A f1(ø ›™ døo6vp°Â,[ p°ÿG¤~†9$ÊMÌÀœðæý7†—/ž0<äÒæT Ž‘gùyߘáûS€baÒ|uïéÛWßþÈ*‚]ÍÌÈðíÇ7†Å'»˜þq2x©Ç2ˆ HAâç°ú ¥aQð© ý F '8¸yÞyÅpãþC†·ÿ%˜Þføv{¨x@, â–_¼xûþËOEïØ€Yp÷ÕÕ ¼"/Î=¼Á r]”AY)‰áÙG†·ß ‰ dÉh[ \ôBéÿÿQÓÈ!ÿ€Ñ!,&Êðéù5†s÷Þ1üf×døõèΆ·—@ ñ@±0üùðáÕë¯Þ|ùÏÀ̃o>g¸òòCclƒè­ +Wnf‘‹aøÉ ´„-àèa„ÐàœÊq(*` õ7R¢ax{÷7ë?˜Ä8>Ü:ü‘á÷p9@, ?_1|y+üôýçŸ ¼‚ ·žÝfçbøÊø›AK^™á-ãF†µÇ¯0¨*ª3ˆpþdàãbc`çà½?5äÃW·¾|{LáÀÀÐb–døõü 0Kߟ€õÃý ¥#Ãï§'@åÀ= þ@, Ÿî½"öø50'(s0\z²›ARŸ¡ß"†4G?C}q†³G0°H1<ýÉÆÀóñ+ƒ;0.þ>axýuƒ¨Ð{†?@‡ý:æÄ… *\) F†q ?ÿAâè0ñ?òáËn`Iû“ùûW†ßOŽ\ÊÞ%)€bb²†÷‹÷¿0|þùƒáͯ« oþ|e8°m+Ãí7 õT¾}ÛÆðóÆ?̬ _™žÿæc¸ðl C¦—&ƒ°¬ÑsWĤä¢mŽ=éaxôà¨ÎFɆÓÇ0Dº(0°òofA`€?øòïë å¯@å @•SÝïŸwß½ÿýï΋C rŠ Î]bøzÇ–aÇ‘# Â’BÀ4ðŒáí£ƒ À NõŸ¿¶ÿ>2HÊ0\¸™áË#†m[ï20ë Qy6†ó—3<}û‡áà‘û fr\Àdø, ˜yä¾=8ý’áï— bä€bbøtÈï·7o=þüõÌ£½ 2âÀR™AÅä7Ã·ïŸ ’? Šú‚ ïßîdø ¬ ~ýÕ ¯?Y3„Ôg1œ?|ŠAL샊 ×??€‰ñÃgv†‹wÞ3°}øÀ`l*Ïpþƒ”8Ð÷¿8¾Þ?tZü9 €˜>¿fèw/öžÜóâ=Ók†·?>2I²2È›|eøÏù•á°ì–Ö”V'¾>ÌðX?üþª'„ÔD”’âÂM¿0¼ùú”áý¯ÏÀĬx~q1|ñ•!!PáÚWF iuEa†7·nüýõêÒE ½Oaí0€baÐÞÅÀp_å÷ÿ¯¨i¨©.ݸáé{6~†?ßž1¼´ÞÁ`#ÍÀ¯òšáý¥ \b±ÀÚñƒ²Ä†¸¨†Y·1œÙ!Í $ò‚á‹ó[pìíÝ× &v\ Wß03\yø’AŒõÃ[/þ=9ô„á×Çk@{ßÁ@, ‚ï~T4r°•b6¥_› üÌ% ìì¢ÀLþáù¹ Ï]Ÿ1²0Ü<¼–AàIÃ–Û š| ¯|`¸qè9ƒk«ÈT`ÖýÈðëûO†ßw¯üÝþò݇¿yïûË ?>óà‡w _¯ÚyÔ„9 €˜Ytx2=]VF……ȱs³1|c}ÅðüízÆÏ†À|;AÄø ›Âv1fѧ ïnnføzå “ä#U)Fþ? ¿¸·1°Ê¿a`æ;~Pó:Ó3;Ï3<:ÚÇðåÆ2†63ü|±ƒáÿ_åO -X0 †LJïÿþœ·q5Ã÷ߘ8AÉè1ßG«þ“ÞÊÄöý9ë­5¬à03'¨(¾Êðóìõ£Ç¿~eyýý…¹ˆ?ÃÇ_ož,xÿƒK…O›…é ¨1ªà.ñ%|Íx€bdfQ–ŸaÀ\â2PáÎñáçG–ŸÀ”úØ/cb‹Ÿàr÷×÷‹@ó/Ûqö ¬Œ: ?ÄŸ@Ÿ13ënFI†ß@þï—€®^*ïñ9 À²Ê­ÎíØ?GIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/file_locked.png0000644000000000000000000000315711550446574024402 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?Ã@€bAæ8::Ê(**.×Ðаr‰5„‘‘8¥þüùúôé“÷ïß»pá Ðo€b… {xx,~öìÙbÀ¿ÿÀøïß¿` 2„ÿþ Æ¿~ýãŸ?‚ñ?ÀòGŽù¯§§·h¹(%$$$ô%%%Áld‡Á¢‰1d> ƒŠŠ ›PXˆ¿ Zý!Ç`ät„̆0ä@\.P²H± L211010àTM/(ê@ºAÉ €XЀË0ÌÌζðÇÏŸ ?>~dø÷÷/ //3PþÏ·o`ò  ¾@cdff`Æáóóç^®YÃðïÚ5–?ÀYå'Pî·„¯»;ƒ¼§'Ão CðE% Î@ÖÌÄÊÊðhàÖVŽƒÔ ø½½DE€–3|úÄðãÖ-†G³g3œ[¼˜A¦¶–A¨æ×çÏXCšÀ €P€-è@>ÿ´àZFƒ*Ð@‘ØX>>`þÍÀðæ ¬ `àPVfPSRbP8}šádv6Öe{{†Ÿ@=ø¢ €¦@ÃoÖÔ0è â55e`xô”]p•H lBB ¶ÆÆ ûØ&MbRScø Œ*´D×@XÓ<ßãòÞ–- "Û·3pòð0üùþ˜àidr 2˜ ÿ-ûûáƒéë× û&Nd:‚ GZ€ÂˆxH ÿùë×µk”ß½cxïXd0Z@ŽÑ0õÿ€¡ò”Ç¡fqå$€ öîÉ“ š–– ¿€ŽÇ–g0Þ§;w8‰ëç—/ 89Xþ€ÃX¢„ÿüéåK `´?vŒAÍÚÅ×È ¬ilÐß?f`òè;v`ª;uЍJçC_ÃË’`þ}ò„á;0±â(9k.c¨Xã0|…•|ÄÖzÀÒT °BX`ýbV`ˆb‹€b— ¥Þ?` ªn¹¹‰®ã™€  €Ùõ7ÐbXQ Î4JPlââ ?… —”Ã`Y𦫋˜ÆÃ÷sç8øù€ú 2ps°nÆ„3 üjàQP`x-+Ë ´ü0=¼Ÿ<™¸ Ð×|ÀBé©€°`¦§_@K™€Qƒî€Â™@lv`ð³Sð·o¸€yü•€¡Ç ¬÷¯¯ž•Ã?`À–ÝA €ðÖ šM X¹Ü:s†AŸ,Àý$ÇÄ„×r>`¨f]viii†ßHez. &|%!¸ª&D`=p ¬L <@Y‰Œè V`<ƒ1ˆ ãÆ· ¾>ÃY Ïïë«À@†¿HÅ0¶Ú €p¦d¯Œ ƒL~>ÃE`m' ,Še€Í6v %ÿA´ÐúÏÆÆð˜nv늯:: .qq l PDÎÚX!@áLð B^ ¥º•• wvíb¸ŒN e\ "˜&¾ƒdùW`¢SHH`°12b`òÿ€‰¥qƒì€Â["ã¿À„Š/M__†ÎÎ o€¹âÓ«W ¿±‹iM …ÙdàoÁŽ- omˆÍ€¿@ß‚"!'Ç ¬ÀrÀ´òèÛ¿@Çü&¢åŒì€ÂYâjÂø@ñĤ´œ±¥€bAëá0’Ü:&ÑŒb^˜Š¾ó=;0Û:A…,D™ ì!Óç/¸ÅçÎ[ÜÞÞnà LdÈÁ„žpÐ69\êg³2У'A9¤ €QÚŒŒ@*ˆ]˜•”* àoâÛ@ü €ÐÀí2 1zII%²Ô\xÄ_ ho$¯‘D IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_red.png0000644000000000000000000000577011550446574024252 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ŠIDATxÚbüÿÿ?Ã@€bœ$~ñ þÄì@ÌÄ'LLÞÉH30ýû‡¢áïß¿ ||Innn½Ïž=¿uîÜÙݧNÜÃÍÍ}áÓ§O~þüÉÀÎÎÎ ++ËpäÈCCC†{÷î1¨¨¨0<}ú”áÁƒ@¶2ÃÍ›·ˆ—ËÄnÝbx'/ÇÀˆB@p9;;—$$Ä üû÷ÏìåËWfwïÞ-½xñÒµC‡ž}ñâù»wïmceey÷û÷o†h@„ÕÌ@üêÓ'° uÕÔÀ>Pt±°°šèëëk‚øLLL ’’ ÌfccmœœdpëÖäK—.½¹zõêé7®íÜ÷çÏŸë@ü‘‘Ã.€Â G<|øA]Ah) ØroDDDTUU±êáà`gÐÓÓa‘Ÿ?y>yòÔóöí;ŸºtôèáS¿~ýÜ •ý@¥_ÿþ…„ @1{‚‚ÿÿ¡.¥ƒg@|æ×/^^^~~~°~ýúÅnoïÐbgg+I(q±°03 ‚âšÝÚÚJÎÕÕÃRKK7JQQ)ˆM>|xÿõÙ³§ˆ…A7oÞdPTTYÎÀÌÌla`` ANj`°±1g°²2—ýüùkÔþý²²Ò’ˆ @ ˜ºÁÑ ##c¥­­Å‰SñH(‚³#v%Àd QnqqI.`”ZLâ4*þB³ä_¨8(>fNnuu !!!†ÿ3üâ¿P a–þg„X ÂÿýgøööÃ÷÷Áòþüâ¿`NŸ>ùýãÇ÷ŸÌ@ËŒØ Ùx¸¤9•ø…„tœ>~øyÿÁ£Îƒ Ù¾|ùÇÎÂ*¯kläΊ̌  Dôëõ†Ÿ>0üxóŽáÇ[ ûík†ßoÞ0üùø(þžáûóg ?Qg2qƒ°Lùÿç0™>|øÎpòäñ7?~ü¼ @,@×%XDÏPóvgádàb>†ÿ÷10'eϼôâÅw͇Oˆ‰Š†s\½Æyéê5†o¯_1üýü‰á×»· ÀÄÁÀÆÍÅÀÄÌÀ¡(Ç kiÄÀ ´€Xê±°±³,Ä`†¿ÀÈû,3~ÿdøÿóÃë ¼À¬ùúÅs†o@q.f ÊÿL W®\ú÷àÁýK@Mˆå÷ŸßÿÎc``ãdøËÍÏÀ(®,‹yþó 3¨9„3¨ñ üecbøþî$0÷ýYò”:¾Zöã;P ¯ÿþ¥þ2üÕÿÿA0ëÏß ¼lì ߀!õÈfccdøTæÌÉß¾}¿ tÀ[€byûæÝÝï6†¼:ú LÞŠ;Py L5@]Ëðó÷çïÀ‰š“âËÿÿ øßˆz ûßû? ²,÷ú#Ãï»O¾~ýÎÀÍÂÆðîÝ;†³gÏÜšvˆ ™ u„a zACøÿnA ƒmlÒr£¢¦iÚ{—^—KÙŸ€ÈoMÊAÜ$¬$¬Êz©z{ËÊ؈‰käb=s  ‘+á=¦e†Æ€|r?câ7¯nuÍþæ€|ˆéËï¾>yŒBV £0(oŠIe`0ÿúš” >Øb0þ¶ ì ñ¡–ÓÃÿo?þ?}Ëð÷×n>`Tü`øÌ1¿¡röì©O_Þ¾}iŒt) j€bzÄÀpÿÛËW ¬Àùèë߀Ùå7„ ´ø70¾Ù€…# 0:þþ†DÈAêþ‚ùÿ@l¨ÏÿùÆðï!Ð<`œƒb èk.`è}xþœáÝ÷ ,gNp¬b`È‹d`XöA €˜N00<úòäñ{` ÁÀ²ôßoFP<ƒ0ÿèz6`Ýó5$€A I@ú83|Züô5ÿÀÜÌ $ñ˜`™þ11psq0|–Ož<`Ðv›Ý_œ‡˜ß>00(‹"0%¾yø>ßAŽøÊR PŸ«Qp>g`Z*Å€Ùé(«}ûÎð˜^þ}Êðhá/P(üƒ&Äÿ`Ëÿ£$/(ÀÏðòã†çWÎ3h¼{ÍðàÛ†£ ·î@,z ï_>{öŽáëgp ûÏ¿@ŽÖj ÀÄÉpó9PåG† ü ŠsP¢gdîÿ™˜þÎjœ†€ôï/ßÄ%¥.õ~?}›ARg~üùó€á ¨ `0|}ùäÅó_ïÞ‹I6höºœ•™íæm†¯g.2|fç``b6`6dbegøj01Ã) Èð—R/üƒfOp®zZÂÀúãÏÝ‹ÀŒwñç†cþ¾Úr¨ü=@±¼’B>?ûÌŠ¢À¨ÿöõïí{þïÚË,šþðò0üäáaøl°ðð2°rs30s1ÐQÿYÙA!r(‹‚s,þÎÎpïÔY†WgN2È|ÿÂðû×_†ÓÿÁeÀ}P]@,[€d0(¾½~Í %.QlÚÊðgÓvV`c„X”²K=`•ÌðíÃ/–× ?98¾€&³pp20óò1°pr10±q0ücf…4n€–³±°2Ü¿s›áó¡C ¢ÀÒXÏ>ýýÿïUHðƒê‚ÿÄ $  ·À FŠ‹‹á÷™Ó ß·îd`fË¿ ªhÐ`ýÊ ŒkP ™ d00kò+¡ß@ýcüL᯾2³Õ0 t8?ÐQü Ÿ‰ôþ™ 6™é 'OaàyõŠhù'`´ßZû…Ä"$€ñqëý“'Àº’‰åûŽ= ¾|a`7#0:þ"·&@q ÃÀŠäP"äE°qlu2|–¨?ž<§™ ÀÖ”†—/0Jx€Ñô(Ãj`•÷R ~ @,¯ [žÓÃ{ %/­Š§¿|ñˆüüôôû·ïþý¬TÞò{`%þò¤KJZ@{¾A ÿ€Ä8FãY‹!Ö›+ïËÿÿ¯~þüøñï¿÷ŸÁ…0Ø/ÿC\ÿŒ‘,ú…„ÿÛ_ l­wPä“.ƒ$´ã óÅ7$_ü%Å| ÀÒð‹Ñ}åZçIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_blue.png0000644000000000000000000000563411550446574024426 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< .IDATxÚbüÿÿ?Ã@€bdˆ9ÈÀð÷Ãïß@ú/ 7?ƒÉûÅ 2ÿï2üc`FÑð¨†O ÉÍÍ­÷Ù³ç·Î;»ûÔ©“{¸¹¹/|úô郀€ÃÏŸ?ØÙÙdeeŽ9Â`hhÈpïÞ=†§OŸ2ÿdøðõ7XúÏŸ¿P 1÷ôé“ß?~|ÿ €@!ÀÌðë¿»!7£´ »’€«Îg~·ŸÏ^]îd¸µjã—ÿ<ÿXØ8äõµÁé“è ao¾ýeøðýÛO¿Þ|ùÄ^}ŠýøÇðîë?†§3üz`F”$ƒ´/Ð_ÿÑÈÄðáÃw†“'¿ùñãçM€baøû?ÁÛNy†›‘(‹0+ƒ ˆ¾÷ž!ówáÌWŽÈîqBì?wøõobœWv=gxùñÃÇŸÿÞ|ýËð Xvq²³0p±(/;ƒ´0ƒ 4C¡nÁY†mÎ2ÄùX0ügb—}>f¸páì ç@±H‰pçÆ¹*²üýËÄðöã'À<Ìö¬@µ**Š¢I‹—ËÉHü“áÿËÿàƒ8+ƒ®?ƒÐan& :&`3Ìeø ÝïÀÿñH ×g_€¡ÅÎÉðüý7†ïß¿ÙÜÀÜôáÊ•Kÿ<¸ è€ÇÄòû÷χï02ˆ“Ðl –âb`òÝÃÄø¹Åÿÿaøñõƒ˜0ä~-ùù‚¿ÿ&—ÿdrÀ¦î7°gçädxóú7ÃÏ?ؘ9~ræÌÉß¾}¿ tÀ[€bùøúÃ]oÕ_†¦rì o¿“ÔH•ð h8¨þôÉûßXqÇüb08éý‡b4þHúýó |<œ ¯ïÿeøöõ;°š`x÷îÃÙ³gîµÜâÄôëû×Çï¾üføøô?þ-üÏðh9P/Ãw e_€üŸÀˆfccüj˜þÈ4`¾†f P(¢RDˆ˜X ïóWpavÿÞíÿ×®]?(þÃ×/¿ùÅÀÆJÝ òâ#á Ã~ƒâ(õË?È–Cƒü4ØÁ4ÔA?|'@!ÉÏËÅðù/+Û÷_þ]xæÌ™Ooßþ~É áÊÆÀ«Â@L ïnßõþ0{0€Sô/$Á†ýúÍÀÊÆN½ q˜å ß‚} õ5Lß/¨å°¢d.(!¾xó™áûç7 —ß°rðÅnÏã4Ì\Æðë‹.@11<ØþèÑ›_ïB ƒú☿üAŠ_pÐ#%¼_°ù ‚ÿüCȃJ> Þ|øÁðäÉC†'œêìŠvÖÜÿ_Ÿ6^( ƒÎÛ{ÏÞ½ùú[AìCF¨ ƒÿƒí0þÙÀQŽÛ¿Ë@qü ê{pâû:$ËAæ1ÀÍÇ,Ÿ1\¹û˜á£ã‹× ?îí¿ Tþ €X$­Þ¿zñú°lô VƒRÈ¿ßàò˜Fž|d`–¬`9PÁ *É‚aÕ,„`Q4‚AT\ŒáÓýó ÏÞ½eøËaÌðõÞµ? ®^•ÄÂðóå×7¯Ÿ¿¡<,ÀRè|O™ÿ3Ü}ÏÆpù1#ƒ ÷g`õ *íØX€‘ ²„A¾YΫ ¢é÷?DŽà`xqé7ÃëϘ%Y>ß=ý–áß×@-áÛc†ï…ž½z[ˆ ìr&`ÂÙ{í?ÃnPaÉ*ÈÀÃñ‹A˜í;:†…‡“-¬l,@‡@\ªËþ#•àD ¤™é÷ö­7 ob`5l€¹éÉaPpT× ÃÍùÀ27íñëäE >Ùvþö+Àáef`c';Ãk Ö9 Oÿbàúø“‡ñ;°ô† '+Ð1œÀ¬ ‰‹ÐÜ*ÈnÝ~Ãðìþ'†wÿĸþ|b`ýøîïïç@ÁòÞ€baPÍúRâÙ«·ï8´øîÞýǰóüVFpd‚Ìàªä¿Au-ÐKÿ˜Ø~0ð0|&f fÿø•á#б¬ l lÀTÏÆÎÌðèÐûWŸ3äDª14LyÀðŸƒáû‹;Ÿþ{u hè;É O9P^»õôå§?@óYöžû,›þ3ðñ3-‡¶.@á JvÀþt(˜ÿƒþ/+°îgeøÁÌ qäÏï LÀ:ƒñ?°èfge¸}á C”•ÃsFv6NnF.!†o«»_ Rð;Èh€¦G ütëÉËOï_}b½óø/ËF†?¿ –‚[ÿ¡î`„d7`Ðþ78À”€["\@9.P{èó{ ö¬  ¢ W9HQN˜ ß­;vÿà– @±0¼?*;?¼}áñâÍGÑ/Ÿ€¢À„ó÷çpª§l ÅÿÑÁ ªˆþ@ªÚAÑÂM„ŒÐbäæ/o¾2(²üapsWe8úŠACŒá#°pdÛîo ï®_ªzk¢ ë£àtóð΃+gî}ÒåÖ^>üÈMÚ _3j30%ó?PtC€8LÐl nßùàÊm!Q&†Yko1¼~óžáÀ— oŸ?ÿËðdÓE†ÿ@ÑG˜ˆ‘W h Ð[ÌÂüæE[´ƒ¥ï_ÿËðãç?v`–cãbf`ÖT¬ÀÏÊÆ,Ûÿ÷XÀüdøõõÃï¯ïEú[†ß_Þüúýéå·Ÿïî}üúöÑG†>0üâßß1üz÷†áï»×@WƒJ¿c@üæ€Bm»ò›‡ˆ9Ö-”Öóàúüá7Ãß߀QŸ~ÿüÈðçó‹ß>?ùøçË3 ~õé÷ÇGoÿýžáÏ×w ¼gøûhðÏg@“€ÏŠÌoÐÄÃ?@ md+³ñÌoË&ešÇðûÇﯯ>þÿñá=Ão þ ôÅïw@ þ\ÿŒ‘,ú…„ÿÛ_ l­wPT*±$¨¤BòÅ7$_ü%Å| ÀütL¢õD…IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/network.png0000644000000000000000000000542611550446574023634 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe< ¨IDATxÚbüÿÿ?Ã@€bDwcàãÿ?†ß?€¬ ?10°é/ß$þ3¸³°³8 p q˰²2³~ÿöóÇ›¾{ûþó£>žÙËðÿÃ+†¯pZ ³ €ˆsÀ×ïB ŒÌÅÊ*Â>6²JŽz‚ Êbì <\¬ ÜlL ¯>ýeøñë7ù{ßöŸ{ϰgß•›¯Ïo›ÏðbÑ4†?>ãs@vÀ/G11Þ)i!ZZQvb *ÂŒ ,@é›/ÿ1ð°32p120120pô ¶Sÿ3ÌÚøˆaëŠç¿\[PÄðùÄ\ üøü5J_Wzf~´>£*;ÐA@Ÿþ©gd‘\@°-efÑÆÌÄÀÀxôƒ‘aÅá Kçîód{Ã×Sk±9 €X0SÄ´Ÿ<ÍÍçFújrÈ 03Ä9‰lýókæ“ýõ¿~ÞØŒn@1a8€ (ôó·„¢ÿ$G[eŽÿß2¼ûð‹á/#ƒ 0ιYXñþèÕ¿@›ÞûËðîˆ÷Püñû†_ÿ1¼¦ Î â<lí…ù4b[¹´Ñ­ LüýÃÀÂÎZni*£rôÔU– ²’œ ü@Ëÿ-ùú+0S|ûÃÀðêÝo†O_þ2üùÏÄðõç`ô02|ÿõáÝÇ_ o?ýføñ“…Aœá;ã·Olƒƒuó€6ð"[@˜Qðý§Š®®Lèï?Ÿž¾zÉðŽYá+Ð`ÖÐxf„ó‡çß>}øÎÀ 3330Ýþ¦f†ÿÿ2<}žaÉž o>|aˆ aÖõözp×2`„Y@˜`gw•—b—¾û&ƒ½ƒ-Ãû¿œ gŸ10Hð00ðÓ!0q>½ù’áïO £X˜!ñtп¿iô7ÃÇ/Ÿî=ÊpâÒE†·nC3PþþÍ3 ZæfâOOiº3|¿p¨ëH+@a8€ŸƒÁ„_áúÍoÀt ^ }ý˜›?ƒž›•‰áÀ¥Ë W/ݦ ~ ïÞgü 8`ZùôáÅëW ß¾ef`ãæb`ãäføòüÃÓ»w,l ùUB +B0†x¸9T|ÿÄððú†W.3H*(3蛚2›ê3üºä7ÐËÆV 7Ÿ>g¸úð1°€dexõò%8$ •˜8Y¹ø˜™•€$ƒœ¦>³Þw†o^0°°üa`åùýŽA¨ü È>€Âp+'߇WÏA,V6†g2¼|ò”áï?F]}`"c`à`åaˆŒcø÷÷çO_fN™ÉðóÇOHh(þ¿}ùΠkåÀÀ/ÀÏÀ ̳b¢Â bâÀ•‰‰Ñ0ûÃüúÎÁÁÍÀÆô æZô—aÿÖ Lì| *šŠ _¾Ç J|ÌÀÒˆŸAJ^…áÁí;ÀÜÃÎð¨ö߯_ ¦® – ï=cxóø>ƒ¥¹.ÿïÌ ¿@õ ¤´€ÂpÀ÷oßró[ppòƒ’È~üþΠfdÌÀ'­Àðú0Å3AJ?pˆýÂÎ+Œ N6v†@eUåt µþ|úÆðæÙ3 Uq†3Çcþ(îÿÂì ŒràÍÛWY¸„„E˜X9€p1¨hk1˜™0p‹^½¿€Ú¿ÿ†”„_2œ,;'/Ã`èŠHÊ2[™1ˆñ³2q33ܸzaþü- §O^gxúè-0> 4â+Ì>€Â,ˆ®­9ððÅÏo:ZJÀŽ…ÁÄD!,Â…AJ„‡è;AN …@_óq€s /ƒ†¦ƒ°„ ƒ°˜ƒµ½ ƒŠ¼ïÏߘÿý¦!v.^i a†K§/ýdøqó&Ж0ë³xæôÙ³&EØ{*Êf°4Uaz„h'å‚?ÿ•¤beðô¶f`ÑB@×1å^¿ÿÈ &/ÈaÅðç׆7¿0Ü?½X0üº²¦ €0kCPM"éngšÐµÓNO”ã?0ké‰3|ÖÌÀbá÷?P*‡`Xjiae¤ fgÑÿÀe†˜ 0¿½øÅ™6ýë‡S5ó€ö –{0{ˆksåù®C§·êõÉHæVZ‹ƒœhñ¨ï±9\ƒ´h/°<âF6Ðá-û>œŸ~ hùN r”f@ap¸S•^Ù¬ „¤ˆì@Y6 ×>ý€Hý:Ô,Ñ`å 1È7ÀÒÀ”áÉë 5‡ί(;ÁðíôL ôXüÃì Ü'QQŘfß´”Ò#fMYf†»Oÿ‹èàv0þº„•Ô>`¶€é„J;`˜8yÛŸg:3ü¸´hÚ& ~Þ  ü 0q1ðÄpÆY;¹ª+)Jƒ›ƒáÓ7F`‹ˆ ˜SþŸƒ²Ä?†ç/?1lÞq™áìö¥þ=Z¿Ÿáÿ[P#ä¿ÅÖ" prr¢ð+ `±Ç¡ÇÀ¥Ä­êà*¬b¦Å+,ËÇÉÉ ,þ™~ýøÅðáý‡ŸŸ^ûôñöчŸ»Êðÿ0Îÿq T–áj†RRRGL ÇŽcøúõ+ÃÓ§O~ÿþ *Ã%XAËÈ1;%#?äË×ÿ W.Ÿú¿{óÒ}ï_?ó ¾ÄÏ€ÕW999†Gôbu@aä‚ ”…¤ÈÈÈì!?YXXÜ{ðà Ï/CO#©_Àvã‹“Œÿ}¾Ô²TIIé­””ØB666iii†×¯_c8¯€@ aœœ\ÜŠŠJÿ@é㰘ё“ú‘%}Ì_åy507°1di Túd ®¤ÁÀÄÈðùÃ[†ç /d•Àøóç7‹¾¾¡ƒ€€Á åææƳ {zzX½|ùÚêÊ•ËÕÀ¨ºq÷îÝçÏŸÙÀÈÈx €X$Q†[·n3¨j2]Œÿ–†††Z¤¦t -ÒÒ¢@ìÄèêê¨ùñãWÍÝ»w'd'~02üþõáÓ§O@ßÿa’’6ÓÖÖâ§”«ñål&`È ò0(**ñÕÙ’€ºþ00nþñß`üRïßa`eefTVV¶*ùÎŽÿ@jþƒâòD?ƒ$±ýcøõû/Ão Yèû ÆÿBâþܹ3??~üð € Qðó0ÝiÃJ›“CKˆCîÛo†Ÿ9„&ewaàÿÏÊÎ%c¬¯í ñÅ_°7ÿþþÇðæË?†·_~3¼ûò‡áÍç¿ Þÿb¸ýòÇ>~ÿÏÀúÿC„4ƒ?Ð_ÿÁeÄׯ¿Nœ8ööû÷ï·ˆ…á?c …Žø\=AiA6i6†»ï ÿ¦ë|¸¹)ì!³å FQ·L’¼«O¾axòú+Ãûïÿ€–ügx÷èËŒ ì, œ@,ÌËΠ,Ïà ÎÇÊ &ÀÅбü,Ãöƒg"ÝMþ1²‚œÏðäÉS†óçÏÞr_eE„† +3ëÏÀÒã;ÇÀ`df¦~5Ù~s‹Ë«0pI²Ê|-ÊÀõñƒœ(ƒ®,ƒ/3ƒ'0à˜€ÏŽ„_ÀÀùþ˜Ï~1ÏÊÎtð†ß00±1ƒ£æúõkÀÒðÞ% ç@±01ýçÜu‹‰o|À™—ƒAHs#§ÜKœA(<\E„ë?ÃÿŸ_ä$øÀ16Š-üú’d@Iä€_@—ü:â0…±sr2¼~ÿ›áÇ lL ¿~ýa8sæä§ÏŸ?ß•–ÄòþÕÛ».ò¿tŒeؾýg°a ƒX€¡ÂDï߯9#Ãk LGà´ú–f¡TZ‚Ó.D?ˆ¦# ýaøþí3ÐsÞ`8{ö40Œî‚”˯_ÿ:÷ßv†¯`в¿jlð`˜ ðs!,þµ˜Bÿ:„ \§ý†À7 äexü‰áãço ÜÀòëáÃû —/¿ Ô ÄtÚ£‡o~ƒ<ÊÀÆøŸV^ƒ &r†ŸÀ ûûÿ/3++Ø÷`_B-ý ©?Ðàÿ ͽ dùo äçaøø›…á퇯Àlû—áÒ…3Ÿ^¿þxŸAÐü+¯2@11|zqïÕ‡  ÐÇß ò È’@V Ã!€ùfÙ_ˆE0‡€øßC¢ Z s™X9^¼ýÌðëë†ó¿±²¸Îa3.šÂðç‡@11ÜZõèéÛß_A fño A4ˆÿX³²±ƒƒf1Ø"h€ƒý?"õƒ0Ìñ yPnbæ„7ï¿1¼|ñ„á!—6§jpŒ<ËÏûÆ ßŸêƒ æ«{Oß½úŠ;`~þŒÿßÿ!ü6¿ØØÙ FDÔ€|ùù'0Q³íG þÌ  4ôóDþ4d@¡ÀÁÍÃðXXݸÿáí~†¿ï?3|»½ T¼ fIË×÷¾|ùæË_Å@¿ ©ù0È¿ÿüÅÀä|zïý·ÿÀÂhñ_ˆáœ\, L@“¼øýÿ5}€Ìùt¨°˜(çç×ÎÝ{Çð›]“á×£;ÿÞ^%ÄGÄâ#ÊfÎÅ÷SåäöË €a÷ë7(ÿ‡30þA çû?†@üû©mþ“þg ÷L xù Õ"kÂ$,Q ‹0¼½û›áÕÇŸ Lbœ nþÈðû ¸ .ÖÀš4CE åÿ 5¼:c„ÖnÐrˆ˜€eù_`û± h/Ãí«O ø~GXʾÿ`‰ó(£é°~¸ÿ‘á/°´cd`cøýô¨¸ÄßØÂšÉÆÊðXØHI + ü5ô›7Àòšéƒ„¬ ÕwŸÞ|ø t  3$ÿ‚+Shy”`xL|Ç0Ü¿ÿ†ADTX#23<þ¬ù¾1Ü}ü’áá³7 /€–}–@?þBBâ70XN{Àé¢ÀÀ* Åð›Yáç«_þ}}²üÈÁÄ)Ùþ–‚ ߀eçÑ#· •¾g†7.€‰ج~ÍðúÕ;kH{ð0|gàfxÏÄäñ20~ÿÎÀôXÜþ¶!ÿ2pñò2ܼñšÁLŽ‹ARMá?°,`æágøre÷K†¿_n€Ša9Ä;`Ð)+‹1 q2>x˜ªÿCîßyÉpãæ3Ss%`2`†8œ÷ÿË `DþcbøÆÄÍð•Eˆá‹Ã;fa† wß3°}xÏ`l*Ïpþƒ”8Ð÷¿8¾Þ?tZü™@àÿóÄÀ–ƒ®Ž,ÐÜ [6v@þ3ܹ ¬»/<`prÒ†+0” Ù TÛ,ÿÁ?~Bi`øé3Ã÷ç_Ô®}edÐf`PWfxsëÆß_¯.]Zù–¦Ü"ú Ô ¬-ÁŽVZ ††Š _¿üe˜6y7Ø1Q1&Àbeø `µ. ÀŽø nÅÓ› Oo>a0–àb¸ú–™áÊ× b¬ßîÜzÁðïÉ¡' ¿>^êxs@±€òðW ¯8¾€J>ˆàׯ :z* ìÁ ++Êðë'°¦ü¯¨@4¨¼`&wV`£ñ0¥~ûò‘áÏ×÷ ¿>¿ùÿîî­_;¾¿ýúïÓ“ ß_~døñ˜?¼cøzí Pû Ÿa  iLÀÆ Ã·ï¢Ö…„¢Š8z>…ö¡`û J„L /Íûþüï·¿?=ýøûã“÷ ?ÞûrßÞ10þÒŸ_1üûù”sø34Ñ}„òá €Xþýgúyû0=s3CRJºÿЄù\ò‚fç`cxpÿ=Ãßûs¶~cø´hÎ3¨% üÔ2CÂÿð•+Ä(*ª©ÅÆÊ´OþÔâÿ` ÿð’UŒ‘ñÇO¿þý»¿ (² j1Y À˜Y·Ô¬ŸˆIEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/lockoverlay.png0000644000000000000000000000164411550446574024473 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<6IDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €Ü4à w@ ¸hÀ@î€pЀ; €Ü4à w@ ¸hÀ@,Ô2(›‘Lÿp•€¼P>v…¿ÿþüôÿÿõ; ÛŽ10lúÌÀ𦠀X¨éPãî7C¤"+k«“™™¢‚µ5§„ߟ?Þ_¹b|úàÁ‰'Ovìb`({ÎÀp¤ €¨æ€¿@üƒ!ÂDDdAtP› ¹9\^LNŽAMOAuÃæS§$×üýÿ‰á"@QÍÀ WTäàè‰×ÑaãElj ÿþ10@£YXÌ•”>?®ÿÁƒÆƒ éD5ügdŒp‘’’f9{–áñ LÌÌ ÌÀ`Ò ‡üûý›á/0*ؘ˜Lddì\Ïøà@Ts€ 7·ô W|ÏÍeàâæfø X³Œ¬¬ ïfÐ<}šAOB‚‹ýÃC€¢š8YXäÿ|ûÆðCX˜ÁdÒ$Nê.MÊðúÐ!n ›A €¨—¿ÿåãc`ùû÷ùù¾‡ ãû÷ Ìœœ €ÑL¸ÌD5¼ýöíúo}}¡gÏîÇÇ3°°³C¢Íž>eÐ×g8þáÃO†oD5Üøùsû•÷ïc=´µØnÜ`øò-( ¥þ0ðCæ½”Ãáóçß ¤{D5œa`غùÚµ* îZ66 ß^¾— °lÈ ..†_À4²edž?žùÔ@ŒÔ꜂|+ÊÀ ãÉÆ¶8ÁÝÝÀXK‹äë_¿9ã?ÃS`°¯ß³‡aþ­[ç¯10Ìj[ @TuS·¾1C£“œœ³ž– 0Áýúû—áþ«Wà`?ôóçéÇ J·ñ#€¢º @X¹±30²³0)2ƒû0ÎïÿÇà ~ R`дì ø%IEND®B`‚jets3t-0.8.1+dfsg.orig/resources/images/nuvola/32x32/filesystems/folder_blue_open.png0000644000000000000000000000437411550446574025447 0ustar ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ŽIDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €"v10ücÑføûÏ”ù¿';“Œ?§Ò×?,ŒïŽÎœÅpyîZí˜? †¹ __10üêâàd``gg`øþ…áçv†ÿ9…Ø9d˜þÈ3²0Ëó°ÍäVþÃÆ«öøÀÌ:†SæuþBw@±0ügJr1“™äk$ÂÍÏÃÊÀÃÉÌÀÇÉÆðö;C9›Ñ£Ë+>3üþ½“á÷_†ßÿ5þ3¨1üù+ÍÀüOŠ‹ŸWF”_TLJCHA„SDZ”STˆƒ‡ h+ƒ Ãá‡ú÷3„óÚ^ }wÐ@,Ò‚¥ùþ*ÜÌLŒ Ï>20<üôèkyÏ‹§JÉJ~“’—‘á—dcáccæagàçegà:˜hІŸÀÐùü‚¿ýúê0þ°0°òŠÉ¹¢(`êùÇ@,ÿþÿeÝyƒ‘‡™A² â|ÀPªã.ÈÀ  ÄÍÈÀ”%˜A†i ‰ß30|ø´ø30fþ10üâ?@ùß@ü Ê*a`–*BD<3“nÃÿkˆåÓ«··|Õ)눳1|ù‘ÿÔøh  ØÖï@ñ ÿúôÿ lF¨¹ " ”Dþ0@ÄA!ñ(É-(É÷…]Xžáç[°4¯ #¿&Ãÿ¿ßˆåÛׯ¿~ûôÃçÿ€1Áðh$È@âß?ˆa ô?¨åpGüƒ8 ,ÿ ü @o³=ÀÃ'Àú’]Hè6n…?ŒZÅ@¿ÁŽ ¦ÿß¿>¾ñòX!3€±è74ýC Rþ‹$÷!þJƒ|r3ؼŒ ¬< ŒÜÿTKþÿaäýûû‡$Ð 6€baøôúÞ£W?Àÿ†úì7°~ø …¨Aþæ[$>,4`Ž9æë/H‚< !>~^fe?N}±™¬b:‚lÜ’ÿ³Š¾½ÊX@, 7ßò*øûÏ œ¿šþÂÂr"øaQð*÷ï"áÁ,þñ‚"§`Hsss0zëH+Ië0sp1° 0~yý ¤ò?Pã°X˜ÿ3<øÀÈpð!ãO¬ÆÅÆÀÀ ,@eÂfDiöœšGÛ_ˆ'~²3+ °”fgøõù%ŸÃ—·Oþ½ºx¨ô@±0|¸ÆðûÁ»/¿„¹ØÁ‰‡hɾ›ÿöÜùÇðèrn`A,]Á¡^hžG.˜ ÕÚ?hùŠ.P(üJ~~÷áí“÷ÀRóØïO¯føzçPù+€ba¸³Hs^ôö¸x•®þcX}˜*¹€% ׆ÿ¿~2A,c&¨/4¨¬bêaü‹(ŒÀû IC¿€Œ{0ðó3üøòX0q2üzr® ×€ø@11hÃTþÁýgo€QÅpïÅ?† §þ00m`ò˜ŠþÆ ýó7"¥ƒ1ÿí7¤H†ch ’…ÔÕ3÷b¬EŒ e¾ º?@‰ßJÝÅ@±0pHUþ~òìÅÇßÌÀzcÿ¥? ?þgàçg[/gŒÿ@¯ý–­ÿ€ñÏò’𘠥58`AŽ gÜ|Á`È÷‹AVC”aÿ£g \BÀÒøÃ«ï¿ßß¿ ~r€baøû”b½|þöë»Ï W€ñ.°¾þ‰] ý´Ì tú Ø|Ê³Ì eŒ œN€üøö+ïûW ¡‘š '€µ«š,+ÃÍk ﯭzÆðûýePðƒ@, ¯€JŽ÷_½yýžAà˧ÿ ÌÀñïO¨‘ÿ€í&pêú²è=˜€–üÕÀDªp@!²Dÿ:þÓÍÇ %þ ×±2ðÍ–æa`üòá˽  ¿ kœ Ã˃à ðÞ€Óû®}PáåçaøðîÐ &pû´ü/ÐRï™YAî²ÿC…è˜ÿŠ%̬ÊÏï>eøÿñÆ£ÿî=½ÂÀòëÃïÏÿ¾¿}üÃÛ3Ç€JžÁ" €€•°òÿL5,âZü6ÍÛu\#äîßøËðíë_v6`ƒƒ™‰X°²1*ºòÿŸ_ ?¿~bøýõ=ï¯ïþÿùúîÏïO/¾ÿúðèó·w>üýúöÃþ]òóÝ[†?ï€ñë9ÐÎ3ÐÊ$ ĈÒ>â7ö¶©Y"gäÅt00Þ3ü¡}bøóý#Ãï/¯~þùüèÓŸ//€¼úôûÓ“÷ÿ¿½|Çðçë[† …߀–üYòˆí+`ÆgøŽ„A-ŽßÈV#F3•× ŒUÒ¬áï®?__þÿóÃ;†ß߃}ñû=Ð࿯ )ø#4!ðWhœ‚ ÿ -‰ĈCLˆ¥ †~CÂ? ø/)–àÄ8Ð}C€ðŽ @ ¸hÀ`kåü–ixëIEND®B`‚jets3t-0.8.1+dfsg.orig/LICENSE-2.0.txt0000644000000000000000000002645011550446652013637 0ustar Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. jets3t-0.8.1+dfsg.orig/NOTICE.txt0000644000000000000000000000115211550446652013231 0ustar ========================================================================= == NOTICE file corresponding to section 4(d) of the Apache License, == == Version 2.0, in this case for the distribution of jets3t. == ========================================================================= This product includes software developed by: The Apache Software Foundation (http://www.apache.org/). The ExoLab Project (http://www.exolab.org/) Sun Microsystems (http://www.sun.com/) Codehaus (http://castor.codehaus.org) Safehaus (http://jug.safehaus.org/Home)jets3t-0.8.1+dfsg.orig/applets/0002755000000000000000000000000011550446622013157 5ustar jets3t-0.8.1+dfsg.orig/src/0002755000000000000000000000000011463710656012302 5ustar jets3t-0.8.1+dfsg.orig/src/contribs/0002755000000000000000000000000011336150666014123 5ustar jets3t-0.8.1+dfsg.orig/src/contribs/mx/0002755000000000000000000000000011441613550014540 5ustar jets3t-0.8.1+dfsg.orig/src/contribs/mx/S3BucketMx.java0000644000000000000000000001003111441613550017324 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2009 Doug MacEachern * Copyright 2009 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package contribs.mx; import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.management.ObjectName; import org.jets3t.service.model.StorageBucket; public class S3BucketMx implements S3BucketMxMBean { public static final boolean isEnabled = "true".equals(System.getProperty("jets3t.bucket.mx")); private static Map objects = Collections.synchronizedMap(new HashMap()); private static final int TOTAL = 0, O_GET = 1, O_HEAD = 2, O_PUT = 3, O_DELETE = 4, O_COPY = 5, LIST = 6, MAX = 7; private final LongCounter[] counters = new LongCounter[MAX]; S3BucketMx() { for (int i=0; i minTaskValue) { progressBar.setStringPainted(true); progressBar.setMinimum(minTaskValue); progressBar.setMaximum(maxTaskValue); progressBar.setValue(minTaskValue); progressBar.setIndeterminate(false); } else { progressBar.setStringPainted(false); progressBar.setMinimum(0); progressBar.setMaximum(0); progressBar.setValue(0); progressBar.setIndeterminate(true); } statusMessageLabel.setText(statusMessage); if (detailsText == null) { detailsTextLabel.setText(""); } else { detailsTextLabel.setText(detailsText); } if (this.cancelEventTrigger != null) { cancelButton.setText(cancelButtonText); cancelButton.setEnabled(true); cancelButton.setVisible(true); } else { cancelButton.setVisible(false); // cancelButton.setText("Cannot Cancel"); // cancelButton.setEnabled(false); } this.setVisible(true); } public void stopDialog() { progressBar.setIndeterminate(false); progressBar.setValue(progressBar.getMaximum()); this.setVisible(false); } /** * Updates the dialog's information. * * @param statusMessage * text describing the status of a task text meaningful to the user, such as "3 files of 7 uploaded" * @param detailsText * detailed description of the task's status, such as the current transfer rate and remaining time. * @param progressValue * value representing how far through the task we are, somewhere between * minTaskValue and maxTaskValue as set in the constructor. */ public void updateDialog(String statusMessage, String detailsText, int progressValue) { statusMessageLabel.setText(statusMessage); detailsTextLabel.setText(detailsText); if (!progressBar.isIndeterminate()) { progressBar.setValue(progressValue); } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/ErrorDialog.java0000644000000000000000000002736111441613550020143 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2007 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Properties; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.LookAndFeel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.gui.skins.SkinsFactory; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.S3ServiceException; /** * An Error dialog that displays information about an error that has occurred. * * @author James Murty */ public class ErrorDialog extends JDialog implements ActionListener { private static final long serialVersionUID = 6538639968961532471L; private static final Log log = LogFactory.getLog(ErrorDialog.class); private Jets3tProperties jets3tProperties = Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME); private Properties applicationProperties = null; private HyperlinkActivatedListener hyperlinkListener = null; private SkinsFactory skinsFactory = null; private final Insets insetsDefault = new Insets(3, 5, 3, 5); private ErrorDialog(Frame ownerFrame, HyperlinkActivatedListener hyperlinkListener, Properties applicationProperties) { super(ownerFrame, "Error Message", true); this.hyperlinkListener = hyperlinkListener; this.applicationProperties = applicationProperties; } private ErrorDialog(JDialog ownerDialog, HyperlinkActivatedListener hyperlinkListener, Properties applicationProperties) { super(ownerDialog, "Error Message", true); this.hyperlinkListener = hyperlinkListener; this.applicationProperties = applicationProperties; } /** * Initialises all GUI elements. */ private void initGui(String message, String details) { // Initialise skins factory. skinsFactory = SkinsFactory.getInstance(applicationProperties); // Set Skinned Look and Feel. LookAndFeel lookAndFeel = skinsFactory.createSkinnedMetalTheme("SkinnedLookAndFeel"); try { UIManager.setLookAndFeel(lookAndFeel); } catch (UnsupportedLookAndFeelException e) { log.error("Unable to set skinned LookAndFeel", e); } this.setResizable(false); this.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE); JHtmlLabel messageLabel = skinsFactory .createSkinnedJHtmlLabel("ErrorMessageLabel", hyperlinkListener); messageLabel.setText(message); messageLabel.setHorizontalAlignment(JLabel.CENTER); JHtmlLabel detailsLabel = skinsFactory .createSkinnedJHtmlLabel("ErrorDetailsLabel", hyperlinkListener); detailsLabel.setText(details); JButton okButton = skinsFactory.createSkinnedJButton("ErrorOkButton"); okButton.setName("OK"); okButton.setText("OK"); okButton.addActionListener(this); this.getRootPane().setDefaultButton(okButton); JPanel dialogPanel = skinsFactory.createSkinnedJPanel("ErrorDialogPanel"); int row = 0; dialogPanel.setLayout(new GridBagLayout()); dialogPanel.add(messageLabel, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(12, 5, 12, 5), 0, 0)); dialogPanel.add(detailsLabel, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); dialogPanel.add(okButton, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsDefault, 0, 0)); this.getContentPane().add(dialogPanel); this.pack(); this.setLocationRelativeTo(this.getOwner()); } public void actionPerformed(ActionEvent e) { if ("OK".equals(e.getActionCommand())) { this.setVisible(false); } } private String buildDetailedText(Throwable throwable) { if (!jets3tProperties.getBoolProperty("gui.verboseErrorDialog", true)) { return null; } StringBuffer detailsText = new StringBuffer(); if (throwable instanceof S3ServiceException) { detailsText.append(""); S3ServiceException s3se = (S3ServiceException) throwable; if (s3se.getS3ErrorCode() != null) { detailsText.append(""); } else { detailsText.append(""); } if (s3se.getS3ErrorMessage() != null) { detailsText.append(""); } if (s3se.getS3ErrorRequestId() != null) { detailsText.append(""); } if (s3se.getS3ErrorHostId() != null) { detailsText.append(""); } boolean firstCause = true; Throwable cause = s3se.getCause(); while (cause != null && cause.getMessage() != null) { if (firstCause) { detailsText.append(""); } detailsText.append(""); firstCause = false; cause = cause.getCause(); } detailsText.append("
S3 Error Code").append(s3se.getS3ErrorCode()).append("
Exception message
") .append(throwable.getMessage()).append("
S3 Message") .append(s3se.getS3ErrorMessage()).append("
S3 Request Id") .append(s3se.getS3ErrorRequestId()).append("
S3 Host Id") .append(s3se.getS3ErrorHostId()).append("
Cause
").append(cause.getMessage()).append("
"); } else { boolean firstCause = true; Throwable cause = throwable; while (cause != null && cause.getMessage() != null) { if (firstCause) { detailsText.append("Cause"); } detailsText.append("").append(cause.getMessage()).append(""); firstCause = false; cause = cause.getCause(); } } if (detailsText.length() > 0) { detailsText.insert(0, ""); detailsText.append(""); } return detailsText.toString(); } /** * Shows the error dialog and waits for the user to acknowledge the dialog. *

* If the JetS3t property gui.verboseErrorDialog is set to true, this dialog will * display detailed information about the root cause of the error (the throwable, if provided) *

* * @param ownerFrame * the frame that will own the dialog * @param hyperlinkListener * the listener that will act on any hyperlink events triggered by the user clicking on HTTP links. * @param message * a general error message, which should ideally be somewhat user-friendly. * @param throwable * the underlying exception that caused the error. */ public static void showDialog(Frame ownerFrame, HyperlinkActivatedListener hyperlinkListener, Properties applicationProperties, String message, Throwable throwable) { ErrorDialog dialog = new ErrorDialog(ownerFrame, hyperlinkListener, applicationProperties); dialog.initGui(message, dialog.buildDetailedText(throwable)); dialog.setVisible(true); dialog.dispose(); } /** * Shows the error dialog and waits for the user to acknowledge the dialog. *

* If the JetS3t property gui.verboseErrorDialog is set to true, this dialog will * display detailed information about the root cause of the error (the throwable, if provided) *

* * @param ownerDialog * the dialog that will own this dialog * @param hyperlinkListener * the listener that will act on any hyperlink events triggered by the user clicking on HTTP links. * @param message * a general error message, which should ideally be somewhat user-friendly. * @param throwable * the underlying exception that caused the error. */ public static void showDialog(JDialog ownerDialog, HyperlinkActivatedListener hyperlinkListener, Properties applicationProperties, String message, Throwable throwable) { ErrorDialog dialog = new ErrorDialog(ownerDialog, hyperlinkListener, applicationProperties); dialog.initGui(message, dialog.buildDetailedText(throwable)); dialog.setVisible(true); dialog.dispose(); } /** * Shows the error dialog and waits for the user to acknowledge the dialog. *

* If the JetS3t property gui.verboseErrorDialog is set to true, this dialog will * display detailed information about the root cause of the error (the throwable, if provided) *

* * @param ownerFrame * the frame that will own the dialog * @param hyperlinkListener * the listener that will act on any hyperlink events triggered by the user clicking on HTTP links. * @param message * a general error message, which should ideally be somewhat user-friendly. * @param throwable * the underlying exception that caused the error. */ public static void showDialog(Frame ownerFrame, HyperlinkActivatedListener hyperlinkListener, String message, Throwable throwable) { showDialog(ownerFrame, hyperlinkListener, null, message, throwable); } /** * Shows the error dialog and waits for the user to acknowledge the dialog. *

* If the JetS3t property gui.verboseErrorDialog is set to true, this dialog will * display detailed information about the root cause of the error (the throwable, if provided) *

* * @param ownerDialog * the dialog that will own this dialog * @param hyperlinkListener * the listener that will act on any hyperlink events triggered by the user clicking on HTTP links. * @param message * a general error message, which should ideally be somewhat user-friendly. * @param throwable * the underlying exception that caused the error. */ public static void showDialog(JDialog ownerDialog, HyperlinkActivatedListener hyperlinkListener, String message, Throwable throwable) { showDialog(ownerDialog, hyperlinkListener, null, message, throwable); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/CopyObjectsDialog.java0000644000000000000000000005675711537563564021330 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.regex.Matcher; import javax.swing.AbstractAction; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.table.DefaultTableModel; import org.jets3t.gui.skins.SkinsFactory; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.model.S3Bucket; import org.jets3t.service.model.S3Object; /** * Dialog for choosing the destination bucket for an Object copy operation, and * specifying how the copy will be performed. The dialog includes options for * renaming object keys during the copy, and for indicating that the copy will * actually be a Move operation - in which case the original objects should be * deleted after the copy has completed successfully. * * @author James Murty */ public class CopyObjectsDialog extends JDialog implements ActionListener { private static final long serialVersionUID = -1131752874387139972L; private SkinsFactory skinsFactory = null; private final Insets insetsZero = new Insets(0, 0, 0, 0); private final Insets insetsDefault = new Insets(5, 7, 5, 7); private final Insets insetsHorizontalSpace = new Insets(0, 7, 0, 7); private S3Object[] destinationObjects = null; private String[] sourceObjectKeys = null; private S3Bucket[] buckets = null; private String sourceBucketName = null; private JTextField renamePatternTextField = null; private JButton okButton = null; private JPanel warningPanel = null; private DefaultTableModel previewTableModel = null; private JTable previewTable = null; private JComboBox destinationBucketComboBox = null; private JComboBox destinationAclComboBox = null; private JComboBox destinationStorageClassComboBox = null; private JCheckBox moveObjectsCheckBox = null; private boolean copyActionApproved = false; private boolean copyOriginalAccessControlLists = false; /** * Construct a modal dialog for controlling copy opeations. * * @param owner * the Frame over which the dialog will be displayed and centred. * @param title * a title for the dialog. * @param skinsFactory * factory for producing skinned GUI components. * @param objects * the S3 objects that will be copied if the user confirms the dialog. * @param buckets * a list of S3 buckets to which the user can copy objects. */ public CopyObjectsDialog(Frame owner, String title, SkinsFactory skinsFactory, S3Object[] objects, S3Bucket[] buckets) { super(owner, title, true); this.skinsFactory = skinsFactory; this.buckets = buckets; // Clone the objects provided. this.destinationObjects = new S3Object[objects.length]; for (int i = 0; i < objects.length; i++) { this.destinationObjects[i] = (S3Object) objects[i].clone(); } sourceObjectKeys = new String[objects.length]; for (int i = 0; i < objects.length; i++) { sourceObjectKeys[i] = objects[i].getKey(); } sourceBucketName = destinationObjects[0].getBucketName(); this.initGui(); } /** * Initialise the GUI elements to display the dialog. */ private void initGui() { this.setResizable(true); this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); JPanel optionsPanel = skinsFactory.createSkinnedJPanel("CopyObjectsDialogOptionsPanel"); optionsPanel.setLayout(new GridBagLayout()); // Destination bucket chooser. destinationBucketComboBox = skinsFactory.createSkinnedJComboBox("DestinationBucketComboBox"); for (int i = 0; i < buckets.length; i++) { destinationBucketComboBox.addItem(buckets[i].getName()); } destinationBucketComboBox.setSelectedItem(sourceBucketName); JLabel destinationBucketLabel = skinsFactory.createSkinnedJHtmlLabel("DestinationBucketLabel"); destinationBucketLabel.setText("Copy to Bucket:"); JPanel bucketPanel = skinsFactory.createSkinnedJPanel("CopyObjectsDialogBucketPanel"); bucketPanel.setLayout(new GridBagLayout()); bucketPanel.add(destinationBucketLabel, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsZero, 0, 0)); bucketPanel.add(destinationBucketComboBox, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsZero, 0, 0)); // Destination Access Control List setting. destinationAclComboBox = skinsFactory.createSkinnedJComboBox("DestinationAclComboBox"); destinationAclComboBox.addItem("Unchanged"); destinationAclComboBox.addItem("Private"); destinationAclComboBox.addItem("Publically Accessible"); JLabel destinationAclLabel = skinsFactory.createSkinnedJHtmlLabel("DestinationAclLabel"); destinationAclLabel.setText("Access permissions for copied objects: "); JPanel aclPanel = skinsFactory.createSkinnedJPanel("CopyObjectsDialogAclPanel"); aclPanel.setLayout(new GridBagLayout()); aclPanel.add(destinationAclLabel, new GridBagConstraints(0, 1, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsZero, 0, 0)); aclPanel.add(destinationAclComboBox, new GridBagConstraints(1, 1, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsZero, 0, 0)); // Destination Storage Class setting. destinationStorageClassComboBox = skinsFactory.createSkinnedJComboBox( "DestinationStorageClassComboBox"); destinationStorageClassComboBox.addItem(S3Object.STORAGE_CLASS_STANDARD); destinationStorageClassComboBox.addItem(S3Object.STORAGE_CLASS_REDUCED_REDUNDANCY); JLabel destinationStorageClassLabel = skinsFactory.createSkinnedJHtmlLabel( "DestinationStorageClassLabel"); destinationStorageClassLabel.setText("Storage Class for copied objects: "); JPanel storageClassPanel = skinsFactory.createSkinnedJPanel( "CopyObjectsDialogStorageClassPanel"); storageClassPanel.setLayout(new GridBagLayout()); storageClassPanel.add(destinationStorageClassLabel, new GridBagConstraints(0, 1, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsZero, 0, 0)); storageClassPanel.add(destinationStorageClassComboBox, new GridBagConstraints(1, 1, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsZero, 0, 0)); // Move objects checkbox moveObjectsCheckBox = skinsFactory.createSkinnedJCheckBox("MoveObjectsCheckBox"); moveObjectsCheckBox.setSelected(false); moveObjectsCheckBox.setText("Move Objects (Originals will be deleted after copy)"); // Object renaming options and renaming pattern text field. JRadioButton unchangedNamesRadioButton = skinsFactory.createSkinnedJRadioButton("UnchangedObjectNamesRadioButton"); unchangedNamesRadioButton.setText("Leave object names unchanged"); unchangedNamesRadioButton.setSelected(true); final JRadioButton changedNamesRadioButton = skinsFactory.createSkinnedJRadioButton("ChangedObjectNamesRadioButton"); changedNamesRadioButton.setText("Rename objects with pattern:"); renamePatternTextField = skinsFactory.createSkinnedJTextField("RenamePatternTextField"); renamePatternTextField.setEnabled(false); renamePatternTextField.setText( (destinationObjects.length == 1 ? destinationObjects[0].getKey() : "{key}")); renamePatternTextField.setToolTipText("Use variables to rename your objects: {key} {path} {filename} {basename} {ext} {count}"); renamePatternTextField.getDocument().addDocumentListener(new DocumentListener() { public void changedUpdate(DocumentEvent e) { refreshNamesPreviewTable(); } public void insertUpdate(DocumentEvent e) { refreshNamesPreviewTable(); } public void removeUpdate(DocumentEvent e) { refreshNamesPreviewTable(); } }); changedNamesRadioButton.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { if (changedNamesRadioButton.isSelected()) { renamePatternTextField.setEnabled(true); renamePatternTextField.requestFocus(); } else { renamePatternTextField.setText( (destinationObjects.length == 1 ? destinationObjects[0].getKey() : "{key}")); renamePatternTextField.setEnabled(false); } } }); ButtonGroup radioButtonGroup = new ButtonGroup(); radioButtonGroup.add(unchangedNamesRadioButton); radioButtonGroup.add(changedNamesRadioButton); JPanel renamePanel = skinsFactory.createSkinnedJPanel("CopyObjectsDialogRenamePanel"); renamePanel.setLayout(new GridBagLayout()); renamePanel.add(unchangedNamesRadioButton, new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsZero, 0, 0)); renamePanel.add(changedNamesRadioButton, new GridBagConstraints(0, 1, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsZero, 0, 0)); int textOffset = changedNamesRadioButton.getIconTextGap() + (int) changedNamesRadioButton.getPreferredSize().getHeight(); renamePanel.add(renamePatternTextField, new GridBagConstraints(0, 2, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, textOffset, 0, 0), 0, 0)); // Build preview table for object names after copy. previewTableModel = new DefaultTableModel(new Object[] {"Object Key"}, 0) { private static final long serialVersionUID = -2859341917353477009L; @Override public boolean isCellEditable(int row, int column) { return false; } }; TableSorter previewTableSorter = new TableSorter(previewTableModel); previewTableSorter.setSortingStatus(0, TableSorter.ASCENDING); previewTable = skinsFactory.createSkinnedJTable("MetadataTable"); previewTable.setModel(previewTableSorter); previewTableSorter.setTableHeader(previewTable.getTableHeader()); JHtmlLabel copyPreviewTableLabel = skinsFactory.createSkinnedJHtmlLabel("CopyObjectsDialogCopyPreviewLabel"); copyPreviewTableLabel.setText("Copy Preview"); copyPreviewTableLabel.setHorizontalAlignment(JLabel.CENTER); // OK Button (Accept copy or move operation). okButton = skinsFactory.createSkinnedJButton("CopyObjectsDialogOKButton"); okButton.setText("Copy Object" + (destinationObjects.length > 0 ? "s" : "")); okButton.setActionCommand("OK"); okButton.addActionListener(this); okButton.setEnabled(false); moveObjectsCheckBox.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { if (moveObjectsCheckBox.isSelected()) { okButton.setText("Move Object" + (destinationObjects.length > 0 ? "s" : "")); } else { okButton.setText("Copy Object" + (destinationObjects.length > 0 ? "s" : "")); } } }); // Cancel Button. JButton cancelButton = skinsFactory.createSkinnedJButton("CopyObjectsDialogCancelButton"); cancelButton.setText("Cancel"); cancelButton.setActionCommand("Cancel"); cancelButton.addActionListener(this); // Warning message displayed when the user's proposed renaming pattern will cause // copied objects to overwrite each other. warningPanel = skinsFactory.createSkinnedJPanel("CopyObjectsDialogWarningPanel"); warningPanel.setLayout(new GridBagLayout()); JHtmlLabel warningLabel = skinsFactory.createSkinnedJHtmlLabel("CopyObjectsDialogWarningLabel"); warningLabel.setText("ERROR: Object renaming pattern is causing key name clashes."); warningLabel.setHorizontalAlignment(JLabel.CENTER); warningPanel.add(warningLabel, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsZero, 0, 0)); JPanel actionButtonsPanel = skinsFactory.createSkinnedJPanel("CopoyObjectsDialogActionButtonsPanel"); actionButtonsPanel.setLayout(new GridBagLayout()); actionButtonsPanel.add(cancelButton, new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsHorizontalSpace, 0, 0)); actionButtonsPanel.add(okButton, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsHorizontalSpace, 0, 0)); // Put all dialog panels and fragments together. int row = 0; optionsPanel.add(bucketPanel, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); optionsPanel.add(aclPanel, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); optionsPanel.add(storageClassPanel, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); optionsPanel.add(moveObjectsCheckBox, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsHorizontalSpace, 0, 0)); optionsPanel.add(renamePanel, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); optionsPanel.add(copyPreviewTableLabel, new GridBagConstraints(0, row++, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); optionsPanel.add(new JScrollPane(previewTable), new GridBagConstraints(0, row++, 2, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsHorizontalSpace, 0, 0)); optionsPanel.add(warningPanel, new GridBagConstraints(0, row++, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); optionsPanel.add(actionButtonsPanel, new GridBagConstraints(0, row++, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); // Recognize and handle ENTER and ESCAPE. this.getRootPane().setDefaultButton(okButton); this.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke("ESCAPE"), "ESCAPE"); this.getRootPane().getActionMap().put("ESCAPE", new AbstractAction() { private static final long serialVersionUID = 921962767729511631L; public void actionPerformed(ActionEvent actionEvent) { setVisible(false); } }); this.getContentPane().add(optionsPanel); this.pack(); this.setSize(450, 400); this.setLocationRelativeTo(this.getOwner()); refreshNamesPreviewTable(); } /** * @param objects * the objects that will be renamed. * * @return * the renamed keys that will result from the proposed renaming pattern. */ protected Set renameObjectKeys(S3Object[] objects) { Set newNames = new HashSet(); for (int i = 0; i < objects.length; i++) { String newName = renameObjectKey(objects[i].getKey(), i); newNames.add(newName); } return newNames; } /** * Return the renamed key for an object based on the current renaming pattern. * This method calculates values for the {key}, {count}, {path}, {filename}, * {basename} and {ext} variables from the original key name, and returns the * destination key name when these values are substituted into the current pattern. *

* The substitution variables supported by this method are: *

    *
  • {key} - the original object key
  • *
  • {count} - an offset value for this object (one greater than the offset * value provided to this method)
  • *
  • {path} - the path portion of the key name, up to the last occurence of * a slash (/) character. If the key contains no slash characters, this variable * will be an empty string.
  • *
  • {filename} - the filename portion of the key name, everything after the * last slash (/) character. If the key contains no slash characters, this variable * will be the original key name.
  • *
  • {ext} - the extension portion of a filename, if any.
  • *
  • {basename} - the file's base name, excluding the extension.
  • *
* * @param key * the original name of an S3 object. * @param offset * the offset for the current object in a set of objects, eg this is the * ith object in the list. This information is necessary to enable the * {count} * * @return * the renamed object key generated by the renaming pattern. */ protected String renameObjectKey(String key, int offset) { // Generate subsitution variables: key, path, filename, count. String count = "" + (offset + 1); String filename = key; String path = ""; int lastSlash = key.lastIndexOf('/'); if (lastSlash >= 0) { path = key.substring(0, lastSlash + 1); filename = key.substring(lastSlash + 1); } String basename = filename; String ext = ""; int lastPeriod = filename.lastIndexOf('.'); if (lastPeriod >= 0) { basename = filename.substring(0, lastPeriod); ext = filename.substring(lastPeriod + 1); } // Perform substitutions to generate new names. String newName = renamePatternTextField.getText(); newName = newName.replaceAll("\\{key\\}", Matcher.quoteReplacement(key)); newName = newName.replaceAll("\\{count\\}", Matcher.quoteReplacement(count)); newName = newName.replaceAll("\\{path\\}", Matcher.quoteReplacement(path)); newName = newName.replaceAll("\\{filename\\}", Matcher.quoteReplacement(filename)); newName = newName.replaceAll("\\{ext\\}", Matcher.quoteReplacement(ext)); newName = newName.replaceAll("\\{basename\\}", Matcher.quoteReplacement(basename)); return newName; } /** * Refreshes the preview table to display the target keys that will be * generated by the proposed renaming pattern. */ protected void refreshNamesPreviewTable() { while (previewTableModel.getRowCount() > 0) { previewTableModel.removeRow(0); } Set renamedKeys = renameObjectKeys(destinationObjects); Iterator nameIter = renamedKeys.iterator(); while (nameIter.hasNext()) { previewTableModel.addRow(new Object[] {nameIter.next()}); } if (destinationObjects.length != renamedKeys.size()) { okButton.setEnabled(false); warningPanel.setVisible(true); } else { okButton.setEnabled(true); warningPanel.setVisible(false); } } /** * Event handler for this dialog. */ public void actionPerformed(ActionEvent e) { if ("OK".equals(e.getActionCommand())) { copyActionApproved = true; for (int i = 0; i < destinationObjects.length; i++) { destinationObjects[i].setKey( renameObjectKey(destinationObjects[i].getKey(), i)); if ("Publically Accessible".equals(destinationAclComboBox.getSelectedItem())) { destinationObjects[i].setAcl(AccessControlList.REST_CANNED_PUBLIC_READ); } else if ("Unchanged".equals(destinationAclComboBox.getSelectedItem())) { copyOriginalAccessControlLists = true; } // Apply storage class destinationObjects[i].setStorageClass( (String) destinationStorageClassComboBox.getSelectedItem()); } this.setVisible(false); } else if ("Cancel".equals(e.getActionCommand())) { copyActionApproved = false; this.setVisible(false); } } /** * @return * true if the user accepted the copy/move operation, false if the user * cancelled the dialog. */ public boolean isCopyActionApproved() { return copyActionApproved; } /** * @return * true if the user selected the Move option to indicate that objects should * be moved, rather than merely copied. */ public boolean isMoveOptionSelected() { return moveObjectsCheckBox.isSelected(); } /** * @return * true if the use wishes to have the ACL settings of their source objects * retained after the copy. */ public boolean isCopyOriginalAccessControlLists() { return copyOriginalAccessControlLists; } /** * @return * the original key names of the S3 objects that should be copied or moved * when this dialog is accepted. */ public String[] getSourceObjectKeys() { if (!isCopyActionApproved()) { return null; } return sourceObjectKeys; } /** * @return * the objects that will be created as the destination of a copy or move * operation. These objects include the metadata changes and Access Control * List setting applied by the user. */ public S3Object[] getDestinationObjects() { if (!isCopyActionApproved()) { return null; } return destinationObjects; } /** * @return * the name of the bucket to which objects should be copied or moved, as * chosen by the user. */ public String getDestinationBucketName() { if (!isCopyActionApproved()) { return null; } return (String) destinationBucketComboBox.getSelectedItem(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/HyperlinkActivatedListener.java0000644000000000000000000000257411441613550023231 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui; import java.net.URL; /** * Listener responsible for following HTML links that have been activated. * * @author James Murty */ public interface HyperlinkActivatedListener { /** * This method is triggered when an HTML link is activated, such as by an HTML link in a * {@link JHtmlLabel} - any class that implements this listener should do something useful * with the triggered hyperlink, preferrably opening it in a web browser. * * @param url * the url contained in the href. * @param target * the target attribute of the href, may be null if the attribute is not present. */ public void followHyperlink(URL url, String target); } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/skins/0002755000000000000000000000000011526136076016216 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/skins/html/0002755000000000000000000000000011427702124017153 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/skins/html/SkinnedJRadioButton.java0000644000000000000000000000223011427702124023671 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui.skins.html; import java.util.Properties; import javax.swing.JRadioButton; /** * A skinned JRadioButton, which is actually just a standard button - useful only as a base for someone * to specialise. * * @author James Murty */ public class SkinnedJRadioButton extends JRadioButton { private static final long serialVersionUID = -9164565945212356520L; public SkinnedJRadioButton(Properties skinProperties, String itemName) { super(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/skins/html/SkinnedLookAndFeel.java0000644000000000000000000001173311427702124023460 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui.skins.html; import java.awt.Color; import java.awt.Font; import java.util.Properties; import javax.swing.JLabel; import javax.swing.plaf.ColorUIResource; import javax.swing.plaf.FontUIResource; import javax.swing.plaf.metal.DefaultMetalTheme; import javax.swing.plaf.metal.MetalLookAndFeel; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * A specialisation of the default Metal theme that allows specific colours and * fonts to be used instead of those in the Metal theme. *

* This class controls: *

    *
  • the colour used for Window and Control backgrounds
  • *
  • the colour used for System, Control and User text
  • *
  • the font used for System, Control and User text
  • *
* * @author James Murty */ public class SkinnedLookAndFeel extends MetalLookAndFeel { private static final long serialVersionUID = 4391824305469950437L; private static final Log log = LogFactory.getLog(SkinnedLookAndFeel.class); public SkinnedLookAndFeel(Properties skinProperties, String itemName) { super(); // Determine system defaults. JLabel defaultLabel = new JLabel(); Color backgroundColor = defaultLabel.getBackground(); Color textColor = defaultLabel.getForeground(); Font font = defaultLabel.getFont(); // Find skinning configurations. String backgroundColorValue = skinProperties.getProperty("backgroundColor", null); String textColorValue = skinProperties.getProperty("textColor", null); String fontValue = skinProperties.getProperty("font", null); // Apply skinning configurations. if (backgroundColorValue != null) { Color color = Color.decode(backgroundColorValue); if (color == null) { log.error("Unable to set background color with value: " + backgroundColorValue); } else { backgroundColor = color; } } if (textColorValue != null) { Color color = Color.decode(textColorValue); if (color == null) { log.error("Unable to set text color with value: " + textColorValue); } else { textColor = color; } } if (fontValue != null) { Font myFont = Font.decode(fontValue); if (myFont == null) { log.error("Unable to set font with value: " + fontValue); } else { font = myFont; } } // Update metal theme with configured display properties. SkinnedMetalTheme skinnedTheme = new SkinnedMetalTheme(new ColorUIResource(backgroundColor), new ColorUIResource(textColor), new FontUIResource(font)); MetalLookAndFeel.setCurrentTheme(skinnedTheme); } private class SkinnedMetalTheme extends DefaultMetalTheme { private ColorUIResource backgroundColorUIResource = null; private ColorUIResource textColorUIResource = null; private FontUIResource fontUIResource = null; public SkinnedMetalTheme(ColorUIResource backgroundColorUIResource, ColorUIResource textColorUIResource, FontUIResource fontUIResource) { this.backgroundColorUIResource = backgroundColorUIResource; this.textColorUIResource = textColorUIResource; this.fontUIResource = fontUIResource; } public String getName() { return "Uploader HTML skinnable theme"; } public FontUIResource getSystemTextFont() { return fontUIResource; } public FontUIResource getControlTextFont() { return fontUIResource; } public FontUIResource getUserTextFont() { return fontUIResource; } public ColorUIResource getSystemTextColor() { return textColorUIResource; } public ColorUIResource getControlTextColor() { return textColorUIResource; } public ColorUIResource getUserTextColor() { return textColorUIResource; } public ColorUIResource getWindowBackground() { return backgroundColorUIResource; } public ColorUIResource getControl() { return backgroundColorUIResource; } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/skins/html/SkinnedJCheckBox.java0000644000000000000000000000221211427702124023125 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui.skins.html; import java.util.Properties; import javax.swing.JCheckBox; /** * A skinned JCheckBox, which is actually just a standard combo box - useful only as a * base for someone to specialise. * * @author James Murty */ public class SkinnedJCheckBox extends JCheckBox { private static final long serialVersionUID = 900121439796911148L; public SkinnedJCheckBox(Properties skinProperties, String itemName) { super(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/skins/html/SkinnedJPasswordField.java0000644000000000000000000000225111427702124024210 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui.skins.html; import java.util.Properties; import javax.swing.JPasswordField; /** * A skinned JPasswordField, which is actually just a standard password field - useful only as a * base for someone to specialise. * * @author James Murty */ public class SkinnedJPasswordField extends JPasswordField { private static final long serialVersionUID = 1804231716387738924L; public SkinnedJPasswordField(Properties skinProperties, String itemName) { super(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/skins/html/SkinnedJHtmlLabel.java0000644000000000000000000000222311427702124023305 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui.skins.html; import java.util.Properties; import org.jets3t.gui.JHtmlLabel; /** * A skinned JHtmlLabel, which is actually just a standard label - useful only as a base for someone * to specialise. * * @author James Murty */ public class SkinnedJHtmlLabel extends JHtmlLabel { private static final long serialVersionUID = 6579194324630151579L; public SkinnedJHtmlLabel(Properties skinProperties, String itemName) { super(null); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/skins/html/SkinnedJPanel.java0000644000000000000000000000217011427702124022501 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui.skins.html; import java.util.Properties; import javax.swing.JPanel; /** * A skinned JPanel, which is actually just a standard panel - useful only as a base for someone * to specialise. * * @author James Murty */ public class SkinnedJPanel extends JPanel { private static final long serialVersionUID = 1349987043338696640L; public SkinnedJPanel(Properties skinProperties, String itemName) { super(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/skins/html/SkinnedJTextArea.java0000644000000000000000000000226111427702124023160 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui.skins.html; import java.util.Properties; import javax.swing.JTextArea; /** * A skinned JTextArea, which is actually just a standard text area - useful only as a base for someone * to specialise. * * @author James Murty */ public class SkinnedJTextArea extends JTextArea { private static final long serialVersionUID = 3823479029525524894L; public SkinnedJTextArea(Properties skinProperties, String itemName) { super(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/skins/html/SkinnedJComboBox.java0000644000000000000000000000221511427702124023152 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui.skins.html; import java.util.Properties; import javax.swing.JComboBox; /** * A skinned JComboBox, which is actually just a standard text field - useful only as a * base for someone to specialise. * * @author James Murty */ public class SkinnedJComboBox extends JComboBox { private static final long serialVersionUID = -5551468589817996956L; public SkinnedJComboBox(Properties skinProperties, String itemName) { super(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/skins/html/SkinnedJTextField.java0000644000000000000000000000222211427702124023330 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui.skins.html; import java.util.Properties; import javax.swing.JTextField; /** * A skinned JTextField, which is actually just a standard text field - useful only as a * base for someone to specialise. * * @author James Murty */ public class SkinnedJTextField extends JTextField { private static final long serialVersionUID = -6583518036836328311L; public SkinnedJTextField(Properties skinProperties, String itemName) { super(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/skins/html/SkinnedJScrollPane.java0000644000000000000000000000223011427702124023501 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui.skins.html; import java.util.Properties; import javax.swing.JScrollPane; /** * A skinned JScrollPane, which is actually just a standard scroll pane - useful only as a base * for someone to specialise. * * @author James Murty */ public class SkinnedJScrollPane extends JScrollPane { private static final long serialVersionUID = -8541837990015326148L; public SkinnedJScrollPane(Properties skinProperties, String itemName) { super(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/skins/html/SkinnedJProgressBar.java0000644000000000000000000000223511427702124023675 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui.skins.html; import java.util.Properties; import javax.swing.JProgressBar; /** * A skinned JProgressBar, which is actually just a standard progress bar - useful only as a base * for someone to specialise. * * @author James Murty */ public class SkinnedJProgressBar extends JProgressBar { private static final long serialVersionUID = 1610187478874024196L; public SkinnedJProgressBar(Properties skinProperties, String itemName) { super(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/skins/html/SkinnedJButton.java0000644000000000000000000000245111427702124022717 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui.skins.html; import java.util.Properties; import javax.swing.JButton; /** * A skinned JButton, which is actually just a standard button - useful only as a base for someone * to specialise. * * @author James Murty */ public class SkinnedJButton extends JButton { private static final long serialVersionUID = 7544903896112071279L; public SkinnedJButton(Properties skinProperties, String itemName) { super(); // Reduce the margin to the border and turn off the focus rectangle. this.setMargin(new java.awt.Insets(0, 2, 0, 2)); this.setFocusPainted(false); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/skins/html/SkinnedJTable.java0000644000000000000000000000216611427702124022476 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2007 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui.skins.html; import java.util.Properties; import javax.swing.JTable; /** * A skinned JTable, which is actually just a standard JTable - useful only as a * base for someone to specialise. * * @author James Murty */ public class SkinnedJTable extends JTable { private static final long serialVersionUID = -8799193197737732023L; public SkinnedJTable(Properties skinProperties, String itemName) { super(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/skins/html/SkinnedJMenuItem.java0000644000000000000000000000220711427702124023166 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2007 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui.skins.html; import java.util.Properties; import javax.swing.JMenuItem; /** * A skinned JMenuItem, which is actually just a standard menu item - useful only as a * base for someone to specialise. * * @author James Murty */ public class SkinnedJMenuItem extends JMenuItem { private static final long serialVersionUID = 6924026586746462101L; public SkinnedJMenuItem(Properties skinProperties, String itemName) { super(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/skins/html/SkinnedJPopupMenu.java0000644000000000000000000000221511427702124023372 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2007 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui.skins.html; import java.util.Properties; import javax.swing.JPopupMenu; /** * A skinned JPopupMenu, which is actually just a standard JPopupMenu - useful only as a * base for someone to specialise. * * @author James Murty */ public class SkinnedJPopupMenu extends JPopupMenu { private static final long serialVersionUID = -887812806309676341L; public SkinnedJPopupMenu(Properties skinProperties, String itemName) { super(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/skins/SkinUtils.java0000644000000000000000000000632011427702124020776 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui.skins; import java.awt.Color; import java.net.URL; import java.util.Properties; import javax.swing.ImageIcon; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Utility methods for loading skin resources from settings in skin properties. * * @author James Murty */ public class SkinUtils { private static final Log log = LogFactory.getLog(SkinUtils.class); /** * Loads a skin property setting for a color. * * @param skinProperties * contains skin property settings. * @param colorPropertyName * the name of the property expected to contain a color value. * * @return * the parsed color value if the given property is available and valid, null otherwise. */ public Color loadColor(Properties skinProperties, String colorPropertyName) { Color color = null; String colorValue = skinProperties.getProperty(colorPropertyName, null); log.debug("Loading skin color with property '" + colorPropertyName + "', value: " + colorValue); if (colorValue != null) { color = Color.decode(colorValue); } else { log.warn("Color is not available for property '" + colorPropertyName + "'"); } return color; } /** * Loads a skin property setting for an icon image. * * @param skinProperties * contains skin property settings. * @param iconPathPropertyName * the name of the property expected to contain the path to an icon image resource. * * @return * an icon image resource when the path property is available and it points to a valid * image resource, null otherwise. */ public ImageIcon loadIcon(Properties skinProperties, String iconPathPropertyName) { ImageIcon imageIcon = null; String imageIconPath = skinProperties.getProperty(iconPathPropertyName, null); log.debug("Loading image icon with property '" + iconPathPropertyName + "', value: " + imageIconPath); if (imageIconPath != null && imageIconPath.length() > 0) { URL iconURL = this.getClass().getResource(imageIconPath); if (iconURL != null) { imageIcon = new ImageIcon(iconURL); } else { log.warn("Image icon resources is not available in classpath for path '" + imageIconPath + "'"); } } else { log.warn("Image icon path is not available for property '" + iconPathPropertyName + "'"); } return imageIcon; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/skins/SkinsFactory.java0000644000000000000000000004272111526136054021500 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui.skins; import java.lang.reflect.Constructor; import java.util.HashMap; import java.util.Iterator; import java.util.Locale; import java.util.Map; import java.util.Properties; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JPopupMenu; import javax.swing.JProgressBar; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.LookAndFeel; import javax.swing.UIManager; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.gui.HyperlinkActivatedListener; import org.jets3t.gui.JHtmlLabel; import java.awt.Component; /** * Manages the creation of skinned GUI elements. * Skinned elements are created using the following process: *
    *
  1. Instantiate a skin-specific class in the skin's package * org.jets3t.gui.skins.<skinName>
  2. *
  3. If a skin-specific class is not available or cannot be created, * instantiate a generic GUI class instead
  4. *
*

* Skinned classes are specially-named extensions to standard Swing classes, which must have a * constructor of the form
public SkinnedJButton(Properties skinProperties, String itemName). * This constructor allows skinned GUI elements to change their look or behaviour based on any * skin-specific properties that are provided, or based on the name of a specific GUI element. *

* The skinned class names supported by this factory include: * * * * * * *
Class nameExtends
SkinnedJButtonjavax.swing.JButton
SkinnedJHtmlLabelorg.jets3t.gui.JHtmlLabel
SkinnedJPaneljavax.swing.JPanel
SkinnedLookAndFeeljavax.swing.plaf.metal.MetalLookAndFeel
* * @author James Murty * */ public class SkinsFactory { private static final Log log = LogFactory.getLog(SkinsFactory.class); public static final String NO_SKIN = "noskin"; /** * The name of the chosen skin. */ private String skinName = null; /** * Properties that apply specifically to the chosen skin. */ private Properties skinProperties = new Properties(); /** * Track component class names that are not available. */ private static Map unavailableClassMap = new HashMap(); /** * Construct the factory and find skin-specific properties in the provided properties set. * * @param properties * A set of properties that may contain skin-specific properties. */ private SkinsFactory(Properties properties) { // Gracefully handle missing properties. if (properties == null) { properties = new Properties(); } this.skinName = properties.getProperty("skin.name"); if (this.skinName == null) { this.skinName = NO_SKIN; } // Find skin-specific properties. String skinPropertyPrefix = "skin." + this.skinName.toLowerCase(Locale.getDefault()) + "."; Iterator iter = properties.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); String propertyName = (String) entry.getKey(); String propertyValue = (String) entry.getValue(); if (propertyName.toLowerCase(Locale.getDefault()).startsWith(skinPropertyPrefix)) { String skinPropertyName = propertyName.substring(skinPropertyPrefix.length()); this.skinProperties.put(skinPropertyName, propertyValue); } } } /** * Provides a skin factory initialised with skin-specific properties from the provided * properties set. Skin-specific properties are identified as those properties with the * prefix skin.<skinName>. * * @param properties * a set of properties that may contain skin-specific properties. * * @return * the skins factory initialised with skin settings. */ public static SkinsFactory getInstance(Properties properties) { return new SkinsFactory(properties); } /** * @param itemName * the name of this specific item in the GUI, which may be used to determine how the skinned * item should look or behave. * * @return * a SkinnedLookAndFeel class implementation for the current skin, or the default * system LookAndFeel if no skin-specific implementation is available. */ public LookAndFeel createSkinnedMetalTheme(String itemName) { Object instance = instantiateClass(buildSkinnedClassName("SkinnedLookAndFeel"), itemName); if (instance != null) { return (LookAndFeel) instance; } else { return UIManager.getLookAndFeel(); } } /** * @param itemName * the name of this specific item in the GUI, which may be used to determine how the skinned * item should look or behave. * * @return * a SkinnedJButton class implementation for the current skin, or a default * JButton if no skin-specific implementation is available. */ public JButton createSkinnedJButton(String itemName) { Object instance = instantiateClass(buildSkinnedClassName("SkinnedJButton"), itemName); if (instance != null) { return (JButton) instance; } else { return new JButton(); } } /** * @param itemName * the name of this specific item in the GUI, which may be used to determine how the skinned * item should look or behave. * * @return * a SkinnedJRadioButton class implementation for the current skin, or a default * JRadioButton if no skin-specific implementation is available. */ public JRadioButton createSkinnedJRadioButton(String itemName) { Object instance = instantiateClass(buildSkinnedClassName("SkinnedJRadioButton"), itemName); if (instance != null) { return (JRadioButton) instance; } else { return new JRadioButton(); } } /** * @param itemName * the name of this specific item in the GUI, which may be used to determine how the skinned * item should look or behave. * * @return * a SkinnedJComboBox class implementation for the current skin, or a default * JComboBox if no skin-specific implementation is available. */ public JComboBox createSkinnedJComboBox(String itemName) { Object instance = instantiateClass(buildSkinnedClassName("SkinnedJComboBox"), itemName); if (instance != null) { return (JComboBox) instance; } else { return new JComboBox(); } } /** * @param itemName * the name of this specific item in the GUI, which may be used to determine how the skinned * item should look or behave. * * @return * a SkinnedJComboBox class implementation for the current skin, or a default * JComboBox if no skin-specific implementation is available. */ public JCheckBox createSkinnedJCheckBox(String itemName) { Object instance = instantiateClass(buildSkinnedClassName("SkinnedJCheckBox"), itemName); if (instance != null) { return (JCheckBox) instance; } else { return new JCheckBox(); } } /** * @param itemName * the name of this specific item in the GUI, which may be used to determine how the skinned * item should look or behave. * * @return * a SkinnedJPanel class implementation for the current skin, or a default * JPanel if no skin-specific implementation is available. */ public JPanel createSkinnedJPanel(String itemName) { Object instance = instantiateClass(buildSkinnedClassName("SkinnedJPanel"), itemName); if (instance != null) { return (JPanel) instance; } else { return new JPanel(); } } /** * @param itemName * the name of this specific item in the GUI, which may be used to determine how the skinned * item should look or behave. * * @return * a SkinnedJTable class implementation for the current skin, or a default * JPanel if no skin-specific implementation is available. */ public JTable createSkinnedJTable(String itemName) { Object instance = instantiateClass(buildSkinnedClassName("SkinnedJTable"), itemName); if (instance != null) { return (JTable) instance; } else { return new JTable(); } } /** * @param itemName * the name of this specific item in the GUI, which may be used to determine how the skinned * item should look or behave. * * @param view * the client's viewport view to be used. * * @return * a SkinnedJScrollPane class implementation for the current skin, or a default * JScrollPane if no skin-specific implementation is available. */ public JScrollPane createSkinnedJScrollPane(String itemName, Object view) { Object instance = instantiateClass(buildSkinnedClassName("SkinnedJScrollPane"), itemName); if (instance != null) { JScrollPane scrollPane = (JScrollPane) instance; scrollPane.setViewportView((Component) view); return scrollPane; } else { return new JScrollPane((Component) view); } } /** * @param itemName * the name of this specific item in the GUI, which may be used to determine how the skinned * item should look or behave. * * @return * a SkinnedJScrollPane class implementation for the current skin, or a default * JScrollPane if no skin-specific implementation is available. */ public JScrollPane createSkinnedJScrollPane(String itemName) { Object instance = instantiateClass(buildSkinnedClassName("SkinnedJScrollPane"), itemName); if (instance != null) { return (JScrollPane) instance; } else { return new JScrollPane(); } } /** * @param itemName * the name of this specific item in the GUI, which may be used to determine how the skinned * item should look or behave. * * @return * a SkinnedJLabel class implementation for the current skin, or a default * JHtmlLabel if no skin-specific implementation is available. */ public JHtmlLabel createSkinnedJHtmlLabel(String itemName, HyperlinkActivatedListener hyperlinkListener) { Object instance = instantiateClass(buildSkinnedClassName("SkinnedJHtmlLabel"), itemName); if (instance != null) { JHtmlLabel label = (JHtmlLabel) instance; label.setHyperlinkeActivatedListener(hyperlinkListener); return label; } else { return new JHtmlLabel(hyperlinkListener); } } /** * @param itemName * the name of this specific item in the GUI, which may be used to determine how the skinned * item should look or behave. * * @return * a SkinnedJLabel class implementation for the current skin, or a default * JHtmlLabel if no skin-specific implementation is available. */ public JHtmlLabel createSkinnedJHtmlLabel(String itemName) { return createSkinnedJHtmlLabel(itemName, null); } /** * @param itemName * the name of this specific item in the GUI, which may be used to determine how the skinned * item should look or behave. * * @return * a SkinnedJPasswordField class implementation for the current skin, or a default * JPasswordField if no skin-specific implementation is available. */ public JPasswordField createSkinnedJPasswordField(String itemName) { Object instance = instantiateClass(buildSkinnedClassName("SkinnedJPasswordField"), itemName); if (instance != null) { return (JPasswordField) instance; } else { return new JPasswordField(); } } /** * @param itemName * the name of this specific item in the GUI, which may be used to determine how the skinned * item should look or behave. * * @return * a SkinnedJTextField class implementation for the current skin, or a default * JTextField if no skin-specific implementation is available. */ public JTextField createSkinnedJTextField(String itemName) { Object instance = instantiateClass(buildSkinnedClassName("SkinnedJTextField"), itemName); if (instance != null) { return (JTextField) instance; } else { return new JTextField(); } } /** * @param itemName * the name of this specific item in the GUI, which may be used to determine how the skinned * item should look or behave. * * @return * a SkinnedJTextArea class implementation for the current skin, or a default * JTextArea if no skin-specific implementation is available. */ public JTextArea createSkinnedJTextArea(String itemName) { Object instance = instantiateClass(buildSkinnedClassName("SkinnedJTextArea"), itemName); if (instance != null) { return (JTextArea) instance; } else { return new JTextArea(); } } public JPopupMenu createSkinnedJPopupMenu(String itemName) { Object instance = instantiateClass(buildSkinnedClassName("SkinnedJPopupMenu"), itemName); if (instance != null) { return (JPopupMenu) instance; } else { return new JPopupMenu(); } } public JMenuItem createSkinnedJMenuItem(String itemName) { Object instance = instantiateClass(buildSkinnedClassName("SkinnedJMenuItem"), itemName); if (instance != null) { return (JMenuItem) instance; } else { return new JMenuItem(); } } /** * @param itemName * the name of this specific item in the GUI, which may be used to determine how the skinned * item should look or behave. * * @return * a SkinnedJProgressBar class implementation for the current skin, or a default * JProgressBar if no skin-specific implementation is available. */ public JProgressBar createSkinnedJProgressBar(String itemName, int min, int max) { JProgressBar jProgressBar = (JProgressBar) instantiateClass( buildSkinnedClassName("SkinnedJProgressBar"), itemName); if (jProgressBar != null) { jProgressBar.setMinimum(min); jProgressBar.setMaximum(max); return (JProgressBar) jProgressBar; } else { jProgressBar = new JProgressBar(min, max); return jProgressBar; } } private String buildSkinnedClassName(String className) { if (NO_SKIN.equals(skinName)) { return null; } else { String skinnedClassName = this.getClass().getPackage().getName() + "." + this.skinName + "." + className; return skinnedClassName; } } private Object instantiateClass(String className, String itemName) { if (className == null) { return null; } if (unavailableClassMap.get(className) != null) { // This class name is not available, don't waste time trying to load it. return null; } try { Class myClass = Class.forName(className); Constructor constructor = myClass.getConstructor( new Class[] { Properties.class, String.class }); Object instance = constructor.newInstance(new Object[] { skinProperties, itemName }); return instance; } catch (ClassNotFoundException e) { log.debug("Class does not exist, will use default. Skinned class name: " + className); } catch (Exception e) { log.warn("Unable to instantiate skinned class '" + className + "'", e); } unavailableClassMap.put(className, Boolean.TRUE); return null; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/ManageDistributionsDialog.java0000644000000000000000000010645611537563564023047 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableColumnModel; import org.jets3t.samples.SamplesUtils; import org.jets3t.service.CloudFrontService; import org.jets3t.service.CloudFrontServiceException; import org.jets3t.service.S3Service; import org.jets3t.service.impl.rest.httpclient.RestS3Service; import org.jets3t.service.model.S3Bucket; import org.jets3t.service.model.cloudfront.Distribution; import org.jets3t.service.model.cloudfront.DistributionConfig; import org.jets3t.service.model.cloudfront.LoggingStatus; import org.jets3t.service.model.cloudfront.S3Origin; /** * Dialog box for displaying and modifying CloudFront distributions. *

* The first time a bucket is selected its logging status is retrieved from S3 and the details are * displayed, as well as being cached so further lookups aren't necessary. The logging status is * modified by choosing/changing the target log bucket. * * @author James Murty */ public class ManageDistributionsDialog extends JDialog implements ActionListener, ListSelectionListener, HyperlinkActivatedListener { private static final long serialVersionUID = 4375982994004017092L; private CloudFrontService cloudFrontService = null; private final GuiUtils guiUtils = new GuiUtils(); private Frame ownerFrame = null; private JTable distributionListTable = null; private DistributionListTableModel distributionListTableModel = null; private TableSorter distributionListTableModelSorter = null; private JComboBox bucketComboBox = null; private JCheckBox enabledCheckbox = null; private JCheckBox httpsOnlyCheckbox = null; private JComboBox loggingBucketComboBox = null; private JTextField defaultRootObjectTextField = null; private JTextField loggingPrefixTextField = null; private JTable cnamesTable = null; private CNAMETableModel cnamesTableModel = null; private JButton addCname = null; private JButton removeCname = null; private JTextArea commentTextArea = null; private JButton actionButton = null; private JButton deleteButton = null; private JButton finishedButton = null; private final Insets insetsDefault = new Insets(3, 5, 3, 5); private final Insets insetsHorizontalOnly = new Insets(0, 5, 0, 5); public ManageDistributionsDialog(Frame ownerFrame, CloudFrontService cloudFrontService, String bucketNames[], HyperlinkActivatedListener hyperlinkListener) { super(ownerFrame, "CloudFront Distributions", true); this.ownerFrame = ownerFrame; this.cloudFrontService = cloudFrontService; distributionListTableModel = new DistributionListTableModel(); distributionListTableModelSorter = new TableSorter(distributionListTableModel); distributionListTable = new JTable(distributionListTableModelSorter); distributionListTableModelSorter.setTableHeader(distributionListTable.getTableHeader()); distributionListTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); distributionListTable.getSelectionModel().addListSelectionListener(this); JLabel bucketLabel = new JLabel("Bucket"); bucketComboBox = new JComboBox(bucketNames); JLabel enabledLabel = new JLabel("Enabled"); enabledCheckbox = new JCheckBox(); JLabel httpsOnlyLabel = new JLabel("HTTPS Only"); httpsOnlyCheckbox = new JCheckBox(); JLabel defaultRootObjectLabel = new JLabel("Default Root Object"); defaultRootObjectTextField = new JTextField(); JLabel loggingBucketLabel = new JLabel("Logging bucket"); loggingBucketComboBox = new JComboBox(bucketNames); loggingBucketComboBox.insertItemAt("-- Logging Disabled --", 0); loggingBucketComboBox.setSelectedIndex(0); loggingBucketComboBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { loggingPrefixTextField.setEnabled( loggingBucketComboBox.getSelectedIndex() > 0); } }); JLabel loggingPrefixLabel = new JLabel("Logging prefix"); loggingPrefixTextField = new JTextField(); loggingPrefixTextField.setEnabled(false); cnamesTableModel = new CNAMETableModel(); TableSorter cnamesTableModelSorter = new TableSorter(cnamesTableModel); cnamesTable = new JTable(cnamesTableModelSorter); cnamesTableModelSorter.setTableHeader(cnamesTable.getTableHeader()); cnamesTable.getSelectionModel().addListSelectionListener(this); removeCname = new JButton(); removeCname.setToolTipText("Remove the selected CNAME"); guiUtils.applyIcon(removeCname, "/images/nuvola/16x16/actions/viewmag-.png"); removeCname.addActionListener(this); removeCname.setActionCommand("RemoveCname"); removeCname.setEnabled(false); addCname = new JButton(); addCname.setToolTipText("Add a new CNAME"); guiUtils.applyIcon(addCname, "/images/nuvola/16x16/actions/viewmag+.png"); addCname.setActionCommand("AddCname"); addCname.addActionListener(this); JLabel commentLabel = new JLabel("Comment"); commentTextArea = new JTextArea(); commentTextArea.setLineWrap(true); JButton refreshButton = new JButton("Refresh Distributions"); refreshButton.setActionCommand("RefreshDistributions"); refreshButton.addActionListener(this); guiUtils.applyIcon(refreshButton, "/images/nuvola/16x16/actions/reload.png"); deleteButton = new JButton("Delete Distribution"); deleteButton.setActionCommand("DeleteDistribution"); deleteButton.addActionListener(this); deleteButton.setEnabled(false); deleteButton.setToolTipText("To delete a distribution it must first be disabled and deployed"); guiUtils.applyIcon(deleteButton, "/images/nuvola/16x16/actions/cancel.png"); actionButton = new JButton("New Distribution"); actionButton.setActionCommand("NewDistribution"); actionButton.addActionListener(this); finishedButton = new JButton("Finished"); finishedButton.setActionCommand("Finished"); finishedButton.addActionListener(this); // Set default ENTER and ESCAPE buttons. this.getRootPane().setDefaultButton(finishedButton); this.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke("ESCAPE"), "ESCAPE"); this.getRootPane().getActionMap().put("ESCAPE", new AbstractAction() { private static final long serialVersionUID = -7782288899638043533L; public void actionPerformed(ActionEvent actionEvent) { setVisible(false); } }); JPanel distributionsButtonsPanel = new JPanel(new GridBagLayout()); distributionsButtonsPanel.add(refreshButton, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsHorizontalOnly, 0, 0)); distributionsButtonsPanel.add(deleteButton, new GridBagConstraints(1, 0, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsHorizontalOnly, 0, 0)); JPanel tablePanel = new JPanel(new GridBagLayout()); tablePanel.add(new JScrollPane(distributionListTable), new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 5, 0, 3), 0, 0)); tablePanel.add(distributionsButtonsPanel, new GridBagConstraints(0, 1, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsHorizontalOnly, 0, 0)); JPanel cnameAddRemoveButtonsPanel = new JPanel(new GridBagLayout()); cnameAddRemoveButtonsPanel.add(removeCname, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsHorizontalOnly, 0, 0)); cnameAddRemoveButtonsPanel.add(addCname, new GridBagConstraints(1, 0, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsHorizontalOnly, 0, 0)); JPanel detailPanel = new JPanel(new GridBagLayout()); detailPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Distribution Details")); int row = 0; detailPanel.add(bucketLabel, new GridBagConstraints(0, row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); detailPanel.add(bucketComboBox, new GridBagConstraints(1, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); detailPanel.add(enabledLabel, new GridBagConstraints(0, row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); detailPanel.add(enabledCheckbox, new GridBagConstraints(1, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); detailPanel.add(httpsOnlyLabel, new GridBagConstraints(0, row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); detailPanel.add(httpsOnlyCheckbox, new GridBagConstraints(1, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); detailPanel.add(defaultRootObjectLabel, new GridBagConstraints(0, row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); detailPanel.add(defaultRootObjectTextField, new GridBagConstraints(1, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); detailPanel.add(loggingBucketLabel, new GridBagConstraints(0, row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); detailPanel.add(loggingBucketComboBox, new GridBagConstraints(1, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); detailPanel.add(loggingPrefixLabel, new GridBagConstraints(0, row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); detailPanel.add(loggingPrefixTextField, new GridBagConstraints(1, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); detailPanel.add(new JScrollPane(cnamesTable), new GridBagConstraints(0, row++, 2, 1, 1, 2, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(3, 5, 0, 5), 0, 0)); detailPanel.add(cnameAddRemoveButtonsPanel, new GridBagConstraints(0, row++, 2, 1, 1, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsHorizontalOnly, 0, 0)); detailPanel.add(commentLabel, new GridBagConstraints(0, row++, 2, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsHorizontalOnly, 0, 0)); detailPanel.add(new JScrollPane(commentTextArea), new GridBagConstraints(0, row++, 2, 1, 0, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); detailPanel.add(actionButton, new GridBagConstraints(0, row++, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsHorizontalOnly, 0, 0)); this.getContentPane().setLayout(new GridBagLayout()); this.getContentPane().add(tablePanel, new GridBagConstraints(0, 0, 1, 1, 1, 2, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); this.getContentPane().add(detailPanel, new GridBagConstraints(0, 1, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsHorizontalOnly, 0, 0)); this.getContentPane().add(finishedButton, new GridBagConstraints(0, 2, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsHorizontalOnly, 0, 0)); // Size dialog this.pack(); this.setSize(690, 550); // Micro-managed column widths, because Java table columns are stupid... yuk. TableColumnModel columnModel = distributionListTable.getColumnModel(); columnModel.getColumn(0).setPreferredWidth(40); // Status columnModel.getColumn(1).setPreferredWidth(50); // Enabled? columnModel.getColumn(2).setPreferredWidth(170); // Bucket columnModel.getColumn(3).setPreferredWidth(210); // Domain name columnModel.getColumn(4).setPreferredWidth(220); // Last Modified this.setLocationRelativeTo(ownerFrame); refreshDistributions(); } protected void refreshDistributions() { (new Thread() { @Override public void run() { final ProgressDialog progressDialog = new ProgressDialog(ownerFrame, "Listing Distributions", null); SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.startDialog("Listing Distributions", null, 0, 0, null, null); } }); try { final Distribution[] distributions = cloudFrontService.listDistributions(); SwingUtilities.invokeLater(new Runnable() { public void run() { int priorSelection = distributionListTable.getSelectedRow(); distributionListTableModel.removeAll(); for (int i = 0; i < distributions.length; i++) { distributionListTableModel.addDistribution(distributions[i]); } if (priorSelection >= 0 && priorSelection < distributionListTable.getRowCount()) { distributionListTable.setRowSelectionInterval(priorSelection, priorSelection); } else if (distributionListTable.getRowCount() > 0) { distributionListTable.setRowSelectionInterval(0, 0); } } }); } catch (Exception e) { SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.stopDialog(); } }); String errorMessage = "Failed to list distributions"; if (e instanceof CloudFrontServiceException) { errorMessage = ((CloudFrontServiceException)e).getErrorMessage(); } ErrorDialog.showDialog(ownerFrame, null, errorMessage, e); } SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.stopDialog(); } }); } }).start(); } public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting()) { return; } if (e.getSource().equals(distributionListTable.getSelectionModel())) { int tableIndex = distributionListTable.getSelectedRow(); if (tableIndex < 0) { return; } Distribution distribution = distributionListTableModel.getDistributionAtRow( distributionListTableModelSorter.modelIndex(tableIndex)); if (distribution == null) { // Special case, allow the creation of a new distribution. deleteButton.setEnabled(false); bucketComboBox.setEnabled(true); enabledCheckbox.setSelected(false); httpsOnlyCheckbox.setEnabled(false); defaultRootObjectTextField.setText(""); loggingBucketComboBox.setSelectedIndex(0); loggingPrefixTextField.setText(""); cnamesTableModel.removeAll(); commentTextArea.setText(""); actionButton.setText("New Distribution"); actionButton.setActionCommand("NewDistribution"); actionButton.setEnabled(true); } else { // Retrieve distribution's configuration to access current logging status settings. DistributionConfig distributionConfig = null; try { distributionConfig = cloudFrontService.getDistributionConfig(distribution.getId()); } catch (CloudFrontServiceException ex) { String message = "Unable to retrieve configuration information " + "for distribution: " + distribution.getId(); ErrorDialog.showDialog(ownerFrame, this, message, ex); return; } if (distribution.getOrigin() instanceof S3Origin) { bucketComboBox.setSelectedItem( ((S3Origin)distribution.getOrigin()).getOriginAsBucketName()); } bucketComboBox.setEnabled(false); enabledCheckbox.setSelected(distribution.isEnabled()); httpsOnlyCheckbox.setSelected(distributionConfig.isHttpsProtocolRequired()); defaultRootObjectTextField.setText(distributionConfig.getDefaultRootObject()); if (distributionConfig.getLoggingStatus() != null) { loggingBucketComboBox.setSelectedItem( distributionConfig.getLoggingStatus().getShortBucketName()); loggingPrefixTextField.setText( distributionConfig.getLoggingStatus().getPrefix()); } else { loggingBucketComboBox.setSelectedIndex(0); loggingPrefixTextField.setText(""); } cnamesTableModel.removeAll(); String[] cnames = distribution.getCNAMEs(); for (int i = 0; i < cnames.length; i++) { cnamesTableModel.addCname(cnames[i]); } commentTextArea.setText(distribution.getComment()); // Update possible actions deleteButton.setEnabled(!distribution.isEnabled() && distribution.isDeployed()); actionButton.setText("Update Distribution"); actionButton.setActionCommand("UpdateDistribution"); actionButton.setEnabled(distribution.isDeployed()); } } else if (e.getSource().equals(cnamesTable.getSelectionModel())) { removeCname.setEnabled(cnamesTable.getSelectedRowCount() != 0); } } public void actionPerformed(ActionEvent event) { if (event.getSource().equals(finishedButton)) { this.setVisible(false); } else if (event.getActionCommand().equals("AddCname")) { cnamesTableModel.addCname("New CNAME"); int newRowIndex = cnamesTable.getRowCount() - 1; cnamesTable.setRowSelectionInterval(newRowIndex, newRowIndex); cnamesTable.editCellAt(newRowIndex, 0); } else if (event.getActionCommand().equals("RemoveCname")) { cnamesTableModel.removeRow(cnamesTable.getSelectedRow()); } else if (event.getActionCommand().equals("RefreshDistributions")) { refreshDistributions(); } else if (event.getActionCommand().equals("DeleteDistribution")) { final Distribution distribution = distributionListTableModel.getDistributionAtRow( distributionListTableModelSorter.modelIndex( distributionListTable.getSelectedRow())); int answer = JOptionPane.showConfirmDialog(this, "Delete the distribution " + distribution.getDomainName() + "?", "Delete Distribution", JOptionPane.YES_NO_OPTION); if (answer == 1) { // NO return; } else { (new Thread() { @Override public void run() { final ProgressDialog progressDialog = new ProgressDialog(ownerFrame, "Deleting Distribution", null); SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.startDialog("Deleting distribution: " + distribution.getDomainName(), null, 0, 0, null, null); } }); try { cloudFrontService.deleteDistribution(distribution.getId()); refreshDistributions(); } catch (Exception e) { SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.stopDialog(); } }); String errorMessage = "Failed to delete distribution"; if (e instanceof CloudFrontServiceException) { errorMessage = ((CloudFrontServiceException)e).getErrorMessage(); } ErrorDialog.showDialog(ownerFrame, null, errorMessage, e); } SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.stopDialog(); } }); } }).start(); } } else if (event.getActionCommand().equals("NewDistribution")) { final String bucketName = bucketComboBox.getSelectedItem() + ".s3.amazonaws.com"; (new Thread() { @Override public void run() { final ProgressDialog progressDialog = new ProgressDialog(ownerFrame, "Creating Distribution", null); SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.startDialog("Creating distribution for: " + bucketComboBox.getSelectedItem(), null, 0, 0, null, null); } }); try { LoggingStatus loggingStatus = null; if (loggingBucketComboBox.getSelectedIndex() > 0) { String loggingBucket = (String) loggingBucketComboBox.getSelectedItem() + CloudFrontService.DEFAULT_BUCKET_SUFFIX; loggingStatus = new LoggingStatus( loggingBucket, loggingPrefixTextField.getText()); } String[] requiredProtocols = null; if (httpsOnlyCheckbox.isSelected()) { requiredProtocols = new String[] {"https"}; } else { requiredProtocols = new String[0]; } String defaultRootObject = defaultRootObjectTextField.getText(); if (defaultRootObject.length() == 0) { defaultRootObject = null; } cloudFrontService.createDistribution( new S3Origin(bucketName), null, cnamesTableModel.getCnames(), commentTextArea.getText(), enabledCheckbox.isSelected(), loggingStatus, false, // trustedSignerSelf null, // trustedSignerAwsAccountNumbers requiredProtocols, defaultRootObject); refreshDistributions(); } catch (Exception e) { SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.stopDialog(); } }); String errorMessage = "Failed to create distribution"; if (e instanceof CloudFrontServiceException) { errorMessage = ((CloudFrontServiceException)e).getErrorMessage(); } ErrorDialog.showDialog(ownerFrame, null, errorMessage, e); } SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.stopDialog(); } }); } }).start(); } else if (event.getActionCommand().equals("UpdateDistribution")) { final Distribution distribution = distributionListTableModel.getDistributionAtRow( distributionListTableModelSorter.modelIndex( distributionListTable.getSelectedRow())); (new Thread() { @Override public void run() { final ProgressDialog progressDialog = new ProgressDialog(ownerFrame, "Updating Distribution", null); SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.startDialog("Updating distribution: " + distribution.getDomainName(), null, 0, 0, null, null); } }); try { LoggingStatus loggingStatus = null; if (loggingBucketComboBox.getSelectedIndex() > 0) { String loggingBucket = (String) loggingBucketComboBox.getSelectedItem() + CloudFrontService.DEFAULT_BUCKET_SUFFIX; loggingStatus = new LoggingStatus( loggingBucket, loggingPrefixTextField.getText()); } String[] requiredProtocols = null; if (httpsOnlyCheckbox.isSelected()) { requiredProtocols = new String[] {"https"}; } else { requiredProtocols = new String[0]; } String defaultRootObject = defaultRootObjectTextField.getText(); if (defaultRootObject.length() == 0) { defaultRootObject = null; } cloudFrontService.updateDistributionConfig(distribution.getId(), null, // origin cnamesTableModel.getCnames(), commentTextArea.getText(), enabledCheckbox.isSelected(), loggingStatus, false, // trustedSignerSelf null, // trustedSignerAwsAccountNumbers requiredProtocols, defaultRootObject); refreshDistributions(); } catch (Exception e) { SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.stopDialog(); } }); String errorMessage = "Failed to update distribution"; if (e instanceof CloudFrontServiceException) { errorMessage = ((CloudFrontServiceException)e).getErrorMessage(); } ErrorDialog.showDialog(ownerFrame, null, errorMessage, e); } SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.stopDialog(); } }); } }).start(); } } /** * Dialog box for displaying and modifying CloudFront distributions. * * @param ownerFrame * the frame that will own the dialog. * @param cloudFrontService * a CloudFrontService that will be used to query and update distributions. This * service must be initialised with the necessary AWS credentials to perform the * API operations. * @param hyperlinkListener * the listener that will act on any hyperlink events triggered by the user clicking on HTTP links. */ public static void showDialog(Frame ownerFrame, CloudFrontService cloudFrontService, String[] bucketNames, HyperlinkActivatedListener hyperlinkListener) { ManageDistributionsDialog dialog = new ManageDistributionsDialog( ownerFrame, cloudFrontService, bucketNames, hyperlinkListener); dialog.setVisible(true); dialog.dispose(); } private class DistributionListTableModel extends DefaultTableModel { private static final long serialVersionUID = -8315527286580422385L; private final ArrayList distributionList = new ArrayList(); private Icon inProgressIcon = null; private Icon deployedIcon = null; public DistributionListTableModel() { super(new String[] {"Status", "Enabled", "Bucket", "Domain Name", "Last Modified"}, 0); this.addRow(new Object[] {null, null, "Add New Distribution", null, null}); JLabel dummyLabel = new JLabel(); if (guiUtils.applyIcon(dummyLabel, "/images/nuvola/16x16/actions/noatunloopsong.png")) { inProgressIcon = dummyLabel.getIcon(); } if (guiUtils.applyIcon(dummyLabel, "/images/nuvola/16x16/actions/ok.png")) { deployedIcon = dummyLabel.getIcon(); } } protected int findDistributionIndex(String bucketName) { return Collections.binarySearch( distributionList, bucketName, new Comparator() { public int compare(Object o1, Object o2) { String b1Name = ((Distribution)o1).getOrigin().getDnsName(); String b2Name = (String) o2; int result = b1Name.compareTo(b2Name); return result; } } ); } public void addDistribution(Distribution distribution) { distributionList.add(distribution); this.insertRow(distributionList.size() - 1, new Object[] { (distribution.isDeployed() ? deployedIcon : inProgressIcon), Boolean.valueOf(distribution.isEnabled()), distribution.getOrigin().getDnsName(), distribution.getDomainName(), distribution.getLastModifiedTime() }); } public Distribution getDistributionAtRow(int rowIndex) { if (rowIndex < distributionList.size()) { return (Distribution) distributionList.get(rowIndex); } else { return null; } } public void removeDistribution(String bucketName) { int index = findDistributionIndex(bucketName); this.removeRow(index); distributionList.remove(index); } public void removeAll() { int rowCount = distributionList.size(); for (int i = 0; i < rowCount; i++) { this.removeRow(0); } distributionList.clear(); } @Override public boolean isCellEditable(int row, int column) { return (column == 3 && row < distributionList.size()); } @Override public Class getColumnClass(int columnIndex) { switch (columnIndex) { case 0: return Icon.class; case 1: return Boolean.class; default:return String.class; } } } private class CNAMETableModel extends DefaultTableModel { private static final long serialVersionUID = 7975150589167172506L; public CNAMETableModel() { super(new String[] {"CNAME Aliases"}, 0); } public void addCname(String cname) { this.addRow(new Object[] {cname}); } public String[] getCnames() { String[] cnames = new String[this.getRowCount()]; for (int i = 0; i < this.getRowCount(); i++) { cnames[i] = (String) this.getValueAt(i, 0); } return cnames; } public void removeAll() { int rowCount = this.getRowCount(); for (int i = 0; i < rowCount; i++) { this.removeRow(0); } } @Override public boolean isCellEditable(int row, int column) { return true; } } public void followHyperlink(URL url, String target) { } /** * TODO: Remove once testing is complete. * * @param args * @throws Exception */ public static void main(String[] args) throws Exception { JFrame testFrame = new JFrame("Test"); CloudFrontService cloudFrontService = new CloudFrontService(SamplesUtils.loadAWSCredentials()); S3Service s3Service = new RestS3Service(SamplesUtils.loadAWSCredentials()); S3Bucket[] buckets = s3Service.listAllBuckets(); String[] bucketNames = new String[buckets.length]; for (int i = 0; i < buckets.length; i++) { bucketNames[i] = buckets[i].getName(); } ManageDistributionsDialog.showDialog(testFrame, cloudFrontService, bucketNames, null); testFrame.dispose(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/ObjectsAttributesDialog.java0000644000000000000000000006501611427702124022511 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui; import java.awt.Dimension; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Iterator; import java.util.Map; import java.util.Set; import javax.swing.AbstractAction; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.DefaultTableModel; import org.jets3t.gui.skins.SkinsFactory; import org.jets3t.service.model.S3Object; /** * Dialog to display detailed information about one or more {@link S3Object}s, * and optionally to allow the objects metadata attributes to be modified. * * @author James Murty */ public class ObjectsAttributesDialog extends JDialog implements ActionListener { private static final long serialVersionUID = 7306510092130196820L; private GuiUtils guiUtils = new GuiUtils(); private SkinsFactory skinsFactory = null; private final Insets insetsZero = new Insets(0, 0, 0, 0); private final Insets insetsDefault = new Insets(5, 7, 5, 7); private final Insets insetsVerticalSpace = new Insets(5, 0, 5, 0); private final Insets insetsHorizontalSpace = new Insets(0, 7, 0, 7); private S3Object[] destinationObjects = null; private S3Object currentObject = null; private int currentObjectIndex = 0; private JTextField objectKeyTextField = null; private JTextField objectContentLengthTextField = null; private JTextField objectLastModifiedTextField = null; private JTextField objectETagTextField = null; private JTextField bucketLocationTextField = null; private JTextField storageClassTextField = null; private DefaultTableModel objectMetadataTableModel = null; private TableSorter metadataTableSorter = null; private JLabel ownerNameLabel = null; private JLabel ownerIdLabel = null; private JLabel currentObjectLabel = null; private JTable metadataTable = null; private JButton removeMetadataItemButton = null; private JButton addMetadataItemButton = null; private JButton previousObjectButton = null; private JButton nextObjectButton = null; private JButton okButton = null; private JButton cancelButton = null; private JPanel metadataButtonsContainer = null; private JPanel destinationPanel = null; private JPanel nextPreviousPanel = null; private JTextField ownerNameTextField = null; private JTextField ownerIdTextField = null; private boolean modifyMode = false; private boolean modifyActionApproved = false; /** * Construct a modal dialog to display the attributes for one or more objects. * * @param owner * the Frame over which the dialog will be displayed and centred. * @param title * a title for the dialog. * @param skinsFactory * factory for producing skinned GUI components. */ public ObjectsAttributesDialog(Frame owner, String title, SkinsFactory skinsFactory) { super(owner, title, true); this.skinsFactory = skinsFactory; this.initGui(); } /** * Display the dialog with data - always use this method instead of setVisible. * * @param objects * the S3 objects whose attributes will be displayed, and that may be modified. * @param modifyMode * if this parameter is true, the user will be able to modify object metadata * items. If false, the user will only be able to view object attributes and * will not be able to change the metadata. */ public void displayDialog(S3Object[] objects, boolean modifyMode) { this.currentObjectIndex = 0; this.modifyActionApproved = false; // Clone the objects provided. this.modifyMode = modifyMode; this.destinationObjects = new S3Object[objects.length]; for (int i = 0; i < objects.length; i++) { this.destinationObjects[i] = (S3Object) objects[i].clone(); } if (modifyMode) { okButton.setText("Modify Object" + (destinationObjects.length > 0 ? "s" : "")); cancelButton.setVisible(true); metadataButtonsContainer.setVisible(true); destinationPanel.setVisible(true); } else { okButton.setText("OK"); cancelButton.setVisible(false); metadataButtonsContainer.setVisible(false); destinationPanel.setVisible(false); } if (destinationObjects.length > 1) { nextPreviousPanel.setVisible(true); } else { nextPreviousPanel.setVisible(false); } displayObjectProperties(); int height = (isModifyMode() ? 450 : 400); if (objects.length > 1) { height += 30; } this.pack(); this.setSize(new Dimension(450, height)); this.setLocationRelativeTo(this.getOwner()); this.setVisible(true); } /** * Initialise the GUI elements to display the given item. */ private void initGui() { this.setResizable(true); this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); JPanel unmodifiableAttributesPanel = skinsFactory.createSkinnedJPanel("ObjectStaticAttributesPanel"); unmodifiableAttributesPanel.setLayout(new GridBagLayout()); JPanel metadataContainer = skinsFactory.createSkinnedJPanel("ObjectPropertiesMetadataPanel"); metadataContainer.setLayout(new GridBagLayout()); metadataButtonsContainer = skinsFactory.createSkinnedJPanel("ObjectPropertiesMetadataButtonsPanel"); metadataButtonsContainer.setLayout(new GridBagLayout()); // Fields to display unmodifiable object details. JLabel objectKeyLabel = skinsFactory.createSkinnedJHtmlLabel("ObjectKeyLabel"); objectKeyLabel.setText("Object key:"); objectKeyTextField = skinsFactory.createSkinnedJTextField("ObjectKeyTextField"); objectKeyTextField.setEditable(false); JLabel objectContentLengthLabel = skinsFactory.createSkinnedJHtmlLabel("ObjectContentLengthLabel"); objectContentLengthLabel.setText("Size:"); objectContentLengthTextField = skinsFactory.createSkinnedJTextField("ObjectContentLengthTextField"); objectContentLengthTextField.setEditable(false); JLabel objectLastModifiedLabel = skinsFactory.createSkinnedJHtmlLabel("ObjectLastModifiedLabel"); objectLastModifiedLabel.setText("Last modified:"); objectLastModifiedTextField = skinsFactory.createSkinnedJTextField("ObjectLastModifiedTextField"); objectLastModifiedTextField.setEditable(false); JLabel objectETagLabel = skinsFactory.createSkinnedJHtmlLabel("ObjectETagLabel"); objectETagLabel.setText("ETag:"); objectETagTextField = skinsFactory.createSkinnedJTextField("ObjectETagTextField"); objectETagTextField.setEditable(false); JLabel bucketNameLabel = skinsFactory.createSkinnedJHtmlLabel("BucketNameLabel"); bucketNameLabel.setText("Bucket:"); bucketLocationTextField = skinsFactory.createSkinnedJTextField("BucketLocationTextField"); bucketLocationTextField.setEditable(false); JLabel storageClassLabel = skinsFactory.createSkinnedJHtmlLabel("StorageClassLabel"); storageClassLabel.setText("Storage Class:"); storageClassTextField = skinsFactory.createSkinnedJTextField("StorageClassTextField"); storageClassTextField.setEditable(false); ownerNameLabel = skinsFactory.createSkinnedJHtmlLabel("OwnerNameLabel"); ownerNameLabel.setText("Owner name:"); ownerNameTextField = skinsFactory.createSkinnedJTextField("OwnerNameTextField"); ownerNameTextField.setEditable(false); ownerIdLabel = skinsFactory.createSkinnedJHtmlLabel("OwnerIdLabel"); ownerIdLabel.setText("Owner ID:"); ownerIdTextField = skinsFactory.createSkinnedJTextField("OwnerIdTextField"); ownerIdTextField.setEditable(false); Insets textFieldInsets = new Insets(2, 4, 2, 4); int row = 0; unmodifiableAttributesPanel.add(objectKeyLabel, new GridBagConstraints(0, row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, textFieldInsets, 0, 0)); unmodifiableAttributesPanel.add(objectKeyTextField, new GridBagConstraints(1, row, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, textFieldInsets, 0, 0)); row++; unmodifiableAttributesPanel.add(objectContentLengthLabel, new GridBagConstraints(0, row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, textFieldInsets, 0, 0)); unmodifiableAttributesPanel.add(objectContentLengthTextField, new GridBagConstraints(1, row, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, textFieldInsets, 0, 0)); row++; unmodifiableAttributesPanel.add(objectLastModifiedLabel, new GridBagConstraints(0, row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, textFieldInsets, 0, 0)); unmodifiableAttributesPanel.add(objectLastModifiedTextField, new GridBagConstraints(1, row, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, textFieldInsets, 0, 0)); row++; unmodifiableAttributesPanel.add(objectETagLabel, new GridBagConstraints(0, row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, textFieldInsets, 0, 0)); unmodifiableAttributesPanel.add(objectETagTextField, new GridBagConstraints(1, row, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, textFieldInsets, 0, 0)); row++; unmodifiableAttributesPanel.add(ownerNameLabel, new GridBagConstraints(0, row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, textFieldInsets, 0, 0)); unmodifiableAttributesPanel.add(ownerNameTextField, new GridBagConstraints(1, row, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, textFieldInsets, 0, 0)); row++; unmodifiableAttributesPanel.add(ownerIdLabel, new GridBagConstraints(0, row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, textFieldInsets, 0, 0)); unmodifiableAttributesPanel.add(ownerIdTextField, new GridBagConstraints(1, row, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, textFieldInsets, 0, 0)); row++; unmodifiableAttributesPanel.add(bucketNameLabel, new GridBagConstraints(0, row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, textFieldInsets, 0, 0)); unmodifiableAttributesPanel.add(bucketLocationTextField, new GridBagConstraints(1, row, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, textFieldInsets, 0, 0)); row++; unmodifiableAttributesPanel.add(storageClassLabel, new GridBagConstraints(0, row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, textFieldInsets, 0, 0)); unmodifiableAttributesPanel.add(storageClassTextField, new GridBagConstraints(1, row, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, textFieldInsets, 0, 0)); // Build metadata table. objectMetadataTableModel = new DefaultTableModel(new Object[] {"Name", "Value" }, 0) { private static final long serialVersionUID = -3762866886166776851L; public boolean isCellEditable(int row, int column) { return isModifyMode(); } }; metadataTableSorter = new TableSorter(objectMetadataTableModel); metadataTable = skinsFactory.createSkinnedJTable("MetadataTable"); metadataTable.setModel(metadataTableSorter); metadataTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { if (!e.getValueIsAdjusting() && removeMetadataItemButton != null) { int row = metadataTable.getSelectedRow(); removeMetadataItemButton.setEnabled(row >= 0); } } }); metadataTableSorter.setTableHeader(metadataTable.getTableHeader()); metadataTableSorter.setSortingStatus(0, TableSorter.ASCENDING); metadataContainer.add(new JScrollPane(metadataTable), new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsHorizontalSpace, 0, 0)); // Add/remove buttons for metadata table. removeMetadataItemButton = skinsFactory.createSkinnedJButton("ObjectPropertiesAddMetadataButton"); removeMetadataItemButton.setEnabled(false); removeMetadataItemButton.setToolTipText("Remove the selected metadata item(s)"); guiUtils.applyIcon(removeMetadataItemButton, "/images/nuvola/16x16/actions/viewmag-.png"); removeMetadataItemButton.addActionListener(this); removeMetadataItemButton.setActionCommand("removeMetadataItem"); addMetadataItemButton = skinsFactory.createSkinnedJButton("ObjectPropertiesAddMetadataButton"); addMetadataItemButton.setToolTipText("Add a new metadata item"); guiUtils.applyIcon(addMetadataItemButton, "/images/nuvola/16x16/actions/viewmag+.png"); addMetadataItemButton.setActionCommand("addMetadataItem"); addMetadataItemButton.addActionListener(this); metadataButtonsContainer.add(removeMetadataItemButton, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsZero, 0, 0)); metadataButtonsContainer.add(addMetadataItemButton, new GridBagConstraints(1, 0, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsZero, 0, 0)); metadataContainer.add(metadataButtonsContainer, new GridBagConstraints(0, 1, 1, 1, 1, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsHorizontalSpace, 0, 0)); metadataButtonsContainer.setVisible(false); // OK Button. okButton = skinsFactory.createSkinnedJButton("ObjectPropertiesOKButton"); okButton.setText("OK"); okButton.setActionCommand("OK"); okButton.addActionListener(this); // Cancel Button. cancelButton = null; cancelButton = skinsFactory.createSkinnedJButton("ObjectPropertiesCancelButton"); cancelButton.setText("Cancel"); cancelButton.setActionCommand("Cancel"); cancelButton.addActionListener(this); cancelButton.setVisible(false); // Recognize and handle ENTER, ESCAPE, PAGE_UP, and PAGE_DOWN key presses. this.getRootPane().setDefaultButton(okButton); this.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke("ESCAPE"), "ESCAPE"); this.getRootPane().getActionMap().put("ESCAPE", new AbstractAction() { private static final long serialVersionUID = -7768790936535999307L; public void actionPerformed(ActionEvent actionEvent) { setVisible(false); } }); this.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke("PAGE_UP"), "PAGE_UP"); this.getRootPane().getActionMap().put("PAGE_UP", new AbstractAction() { private static final long serialVersionUID = -6324229423705756219L; public void actionPerformed(ActionEvent actionEvent) { previousObjectButton.doClick(); } }); this.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke("PAGE_DOWN"), "PAGE_DOWN"); this.getRootPane().getActionMap().put("PAGE_DOWN", new AbstractAction() { private static final long serialVersionUID = -5808972377672449421L; public void actionPerformed(ActionEvent actionEvent) { nextObjectButton.doClick(); } }); // Put it all together. row = 0; JPanel container = skinsFactory.createSkinnedJPanel("ObjectPropertiesPanel"); container.setLayout(new GridBagLayout()); container.add(unmodifiableAttributesPanel, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsZero, 0, 0)); // Object previous and next buttons, if we have multiple objects. previousObjectButton = skinsFactory.createSkinnedJButton("ObjectPropertiesPreviousButton"); guiUtils.applyIcon(previousObjectButton, "/images/nuvola/16x16/actions/1leftarrow.png"); previousObjectButton.addActionListener(this); previousObjectButton.setEnabled(false); nextObjectButton = skinsFactory.createSkinnedJButton("ObjectPropertiesNextButton"); guiUtils.applyIcon(nextObjectButton, "/images/nuvola/16x16/actions/1rightarrow.png"); nextObjectButton.addActionListener(this); nextObjectButton.setEnabled(false); currentObjectLabel = skinsFactory.createSkinnedJHtmlLabel("ObjectPropertiesCurrentObjectLabel"); currentObjectLabel.setHorizontalAlignment(JLabel.CENTER); nextPreviousPanel = skinsFactory.createSkinnedJPanel("ObjectPropertiesNextPreviousPanel"); nextPreviousPanel.setLayout(new GridBagLayout()); nextPreviousPanel.add(previousObjectButton, new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsZero, 0, 0)); nextPreviousPanel.add(currentObjectLabel, new GridBagConstraints(1, 0, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsHorizontalSpace, 0, 0)); nextPreviousPanel.add(nextObjectButton, new GridBagConstraints(2, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsZero, 0, 0)); container.add(nextPreviousPanel, new GridBagConstraints(0, row, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsZero, 0, 0)); nextPreviousPanel.setVisible(false); row++; JHtmlLabel metadataLabel = skinsFactory.createSkinnedJHtmlLabel("MetadataLabel"); metadataLabel.setText("Metadata Attributes"); metadataLabel.setHorizontalAlignment(JLabel.CENTER); container.add(metadataLabel, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsVerticalSpace, 0, 0)); container.add(metadataContainer, new GridBagConstraints(0, row++, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsZero, 0, 0)); // Destination Access Control List setting. destinationPanel = skinsFactory.createSkinnedJPanel("DestinationPanel"); destinationPanel.setLayout(new GridBagLayout()); JPanel actionButtonsPanel = skinsFactory.createSkinnedJPanel("ObjectPropertiesActionButtonsPanel"); actionButtonsPanel.setLayout(new GridBagLayout()); actionButtonsPanel.add(cancelButton, new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsZero, 0, 0)); actionButtonsPanel.add(okButton, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsZero, 0, 0)); cancelButton.setVisible(false); container.add(actionButtonsPanel, new GridBagConstraints(0, row++, 3, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsDefault, 0, 0)); this.getContentPane().add(container); this.pack(); this.setSize(new Dimension(450, 500)); this.setLocationRelativeTo(this.getOwner()); } /** * Update the dialog to display the attributes of a single object. The user * may choose which object to display by iterating forward and back through * the set of objects. */ private void displayObjectProperties() { currentObject = destinationObjects[currentObjectIndex]; // Manage previous/next buttons. if (destinationObjects.length > 1) { currentObjectLabel.setText((currentObjectIndex + 1) + " of " + destinationObjects.length); previousObjectButton.setEnabled(currentObjectIndex > 0); nextObjectButton.setEnabled(currentObjectIndex < (destinationObjects.length -1)); } // Unmodifiable fields. objectKeyTextField.setText(currentObject.getKey()); objectContentLengthTextField.setText(String.valueOf(currentObject.getContentLength())); objectLastModifiedTextField.setText(String.valueOf(currentObject.getLastModifiedDate())); objectETagTextField.setText(currentObject.getETag()); bucketLocationTextField.setText(currentObject.getBucketName()); String storageClass = (currentObject.getStorageClass() != null ? currentObject.getStorageClass() : S3Object.STORAGE_CLASS_STANDARD); storageClassTextField.setText(storageClass); if (currentObject.getOwner() != null) { ownerNameLabel.setVisible(true); ownerNameTextField.setVisible(true); ownerIdLabel.setVisible(true); ownerIdTextField.setVisible(true); ownerNameTextField.setText(currentObject.getOwner().getDisplayName()); ownerIdTextField.setText(currentObject.getOwner().getId()); } else { ownerNameLabel.setVisible(false); ownerNameTextField.setVisible(false); ownerIdLabel.setVisible(false); ownerIdTextField.setVisible(false); } // Clear old table contents while (objectMetadataTableModel.getRowCount() > 0) { objectMetadataTableModel.removeRow(0); } // Display remaining metadata items in the table. Iterator mdIter = currentObject.getModifiableMetadata().entrySet().iterator(); while (mdIter.hasNext()) { Map.Entry entry = (Map.Entry) mdIter.next(); Object name = entry.getKey(); Object value = entry.getValue(); objectMetadataTableModel.addRow(new Object[] {name, value}); } } /** * Event handler for this dialog. */ public void actionPerformed(ActionEvent e) { // Force table to accept any partial edits. if (metadataTable.isEditing()) { metadataTable.getCellEditor().stopCellEditing(); } // Apply new/modified attributes to the object. Map currentObjectMetadata = currentObject.getModifiableMetadata(); Set obsoleteMetadataItems = currentObjectMetadata.keySet(); for (int row = 0; row < metadataTable.getRowCount(); row++) { String name = (String) objectMetadataTableModel.getValueAt(row, 0); String value = (String) objectMetadataTableModel.getValueAt(row, 1); currentObject.addMetadata(name, value); obsoleteMetadataItems.remove(name); } // Remove obsolete attributes. Iterator obsoleteNamesIter = obsoleteMetadataItems.iterator(); while (obsoleteNamesIter.hasNext()) { currentObject.removeMetadata((String) obsoleteNamesIter.next()); } if (e.getSource().equals(nextObjectButton)) { currentObjectIndex++; displayObjectProperties(); } else if (e.getSource().equals(previousObjectButton)) { currentObjectIndex--; displayObjectProperties(); } else if ("OK".equals(e.getActionCommand())) { modifyActionApproved = isModifyMode(); this.setVisible(false); } else if ("Cancel".equals(e.getActionCommand())) { modifyActionApproved = false; this.setVisible(false); } else if ("addMetadataItem".equals(e.getActionCommand())) { int newRowNumber = metadataTable.getRowCount() + 1; objectMetadataTableModel.addRow( new String[] {"name-" + newRowNumber, "value-" + newRowNumber}); } else if ("removeMetadataItem".equals(e.getActionCommand())) { int[] rows = metadataTable.getSelectedRows(); for (int i = rows.length - 1; i >= 0; i--) { int modelIndex = metadataTableSorter.modelIndex(rows[i]); objectMetadataTableModel.removeRow(modelIndex); } } } /** * @return * true if the dialog allows the user to modify object metadata. */ public boolean isModifyMode() { return modifyMode; } /** * @return * true if the user approved the dialog to indicate that objects should be * updated, false if the user cancelled the dialog. */ public boolean isModifyActionApproved() { return modifyActionApproved; } /** * @return * the original key names of the S3 objects that should be modified when * this dialog is accepted. Because objects are modified in-place, these * source key names will match the key names of the destination objects * available from the {@link #getDestinationObjects()} method. */ public String[] getSourceObjectKeys() { String[] sourceObjectKeys = new String[destinationObjects.length]; for (int i = 0; i < destinationObjects.length; i++) { sourceObjectKeys[i] = destinationObjects[i].getKey(); } return sourceObjectKeys; } /** * @return * objects containing updated metadata and Access Control List settings * provided by the user. When this dialog is approved, the S3 objects * should be updated in-place by copying over each object with an updated * version from this list. */ public S3Object[] getDestinationObjects() { if (!isModifyMode()) { return null; } return destinationObjects; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/GuiUtils.java0000644000000000000000000000756011427702124017476 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui; import java.awt.Frame; import java.net.URL; import java.util.HashMap; import java.util.Map; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JMenuItem; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.utils.RestUtils; /** * Utility methods for GUI-related tasks. * * @author James Murty */ public class GuiUtils { private static final Log log = LogFactory.getLog(GuiUtils.class); private Map cachedImageIcons = new HashMap(); /** * Loads an icon image from the classpath and sets the icon of the component. * * @param component * the component to apply the icon to, supported components are: JMenuItem, JButton, JLabel, Frame. * @param iconResourcePath * the path to an icon image in the classpath. * * @return * true if the icon was found and applied to the component */ public boolean applyIcon(Object component, String iconResourcePath) { ImageIcon icon = (ImageIcon) cachedImageIcons.get(iconResourcePath); if (icon == null) { // Icon is not yet cached, load it as a resource. URL iconUrl = this.getClass().getResource(iconResourcePath); if (iconUrl == null) { // Try loading icon using an encoded URL, which can help if the path uses characters // that should be URL-encoded (eg '+') try { int firstSlashIndex = iconResourcePath.indexOf('/', 1); String firstPathComponent = iconResourcePath.substring(0, firstSlashIndex); String pathRemainder = iconResourcePath.substring(firstSlashIndex); URL baseUrl = this.getClass().getResource(firstPathComponent); iconUrl = new URL(baseUrl.toString() + RestUtils.encodeUrlPath(pathRemainder, "/")); iconUrl.getContent(); // Check whether there is data availabel at the built path. } catch (Exception e) { log.warn("Unable to load icon with resource path: " + iconResourcePath); return false; } } if (iconUrl != null) { icon = new ImageIcon(iconUrl); cachedImageIcons.put(iconResourcePath, icon); } } if (icon != null) { if (component instanceof JMenuItem) { ((JMenuItem)component).setIcon(icon); } else if (component instanceof JButton) { ((JButton)component).setIcon(icon); } else if (component instanceof JLabel) { ((JLabel)component).setIcon(icon); } else if (component instanceof Frame) { ((Frame)component).setIconImage(icon.getImage()); } else { log.warn("Cannot set icon for unexpected JComponent object: " + component.getClass().getName()); return false; } return true; } else { log.warn("Unable to load icon with resource path: " + iconResourcePath); return false; } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/ItemPropertiesDialog.java0000644000000000000000000006727411441613550022034 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2007 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Properties; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.LookAndFeel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.table.DefaultTableModel; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.gui.skins.SkinsFactory; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.acl.GrantAndPermission; import org.jets3t.service.model.S3Bucket; import org.jets3t.service.model.S3Object; /** * Dialog to display detailed information about an {@link S3Bucket} or a set of {@link S3Object}s. * The item's details cannot be modified within this dialog. * * @author James Murty */ public class ItemPropertiesDialog extends JDialog implements ActionListener { private static final long serialVersionUID = 7921838316856638675L; private static final Log log = LogFactory.getLog(ItemPropertiesDialog.class); private Properties applicationProperties = null; private SkinsFactory skinsFactory = null; private final Insets insetsZero = new Insets(0, 0, 0, 0); private final Insets insetsDefault = new Insets(5, 7, 5, 7); private final Insets insetsVerticalSpace = new Insets(5, 0, 5, 0); private S3Object[] objects = null; private int currentObjectIndex = 0; private JTextField objectKeyTextField = null; private JTextField objectContentTypeTextField = null; private JTextField objectContentLengthTextField = null; private JTextField objectLastModifiedTextField = null; private JTextField objectETagTextField = null; private JTextField bucketNameTextField = null; private JTextField bucketLocationTextField = null; private DefaultTableModel objectMetadataTableModel = null; private JTable grantsTable = null; private DefaultTableModel grantsTableModel = null; private JLabel ownerNameLabel = null; private JLabel ownerIdLabel = null; private JLabel currentObjectLabel = null; private JButton previousObjectButton = null; private JButton nextObjectButton = null; private JPanel nextPreviousPanel = null; private JTextField ownerNameTextField = null; private JTextField ownerIdTextField = null; private JLabel bucketIsRequesterPaysLabel = null; private JCheckBox bucketIsRequesterPaysCheckBox = null; private JTextField bucketCreationDateTextField = null; private boolean includeMetadata = true; /** * Construct a modal dialog displaying details of a bucket or object. * * @param owner * the Frame over which the dialog will be displayed and centered * @param title * a title for the dialog * @param isObjectDialog * if true an object-specific dialog will be displayed, otherwise a bucket-specific dialog. */ protected ItemPropertiesDialog(Frame owner, String title, boolean isObjectDialog, Properties applicationProperties, boolean includeMetadata) { super(owner, title, true); this.applicationProperties = applicationProperties; this.includeMetadata = includeMetadata; this.initGui(isObjectDialog); } /** * Initialise the GUI elements to display the given item. * * @param s3Item * the S3Bucket or an S3Object whose details will be displayed */ private void initGui(boolean isObjectBased) { // Initialise skins factory. skinsFactory = SkinsFactory.getInstance(applicationProperties); // Set Skinned Look and Feel. LookAndFeel lookAndFeel = skinsFactory.createSkinnedMetalTheme("SkinnedLookAndFeel"); try { UIManager.setLookAndFeel(lookAndFeel); } catch (UnsupportedLookAndFeelException e) { log.error("Unable to set skinned LookAndFeel", e); } this.setResizable(true); this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); JPanel commonPropertiesContainer = skinsFactory.createSkinnedJPanel("ItemPropertiesCommonPanel"); commonPropertiesContainer.setLayout(new GridBagLayout()); JPanel metadataContainer = skinsFactory.createSkinnedJPanel("ItemPropertiesMetadataPanel"); metadataContainer.setLayout(new GridBagLayout()); JPanel grantsContainer = skinsFactory.createSkinnedJPanel("ItemPropertiesGrantsPanel"); grantsContainer.setLayout(new GridBagLayout()); if (!isObjectBased) { // Display bucket details. JLabel bucketNameLabel = skinsFactory.createSkinnedJHtmlLabel("BucketNameLabel"); bucketNameLabel.setText("Bucket name:"); bucketNameTextField = skinsFactory.createSkinnedJTextField("BucketNameTextField"); bucketNameTextField.setEditable(false); JLabel bucketLocationLabel = skinsFactory.createSkinnedJHtmlLabel("BucketLocationLabel"); bucketLocationLabel.setText("Location:"); bucketLocationTextField = skinsFactory.createSkinnedJTextField("BucketLocationTextField"); bucketLocationTextField.setEditable(false); JLabel bucketCreationDateLabel = skinsFactory.createSkinnedJHtmlLabel("BucketCreationDateLabel"); bucketCreationDateLabel.setText("Creation date:"); bucketCreationDateTextField = skinsFactory.createSkinnedJTextField("BucketCreationDateTextField"); bucketCreationDateTextField.setEditable(false); ownerNameLabel = skinsFactory.createSkinnedJHtmlLabel("OwnerNameLabel"); ownerNameLabel.setText("Owner name:"); ownerNameTextField = skinsFactory.createSkinnedJTextField("OwnerNameTextField"); ownerNameTextField.setEditable(false); ownerIdLabel = skinsFactory.createSkinnedJHtmlLabel("OwnerIdLabel"); ownerIdLabel.setText("Owner ID:"); ownerIdTextField = skinsFactory.createSkinnedJTextField("OwnerIdTextField"); ownerIdTextField.setEditable(false); bucketIsRequesterPaysLabel = skinsFactory.createSkinnedJHtmlLabel("BucketIsRequesterPaysLabel"); bucketIsRequesterPaysLabel.setText("Requester Pays?"); bucketIsRequesterPaysCheckBox = skinsFactory.createSkinnedJCheckBox("BucketIsRequesterPaysCheckBox"); bucketIsRequesterPaysCheckBox.setEnabled(false); int row = 0; commonPropertiesContainer.add(bucketNameLabel, new GridBagConstraints(0, row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); commonPropertiesContainer.add(bucketNameTextField, new GridBagConstraints(1, row, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); commonPropertiesContainer.add(bucketLocationLabel, new GridBagConstraints(0, ++row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); commonPropertiesContainer.add(bucketLocationTextField, new GridBagConstraints(1, row, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); commonPropertiesContainer.add(bucketCreationDateLabel, new GridBagConstraints(0, ++row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); commonPropertiesContainer.add(bucketCreationDateTextField, new GridBagConstraints(1, row, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); commonPropertiesContainer.add(bucketIsRequesterPaysLabel, new GridBagConstraints(0, ++row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); commonPropertiesContainer.add(bucketIsRequesterPaysCheckBox, new GridBagConstraints(1, row, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); commonPropertiesContainer.add(ownerNameLabel, new GridBagConstraints(0, ++row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); commonPropertiesContainer.add(ownerNameTextField, new GridBagConstraints(1, row, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); commonPropertiesContainer.add(ownerIdLabel, new GridBagConstraints(0, ++row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); commonPropertiesContainer.add(ownerIdTextField, new GridBagConstraints(1, row, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); } else { // Display object details. JLabel objectKeyLabel = skinsFactory.createSkinnedJHtmlLabel("ObjectKeyLabel"); objectKeyLabel.setText("Object key:"); objectKeyTextField = skinsFactory.createSkinnedJTextField("ObjectKeyTextField"); objectKeyTextField.setEditable(false); JLabel objectContentTypeLabel = skinsFactory.createSkinnedJHtmlLabel("ContentTypeLabel"); objectContentTypeLabel.setText("Content type:"); objectContentTypeTextField = skinsFactory.createSkinnedJTextField("ContentTypeTextField"); objectContentTypeTextField.setEditable(false); JLabel objectContentLengthLabel = skinsFactory.createSkinnedJHtmlLabel("ObjectContentLengthLabel"); objectContentLengthLabel.setText("Size:"); objectContentLengthTextField = skinsFactory.createSkinnedJTextField("ObjectContentLengthTextField"); objectContentLengthTextField.setEditable(false); JLabel objectLastModifiedLabel = skinsFactory.createSkinnedJHtmlLabel("ObjectLastModifiedLabel"); objectLastModifiedLabel.setText("Last modified:"); objectLastModifiedTextField = skinsFactory.createSkinnedJTextField("ObjectLastModifiedTextField"); objectLastModifiedTextField.setEditable(false); JLabel objectETagLabel = skinsFactory.createSkinnedJHtmlLabel("ObjectETagLabel"); objectETagLabel.setText("ETag:"); objectETagTextField = skinsFactory.createSkinnedJTextField("ObjectETagTextField"); objectETagTextField.setEditable(false); JLabel bucketNameLabel = skinsFactory.createSkinnedJHtmlLabel("BucketNameLabel"); bucketNameLabel.setText("Bucket name:"); bucketNameTextField = skinsFactory.createSkinnedJTextField("BucketNameTextField"); bucketNameTextField.setEditable(false); ownerNameLabel = skinsFactory.createSkinnedJHtmlLabel("OwnerNameLabel"); ownerNameLabel.setText("Owner name:"); ownerNameTextField = skinsFactory.createSkinnedJTextField("OwnerNameTextField"); ownerNameTextField.setEditable(false); ownerIdLabel = skinsFactory.createSkinnedJHtmlLabel("OwnerIdLabel"); ownerIdLabel.setText("Owner ID:"); ownerIdTextField = skinsFactory.createSkinnedJTextField("OwnerIdTextField"); ownerIdTextField.setEditable(false); commonPropertiesContainer.add(objectKeyLabel, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); commonPropertiesContainer.add(objectKeyTextField, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); commonPropertiesContainer.add(objectContentTypeLabel, new GridBagConstraints(0, 1, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); commonPropertiesContainer.add(objectContentTypeTextField, new GridBagConstraints(1, 1, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); commonPropertiesContainer.add(objectContentLengthLabel, new GridBagConstraints(0, 2, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); commonPropertiesContainer.add(objectContentLengthTextField, new GridBagConstraints(1, 2, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); commonPropertiesContainer.add(objectLastModifiedLabel, new GridBagConstraints(0, 3, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); commonPropertiesContainer.add(objectLastModifiedTextField, new GridBagConstraints(1, 3, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); commonPropertiesContainer.add(objectETagLabel, new GridBagConstraints(0, 4, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); commonPropertiesContainer.add(objectETagTextField, new GridBagConstraints(1, 4, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); commonPropertiesContainer.add(bucketNameLabel, new GridBagConstraints(0, 5, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); commonPropertiesContainer.add(bucketNameTextField, new GridBagConstraints(1, 5, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); commonPropertiesContainer.add(ownerNameLabel, new GridBagConstraints(0, 7, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); commonPropertiesContainer.add(ownerNameTextField, new GridBagConstraints(1, 7, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); commonPropertiesContainer.add(ownerIdLabel, new GridBagConstraints(0, 8, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); commonPropertiesContainer.add(ownerIdTextField, new GridBagConstraints(1, 8, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); // Build metadata table. objectMetadataTableModel = new DefaultTableModel(new Object[] {"Name", "Value" }, 0) { private static final long serialVersionUID = -3762866886166776851L; @Override public boolean isCellEditable(int row, int column) { return false; } }; TableSorter metadataTableSorter = new TableSorter(objectMetadataTableModel); JTable metadataTable = skinsFactory.createSkinnedJTable("MetadataTable"); metadataTable.setModel(metadataTableSorter); metadataTableSorter.setTableHeader(metadataTable.getTableHeader()); metadataContainer.add(new JScrollPane(metadataTable), new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); } // Build grants table. grantsTableModel = new DefaultTableModel(new Object[] {"Grantee", "Permission" }, 0) { private static final long serialVersionUID = -5882427163845726770L; @Override public boolean isCellEditable(int row, int column) { return false; } }; TableSorter grantsTableSorter = new TableSorter(grantsTableModel); grantsTable = skinsFactory.createSkinnedJTable("GrantsTable"); grantsTable.setModel(grantsTableSorter); grantsTableSorter.setTableHeader(grantsTable.getTableHeader()); grantsContainer.add(new JScrollPane(grantsTable), new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); // OK Button. JButton okButton = skinsFactory.createSkinnedJButton("ItemPropertiesOKButton"); okButton.setText("Finished"); okButton.setActionCommand("OK"); okButton.addActionListener(this); // Set default ENTER button. this.getRootPane().setDefaultButton(okButton); // Put it all together. int row = 0; JPanel container = skinsFactory.createSkinnedJPanel("ItemPropertiesPanel"); container.setLayout(new GridBagLayout()); container.add(commonPropertiesContainer, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsZero, 0, 0)); if (isObjectBased) { if (includeMetadata) { JHtmlLabel metadataLabel = skinsFactory.createSkinnedJHtmlLabel("MetadataLabel"); metadataLabel.setText("Metadata"); metadataLabel.setHorizontalAlignment(JLabel.CENTER); container.add(metadataLabel, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsVerticalSpace, 0, 0)); container.add(metadataContainer, new GridBagConstraints(0, row++, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsZero, 0, 0)); } // Object previous and next buttons, if we have multiple objects. previousObjectButton = skinsFactory.createSkinnedJButton("ItemPropertiesPreviousButton"); previousObjectButton.setText("Previous"); previousObjectButton.addActionListener(this); previousObjectButton.setEnabled(false); nextObjectButton = skinsFactory.createSkinnedJButton("ItemPropertiesNextButton"); nextObjectButton.setText("Next"); nextObjectButton.addActionListener(this); nextObjectButton.setEnabled(false); currentObjectLabel = skinsFactory.createSkinnedJHtmlLabel("ItemPropertiesCurrentObjectLabel"); currentObjectLabel.setHorizontalAlignment(JLabel.CENTER); nextPreviousPanel = skinsFactory.createSkinnedJPanel("ItemPropertiesNextPreviousPanel"); nextPreviousPanel.setLayout(new GridBagLayout()); nextPreviousPanel.add(previousObjectButton, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsZero, 0, 0)); nextPreviousPanel.add(currentObjectLabel, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsZero, 0, 0)); nextPreviousPanel.add(nextObjectButton, new GridBagConstraints(2, 0, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsZero, 0, 0)); container.add(nextPreviousPanel, new GridBagConstraints(0, row, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsZero, 0, 0)); row++; } else { JHtmlLabel grantsLabel = skinsFactory.createSkinnedJHtmlLabel("GrantsLabel"); grantsLabel.setText("Permissions"); grantsLabel.setHorizontalAlignment(JLabel.CENTER); container.add(grantsLabel, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsVerticalSpace, 0, 0)); container.add(grantsContainer, new GridBagConstraints(0, row++, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsZero, 0, 0)); } container.add(okButton, new GridBagConstraints(0, row++, 3, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsZero, 0, 0)); this.getContentPane().add(container); this.pack(); if (isObjectBased) { this.setSize(400, (includeMetadata ? 500 : 300)); } this.setLocationRelativeTo(this.getOwner()); } private void displayBucketProperties(S3Bucket bucket) { bucketNameTextField.setText(bucket.getName()); String location = "Unknown"; if (bucket.isLocationKnown()) { location = bucket.getLocation(); if (location == null) { location = "US"; } } bucketLocationTextField.setText(location); bucketCreationDateTextField.setText(String.valueOf(bucket.getCreationDate())); if (bucket.getOwner() != null) { ownerNameLabel.setVisible(true); ownerNameTextField.setVisible(true); ownerIdLabel.setVisible(true); ownerIdTextField.setVisible(true); ownerNameTextField.setText(bucket.getOwner().getDisplayName()); ownerIdTextField.setText(bucket.getOwner().getId()); } else { ownerNameLabel.setVisible(false); ownerNameTextField.setVisible(false); ownerIdLabel.setVisible(false); ownerIdTextField.setVisible(false); } if (bucket.getAcl() != null) { // Display grants table. grantsTable.setVisible(true); while (grantsTableModel.getRowCount() > 0) { grantsTableModel.removeRow(0); } AccessControlList acl = bucket.getAcl(); for (GrantAndPermission gap: acl.getGrantAndPermissions()) { grantsTableModel.addRow(new Object[] { gap.getGrantee().getIdentifier(), gap.getPermission().toString()}); } } else { grantsTable.setVisible(false); } if (bucket.isRequesterPaysKnown()) { bucketIsRequesterPaysLabel.setVisible(true); bucketIsRequesterPaysCheckBox.setVisible(true); bucketIsRequesterPaysCheckBox.setSelected(bucket.isRequesterPays()); } else { bucketIsRequesterPaysLabel.setVisible(false); bucketIsRequesterPaysCheckBox.setVisible(false); } this.pack(); this.setSize(this.getWidth(), 350); this.setLocationRelativeTo(this.getOwner()); } private void displayObjectsProperties(S3Object[] objects) { this.objects = objects; this.currentObjectIndex = 0; displayObjectProperties(); } private void displayObjectProperties() { S3Object object = objects[currentObjectIndex]; // Manage previous/next buttons. if (objects.length > 1) { nextPreviousPanel.setVisible(true); currentObjectLabel.setText((currentObjectIndex + 1) + " of " + objects.length); previousObjectButton.setEnabled(currentObjectIndex > 0); nextObjectButton.setEnabled(currentObjectIndex < (objects.length -1)); } else { nextPreviousPanel.setVisible(false); } objectKeyTextField.setText(object.getKey()); objectContentTypeTextField.setText(object.getContentType()); objectContentLengthTextField.setText(String.valueOf(object.getContentLength())); objectLastModifiedTextField.setText(String.valueOf(object.getLastModifiedDate())); objectETagTextField.setText(object.getETag()); bucketNameTextField.setText(object.getBucketName()); if (object.getOwner() != null) { ownerNameLabel.setVisible(true); ownerNameTextField.setVisible(true); ownerIdLabel.setVisible(true); ownerIdTextField.setVisible(true); ownerNameTextField.setText(object.getOwner().getDisplayName()); ownerIdTextField.setText(object.getOwner().getId()); } else { ownerNameLabel.setVisible(false); ownerNameTextField.setVisible(false); ownerIdLabel.setVisible(false); ownerIdTextField.setVisible(false); } // Clear old table contents while (objectMetadataTableModel.getRowCount() > 0) { objectMetadataTableModel.removeRow(0); } // Remove the metadata items already displayed, or not suitable for gui display. Map objectMetadata = new HashMap(object.getMetadataMap()); objectMetadata.remove(S3Object.METADATA_HEADER_CONTENT_LENGTH); objectMetadata.remove(S3Object.METADATA_HEADER_CONTENT_TYPE); objectMetadata.remove(S3Object.METADATA_HEADER_DATE); objectMetadata.remove(S3Object.METADATA_HEADER_ETAG); objectMetadata.remove(S3Object.METADATA_HEADER_LAST_MODIFIED_DATE); objectMetadata.remove("id-2"); // HTTP request-specific information objectMetadata.remove("request-id"); // HTTP request-specific information // Display remaining metadata items in the table. Iterator mdIter = objectMetadata.entrySet().iterator(); while (mdIter.hasNext()) { Map.Entry entry = (Map.Entry) mdIter.next(); Object name = entry.getKey(); Object value = entry.getValue(); objectMetadataTableModel.addRow(new Object[] {name, value}); } } /** * Displays a dialog showing the detailed properties of a bucket, which will remain until the user * dismisses the dialog. * * @param owner * the Frame over which the dialog will be displayed and centered * @param bucket the bucket whose details will be displayed */ public static void showDialog(Frame owner, S3Bucket bucket, Properties applicationProperties) { ItemPropertiesDialog dialog = new ItemPropertiesDialog(owner, "Bucket properties", false, applicationProperties, false); dialog.displayBucketProperties(bucket); dialog.setVisible(true); dialog.dispose(); } /** * Displays a dialog showing the detailed properties of an object, which will remain until the user * dismisses the dialog. * * @param owner * the Frame over which the dialog will be displayed and centered * @param objects * the object whose details will be displayed */ public static void showDialog(Frame owner, S3Object[] objects, Properties applicationProperties, boolean includeMetadata) { ItemPropertiesDialog dialog = new ItemPropertiesDialog(owner, "Object properties", true, applicationProperties,includeMetadata); dialog.displayObjectsProperties(objects); dialog.setVisible(true); dialog.dispose(); } /** * Event handler for this dialog. */ public void actionPerformed(ActionEvent e) { if (e.getSource().equals(nextObjectButton)) { currentObjectIndex++; displayObjectProperties(); } else if (e.getSource().equals(previousObjectButton)) { currentObjectIndex--; displayObjectProperties(); } else if ("OK".equals(e.getActionCommand())) { this.setVisible(false); } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/JHtmlLabel.java0000644000000000000000000001131211526133674017705 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui; import java.awt.Cursor; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.net.URL; import javax.swing.JLabel; import javax.swing.text.AttributeSet; import javax.swing.text.html.HTML; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Enhanced version of {@link JLabel} that changes the mouse curser to indicate when it passes over a * clickable HTML HREF link, and triggers a listener to follow the link when it is clicked. *

* This class is a modified version of example code authored by Jeffrey Bush:
* http://forum.java.sun.com/thread.jspa?threadID=574895&messageID=2866170. */ public class JHtmlLabel extends JLabel implements MouseListener, MouseMotionListener { private static final long serialVersionUID = -2146502207121434264L; private static final Log log = LogFactory.getLog(JHtmlLabel.class); private HyperlinkActivatedListener listener = null; /** * @param listener * a listener responsible for following an href link if it is triggered. */ public JHtmlLabel(HyperlinkActivatedListener listener) { this(null, listener); } /** * * @param htmlText * the html text to display in the label. This text doesn't necessarily have to be HTML, * but why would you use this control if it isn't? * @param listener * a listener responsible for following an href link if it is triggered. */ public JHtmlLabel(String htmlText, HyperlinkActivatedListener listener) { super(); if (htmlText != null) { this.setText(htmlText); } if (listener != null) { setHyperlinkeActivatedListener(listener); } addMouseListener(this); addMouseMotionListener(this); } public void setHyperlinkeActivatedListener(HyperlinkActivatedListener listener) { this.listener = listener; } /** * Triggers the listener to follow an HTML href link that has been clicked. * */ public void mouseClicked(MouseEvent e) { AccessibleJLabel acc = (AccessibleJLabel) getAccessibleContext(); int stringIndexAtPoint = acc.getIndexAtPoint(e.getPoint()); if (stringIndexAtPoint < 0) { return; } AttributeSet attr = (AttributeSet) acc.getCharacterAttribute( acc.getIndexAtPoint(e.getPoint())).getAttribute(HTML.Tag.A); if (attr != null) { String href = (String) attr.getAttribute(HTML.Attribute.HREF); String target = (String) attr.getAttribute(HTML.Attribute.TARGET); try { if (listener == null) { log.warn("No HyperlinkActivatedListener available to follow HTML link for label: " + getText()); } else { listener.followHyperlink(new URL(href), target); } } catch (Exception ex) { log.error("Unable to load URL: " + href, ex); } } } public void mousePressed(MouseEvent e) { } public void mouseReleased(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mouseDragged(MouseEvent e) { mouseMoved(e); } /** * Changes the mouse cursor to a hand to indicate when the mouse moves over a clickable * HTML link. */ public void mouseMoved(MouseEvent e) { AccessibleJLabel acc = (AccessibleJLabel) getAccessibleContext(); int stringIndexAtPoint = acc.getIndexAtPoint(e.getPoint()); if (stringIndexAtPoint < 0) { return; } javax.swing.text.AttributeSet attr = acc.getCharacterAttribute(stringIndexAtPoint); if (attr.getAttribute(HTML.Tag.A) == null) { setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } else { setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/AuthenticationDialog.java0000644000000000000000000001716011427702124022025 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui; import java.awt.Dialog; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.AbstractAction; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JTextField; import javax.swing.KeyStroke; /** * Dialog box for a user to enter authentication information for HTTP communication, such as * NT or Basic authentication. * * @author James Murty */ public class AuthenticationDialog extends JDialog implements ActionListener { private static final long serialVersionUID = -8112836668013270984L; private final Insets insetsDefault = new Insets(5, 7, 5, 7); private JTextField domainField = null; private JTextField usernameField = null; private JPasswordField passwordField = null; private boolean isNtAuthentication = false; private String domain = ""; private String user = ""; private String password = ""; /** * Construct modal dialog for display over a Frame. * * @param owner Frame over which this dialog will be displayed and centred. * @param title the dialog's title text * @param question the question/statement to prompt the user for their password, may be html * compatible with {@link JHtmlLabel} * @param isNtAuthentication if true a domain name is required in addition to the username and password. */ public AuthenticationDialog(Frame owner, String title, String question, boolean isNtAuthentication) { super(owner, title, true); this.isNtAuthentication = isNtAuthentication; initGui(question); } /** * Construct modal dialog for display over another Dialog. * * @param owner Dialog over which this dialog will be displayed and centred. * @param title the dialog's title text * @param question the question/statement to prompt the user for their password * @param isNtAuthentication if true a domain name is required in addition to the username and password. */ public AuthenticationDialog(Dialog owner, String title, String question, boolean isNtAuthentication) { super(owner, title, true); this.isNtAuthentication = isNtAuthentication; initGui(question); } /** * Initialises all GUI elements. * * @param question the question/statement to prompt the user for their password */ private void initGui(String question) { this.setResizable(false); this.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE); int rowIndex = 0; JPanel container = new JPanel(new GridBagLayout()); JHtmlLabel questionLabel = new JHtmlLabel(question, null); container.add(questionLabel, new GridBagConstraints(0, rowIndex++, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsDefault, 0, 0)); domainField = new JTextField(); usernameField = new JTextField(); passwordField = new JPasswordField(); if (isNtAuthentication) { container.add(new JLabel("Domain:"), new GridBagConstraints(0, rowIndex, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); container.add(domainField, new GridBagConstraints(1, rowIndex++, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); } container.add(new JLabel("User:"), new GridBagConstraints(0, rowIndex, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); container.add(usernameField, new GridBagConstraints(1, rowIndex++, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); container.add(new JLabel("Password:"), new GridBagConstraints(0, rowIndex, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); container.add(passwordField, new GridBagConstraints(1, rowIndex++, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); JPanel buttonsContainer = new JPanel(new GridBagLayout()); final JButton cancelButton = new JButton("Cancel"); cancelButton.setActionCommand("Cancel"); cancelButton.addActionListener(this); JButton okButton = new JButton("Authenticate me"); okButton.setActionCommand("OK"); okButton.setDefaultCapable(true); okButton.addActionListener(this); buttonsContainer.add(cancelButton, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsDefault, 0, 0)); buttonsContainer.add(okButton, new GridBagConstraints(1, 0, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsDefault, 0, 0)); container.add(buttonsContainer, new GridBagConstraints(0, rowIndex++, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsDefault, 0, 0)); // Set default ENTER and ESCAPE buttons. this.getRootPane().setDefaultButton(okButton); this.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke("ESCAPE"), "ESCAPE"); this.getRootPane().getActionMap().put("ESCAPE", new AbstractAction() { private static final long serialVersionUID = 3717631976908670386L; public void actionPerformed(ActionEvent actionEvent) { cancelButton.doClick(); } }); this.getContentPane().add(container); this.pack(); this.setLocationRelativeTo(this.getOwner()); } /** * Event handler for this dialog. */ public void actionPerformed(ActionEvent e) { if ("OK".equals(e.getActionCommand())) { if (isNtAuthentication) { this.domain = domainField.getText(); } this.user = usernameField.getText(); this.password = new String(passwordField.getPassword()); } else if ("Cancel".equals(e.getActionCommand())) { this.domain = ""; this.user = ""; this.password = ""; } this.setVisible(false); } /** * @return * the domain entered by the user, or null if the dialog was cancelled or NT authentication wasn't used. */ public String getDomain() { return domain; } /** * @return * the user name entered by the user, or null if the dialog was cancelled. */ public String getUser() { return user; } /** * @return * the password entered by the user, or null if the dialog was cancelled. */ public String getPassword() { return password; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/ProgressPanel.java0000644000000000000000000001351711427702124020514 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2007 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Properties; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.LookAndFeel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.gui.skins.SkinsFactory; import org.jets3t.service.multithread.CancelEventTrigger; /** * A panel that displays the progress of a task in a progress bar, and allows * the task to be cancelled. * * @author James Murty */ public class ProgressPanel extends JPanel implements ActionListener { private static final long serialVersionUID = 7880101403853417240L; private static final Log log = LogFactory.getLog(ProgressPanel.class); private final Insets insetsDefault = new Insets(5, 2, 5, 2); private final GuiUtils guiUtils = new GuiUtils(); private Properties applicationProperties = null; private SkinsFactory skinsFactory = null; private JLabel statusMessageLabel = null; private JProgressBar progressBar = null; private JButton cancelButton = null; private CancelEventTrigger cancelEventTrigger = null; public ProgressPanel(Properties applicationProperties, CancelEventTrigger cancelEventTrigger) { super(); this.applicationProperties = applicationProperties; this.cancelEventTrigger = cancelEventTrigger; initGui(); } private void initGui() { // Initialise skins factory. skinsFactory = SkinsFactory.getInstance(applicationProperties); // Set Skinned Look and Feel. LookAndFeel lookAndFeel = skinsFactory.createSkinnedMetalTheme("SkinnedLookAndFeel"); try { UIManager.setLookAndFeel(lookAndFeel); } catch (UnsupportedLookAndFeelException e) { log.error("Unable to set skinned LookAndFeel", e); } this.setLayout(new GridBagLayout()); statusMessageLabel = skinsFactory.createSkinnedJHtmlLabel("ProgressPanelStatusMessageLabel"); statusMessageLabel.setText(" "); statusMessageLabel.setHorizontalAlignment(JLabel.CENTER); this.add(statusMessageLabel, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); progressBar = skinsFactory.createSkinnedJProgressBar("ProgressPanelProgressBar", 0, 100); this.add(progressBar, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); // Display the cancel button if a cancel event listener is available. cancelButton = skinsFactory.createSkinnedJButton("ProgressPanelCancelButton"); guiUtils.applyIcon(cancelButton, "/images/nuvola/16x16/actions/cancel.png"); cancelButton.setActionCommand("Cancel"); cancelButton.addActionListener(this); cancelButton.setEnabled(cancelEventTrigger != null); this.add(cancelButton, new GridBagConstraints(2, 0, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); } public void actionPerformed(ActionEvent e) { if ("Cancel".equals(e.getActionCommand())) { cancelButton.setEnabled(false); if (cancelEventTrigger != null) { cancelEventTrigger.cancelTask(this); } } } public void dispose() { // Progress bar must be set to it's maximum value or it won't clean itself up properly. progressBar.setIndeterminate(false); progressBar.setValue(progressBar.getMaximum()); } /** * Displays the progress dialog. * * @param statusMessage * describes the status of a task text meaningful to the user, such as "3 files of 7 uploaded" * @param minTaskValue * the minimum progress value for a task, generally 0 * @param maxTaskValue * the maximum progress value for a task, such as the total number of threads or 100 if * using percentage-complete as a metric. */ public void startProgress(String statusMessage, int minTaskValue, int maxTaskValue) { if (maxTaskValue > minTaskValue) { progressBar.setStringPainted(true); progressBar.setMinimum(minTaskValue); progressBar.setMaximum(maxTaskValue); progressBar.setValue(minTaskValue); progressBar.setIndeterminate(false); } else { progressBar.setStringPainted(false); progressBar.setMinimum(0); progressBar.setMaximum(0); progressBar.setValue(0); progressBar.setIndeterminate(true); } statusMessageLabel.setText(statusMessage); } public void updateProgress(String statusMessage, int progressValue) { statusMessageLabel.setText(statusMessage); if (!progressBar.isIndeterminate()) { progressBar.setValue(progressValue); } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/TableSorter.java0000644000000000000000000004432011335606550020156 0ustar /* * Copyright (c) 1995 - 2008 Sun Microsystems, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of Sun Microsystems nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.jets3t.gui; import java.awt.*; import java.awt.event.*; import java.util.*; import java.util.List; import javax.swing.*; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.*; /** * TableSorter is a decorator for TableModels; adding sorting functionality to a supplied * TableModel. TableSorter does not store or copy the data in its TableModel; instead it maintains a * map from the row indexes of the view to the row indexes of the model. As requests are made of the * sorter (like getValueAt(row, col)) they are passed to the underlying model after the row numbers * have been translated via the internal mapping array. This way, the TableSorter appears to hold * another copy of the table with the rows in a different order.

TableSorter registers itself * as a listener to the underlying model, just as the JTable itself would. Events recieved from the * model are examined, sometimes manipulated (typically widened), and then passed on to the * TableSorter's listeners (typically the JTable). If a change to the model has invalidated the * order of TableSorter's rows, a note of this is made and the sorter will resort the rows the next * time a value is requested.

When the tableHeader property is set, either by using the * setTableHeader() method or the two argument constructor, the table header may be used as a * complete UI for TableSorter. The default renderer of the tableHeader is decorated with a renderer * that indicates the sorting status of each column. In addition, a mouse listener is installed with * the following behavior: *

    *
  • Mouse-click: Clears the sorting status of all other columns and advances the sorting status * of that column through three values: {NOT_SORTED, ASCENDING, DESCENDING} (then back to NOT_SORTED * again). *
  • SHIFT-mouse-click: Clears the sorting status of all other columns and cycles the sorting * status of the column through the same three values, in the opposite order: {NOT_SORTED, * DESCENDING, ASCENDING}. *
  • CONTROL-mouse-click and CONTROL-SHIFT-mouse-click: as above except that the changes to the * column do not cancel the statuses of columns that are already sorting - giving a way to initiate * a compound sort. *
*

This is a long overdue rewrite of a class of the same name that first appeared in the swing * table demos in 1997. * * @author Philip Milne * @author Brendon McLean * @author Dan van Enckevort * @author Parwinder Sekhon * @version 2.0 02/27/04 */ public class TableSorter extends AbstractTableModel { protected TableModel tableModel; public static final int DESCENDING = -1; public static final int NOT_SORTED = 0; public static final int ASCENDING = 1; private static Directive EMPTY_DIRECTIVE = new Directive(-1, NOT_SORTED); public static final Comparator COMPARABLE_COMAPRATOR = new Comparator() { public int compare(Object o1, Object o2) { return ((Comparable) o1).compareTo(o2); } }; public static final Comparator LEXICAL_COMPARATOR = new Comparator() { public int compare(Object o1, Object o2) { return o1.toString().compareTo(o2.toString()); } }; private Row[] viewToModel; private int[] modelToView; private JTableHeader tableHeader; private MouseListener mouseListener; private TableModelListener tableModelListener; private Map columnComparators = new HashMap(); private List sortingColumns = new ArrayList(); public TableSorter() { this.mouseListener = new MouseHandler(); this.tableModelListener = new TableModelHandler(); } public TableSorter(TableModel tableModel) { this(); setTableModel(tableModel); } public TableSorter(TableModel tableModel, JTableHeader tableHeader) { this(); setTableHeader(tableHeader); setTableModel(tableModel); } private void clearSortingState() { viewToModel = null; modelToView = null; } public TableModel getTableModel() { return tableModel; } public void setTableModel(TableModel tableModel) { if (this.tableModel != null) { this.tableModel.removeTableModelListener(tableModelListener); } this.tableModel = tableModel; if (this.tableModel != null) { this.tableModel.addTableModelListener(tableModelListener); } clearSortingState(); fireTableStructureChanged(); } public JTableHeader getTableHeader() { return tableHeader; } public void setTableHeader(JTableHeader tableHeader) { if (this.tableHeader != null) { this.tableHeader.removeMouseListener(mouseListener); TableCellRenderer defaultRenderer = this.tableHeader.getDefaultRenderer(); if (defaultRenderer instanceof SortableHeaderRenderer) { this.tableHeader .setDefaultRenderer(((SortableHeaderRenderer) defaultRenderer).tableCellRenderer); } } this.tableHeader = tableHeader; if (this.tableHeader != null) { this.tableHeader.addMouseListener(mouseListener); this.tableHeader.setDefaultRenderer(new SortableHeaderRenderer(this.tableHeader .getDefaultRenderer())); } } public boolean isSorting() { return sortingColumns.size() != 0; } private Directive getDirective(int column) { for (int i = 0; i < sortingColumns.size(); i++) { Directive directive = (Directive) sortingColumns.get(i); if (directive.column == column) { return directive; } } return EMPTY_DIRECTIVE; } public int getSortingStatus(int column) { return getDirective(column).direction; } private void sortingStatusChanged() { clearSortingState(); fireTableDataChanged(); if (tableHeader != null) { tableHeader.repaint(); } } public void setSortingStatus(int column, int status) { Directive directive = getDirective(column); if (directive != EMPTY_DIRECTIVE) { sortingColumns.remove(directive); } if (status != NOT_SORTED) { sortingColumns.add(new Directive(column, status)); } sortingStatusChanged(); } protected Icon getHeaderRendererIcon(int column, int size) { Directive directive = getDirective(column); if (directive == EMPTY_DIRECTIVE) { return null; } return new Arrow(directive.direction == DESCENDING, size, sortingColumns.indexOf(directive)); } private void cancelSorting() { sortingColumns.clear(); sortingStatusChanged(); } public void setColumnComparator(Class type, Comparator comparator) { if (comparator == null) { columnComparators.remove(type); } else { columnComparators.put(type, comparator); } } protected Comparator getComparator(int column) { Class columnType = tableModel.getColumnClass(column); Comparator comparator = (Comparator) columnComparators.get(columnType); if (comparator != null) { return comparator; } if (Comparable.class.isAssignableFrom(columnType)) { return COMPARABLE_COMAPRATOR; } return LEXICAL_COMPARATOR; } private Row[] getViewToModel() { if (viewToModel == null) { int tableModelRowCount = tableModel.getRowCount(); viewToModel = new Row[tableModelRowCount]; for (int row = 0; row < tableModelRowCount; row++) { viewToModel[row] = new Row(row); } if (isSorting()) { Arrays.sort(viewToModel); } } return viewToModel; } public int modelIndex(int viewIndex) { return getViewToModel()[viewIndex].modelIndex; } public int viewIndex(int modelIndex) { return getModelToView()[modelIndex]; } private int[] getModelToView() { if (modelToView == null) { int n = getViewToModel().length; modelToView = new int[n]; for (int i = 0; i < n; i++) { modelToView[modelIndex(i)] = i; } } return modelToView; } // TableModel interface methods public int getRowCount() { return (tableModel == null) ? 0 : tableModel.getRowCount(); } public int getColumnCount() { return (tableModel == null) ? 0 : tableModel.getColumnCount(); } public String getColumnName(int column) { return tableModel.getColumnName(column); } public Class getColumnClass(int column) { return tableModel.getColumnClass(column); } public boolean isCellEditable(int row, int column) { return tableModel.isCellEditable(modelIndex(row), column); } public Object getValueAt(int row, int column) { return tableModel.getValueAt(modelIndex(row), column); } public void setValueAt(Object aValue, int row, int column) { tableModel.setValueAt(aValue, modelIndex(row), column); } // Helper classes private class Row implements Comparable { private int modelIndex; public Row(int index) { this.modelIndex = index; } public int compareTo(Object o) { int row1 = modelIndex; int row2 = ((Row) o).modelIndex; for (Iterator it = sortingColumns.iterator(); it.hasNext();) { Directive directive = (Directive) it.next(); int column = directive.column; Object o1 = tableModel.getValueAt(row1, column); Object o2 = tableModel.getValueAt(row2, column); int comparison = 0; // Define null less than everything, except null. if (o1 == null && o2 == null) { comparison = 0; } else if (o1 == null) { comparison = -1; } else if (o2 == null) { comparison = 1; } else { comparison = getComparator(column).compare(o1, o2); } if (comparison != 0) { return directive.direction == DESCENDING ? -comparison : comparison; } } return 0; } } private class TableModelHandler implements TableModelListener { public void tableChanged(TableModelEvent e) { // If we're not sorting by anything, just pass the event along. if (!isSorting()) { clearSortingState(); fireTableChanged(e); return; } // If the table structure has changed, cancel the sorting; the // sorting columns may have been either moved or deleted from // the model. if (e.getFirstRow() == TableModelEvent.HEADER_ROW) { cancelSorting(); fireTableChanged(e); return; } // We can map a cell event through to the view without widening // when the following conditions apply: // // a) all the changes are on one row (e.getFirstRow() == e.getLastRow()) and, // b) all the changes are in one column (column != TableModelEvent.ALL_COLUMNS) and, // c) we are not sorting on that column (getSortingStatus(column) == NOT_SORTED) and, // d) a reverse lookup will not trigger a sort (modelToView != null) // // Note: INSERT and DELETE events fail this test as they have column == ALL_COLUMNS. // // The last check, for (modelToView != null) is to see if modelToView // is already allocated. If we don't do this check; sorting can become // a performance bottleneck for applications where cells // change rapidly in different parts of the table. If cells // change alternately in the sorting column and then outside of // it this class can end up re-sorting on alternate cell updates - // which can be a performance problem for large tables. The last // clause avoids this problem. int column = e.getColumn(); if (e.getFirstRow() == e.getLastRow() && column != TableModelEvent.ALL_COLUMNS && getSortingStatus(column) == NOT_SORTED && modelToView != null) { int viewIndex = getModelToView()[e.getFirstRow()]; fireTableChanged(new TableModelEvent(TableSorter.this, viewIndex, viewIndex, column, e.getType())); return; } // Something has happened to the data that may have invalidated the row order. clearSortingState(); fireTableDataChanged(); return; } } private class MouseHandler extends MouseAdapter { public void mouseClicked(MouseEvent e) { JTableHeader h = (JTableHeader) e.getSource(); TableColumnModel columnModel = h.getColumnModel(); int viewColumn = columnModel.getColumnIndexAtX(e.getX()); int column = columnModel.getColumn(viewColumn).getModelIndex(); if (column != -1) { int status = getSortingStatus(column); if (!e.isControlDown()) { cancelSorting(); } // Cycle the sorting states through {NOT_SORTED, ASCENDING, DESCENDING} or // {NOT_SORTED, DESCENDING, ASCENDING} depending on whether shift is pressed. status = status + (e.isShiftDown() ? -1 : 1); status = (status + 4) % 3 - 1; // signed mod, returning {-1, 0, 1} setSortingStatus(column, status); } } } private static class Arrow implements Icon { private boolean descending; private int size; private int priority; public Arrow(boolean descending, int size, int priority) { this.descending = descending; this.size = size; this.priority = priority; } public void paintIcon(Component c, Graphics g, int x, int y) { Color color = c == null ? Color.GRAY : c.getBackground(); // In a compound sort, make each succesive triangle 20% // smaller than the previous one. int dx = (int) (size / 2 * Math.pow(0.8, priority)); int dy = descending ? dx : -dx; // Align icon (roughly) with font baseline. y = y + 5 * size / 6 + (descending ? -dy : 0); int shift = descending ? 1 : -1; g.translate(x, y); // Right diagonal. g.setColor(color.darker()); g.drawLine(dx / 2, dy, 0, 0); g.drawLine(dx / 2, dy + shift, 0, shift); // Left diagonal. g.setColor(color.brighter()); g.drawLine(dx / 2, dy, dx, 0); g.drawLine(dx / 2, dy + shift, dx, shift); // Horizontal line. if (descending) { g.setColor(color.darker().darker()); } else { g.setColor(color.brighter().brighter()); } g.drawLine(dx, 0, 0, 0); g.setColor(color); g.translate(-x, -y); } public int getIconWidth() { return size; } public int getIconHeight() { return size; } } private class SortableHeaderRenderer implements TableCellRenderer { private TableCellRenderer tableCellRenderer; public SortableHeaderRenderer(TableCellRenderer tableCellRenderer) { this.tableCellRenderer = tableCellRenderer; } public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Component c = tableCellRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); if (c instanceof JLabel) { JLabel l = (JLabel) c; l.setHorizontalTextPosition(JLabel.LEFT); int modelColumn = table.convertColumnIndexToModel(column); l.setIcon(getHeaderRendererIcon(modelColumn, l.getFont().getSize())); } return c; } } private static class Directive { private int column; private int direction; public Directive(int column, int direction) { this.column = column; this.direction = direction; } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/gui/UserInputFields.java0000644000000000000000000003433111526136054021015 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.gui; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Properties; import java.util.StringTokenizer; import javax.swing.ButtonGroup; import javax.swing.JComboBox; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.gui.skins.SkinsFactory; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.utils.ServiceUtils; /** * Utility class to manage User Inputs by representing the possible user input fields as GUI * elements, providing the panel that contains these GUI elements, and providing the user's inputs * into the GUI items as properties. * * @author James Murty */ public class UserInputFields { private static final Log log = LogFactory.getLog(UserInputFields.class); private Insets insetsDefault = null; private HyperlinkActivatedListener hyperlinkListener = null; private SkinsFactory skinsFactory = null; private Insets insetsNone = new Insets(0, 0, 0, 0); private Map userInputComponentsMap = new HashMap(); /** * Constructs the object ready to generate GUI elements to represent the configured * user input fields. * * @param defaultInsets * the default insets to use when displaying the GUI elements. * @param hyperlinkListener * a class to listen for hyperlink click events that may be generated by {@link JHtmlLabel}. * This class may be null, in which case these events will be ignored. * @param skinsFactory * the skin factory used to create GUI elements. */ public UserInputFields(Insets defaultInsets, HyperlinkActivatedListener hyperlinkListener, SkinsFactory skinsFactory) { this.insetsDefault = defaultInsets; this.hyperlinkListener = hyperlinkListener; this.skinsFactory = skinsFactory; } /** * Builds a user input panel matching the fields specified in the uploader.properties file. * * @param fieldsPanel * the panel component to add prompt and user input components to. * @param uploaderProperties * properties specific to the Uploader application that includes the field.* settings * necessary to build the User Inputs screen. * * @return * true if there is at least one valid user input field, false otherwise. */ public boolean buildFieldsPanel(JPanel fieldsPanel, Jets3tProperties uploaderProperties) { int fieldIndex = 0; for (int fieldNo = 0; fieldNo < 100; fieldNo++) { String fieldName = uploaderProperties.getStringProperty("field." + fieldNo + ".name", null); String fieldType = uploaderProperties.getStringProperty("field." + fieldNo + ".type", null); String fieldPrompt = uploaderProperties.getStringProperty("field." + fieldNo + ".prompt", null); String fieldOptions = uploaderProperties.getStringProperty("field." + fieldNo + ".options", null); String fieldDefault = uploaderProperties.getStringProperty("field." + fieldNo + ".default", null); if (fieldName == null) { log.debug("No field with index number " + fieldNo); continue; } else { if (fieldType == null || fieldPrompt == null) { log.warn("Field '" + fieldName + "' missing .type or .prompt properties"); continue; } if ("message".equals(fieldType)) { JHtmlLabel label = skinsFactory.createSkinnedJHtmlLabel(fieldName); label.setText(fieldPrompt); label.setHyperlinkeActivatedListener(hyperlinkListener); fieldsPanel.add(label, new GridBagConstraints(0, fieldIndex++, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); } else if ("radio".equals(fieldType)) { if (fieldOptions == null) { log.warn("Radio button field '" + fieldName + "' is missing the required .options property"); continue; } JHtmlLabel label = skinsFactory.createSkinnedJHtmlLabel(fieldName); label.setText(fieldPrompt); label.setHyperlinkeActivatedListener(hyperlinkListener); fieldsPanel.add(label, new GridBagConstraints(0, fieldIndex++, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); JPanel optionsPanel = skinsFactory.createSkinnedJPanel("OptionsPanel"); optionsPanel.setLayout(new GridBagLayout()); int columnOffset = 0; ButtonGroup buttonGroup = new ButtonGroup(); StringTokenizer st = new StringTokenizer(fieldOptions, ","); while (st.hasMoreTokens()) { String option = st.nextToken(); JRadioButton radioButton = skinsFactory.createSkinnedJRadioButton(fieldName); radioButton.setText(option); buttonGroup.add(radioButton); if (fieldDefault != null && fieldDefault.equals(option)) { // This option is the default one. radioButton.setSelected(true); } else if (buttonGroup.getButtonCount() == 1) { // Make first button the default. radioButton.setSelected(true); } optionsPanel.add(radioButton, new GridBagConstraints(columnOffset++, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); } fieldsPanel.add(optionsPanel, new GridBagConstraints(0, fieldIndex++, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsNone, 0, 0)); userInputComponentsMap.put(fieldName, buttonGroup); } else if ("selection".equals(fieldType)) { if (fieldOptions == null) { log.warn("Radio button field '" + fieldName + "' is missing the required .options property"); continue; } JHtmlLabel label = skinsFactory.createSkinnedJHtmlLabel(fieldName); label.setText(fieldPrompt); label.setHyperlinkeActivatedListener(hyperlinkListener); fieldsPanel.add(label, new GridBagConstraints(0, fieldIndex++, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); JComboBox comboBox = skinsFactory.createSkinnedJComboBox(fieldName); StringTokenizer st = new StringTokenizer(fieldOptions, ","); while (st.hasMoreTokens()) { String option = st.nextToken(); comboBox.addItem(option); } if (fieldDefault != null) { comboBox.setSelectedItem(fieldDefault); } fieldsPanel.add(comboBox, new GridBagConstraints(0, fieldIndex++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); userInputComponentsMap.put(fieldName, comboBox); } else if ("text".equals(fieldType)) { JHtmlLabel label = skinsFactory.createSkinnedJHtmlLabel(fieldName); label.setText(fieldPrompt); label.setHyperlinkeActivatedListener(hyperlinkListener); fieldsPanel.add(label, new GridBagConstraints(0, fieldIndex++, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); JTextField textField = skinsFactory.createSkinnedJTextField(fieldName); if (fieldDefault != null) { textField.setText(fieldDefault); } fieldsPanel.add(textField, new GridBagConstraints(0, fieldIndex++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); userInputComponentsMap.put(fieldName, textField); } else if ("password".equals(fieldType)) { JHtmlLabel label = skinsFactory.createSkinnedJHtmlLabel(fieldName); label.setText(fieldPrompt); label.setHyperlinkeActivatedListener(hyperlinkListener); fieldsPanel.add(label, new GridBagConstraints(0, fieldIndex++, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); JPasswordField passwordField = skinsFactory.createSkinnedJPasswordField(fieldName); if (fieldDefault != null) { passwordField.setText(fieldDefault); } fieldsPanel.add(passwordField, new GridBagConstraints(0, fieldIndex++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); userInputComponentsMap.put(fieldName, passwordField); } else if (fieldType.equals("textarea")) { JHtmlLabel label = skinsFactory.createSkinnedJHtmlLabel(fieldName); label.setText(fieldPrompt); label.setHyperlinkeActivatedListener(hyperlinkListener); fieldsPanel.add(label, new GridBagConstraints(0, fieldIndex++, 2, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); JTextArea textArea = skinsFactory.createSkinnedJTextArea(fieldName); textArea.setLineWrap(true); if (fieldDefault != null) { textArea.setText(fieldDefault); } JScrollPane scrollPane = skinsFactory.createSkinnedJScrollPane(fieldName); scrollPane.setViewportView(textArea); fieldsPanel.add(scrollPane, new GridBagConstraints(0, fieldIndex++, 2, 1, 1, 1, GridBagConstraints.WEST, GridBagConstraints.BOTH, insetsDefault, 0, 0)); userInputComponentsMap.put(fieldName, textArea); } else { log.warn("Unrecognised .type setting for field '" + fieldName + "'"); } } } return isUserInputFieldsAvailable(); } /** * * * @return * properties containing the user's answers to the input fields. Property names correspond to * the field's name, and the property values are the user's response. */ public Properties getUserInputsAsProperties(boolean hashPasswords) { Properties properties = new Properties(); for (Iterator iter = userInputComponentsMap.keySet().iterator(); iter.hasNext();) { String fieldName = (String) iter.next(); String fieldValue = null; Object component = userInputComponentsMap.get(fieldName); if (component instanceof ButtonGroup) { ButtonGroup bg = (ButtonGroup) component; Enumeration radioEnum = bg.getElements(); while (radioEnum.hasMoreElements()) { JRadioButton button = (JRadioButton) radioEnum.nextElement(); if (button.isSelected()) { fieldValue = button.getText(); break; } } } else if (component instanceof JComboBox) { fieldValue = ((JComboBox) component).getSelectedItem().toString(); } else if (component instanceof JPasswordField) { if (hashPasswords) { String password = new String(((JPasswordField) component).getPassword()); try { fieldValue = ServiceUtils.toHex( ServiceUtils.computeMD5Hash(password.getBytes(Constants.DEFAULT_ENCODING))); } catch (Exception e) { log.error("Unable to generate hash of password for field named '" + fieldName + "'", e); } } else { fieldValue = new String(((JPasswordField) component).getPassword()); } } else if (component instanceof JTextField) { fieldValue = ((JTextField) component).getText(); } else if (component instanceof JTextArea) { fieldValue = ((JTextArea) component).getText(); } else { log.warn("Unrecognised component type for field named '" + fieldName + "': " + component.getClass().getName()); } properties.put(fieldName, fieldValue); } return properties; } public boolean isUserInputFieldsAvailable() { return userInputComponentsMap.size() > 0; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/tests/0002755000000000000000000000000011550421156015436 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/tests/TestGoogleStorageService.java0000644000000000000000000000407511452163452023232 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.tests; import org.jets3t.service.ServiceException; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.acl.gs.GSAccessControlList; import org.jets3t.service.impl.rest.httpclient.GoogleStorageService; import org.jets3t.service.impl.rest.httpclient.RestStorageService; import org.jets3t.service.security.GSCredentials; import org.jets3t.service.security.ProviderCredentials; /** * Test cases specific to general S3 compatibility -- that is, features supported by * both S3 and Google Storage. * * @author James Murty */ public class TestGoogleStorageService extends BaseStorageServiceTests { public TestGoogleStorageService() throws Exception { super(); } @Override protected String getTargetService() { return TARGET_SERVICE_GS; } @Override protected ProviderCredentials getCredentials() { return new GSCredentials( testProperties.getProperty("gsservice.accesskey"), testProperties.getProperty("gsservice.secretkey")); } @Override protected RestStorageService getStorageService(ProviderCredentials credentials) throws ServiceException { return new GoogleStorageService(credentials); } @Override protected AccessControlList buildAccessControlList() { return new GSAccessControlList(); } /* * Features specific to Google Storage */ } jets3t-0.8.1+dfsg.orig/src/org/jets3t/tests/TestRestS3Service.java0000644000000000000000000010525611537563564021633 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.tests; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.methods.GetMethod; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.S3Service; import org.jets3t.service.S3ServiceException; import org.jets3t.service.ServiceException; import org.jets3t.service.StorageService; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.acl.GrantAndPermission; import org.jets3t.service.acl.GroupGrantee; import org.jets3t.service.acl.Permission; import org.jets3t.service.impl.rest.httpclient.RestS3Service; import org.jets3t.service.impl.rest.httpclient.RestStorageService; import org.jets3t.service.model.MultipartCompleted; import org.jets3t.service.model.MultipartPart; import org.jets3t.service.model.MultipartUpload; import org.jets3t.service.model.NotificationConfig; import org.jets3t.service.model.S3Bucket; import org.jets3t.service.model.S3BucketLoggingStatus; import org.jets3t.service.model.S3Object; import org.jets3t.service.model.StorageBucket; import org.jets3t.service.model.StorageObject; import org.jets3t.service.model.WebsiteConfig; import org.jets3t.service.model.NotificationConfig.TopicConfig; import org.jets3t.service.multi.s3.MultipartUploadAndParts; import org.jets3t.service.multi.s3.S3ServiceEventAdaptor; import org.jets3t.service.multi.s3.ThreadedS3Service; import org.jets3t.service.security.AWSCredentials; import org.jets3t.service.security.ProviderCredentials; import org.jets3t.service.utils.MultipartUtils; import org.jets3t.service.utils.ObjectUtils; import org.jets3t.service.utils.RestUtils; import org.jets3t.service.utils.ServiceUtils; /** * Test the RestS3Service against the S3 endpoint, and apply tests specific to S3. * * @author James Murty */ public class TestRestS3Service extends BaseStorageServiceTests { public TestRestS3Service() throws Exception { super(); } @Override protected AccessControlList buildAccessControlList() { return new AccessControlList(); } @Override protected String getTargetService() { return TARGET_SERVICE_S3; } @Override protected ProviderCredentials getCredentials() { return new AWSCredentials( testProperties.getProperty("aws.accesskey"), testProperties.getProperty("aws.secretkey")); } @Override protected RestStorageService getStorageService(ProviderCredentials credentials) throws ServiceException { return getStorageService(credentials, Constants.S3_DEFAULT_HOSTNAME); } protected RestStorageService getStorageService(ProviderCredentials credentials, String endpointHostname) throws ServiceException { Jets3tProperties properties = new Jets3tProperties(); properties.setProperty("s3service.s3-endpoint", endpointHostname); return new RestS3Service(credentials, null, null, properties); } protected StorageBucket createBucketForTest(String testName, String location) throws Exception { String bucketName = getBucketNameForTest(testName); StorageService service = getStorageService(getCredentials()); return ((S3Service)service).getOrCreateBucket(bucketName, location); } public void testBucketLogging() throws Exception { S3Service s3Service = (S3Service) getStorageService(getCredentials()); StorageBucket bucket = createBucketForTest("testBucketLogging"); String bucketName = bucket.getName(); try { // Check logging status is false S3BucketLoggingStatus loggingStatus = s3Service.getBucketLoggingStatus(bucket.getName()); assertFalse("Expected logging to be disabled for bucket " + bucketName, loggingStatus.isLoggingEnabled()); // Enable logging (non-existent target bucket) try { S3BucketLoggingStatus newLoggingStatus = new S3BucketLoggingStatus( getCredentials().getAccessKey() + ".NonExistentBucketName", "access-log-"); s3Service.setBucketLoggingStatus(bucket.getName(), newLoggingStatus, true); fail("Using non-existent target bucket should have caused an exception"); } catch (Exception e) { } // Enable logging (in same bucket) S3BucketLoggingStatus newLoggingStatus = new S3BucketLoggingStatus(bucketName, "access-log-"); s3Service.setBucketLoggingStatus(bucket.getName(), newLoggingStatus, true); loggingStatus = s3Service.getBucketLoggingStatus(bucket.getName()); assertTrue("Expected logging to be enabled for bucket " + bucketName, loggingStatus.isLoggingEnabled()); assertEquals("Target bucket", bucketName, loggingStatus.getTargetBucketName()); assertEquals("Log file prefix", "access-log-", loggingStatus.getLogfilePrefix()); // Add TargetGrants ACLs for log files newLoggingStatus.addTargetGrant(new GrantAndPermission( GroupGrantee.ALL_USERS, Permission.PERMISSION_READ)); newLoggingStatus.addTargetGrant(new GrantAndPermission( GroupGrantee.AUTHENTICATED_USERS, Permission.PERMISSION_READ_ACP)); s3Service.setBucketLoggingStatus(bucket.getName(), newLoggingStatus, false); // Retrieve and verify TargetGrants loggingStatus = s3Service.getBucketLoggingStatus(bucket.getName()); assertEquals(2, loggingStatus.getTargetGrants().length); GrantAndPermission gap = loggingStatus.getTargetGrants()[0]; assertEquals(gap.getGrantee().getIdentifier(), GroupGrantee.ALL_USERS.getIdentifier()); assertEquals(gap.getPermission(), Permission.PERMISSION_READ); gap = loggingStatus.getTargetGrants()[1]; assertEquals(gap.getGrantee().getIdentifier(), GroupGrantee.AUTHENTICATED_USERS.getIdentifier()); assertEquals(gap.getPermission(), Permission.PERMISSION_READ_ACP); // Disable logging newLoggingStatus = new S3BucketLoggingStatus(); s3Service.setBucketLoggingStatus(bucket.getName(), newLoggingStatus, true); loggingStatus = s3Service.getBucketLoggingStatus(bucket.getName()); assertFalse("Expected logging to be disabled for bucket " + bucketName, loggingStatus.isLoggingEnabled()); } finally { cleanupBucketForTest("testBucketLogging"); } } public void testUrlSigning() throws Exception { RestS3Service service = (RestS3Service) getStorageService(getCredentials()); StorageBucket bucket = createBucketForTest("testUrlSigning"); String bucketName = bucket.getName(); try { // Create test object, with private ACL String dataString = "Text for the URL Signing test object..."; S3Object object = new S3Object("Testing URL Signing", dataString); object.setContentType("text/html"); object.addMetadata(service.getRestMetadataPrefix() + "example-header", "example-value"); object.setAcl(AccessControlList.REST_CANNED_PRIVATE); // Determine what the time will be in 5 minutes. Calendar cal = Calendar.getInstance(); cal.add(Calendar.MINUTE, 5); Date expiryDate = cal.getTime(); // Create a signed HTTP PUT URL. String signedPutUrl = service.createSignedPutUrl(bucket.getName(), object.getKey(), object.getMetadataMap(), expiryDate, false); // Put the object in S3 using the signed URL (no AWS credentials required) RestS3Service restS3Service = new RestS3Service(null); restS3Service.putObjectWithSignedUrl(signedPutUrl, object); // Ensure the object was created. StorageObject objects[] = service.listObjects(bucketName, object.getKey(), null); assertEquals("Signed PUT URL failed to put/create object", objects.length, 1); // Change the object's content-type and ensure the signed PUT URL disallows the put. object.setContentType("application/octet-stream"); try { restS3Service.putObjectWithSignedUrl(signedPutUrl, object); fail("Should not be able to use a signed URL for an object with a changed content-type"); } catch (ServiceException e) { object.setContentType("text/html"); } // Add an object header and ensure the signed PUT URL disallows the put. object.addMetadata(service.getRestMetadataPrefix() + "example-header-2", "example-value"); try { restS3Service.putObjectWithSignedUrl(signedPutUrl, object); fail("Should not be able to use a signed URL for an object with changed metadata"); } catch (ServiceException e) { object.removeMetadata(service.getRestMetadataPrefix() + "example-header-2"); } // Change the object's name and ensure the signed PUT URL uses the signed name, not the object name. String originalName = object.getKey(); object.setKey("Testing URL Signing 2"); object.setDataInputStream(new ByteArrayInputStream(dataString.getBytes())); object = restS3Service.putObjectWithSignedUrl(signedPutUrl, object); assertEquals("Ensure returned object key is renamed based on signed PUT URL", originalName, object.getKey()); // Test last-resort MD5 sanity-check for uploaded object when ETag is missing. S3Object objectWithoutETag = new S3Object("Object Without ETag"); objectWithoutETag.setContentType("text/html"); String objectWithoutETagSignedPutURL = service.createSignedPutUrl( bucket.getName(), objectWithoutETag.getKey(), objectWithoutETag.getMetadataMap(), expiryDate, false); objectWithoutETag.setDataInputStream(new ByteArrayInputStream(dataString.getBytes())); objectWithoutETag.setContentLength(dataString.getBytes().length); restS3Service.putObjectWithSignedUrl(objectWithoutETagSignedPutURL, objectWithoutETag); service.deleteObject(bucketName, objectWithoutETag.getKey()); // Ensure we can't get the object with a normal URL. String s3Url = "https://s3.amazonaws.com"; URL url = new URL(s3Url + "/" + bucket.getName() + "/" + RestUtils.encodeUrlString(object.getKey())); assertEquals("Expected denied access (403) error", 403, ((HttpURLConnection) url .openConnection()).getResponseCode()); // Create a signed HTTP GET URL. String signedGetUrl = service.createSignedGetUrl(bucket.getName(), object.getKey(), expiryDate, false); // Ensure the signed URL can retrieve the object. url = new URL(signedGetUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); assertEquals("Expected signed GET URL ("+ signedGetUrl +") to retrieve object with response code 200", 200, conn.getResponseCode()); // Sanity check the data in the S3 object. String objectData = (new BufferedReader( new InputStreamReader(conn.getInputStream()))) .readLine(); assertEquals("Unexpected data content in S3 object", dataString, objectData); // Clean up. service.deleteObject(bucketName, object.getKey()); } finally { cleanupBucketForTest("testUrlSigning"); } } public void testMultipartUtils() throws Exception { RestS3Service service = (RestS3Service) getStorageService(getCredentials()); StorageBucket bucket = createBucketForTest("testMultipartUtils"); String bucketName = bucket.getName(); try { // Ensure constructor enforces sanity constraints try { new MultipartUtils(MultipartUtils.MIN_PART_SIZE - 1); fail("Expected failure creating MultipartUtils with illegally small part size"); } catch (IllegalArgumentException e) {} try { new MultipartUtils(MultipartUtils.MAX_OBJECT_SIZE + 1); fail("Expected failure creating MultipartUtils with illegally large part size"); } catch (IllegalArgumentException e) {} // Default part size is maximum possible MultipartUtils multipartUtils = new MultipartUtils(); assertEquals("Unexpected default part size", MultipartUtils.MAX_OBJECT_SIZE, multipartUtils.getMaxPartSize()); // Create a util with the minimum part size, for quicker testing multipartUtils = new MultipartUtils(MultipartUtils.MIN_PART_SIZE); assertEquals("Unexpected default part size", MultipartUtils.MIN_PART_SIZE, multipartUtils.getMaxPartSize()); // Create a large (11 MB) file File largeFile = File.createTempFile("JetS3t-testMultipartUtils-large", ".txt"); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(largeFile)); int offset = 0; while (offset < 11 * 1024 * 1024) { bos.write((offset++ % 256)); } bos.close(); // Create a medium (6 MB) file File mediumFile = File.createTempFile("JetS3t-testMultipartUtils-medium", ".txt"); bos = new BufferedOutputStream(new FileOutputStream(mediumFile)); offset = 0; while (offset < 6 * 1024 * 1024) { bos.write((offset++ % 256)); } bos.close(); // Create a small (5 MB) file File smallFile = File.createTempFile("JetS3t-testMultipartUtils-small", ".txt"); bos = new BufferedOutputStream(new FileOutputStream(smallFile)); offset = 0; while (offset < 5 * 1024 * 1024) { bos.write((offset++ % 256)); } bos.close(); assertFalse("Expected small file to be <= 5MB", multipartUtils.isFileLargerThanMaxPartSize(smallFile)); assertTrue("Expected medium file to be > 5MB", multipartUtils.isFileLargerThanMaxPartSize(mediumFile)); assertTrue("Expected large file to be > 5MB", multipartUtils.isFileLargerThanMaxPartSize(largeFile)); // Split small file into 5MB object parts List parts = multipartUtils.splitFileIntoObjectsByMaxPartSize( smallFile.getName(), smallFile); assertEquals(1, parts.size()); // Split medium file into 5MB object parts parts = multipartUtils.splitFileIntoObjectsByMaxPartSize( mediumFile.getName(), mediumFile); assertEquals(2, parts.size()); // Split large file into 5MB object parts parts = multipartUtils.splitFileIntoObjectsByMaxPartSize( largeFile.getName(), largeFile); assertEquals(3, parts.size()); /* * Upload medium-sized file as object in multiple parts */ List objects = new ArrayList(); objects.add( ObjectUtils.createObjectForUpload( mediumFile.getName(), mediumFile, null, // encryptionUtil false // gzipFile )); multipartUtils.uploadObjects(bucketName, service, objects, null); S3Object completedObject = (S3Object) service.getObjectDetails( bucketName, mediumFile.getName()); assertEquals(mediumFile.length(), completedObject.getContentLength()); // Confirm object's mimetype metadata was applied assertEquals("text/plain", completedObject.getContentType()); /* * Upload large-sized file as object in multiple parts */ objects = new ArrayList(); objects.add( ObjectUtils.createObjectForUpload( largeFile.getName(), largeFile, null, // encryptionUtil false // gzipFile )); multipartUtils.uploadObjects(bucketName, service, objects, null); completedObject = (S3Object) service.getObjectDetails( bucketName, largeFile.getName()); assertEquals(largeFile.length(), completedObject.getContentLength()); } finally { cleanupBucketForTest("testMultipartUtils"); } } public void testMultipartUploads() throws Exception { RestS3Service service = (RestS3Service) getStorageService(getCredentials()); StorageBucket bucket = createBucketForTest("testMultipartUploads"); String bucketName = bucket.getName(); try { int fiveMb = 5 * 1024 * 1024; // Check stripping of double-quote characters from etag MultipartPart testEtagSanitized = new MultipartPart( 1, new Date(), "\"fakeEtagWithDoubleQuotes\"", 0l); assertEquals("fakeEtagWithDoubleQuotes", testEtagSanitized.getEtag()); // Create 5MB of test data byte[] testData = new byte[fiveMb]; for (int offset = 0; offset < testData.length; offset++) { testData[offset] = (byte) (offset % 256); } // Define name and String metadata values for multipart upload object String objectKey = "multipart-object.txt"; Map metadata = new HashMap(); metadata.put("test-md-value", "testing, testing, 123"); metadata.put("test-timestamp-value", System.currentTimeMillis()); // Start a multipart upload MultipartUpload testMultipartUpload = service.multipartStartUpload(bucketName, objectKey, metadata); assertEquals(bucketName, testMultipartUpload.getBucketName()); assertEquals(objectKey, testMultipartUpload.getObjectKey()); // List all ongoing multipart uploads List uploads = service.multipartListUploads(bucketName); assertTrue("Expected at least one ongoing upload", uploads.size() >= 1); // Confirm our newly-created multipart upload is present in listing boolean foundNewUpload = false; for (MultipartUpload upload: uploads) { if (upload.getUploadId().equals(testMultipartUpload.getUploadId())) { foundNewUpload = true; } } assertTrue("Expected to find the new upload in listing", foundNewUpload); // Start a second multipart upload MultipartUpload testMultipartUpload2 = service.multipartStartUpload(bucketName, objectKey + "2", metadata); // List multipart uploads with markers -- Find second upload only uploads = service.multipartListUploads(bucketName, "multipart-object.txt", testMultipartUpload.getUploadId(), 10); assertEquals(1, uploads.size()); assertEquals(objectKey + "2", uploads.get(0).getObjectKey()); // Delete incomplete/unwanted multipart upload service.multipartAbortUpload(testMultipartUpload2); // Ensure the incomplete multipart upload has been deleted uploads = service.multipartListUploads(bucketName); for (MultipartUpload upload: uploads) { if (upload.getUploadId().equals(testMultipartUpload2.getUploadId())) { fail("Expected multipart upload " + upload.getUploadId() + " to be deleted"); } } int partNumber = 0; // Upload a first part, must be 5MB+ S3Object partObject = new S3Object( testMultipartUpload.getObjectKey(), testData); MultipartPart uploadedPart = service.multipartUploadPart( testMultipartUpload, ++partNumber, partObject); assertEquals(uploadedPart.getPartNumber().longValue(), partNumber); assertEquals(uploadedPart.getEtag(), partObject.getETag()); assertEquals(uploadedPart.getSize().longValue(), partObject.getContentLength()); // List multipart parts that have been received by the service List listedParts = service.multipartListParts(testMultipartUpload); assertEquals(listedParts.size(), 1); assertEquals(listedParts.get(0).getSize().longValue(), partObject.getContentLength()); // Upload a second and final part, can be as small as 1 byte partObject = new S3Object( testMultipartUpload.getObjectKey(), new byte[] {testData[0]}); uploadedPart = service.multipartUploadPart( testMultipartUpload, ++partNumber, partObject); assertEquals(uploadedPart.getPartNumber().longValue(), partNumber); assertEquals(uploadedPart.getEtag(), partObject.getETag()); assertEquals(uploadedPart.getSize().longValue(), partObject.getContentLength()); // List multipart parts that have been received by the service listedParts = service.multipartListParts(testMultipartUpload); assertEquals(listedParts.size(), 2); assertEquals(listedParts.get(1).getSize().longValue(), partObject.getContentLength()); // Reverse order of parts to ensure multipartCompleteUpload corrects the problem Collections.reverse(listedParts); // Complete multipart upload, despite badly ordered parts. MultipartCompleted multipartCompleted = service.multipartCompleteUpload( testMultipartUpload, listedParts); assertEquals(multipartCompleted.getBucketName(), testMultipartUpload.getBucketName()); assertEquals(multipartCompleted.getObjectKey(), testMultipartUpload.getObjectKey()); // Confirm completed object exists and has expected metadata S3Object completedObject = (S3Object) service.getObjectDetails( bucketName, testMultipartUpload.getObjectKey()); assertEquals( metadata.get("test-md-value"), completedObject.getMetadata("test-md-value")); assertEquals( metadata.get("test-timestamp-value").toString(), completedObject.getMetadata("test-timestamp-value").toString()); /* * Perform a multipart upload using the convenience method. * The object in this case *must* be file-based. */ byte[] testDataOverLimit = new byte[fiveMb + 100]; for (int i = 0; i < testDataOverLimit.length; i++) { testDataOverLimit[i] = (byte) (i % 256); } // Confirm that non-file-based objects are not accepted try { StorageObject myObject = new StorageObject(); service.putObjectMaybeAsMultipart(bucketName, myObject, fiveMb); fail(""); } catch (ServiceException se) { } // Create file for testing File testDataFile = File.createTempFile("JetS3t-testMultipartUploads", ".txt"); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(testDataFile)); bos.write(testDataOverLimit); bos.close(); testDataOverLimit = null; // Free up a some memory // Setup file-based object StorageObject objectViaConvenienceMethod = new StorageObject(testDataFile); objectViaConvenienceMethod.setKey("multipart-object-via-convenience-method.txt"); objectViaConvenienceMethod.addMetadata("my-metadata", "convenient? yes!"); objectViaConvenienceMethod.setAcl(AccessControlList.REST_CANNED_PUBLIC_READ); objectViaConvenienceMethod.setStorageClass(S3Object.STORAGE_CLASS_REDUCED_REDUNDANCY); // Upload object service.putObjectMaybeAsMultipart(bucketName, objectViaConvenienceMethod, fiveMb); // Confirm completed object exists and has expected metadata objectViaConvenienceMethod = service.getObjectDetails( bucketName, objectViaConvenienceMethod.getKey()); assertEquals( "convenient? yes!", objectViaConvenienceMethod.getMetadata("my-metadata")); // Confirm completed object was indeed uploaded as a multipart upload, // not a standard PUT (ETag is not a valid MD5 hash in this case) assertFalse(ServiceUtils.isEtagAlsoAnMD5Hash( objectViaConvenienceMethod.getETag())); /* * Perform a threaded multipart upload */ String objectKeyForThreaded = "threaded-multipart-object.txt"; Map metadataForThreaded = new HashMap(); // Start threaded upload using normal service. MultipartUpload threadedMultipartUpload = service.multipartStartUpload(bucketName, objectKeyForThreaded, metadataForThreaded); // Prepare objects for upload (2 * 5MB, and 1 * 1 byte) S3Object[] objectsForThreadedUpload = new S3Object[] { new S3Object(threadedMultipartUpload.getObjectKey(), testData), new S3Object(threadedMultipartUpload.getObjectKey(), testData), new S3Object(threadedMultipartUpload.getObjectKey(), new byte[] {testData[0]}), }; // Create threaded service and perform upload in multiple threads ThreadedS3Service threadedS3Service = new ThreadedS3Service(service, new S3ServiceEventAdaptor()); List uploadAndParts = new ArrayList(); uploadAndParts.add(new MultipartUploadAndParts( threadedMultipartUpload, Arrays.asList(objectsForThreadedUpload))); threadedS3Service.multipartUploadParts(uploadAndParts); // Complete threaded multipart upload using automatic part listing and normal service. MultipartCompleted threadedMultipartCompleted = service.multipartCompleteUpload( threadedMultipartUpload); // Confirm completed object exists and has expected size S3Object finalObjectForThreaded = (S3Object) service.getObjectDetails( bucketName, threadedMultipartUpload.getObjectKey()); assertEquals(testData.length * 2 + 1, finalObjectForThreaded.getContentLength()); } finally { cleanupBucketForTest("testMultipartUploads"); } } public void testS3WebsiteConfig() throws Exception { // Testing takes place in the us-west-1 location S3Service s3Service = (S3Service) getStorageService(getCredentials()); StorageBucket bucket = createBucketForTest( "testS3WebsiteConfig", // Standard US Bucket location S3Bucket.LOCATION_US_WEST); String bucketName = bucket.getName(); String s3WebsiteURL = "http://" + bucketName + "." // Website location must correspond to bucket location, in this case // the US Standard. For website endpoints see: // docs.amazonwebservices.com/AmazonS3/latest/dev/WebsiteEndpoints.html + "s3-website-us-west-1" + ".amazonaws.com"; try { HttpClient httpClient = new HttpClient(); GetMethod getMethod = null; // Check no existing website config try { s3Service.getWebsiteConfig(bucketName); fail("Unexpected website config for bucket " + bucketName); } catch (S3ServiceException e) { } // Set index document s3Service.setWebsiteConfig(bucketName, new WebsiteConfig("index.html")); Thread.sleep(5000); // Confirm index document set WebsiteConfig config = s3Service.getWebsiteConfig(bucketName); assertTrue(config.isWebsiteConfigActive()); assertEquals("index.html", config.getIndexDocumentSuffix()); assertNull(config.getErrorDocumentKey()); // Upload public index document S3Object indexObject = new S3Object("index.html", "index.html contents"); indexObject.setAcl(AccessControlList.REST_CANNED_PUBLIC_READ); s3Service.putObject(bucketName, indexObject); // Confirm index document is served at explicit path getMethod = new GetMethod(s3WebsiteURL + "/index.html"); httpClient.executeMethod(getMethod); assertEquals(200, getMethod.getStatusCode()); assertEquals("index.html contents", getMethod.getResponseBodyAsString()); // Confirm index document is served at root path // (i.e. website config is effective) getMethod = new GetMethod(s3WebsiteURL + "/"); httpClient.executeMethod(getMethod); assertEquals(200, getMethod.getStatusCode()); assertEquals("index.html contents", getMethod.getResponseBodyAsString()); // Set index document and error document s3Service.setWebsiteConfig(bucketName, new WebsiteConfig("index.html", "error.html")); Thread.sleep(5000); // Confirm index document and error document set config = s3Service.getWebsiteConfig(bucketName); assertTrue(config.isWebsiteConfigActive()); assertEquals("index.html", config.getIndexDocumentSuffix()); assertEquals("error.html", config.getErrorDocumentKey()); // Upload public error document S3Object errorObject = new S3Object("error.html", "error.html contents"); errorObject.setAcl(AccessControlList.REST_CANNED_PUBLIC_READ); s3Service.putObject(bucketName, errorObject); // Confirm error document served at explicit path getMethod = new GetMethod(s3WebsiteURL + "/error.html"); httpClient.executeMethod(getMethod); assertEquals(200, getMethod.getStatusCode()); assertEquals("error.html contents", getMethod.getResponseBodyAsString()); // Confirm error document served instead of 404 Not Found getMethod = new GetMethod(s3WebsiteURL + "/does-not-exist"); httpClient.executeMethod(getMethod); assertEquals(403, getMethod.getStatusCode()); // TODO: Why a 403? assertEquals("error.html contents", getMethod.getResponseBodyAsString()); // Upload private document S3Object privateObject = new S3Object("private.html", "private.html contents"); s3Service.putObject(bucketName, privateObject); // Confirm error document served instead for 403 Forbidden getMethod = new GetMethod(s3WebsiteURL + "/private.html"); httpClient.executeMethod(getMethod); assertEquals(403, getMethod.getStatusCode()); // Delete website config s3Service.deleteWebsiteConfig(bucketName); Thread.sleep(5000); // Confirm website config deleted try { s3Service.getWebsiteConfig(bucketName); fail("Unexpected website config for bucket " + bucketName); } catch (S3ServiceException e) { } } finally { cleanupBucketForTest("testS3WebsiteConfig"); } } public void testNotificationConfig() throws Exception { // Testing takes place in the us-west-1 location S3Service s3Service = (S3Service) getStorageService(getCredentials()); StorageBucket bucket = createBucketForTest("testNotificationConfig"); String bucketName = bucket.getName(); try { // Check no existing notification config NotificationConfig notificationConfig = s3Service.getNotificationConfig(bucketName); assertEquals(0, notificationConfig.getTopicConfigs().size()); // Public SNS topic for testing String topicArn = "arn:aws:sns:us-east-1:916472402845:" + "JetS3t-Test-S3-Bucket-NotificationConfig"; String event = NotificationConfig.EVENT_REDUCED_REDUNDANCY_LOST_OBJECT; // Set notification config notificationConfig = new NotificationConfig(); notificationConfig.addTopicConfig(notificationConfig.new TopicConfig(topicArn, event)); s3Service.setNotificationConfig(bucketName, notificationConfig); Thread.sleep(5000); // Get notification config notificationConfig = s3Service.getNotificationConfig(bucketName); assertEquals(1, notificationConfig.getTopicConfigs().size()); TopicConfig topicConfig = notificationConfig.getTopicConfigs().get(0); assertEquals(topicArn, topicConfig.getTopic()); assertEquals(event, topicConfig.getEvent()); // Unset/clear notification config s3Service.unsetNotificationConfig(bucketName); Thread.sleep(5000); // Confirm notification config is no longer set notificationConfig = s3Service.getNotificationConfig(bucketName); assertEquals(0, notificationConfig.getTopicConfigs().size()); } finally { cleanupBucketForTest("testNotificationConfig"); } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/tests/TestRestS3ServiceToGoogleStorage.java0000644000000000000000000000434211447770622024605 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.tests; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.ServiceException; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.impl.rest.httpclient.RestS3Service; import org.jets3t.service.impl.rest.httpclient.RestStorageService; import org.jets3t.service.security.GSCredentials; import org.jets3t.service.security.ProviderCredentials; /** * Test the S3-targetted RestS3Service against the Google Storage endpoint. * * @author James Murty */ public class TestRestS3ServiceToGoogleStorage extends BaseStorageServiceTests { public TestRestS3ServiceToGoogleStorage() throws Exception { super(); } @Override protected String getTargetService() { return TARGET_SERVICE_GS; } @Override protected ProviderCredentials getCredentials() { return new GSCredentials( testProperties.getProperty("gsservice.accesskey"), testProperties.getProperty("gsservice.secretkey")); } @Override protected RestStorageService getStorageService(ProviderCredentials credentials) throws ServiceException { Jets3tProperties properties = new Jets3tProperties(); properties.setProperty("s3service.s3-endpoint", Constants.GS_DEFAULT_HOSTNAME); return new RestS3Service(credentials, null, null, properties); } @Override protected AccessControlList buildAccessControlList() { return new AccessControlList(); } /* * S3 Features supported by Google Storage */ } jets3t-0.8.1+dfsg.orig/src/org/jets3t/tests/FakeS3Server.java0000644000000000000000000002667411427702124020561 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.tests; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.security.MessageDigest; import java.util.Locale; import javax.net.ServerSocketFactory; import javax.net.ssl.SSLServerSocketFactory; import org.apache.commons.codec.binary.Base64; import org.jets3t.service.security.AWSCredentials; /** * Very basic implementation of an S3 server-side stub that can fake certain S3 interactions * including: *

    *
  • Logging in using S3-stored credentials (passphrase/password=please/please)
  • *
  • Listing buckets
  • *
  • Listing the contents of an empty bucket
  • *
  • Allowing for PUT uploads, with generation and comparison of an MD5 digest for data received
  • *
* * @author James Murty * */ public class FakeS3Server { /** * @param args */ public static void main(String[] args) throws Exception { AWSCredentials fakeAwsCredentials = new AWSCredentials("fake-aws-access-key", "fake-aws-secret-key"); int port = 443; ServerSocketFactory ssocketFactory = SSLServerSocketFactory.getDefault(); ServerSocket ssocket = ssocketFactory.createServerSocket(port); System.out.println("Accepting connections on port 443"); while (port == 443) { // Listen for connections Socket socket = ssocket.accept(); System.out.println("Opened connection"); // Create streams to securely send and receive data to the client InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); byte[] buffer = new byte[1024]; int read; while ((read = in.read(buffer)) != -1) { String receivedDataStr = new String(buffer, 0, read); String requestActionAndHeaders = receivedDataStr.substring(0, receivedDataStr.indexOf("\r\n\r\n") + 4); System.out.println(requestActionAndHeaders); if (requestActionAndHeaders.startsWith("GET")) { String path = requestActionAndHeaders.substring(4, requestActionAndHeaders.indexOf(' ', 4)); if (path.startsWith("/jets3t-")) { // Return fake AWS credentials. String headers = "HTTP/1.1 200 OK\r\n" + "x-amz-id-2: FakeAWSCredentials\r\n" + "x-amz-request-id: FakeAWSCredentials\r\n" + "Date: Thu, 24 May 2007 13:39:21 GMT\r\n" + "Cache-Control: max-age=259200\r\n" + "Last-Modified: Wed, 27 Dec 2006 02:37:58 GMT\r\n" + "ETag: \"fa5d6b0ea9716cf692b286b6aa187f3d\"\r\n" + "Content-Type: application/octet-stream\r\n" + "Content-Length: 139\r\n" + "Server: AmazonS3\r\n\r\n"; out.write(headers.getBytes("UTF-8")); fakeAwsCredentials.save("please", out); } else if (path.equals("/")) { // Return fake bucket listing. String headers = "HTTP/1.1 200 OK\r\n" + "x-amz-id-2: FakeBucketListing\r\n" + "x-amz-request-id: FakeBucketListing\r\n" + "Date: Thu, 24 May 2007 13:39:23 GMT\r\n" + "Content-Type: application/xml\r\n" + "Transfer-Encoding: chunked\r\n" + "Server: AmazonS3\r\n\r\n"; String bucketListing = "17b\r\n" + "\n" + "" + "1a405254c932b52e5b5caaa88186bc431a1bacb9ece631f835daddaf0c47677c" + "jamesmurty"+ "TestUploadBucket" + "2006-12-13T21:21:14.000Z" + "" + "\r\n0\r\n\r\n"; out.write(headers.getBytes("UTF-8")); out.write(bucketListing.getBytes("UTF-8")); } else if (path.startsWith("/TestUploadBucket")) { // Return empty bucket contents String headers = "HTTP/1.1 200 OK\r\n" + "x-amz-id-2: FakeBucketContents\r\n" + "x-amz-request-id: FakeBucketContents\r\n" + "Date: Thu, 24 May 2007 13:39:23 GMT\r\n" + "Content-Type: application/xml\r\n" + "Transfer-Encoding: chunked\r\n" + "Server: AmazonS3\r\n\r\n"; String bucketContents = "f2\r\n" + "\n" + "" + "TestUploadBucket" + "1000false" + "" + "\r\n0\r\n\r\n"; out.write(headers.getBytes("UTF-8")); out.write(bucketContents.getBytes("UTF-8")); } else { System.out.println("ERROR: Unrecognised GET request"); } } else if (requestActionAndHeaders.startsWith("PUT")) { long contentLength = 0; String clientProvidedHash = "NONE"; // Determine content length. int searchIndex = requestActionAndHeaders.indexOf("Content-Length: ") + "Content-Length: ".length(); contentLength = (new Long(requestActionAndHeaders.substring(searchIndex, requestActionAndHeaders.indexOf('\r', searchIndex)))).longValue(); // Determine content MD5 (hex encoded). searchIndex = requestActionAndHeaders.indexOf("Content-MD5: ") + "Content-MD5: ".length(); if (searchIndex >= -1) { clientProvidedHash = requestActionAndHeaders.substring( searchIndex, requestActionAndHeaders.indexOf('\r', searchIndex)); } // Read all PUT data provided by client, generating an MD5 hash as we go. System.out.println("Receiving " + contentLength + " bytes from client"); MessageDigest digest = MessageDigest.getInstance("MD5"); long putdataAlreadyRead = read - requestActionAndHeaders.length(); // read - (requestActionAndHeaders.lastIndexOf("\r\n") + 2); digest.update(buffer, (int)(read - putdataAlreadyRead), (int)putdataAlreadyRead); byte[] putdata = new byte[8192]; int putdataRead = 0; while ((putdataRead = in.read(putdata)) != -1) { digest.update(putdata, 0, putdataRead); putdataAlreadyRead += putdataRead; if (putdataAlreadyRead == contentLength) { System.out.println("PUT object upload is complete"); break; } } if (putdataAlreadyRead != contentLength) { System.err.println("ERROR: Expected " + contentLength + " bytes but received " + putdataAlreadyRead); continue; } String receivedDataHashAsHex = new String(Base64.encodeBase64(digest.digest()), "UTF-8"); // Generate the headers appropriate for the PUT object. String headers = "HTTP/1.1 200 OK\r\n" + "x-amz-id-2: FakePUT\r\n" + "x-amz-request-id: FakePUT\r\n" + "Date: Thu, 24 May 2007 15:12:30 GMT\r\n" + "ETag: \"" + receivedDataHashAsHex + "\"\r\n" + "Content-Length: 0\r\n" + "Server: AmazonS3\r\n\r\n"; out.write(headers.getBytes("UTF-8")); out.flush(); // Compare expected hash (supplied by client) verses actual hash (for retrieved data) if (!receivedDataHashAsHex.equals(clientProvidedHash)) { System.err.println("ERROR: Client-side hash " + clientProvidedHash + " does not match hash of received data " + receivedDataHashAsHex); } else { System.out.println("SUCCESS: Client-side hash matches hash of received data: " + receivedDataHashAsHex); } } else { System.out.println("ERROR: Unrecognised input"); } } // Close the socket System.out.println("Closing connection"); in.close(); out.close(); } } public static void writeFileToOutputStream(File file, OutputStream out) throws Exception { byte[] buffer = new byte[1024]; int read; FileInputStream in = null; try { in = new FileInputStream(file); while ((read = in.read(buffer)) != -1) { out.write(buffer, 0, read); } } finally { if (in != null) { in.close(); } } } public static String toHex(byte[] data) { StringBuffer sb = new StringBuffer(data.length * 2); for (int i = 0; i < data.length; i++) { String hex = Integer.toHexString(data[i]); if (hex.length() == 1) { // Append leading zero. sb.append("0"); } else if (hex.length() == 8) { // Remove ff prefix from negative numbers. hex = hex.substring(6); } sb.append(hex); } return sb.toString().toLowerCase(Locale.getDefault()); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/tests/PutViaSocket.java0000644000000000000000000003154111537563564020703 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.tests; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Properties; import javax.net.SocketFactory; import javax.net.ssl.SSLSocketFactory; import org.jets3t.service.security.AWSCredentials; import org.jets3t.service.utils.RestUtils; import org.jets3t.service.utils.ServiceUtils; /** * Very basic client implementation able to PUT files into S3 using the Java * socket implementation directly, with no HTTP library or transport of any kind. *

* To use this class: *

    *
  • provide a test.properties file in the classpath * that contains the settings aws.accesskey and aws.secretkey
  • *
  • modify the filename and bucketName variables in main() to * provide the file you wish to upload, and the already existing buckety you * want to upload it to in S3
  • *
* * @author James Murty */ public class PutViaSocket { private static String TEST_PROPERTIES_FILENAME = "test.properties"; private static Properties loadTestProperties() throws IOException { InputStream propertiesIS = ClassLoader.getSystemResourceAsStream(TEST_PROPERTIES_FILENAME); if (propertiesIS == null) { throw new IOException("Unable to load test properties file from classpath: " + TEST_PROPERTIES_FILENAME); } Properties testProperties = new Properties(); testProperties.load(propertiesIS); return testProperties; } private static AWSCredentials loadAWSCredentials(Properties testProperties) throws Exception { return new AWSCredentials( testProperties.getProperty("aws.accesskey"), testProperties.getProperty("aws.secretkey")); } private static String generateAuthorizationString(AWSCredentials awsCredentials, String url, Map headersMap) throws Exception { String canonicalString = RestUtils.makeServiceCanonicalString( "PUT", url, headersMap, null, null, null); // Sign the canonical string. String signedCanonical = ServiceUtils.signWithHmacSha1( awsCredentials.getSecretKey(), canonicalString); return "AWS " + awsCredentials.getAccessKey() + ":" + signedCanonical; } public static void main(String[] args) throws Exception { Properties testProperties = loadTestProperties(); AWSCredentials awsCredentials = loadAWSCredentials(testProperties); String filename = testProperties.getProperty("filename"); String bucketName = testProperties.getProperty("bucketName"); String contentType = testProperties.getProperty("contentType", "application/octet-stream"); String serverHostname = testProperties.getProperty("serverHostname", "s3.amazonaws.com"); String bufferSizeStr = testProperties.getProperty("bufferSize", "2048"); int byteBufferSize = Integer.parseInt(bufferSizeStr); int port = 80; boolean isSslEnabled; String enableSslStr = testProperties.getProperty("enableSSL", "false"); if ("true".equalsIgnoreCase(enableSslStr)) { isSslEnabled = true; port = 443; } else if ("false".equalsIgnoreCase(enableSslStr)) { isSslEnabled = false; } else { throw new IllegalArgumentException("Boolean value '" + enableSslStr + "' for property 'enableSSL' must be 'true' or 'false' (case-insensitive)"); } // Over-ride default server ports (80, 443) if a special port is configured. String serverPortStr = testProperties.getProperty("serverPort", null); if (serverPortStr != null) { port = Integer.parseInt(serverPortStr); } boolean isS3AuthEnabled; String disableS3FeaturesStr = testProperties.getProperty("disableS3Features", "false"); if ("true".equalsIgnoreCase(disableS3FeaturesStr)) { isS3AuthEnabled = false; } else if ("false".equalsIgnoreCase(disableS3FeaturesStr)) { isS3AuthEnabled = true; } else { throw new IllegalArgumentException("Boolean value '" + disableS3FeaturesStr + "' for property 'disableS3Features' must be 'true' or 'false' (case-insensitive)"); } boolean isBugBehaviourEnabled; String enableBugBehaviourStr = testProperties.getProperty("enableBugBehaviour", "false"); if ("true".equalsIgnoreCase(enableBugBehaviourStr)) { isBugBehaviourEnabled = true; } else if ("false".equalsIgnoreCase(enableBugBehaviourStr)) { isBugBehaviourEnabled = false; } else { throw new IllegalArgumentException("Boolean value '" + enableBugBehaviourStr + "' for property 'enableBugBehaviour' must be 'true' or 'false' (case-insensitive)"); } System.out.println("AWS Access Key: " + awsCredentials.getAccessKey()); System.out.println("filename: " + filename); System.out.println("bucketName: " + bucketName); System.out.println("contentType: " + contentType); System.out.println("serverHostname: " + serverHostname); System.out.println("serverPort: " + port); System.out.println("bufferSize: " + byteBufferSize); System.out.println("isSslEnabled? " + isSslEnabled); System.out.println("isS3AuthEnabled? " + isS3AuthEnabled); System.out.println("isBugBehaviourEnabled? " + isBugBehaviourEnabled); File file = new File(filename); String url = "/" + bucketName + "/" + file.getName(); System.out.println("\nComputing MD5 hash of file: " + file.getName()); long fileSize = file.length(); byte[] md5Hash = ServiceUtils.computeMD5Hash( new BufferedInputStream(new FileInputStream(file))); System.out.println("MD5 hash of file B64=" + ServiceUtils.toBase64(md5Hash) + " Hex=" + ServiceUtils.toHex(md5Hash)); SocketFactory socketFactory = null; if (isSslEnabled) { socketFactory = SSLSocketFactory.getDefault(); } else { socketFactory = SocketFactory.getDefault(); } System.out.println("\nConnecting to " + serverHostname + ":" + port); Socket socket = socketFactory.createSocket(serverHostname, port); socket.setKeepAlive(true); socket.setSoTimeout(60000); socket.setTcpNoDelay(true); System.out.println("Connected to " + socket.getInetAddress().toString() + ":" + socket.getPort()); OutputStream out = new BufferedOutputStream(socket.getOutputStream(), byteBufferSize); InputStream in = socket.getInputStream(); Map headersMap = new HashMap(); headersMap.put("Content-MD5", ServiceUtils.toBase64(md5Hash)); headersMap.put("Content-Type", contentType); headersMap.put("Date", ServiceUtils.formatRfc822Date(new Date())); headersMap.put("S3Authorization", generateAuthorizationString(awsCredentials, url,headersMap)); String headers = ""; if (isBugBehaviourEnabled) { // Original Headers that exhibit the Bad Digest bug. headers = "PUT " + url + " HTTP/1.1\r\n" + "Content-Length: " + fileSize + "\r\n" + "Content-MD5: " + headersMap.get("Content-MD5") + "\r\n" + "Content-Type: " + headersMap.get("Content-Type") + "\r\n" + "Date: " + headersMap.get("Date") + "\r\n" + (isS3AuthEnabled ? "Authorization: " + headersMap.get("S3Authorization") + "\r\n" : "") + "Host: " + serverHostname + "\r\n" + "\r\n"; } else { // Complete Header set re-ordered following s3curl example, has succeeded at least once. headers = "PUT " + url + " HTTP/1.1\r\n" + "User-Agent: PutViaSocket/1.0\r\n" + "Host: " + serverHostname + "\r\n" + "Accept: */*\r\n" + "Date: " + headersMap.get("Date") + "\r\n" + (isS3AuthEnabled ? "Authorization: " + headersMap.get("S3Authorization") + "\r\n" : "") + "Content-Length: " + fileSize + "\r\n" + "Content-MD5: " + headersMap.get("Content-MD5") + "\r\n" + "Content-Type: " + headersMap.get("Content-Type") + "\r\n" + "Expect: 100-continue\r\n" + "\r\n"; } // Output PUT Headers System.out.println("\nREQUEST:"); System.out.print(headers); System.out.println(); byte[] data = new byte[byteBufferSize]; int dataRead = 0; long megabytesSent = 0; out.write(headers.getBytes()); out.flush(); if (!isBugBehaviourEnabled) { // Handle Expect: 100-Continue Thread.sleep(500); boolean isContinueOK = false; if (in.available() > 0) { System.out.println("\nResponse to Expect: 100-Continue..."); while ((dataRead = in.read(data)) != -1) { String line = new String(data, 0, dataRead); System.out.print(line); if (line.indexOf("HTTP/1.1 100 Continue") >= 0) { isContinueOK = true; break; } } if (!isContinueOK) { // Uh oh, something must have gone wrong. Write the server's response and quit. System.out.println("\n\nQuitting without performing upload"); in.close(); out.close(); return; } } } FileInputStream fis = new FileInputStream(file); long fileBytesTransferred = 0; int failureCount = 0; int MAX_FAILURE_RETRIES = 10; // PUT Data System.out.println("Uploading " + fileSize + " bytes"); while ((dataRead = fis.read(data)) != -1) { try { out.write(data, 0, dataRead); fileBytesTransferred += dataRead; if (fileBytesTransferred / (1024 * 1024) > megabytesSent) { System.out.println("Uploaded " + (int)(fileBytesTransferred / (double)(1024 * 1024)) + "MB of " + (fileSize / (double)(1024 * 1024)) + "MB"); megabytesSent = fileBytesTransferred / (1024 * 1024); } // Check for any data available in the socket input/error streams if (in.available() > 0) { // Uh oh, this shouldn't happen. We'd better stop the upload and print out the error. System.out.println("\nERROR: Unexpected data in server input stream mid-transfer, halting upload"); break; } } catch (Exception e) { // Try to recover from the failure (it's unlikely this will ever work) failureCount++; if (failureCount <= MAX_FAILURE_RETRIES) { System.out.println("SocketException " + failureCount + ", will retry: " + e); Thread.sleep(500); } else { break; } } } out.flush(); fis.close(); if (fileBytesTransferred < fileSize) { System.out.println("Upload did not complete, only " + fileBytesTransferred + " of " + fileSize + " bytes sent"); } else { System.out.println("Upload completed"); } // Read response System.out.println("\nRESPONSE:"); while ((dataRead = in.read(data)) != -1) { String line = new String(data, 0, dataRead); System.out.print(line); if (line.endsWith("\r\n\r\n")) { break; } } in.close(); out.close(); socket.close(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/tests/TestUtilities.java0000644000000000000000000002067211537563564021140 0ustar package org.jets3t.tests; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import org.jets3t.service.io.SegmentedRepeatableFileInputStream; import org.jets3t.service.model.S3Object; import org.jets3t.service.model.StorageObject; import org.jets3t.service.utils.ServiceUtils; import junit.framework.TestCase; public class TestUtilities extends TestCase { public void testIsEtagAlsoAnMD5Hash() { // Valid MD5 ETag value assertTrue(ServiceUtils.isEtagAlsoAnMD5Hash( "cb8aaa4056eb349af16b1907280dee18")); // Non-MD5 ETag values assertFalse(ServiceUtils.isEtagAlsoAnMD5Hash( "cb8aaa4056eb349af16b1907280dee18-1")); assertFalse(ServiceUtils.isEtagAlsoAnMD5Hash( "Xcb8aaa4056eb349af16b1907280dee1")); assertFalse(ServiceUtils.isEtagAlsoAnMD5Hash( "cb8aaa4056eb349af16b1907280dee1")); assertFalse(ServiceUtils.isEtagAlsoAnMD5Hash( "cb8aaa4056eb349af16b1907280dee18cb")); } public void testMd5ETag() throws Exception { StorageObject so = new S3Object(""); // MD5 ETag values so.setETag("cb8aaa4056eb349af16b1907280dee18"); assertEquals("y4qqQFbrNJrxaxkHKA3uGA==", so.getMd5HashAsBase64()); } public void testNonMd5ETag() throws Exception { StorageObject so = new S3Object(""); so.setETag("cb8aaa4056eb349af16b1907280dee18-1"); assertEquals(null, so.getMd5HashAsBase64()); so.setETag("cb8aaa4056eb349af16b1907280dee"); assertEquals(null, so.getMd5HashAsBase64()); so.setETag("cb8aaa4056eb349af16b1907280dee1"); assertEquals(null, so.getMd5HashAsBase64()); so.setETag("cb8aaa4056eb349af16b1907280dee18cb"); assertEquals(null, so.getMd5HashAsBase64()); so.setETag("12345"); String hash = so.getMd5HashAsBase64(); assertEquals(null, hash); so.setETag("123456-7"); hash = so.getMd5HashAsBase64(); assertEquals(null, hash); } public void testSegmentedRepeatableFileInputStream() throws Exception { File testFile = File.createTempFile("JetS3t-testSegmentedRepeatableFileInputStream", null); int read = -1; SegmentedRepeatableFileInputStream segFIS = null; // Create a 1 MB file for testing BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream(testFile)); long testFileLength = 1 * 1024 * 1024; int offset = 0; while (offset < testFileLength) { bos.write((offset % 256)); offset++; } bos.close(); // Invalid segment length try { segFIS = new SegmentedRepeatableFileInputStream(testFile, 0, 0); fail("SegmentedRepeatableFileInputStream accepted invalid arguments"); } catch (IllegalArgumentException e) { } // Segment exceeds file length try { segFIS = new SegmentedRepeatableFileInputStream(testFile, 0, testFileLength + 1); fail("SegmentedRepeatableFileInputStream accepted invalid arguments"); } catch (IllegalArgumentException e) { } // Offset beyond file length try { segFIS = new SegmentedRepeatableFileInputStream(testFile, testFileLength + 1, 1); fail("SegmentedRepeatableFileInputStream accepted invalid arguments"); } catch (IllegalArgumentException e) { } // Offset and segment length exceed file length try { segFIS = new SegmentedRepeatableFileInputStream(testFile, testFileLength - 1, 2); fail("SegmentedRepeatableFileInputStream accepted invalid arguments"); } catch (IllegalArgumentException e) { } // Just right try { segFIS = new SegmentedRepeatableFileInputStream(testFile, testFileLength - 1, 1); segFIS.close(); } catch (IllegalArgumentException e) { fail("SegmentedRepeatableFileInputStream failed to accept valid arguments"); } segFIS = new SegmentedRepeatableFileInputStream(testFile, 0, 10); // Ensure reads stay within segment boundaries... long byteCount = 0; byte[] buffer = new byte[256]; // Read entire segment 1 byte at a time segFIS.reset(); byteCount = 0; while ((read = segFIS.read()) != -1) { byteCount++; } assertEquals("Read beyond segment length", 10, byteCount); // Read entire segment using buffer segFIS.reset(); byteCount = 0; while ((read = segFIS.read(buffer, 0, buffer.length)) != -1) { byteCount += read; } assertEquals("Read beyond segment length", 10, byteCount); // Read partial segment with offset using buffer segFIS.reset(); byteCount = 0; offset = 5; while ((read = segFIS.read(buffer, offset, (int) (5 - byteCount) )) != -1) { byteCount += read; offset = 0; } assertEquals("Read beyond segment length with offset", 5, byteCount); // Read starting beyond segment segFIS.reset(); byteCount = 0; offset = 10; while ((read = segFIS.read(buffer, offset, buffer.length)) != -1) { byteCount += read; } assertEquals("Read beyond segment length", 0, byteCount); segFIS.close(); // Check valid data read from segment... // Read entire file segFIS = new SegmentedRepeatableFileInputStream(testFile, 0, testFileLength); offset = 0; while ((read = segFIS.read()) != -1) { assertEquals("Read unexpected byte at offset " + offset, (offset % 256), read); offset++; } segFIS.close(); // Read an offset segment of file offset = 1234; segFIS = new SegmentedRepeatableFileInputStream( testFile, offset, testFileLength - offset); while ((read = segFIS.read()) != -1) { assertEquals("Read unexpected byte at offset " + offset, (offset % 256), read); offset++; } segFIS.close(); // Set a mark point, read from it, then reset to that point. segFIS = new SegmentedRepeatableFileInputStream( testFile, 0, testFileLength); int targetOffset = 12345; offset = 0; while (offset < targetOffset && (read = segFIS.read()) != -1) { offset++; } assertEquals("Couldn't read up to target offset", targetOffset, offset); assertEquals("Unexpected amount of data available", testFileLength - targetOffset, segFIS.available()); segFIS.mark(0); while ((read = segFIS.read()) != -1) { assertEquals("Read unexpected byte at offset " + offset, (offset % 256), read); offset++; } segFIS.reset(); assertEquals("Unexpected amount of data available", testFileLength - targetOffset, segFIS.available()); offset = targetOffset; while ((read = segFIS.read()) != -1) { assertEquals("Read unexpected byte at offset " + offset, (offset % 256), read); offset++; } assertEquals("Didn't read expected number of bytes after reset", testFileLength, offset); segFIS.close(); // Multiple overlapping segments... int[] offsets = new int[] { 0, 1000, 1080, 3500}; long[] expectedBytesRead = new long[] { 1234, 2000, 3000, 1 }; int i = 0; SegmentedRepeatableFileInputStream[] segFISs = new SegmentedRepeatableFileInputStream[offsets.length]; for (i = 0; i < segFISs.length; i++) { segFISs[i] = new SegmentedRepeatableFileInputStream( testFile, offsets[i], expectedBytesRead[i]); }; // Test correct bytes read, and correct segment lengths read for (i = 0; i < segFISs.length; i++) { segFIS = segFISs[i]; offset = offsets[i]; byteCount = 0; while ((read = segFIS.read()) != -1) { assertEquals("Read unexpected byte at offset " + offset, (offset % 256), read); offset++; byteCount++; } assertEquals("Didn't read expected segment length for segment " + i, expectedBytesRead[i], byteCount); segFIS.close(); } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/tests/BaseStorageServiceTests.java0000644000000000000000000020055511550421156023051 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.tests; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLDecoder; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.TimeZone; import junit.framework.TestCase; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.S3Service; import org.jets3t.service.ServiceException; import org.jets3t.service.StorageObjectsChunk; import org.jets3t.service.StorageService; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.acl.CanonicalGrantee; import org.jets3t.service.acl.GranteeInterface; import org.jets3t.service.acl.GroupGrantee; import org.jets3t.service.acl.Permission; import org.jets3t.service.acl.gs.AllUsersGrantee; import org.jets3t.service.acl.gs.GSAccessControlList; import org.jets3t.service.acl.gs.UserByIdGrantee; import org.jets3t.service.impl.rest.httpclient.GoogleStorageService; import org.jets3t.service.impl.rest.httpclient.RestStorageService; import org.jets3t.service.model.StorageBucket; import org.jets3t.service.model.StorageObject; import org.jets3t.service.model.StorageOwner; import org.jets3t.service.multi.SimpleThreadedStorageService; import org.jets3t.service.multi.StorageServiceEventAdaptor; import org.jets3t.service.multi.ThreadedStorageService; import org.jets3t.service.multi.event.CreateObjectsEvent; import org.jets3t.service.multi.event.DeleteObjectsEvent; import org.jets3t.service.multi.event.GetObjectHeadsEvent; import org.jets3t.service.multi.event.GetObjectsEvent; import org.jets3t.service.security.ProviderCredentials; import org.jets3t.service.utils.FileComparer; import org.jets3t.service.utils.FileComparerResults; import org.jets3t.service.utils.Mimetypes; import org.jets3t.service.utils.ObjectUtils; import org.jets3t.service.utils.RestUtils; import org.jets3t.service.utils.ServiceUtils; /** * Runs generic functional tests that any storage service implementation should be * able to perform. *

* Any test cases for specific StorageService implementations should extend this class as a * starting point, then add test cases specific to that particular implementation. * * @author James Murty */ public abstract class BaseStorageServiceTests extends TestCase { protected static final String TARGET_SERVICE_S3 = "AmazonS3"; protected static final String TARGET_SERVICE_GS = "GoogleStorage"; protected String TEST_PROPERTIES_FILENAME = "test.properties"; protected Properties testProperties = null; public BaseStorageServiceTests() throws Exception { // Load test properties InputStream propertiesIS = ClassLoader.getSystemResourceAsStream(TEST_PROPERTIES_FILENAME); if (propertiesIS == null) { throw new Exception("Unable to load test properties file from classpath: " + TEST_PROPERTIES_FILENAME); } this.testProperties = new Properties(); this.testProperties.load(propertiesIS); } protected abstract ProviderCredentials getCredentials() throws Exception; protected abstract RestStorageService getStorageService(ProviderCredentials credentials) throws Exception; protected abstract String getTargetService(); protected abstract AccessControlList buildAccessControlList(); /** * @param testName * @return unique per-account and per-test bucket name */ protected String getBucketNameForTest(String testName) throws Exception { return "test-" + getCredentials().getAccessKey().toLowerCase() + "-" + testName.toLowerCase(); } protected StorageBucket createBucketForTest(String testName) throws Exception { String bucketName = getBucketNameForTest(testName); StorageService service = getStorageService(getCredentials()); return service.getOrCreateBucket(bucketName); } protected void deleteAllObjectsInBucket(String bucketName) { try { RestStorageService service = getStorageService(getCredentials()); for (StorageObject o: service.listObjects(bucketName)) { service.deleteObject(bucketName, o.getKey()); } } catch (Exception e) { // This shouldn't happen, but if it does don't ruin the test e.printStackTrace(); } } protected void cleanupBucketForTest(String testName, boolean deleteAllObjects) { try { RestStorageService service = getStorageService(getCredentials()); String bucketName = getBucketNameForTest(testName); if (deleteAllObjects) { deleteAllObjectsInBucket(bucketName); } service.deleteBucket(bucketName); } catch (Exception e) { // This shouldn't happen, but if it does don't ruin the test e.printStackTrace(); } } protected void cleanupBucketForTest(String testName) { this.cleanupBucketForTest(testName, true); } ///////////////////////////// // Actual tests start here // ///////////////////////////// public void testListBuckets() throws Exception { // List without credentials try { getStorageService(null).listAllBuckets(); fail("Bucket listing should fail without authentication"); } catch (ServiceException e) { } // List with credentials getStorageService(getCredentials()).listAllBuckets(); // Ensure newly-created bucket is listed String bucketName = createBucketForTest("testListBuckets").getName(); try { StorageBucket[] buckets = getStorageService(getCredentials()).listAllBuckets(); boolean found = false; for (StorageBucket bucket: buckets) { found = (bucket.getName().equals(bucketName)) || found; } assertTrue("Newly-created bucket was not listed", found); } finally { cleanupBucketForTest("testListBuckets"); } } public void testBucketManagement() throws Exception { RestStorageService service = getStorageService(getCredentials()); try { service.createBucket(""); fail("Cannot create a bucket with empty name"); } catch (ServiceException e) { } try { service.createBucket("test"); fail("Cannot create a bucket with non-unique name"); } catch (ServiceException e) { } String bucketName = createBucketForTest("testBucketManagement").getName(); boolean bucketExists = service.isBucketAccessible(bucketName); assertTrue("Bucket should exist", bucketExists); try { service.deleteBucket((String) null); fail("Cannot delete a bucket with null name"); } catch (ServiceException e) { } try { service.deleteBucket(""); fail("Cannot delete a bucket with empty name"); } catch (ServiceException e) { } try { service.deleteBucket("test"); fail("Cannot delete a bucket you don't own"); } catch (ServiceException e) { } // Ensure we can delete our bucket service.deleteBucket(bucketName); } public void testBucketStatusLookup() throws Exception { String bucketName = getBucketNameForTest("testBucketStatusLookup"); RestStorageService service = getStorageService(getCredentials()); // Non-existent bucket int status = service.checkBucketStatus(bucketName); assertEquals(S3Service.BUCKET_STATUS__DOES_NOT_EXIST, status); // Bucket is owned by someone else // NOTE: This test will fail if you actually own the "testing" bucket, // or if it is owned by someone else but has been made publicly readable. status = service.checkBucketStatus("testing"); assertEquals(S3Service.BUCKET_STATUS__ALREADY_CLAIMED, status); try { service.createBucket(bucketName); // Bucket now exists and is owned by me. status = service.checkBucketStatus(bucketName); assertEquals(S3Service.BUCKET_STATUS__MY_BUCKET, status); } finally { // Clean up service.deleteBucket(bucketName); } } public void testObjectManagement() throws Exception { String bucketName = createBucketForTest("testObjectManagement").getName(); RestStorageService service = getStorageService(getCredentials()); try { StorageObject object = new StorageObject("TestObject"); try { service.putObject((String) null, null); fail("Cannot create an object without a valid bucket"); } catch (ServiceException e) { } try { service.putObject((String) null, object); fail("Cannot create an object without a valid bucket"); } catch (ServiceException e) { } try { service.putObject(bucketName, new StorageObject()); fail("Cannot create an object without a valid object"); } catch (ServiceException e) { } // Create basic object with no content type (use the default) and no data. StorageObject basicObject = service.putObject(bucketName, object); // Ensure Content-Type is set to binary by default // TODO: Google Storage bug: Content type returned on initial PUT is always "text/html" if (!TARGET_SERVICE_GS.equals(getTargetService())) { assertTrue("Unexpected default content type", Mimetypes.MIMETYPE_OCTET_STREAM.equals(basicObject.getContentType())); } // Re-retrieve object to ensure it was correctly created. basicObject = service.getObject(bucketName, object.getKey()); assertEquals("Unexpected content type", Mimetypes.MIMETYPE_OCTET_STREAM, basicObject.getContentType()); assertEquals("Unexpected size for 'empty' object", 0, basicObject.getContentLength()); basicObject.closeDataInputStream(); // Make sure bucket cannot be removed while it has contents. try { service.deleteBucket(bucketName); fail("Should not be able to delete a bucket containing objects"); } catch (ServiceException e) { } // Update/overwrite object with real data content and some metadata. String contentType = "text/plain"; String objectData = "Just some rubbish text to include as data"; String dataMd5HashAsHex = ServiceUtils.toHex( ServiceUtils.computeMD5Hash(objectData.getBytes())); HashMap metadata = new HashMap(); metadata.put("creator", "testObjectManagement"); metadata.put("purpose", "For testing purposes"); object.replaceAllMetadata(metadata); object.setContentType(contentType); object.setDataInputStream(new ByteArrayInputStream(objectData.getBytes())); StorageObject dataObject = service.putObject(bucketName, object); // TODO: Google Storage bug: Content type returned on initial PUT is always "text/html" if (TARGET_SERVICE_GS.equals(getTargetService())) { dataObject = service.getObject(bucketName, object.getKey()); } assertEquals("Unexpected content type", contentType, dataObject.getContentType()); assertEquals("Mismatching MD5 hex hash", dataMd5HashAsHex, dataObject.getETag()); // Retrieve data object to ensure it was correctly created, the server-side hash matches // what we expect, and we get our metadata back. dataObject = service.getObject(bucketName, object.getKey()); assertEquals("Unexpected default content type", "text/plain", dataObject.getContentType()); // TODO: Google Storage doesn't reliably return Content-Length in a GET if (!TARGET_SERVICE_GS.equals(getTargetService())) { assertEquals("Unexpected content-length for object", objectData.length(), dataObject.getContentLength()); } assertEquals("Mismatching hash", dataMd5HashAsHex, dataObject.getETag()); assertEquals("Missing creator metadata", "testObjectManagement", dataObject.getMetadata("creator")); assertEquals("Missing purpose metadata", "For testing purposes", dataObject.getMetadata("purpose")); assertNotNull("Expected data input stream to be available", dataObject.getDataInputStream()); // Ensure we can get the data from S3. StringBuffer sb = new StringBuffer(); int b = -1; while ((b = dataObject.getDataInputStream().read()) != -1) { sb.append((char) b); } dataObject.closeDataInputStream(); assertEquals("Mismatching data", objectData, sb.toString()); // Retrieve only HEAD of data object (all metadata is available, but not the object content // data input stream) dataObject = service.getObjectDetails(bucketName, object.getKey()); assertEquals("Unexpected default content type", "text/plain", dataObject.getContentType()); assertEquals("Mismatching hash", dataMd5HashAsHex, dataObject.getETag()); assertEquals("Missing creator metadata", "testObjectManagement", dataObject.getMetadata("creator")); assertEquals("Missing purpose metadata", "For testing purposes", dataObject.getMetadata("purpose")); assertNull("Expected data input stream to be unavailable", dataObject.getDataInputStream()); assertEquals("Unexpected size for object", objectData.length(), dataObject.getContentLength()); // Test object GET constraints. Calendar objectCreationTimeCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"), Locale.US); objectCreationTimeCal.setTime(dataObject.getLastModifiedDate()); Calendar yesterday = (Calendar) objectCreationTimeCal.clone(); yesterday.add(Calendar.DAY_OF_YEAR, -1); Calendar tomorrow = (Calendar) objectCreationTimeCal.clone(); tomorrow.add(Calendar.DAY_OF_YEAR, +2); // Precondition: Modified since yesterday service.getObjectDetails(bucketName, object.getKey(), yesterday, null, null, null); // Precondition: Mot modified since after creation date. try { service.getObjectDetails(bucketName, object.getKey(), objectCreationTimeCal, null, null, null); fail("Cannot have been modified since object was created"); } catch (ServiceException e) { } // Precondition: Not modified since yesterday try { service.getObjectDetails(bucketName, object.getKey(), null, yesterday, null, null); fail("Cannot be unmodified since yesterday"); } catch (ServiceException e) { } // Precondition: Not modified since tomorrow service.getObjectDetails(bucketName, object.getKey(), null, tomorrow, null, null); // Precondition: matches correct hash service.getObjectDetails(bucketName, object.getKey(), null, null, new String[] {dataMd5HashAsHex}, null); // Precondition: doesn't match incorrect hash try { service.getObjectDetails(bucketName, object.getKey(), null, null, new String[] {"__" + dataMd5HashAsHex.substring(2)}, null); fail("Hash values should not match"); } catch (ServiceException e) { } // Precondition: doesn't match correct hash try { service.getObjectDetails(bucketName, object.getKey(), null, null, null, new String[] {dataMd5HashAsHex}); fail("Hash values should mis-match"); } catch (ServiceException e) { } // Precondition: doesn't match incorrect hash service.getObjectDetails(bucketName, object.getKey(), null, null, null, new String[] {"__" + dataMd5HashAsHex.substring(2)}); // Retrieve only a limited byte-range of the data, with a start and end. Long byteRangeStart = new Long(3); Long byteRangeEnd = new Long(12); dataObject = service.getObject(bucketName, object.getKey(), null, null, null, null, byteRangeStart, byteRangeEnd); String dataReceived = ServiceUtils.readInputStreamToString( dataObject.getDataInputStream(), Constants.DEFAULT_ENCODING); String dataExpected = objectData.substring(byteRangeStart.intValue(), byteRangeEnd.intValue() + 1); assertEquals("Mismatching data from range precondition", dataExpected, dataReceived); // Retrieve only a limited byte-range of the data, with a start range only. byteRangeStart = new Long(7); byteRangeEnd = null; dataObject = service.getObject(bucketName, object.getKey(), null, null, null, null, byteRangeStart, byteRangeEnd); dataReceived = ServiceUtils.readInputStreamToString( dataObject.getDataInputStream(), Constants.DEFAULT_ENCODING); dataExpected = objectData.substring(byteRangeStart.intValue()); assertEquals("Mismatching data from range precondition", dataExpected, dataReceived); // Retrieve only a limited byte-range of the data, with an end range only. byteRangeStart = null; byteRangeEnd = new Long(13); dataObject = service.getObject(bucketName, object.getKey(), null, null, null, null, byteRangeStart, byteRangeEnd); dataReceived = ServiceUtils.readInputStreamToString( dataObject.getDataInputStream(), Constants.DEFAULT_ENCODING); dataExpected = objectData.substring(objectData.length() - byteRangeEnd.intValue()); assertEquals("Mismatching data from range precondition", dataExpected, dataReceived); // Clean-up. service.deleteObject(bucketName, object.getKey()); // Create object with tricky key. String trickyKey = "http://example.site.com/some/path/document name.html?param1=a@b#c$d¶m2=(089)"; StorageObject trickyObject = service.putObject(bucketName, new StorageObject(trickyKey, "Some test data")); assertEquals("Tricky key name mistmatch", trickyKey, trickyObject.getKey()); // Make sure the tricky named object really exists with its full name. StorageObject[] objects = service.listObjects(bucketName); boolean trickyNamedObjectExists = false; for (int i = 0; !trickyNamedObjectExists && i < objects.length; i++) { if (trickyKey.equals(objects[i].getKey())) { trickyNamedObjectExists = true; } } assertTrue("Tricky key name object does not exist with its full name", trickyNamedObjectExists); // Delete object with tricky key. service.deleteObject(bucketName, trickyObject.getKey()); } finally { cleanupBucketForTest("testObjectManagement"); } } public void testDirectoryPlaceholderObjects() throws Exception { String bucketName = createBucketForTest("testDirectoryPlaceholderObjects").getName(); RestStorageService service = getStorageService(getCredentials()); try { // Create new-style place-holder object (compatible with Amazon's AWS Console // and Panic's Transmit) -- note trailing slash StorageObject requestObject = new StorageObject("DirPlaceholderObject/"); requestObject.setContentLength(0); requestObject.setContentType(Mimetypes.MIMETYPE_BINARY_OCTET_STREAM); assertTrue(requestObject.isDirectoryPlaceholder()); service.putObject(bucketName, requestObject); StorageObject resultObject = service.getObjectDetails(bucketName, requestObject.getKey()); assertTrue(resultObject.isDirectoryPlaceholder()); // Create legacy-style place-holder object (compatible with objects stored using // JetS3t applications prior to version 0.8.0) -- note content type requestObject = new StorageObject("LegacyDirPlaceholderObject"); requestObject.setContentLength(0); requestObject.setContentType(Mimetypes.MIMETYPE_JETS3T_DIRECTORY); assertTrue(requestObject.isDirectoryPlaceholder()); service.putObject(bucketName, requestObject); resultObject = service.getObjectDetails(bucketName, requestObject.getKey()); assertTrue(resultObject.isDirectoryPlaceholder()); // Create place-holder object compatible with the S3 Organizer Firefox extension // -- note object name suffix. requestObject = new StorageObject("S3OrganizerDirPlaceholderObject_$folder$"); requestObject.setContentLength(0); assertTrue(requestObject.isDirectoryPlaceholder()); service.putObject(bucketName, requestObject); resultObject = service.getObjectDetails(bucketName, requestObject.getKey()); assertTrue(resultObject.isDirectoryPlaceholder()); } finally { cleanupBucketForTest("testDirectoryPlaceholderObjects"); } } public void testCopyObjects() throws Exception { String sourceBucketName = createBucketForTest("testCopyObjects-source").getName(); String targetBucketName = createBucketForTest("testCopyObjects-target").getName(); RestStorageService service = getStorageService(getCredentials()); try { // Create source objects to copy, with potentially troublesome names String[] objectNames = new String[] { "testing.txt", "test me.txt", "virtual-path/testing.txt", "vîrtüál-πå†h/tés†ing.txt" }; for (int i = 0; i < objectNames.length; i++) { StorageObject object = new StorageObject( objectNames[i], "A little data"); object.addMetadata("object-offset", "" + i); service.putObject(sourceBucketName, object); } // Copy objects within bucket, retaining metadata String targetPath = "copies/"; for (String objectName: objectNames) { StorageObject targetObject = new StorageObject( targetPath + objectName); service.copyObject(sourceBucketName, objectName, sourceBucketName, targetObject, false // replaceMetadata ); } // Ensure objects are in target location and have the same metadata for (int i = 0; i < objectNames.length; i++) { StorageObject object = service.getObjectDetails( sourceBucketName, targetPath + objectNames[i]); assertEquals("" + i, object.getMetadata("object-offset")); } // Copy object within bucket, replacing metadata StorageObject targetObject = new StorageObject( targetPath + objectNames[0]); targetObject.addMetadata("replaced-metadata", "booyah!"); service.copyObject(sourceBucketName, objectNames[0], sourceBucketName, targetObject, true // replaceMetadata ); StorageObject copiedObject = service.getObjectDetails( sourceBucketName, targetObject.getName()); assertNull(copiedObject.getMetadata("object-offset")); assertEquals("booyah!", copiedObject.getMetadata("replaced-metadata")); // Copy objects between buckets for (String objectName: objectNames) { targetObject = new StorageObject(objectName); service.copyObject(sourceBucketName, objectName, targetBucketName, targetObject, false // replaceMetadata ); copiedObject = service.getObjectDetails( targetBucketName, targetObject.getName()); } assertEquals(4, service.listObjects(targetBucketName).length); // Rename convenience method int objectOffset = 3; targetObject = new StorageObject("my-new-name"); service.renameObject( sourceBucketName, objectNames[objectOffset], targetObject); copiedObject = service.getObjectDetails( sourceBucketName, targetObject.getName()); // Ensure we have a new object with the same metadata assertEquals("my-new-name", copiedObject.getKey()); assertEquals("" + objectOffset, copiedObject.getMetadata("object-offset")); // Update metadata convenience method objectOffset = 2; targetObject = new StorageObject(objectNames[objectOffset]); targetObject.addMetadata("object-offset", "" + objectOffset); // Unchanged targetObject.addMetadata("was-i-updated", "yes!"); service.updateObjectMetadata(sourceBucketName, targetObject); copiedObject = service.getObjectDetails( sourceBucketName, targetObject.getName()); // Ensure we have the same object with updated metadata assertEquals("yes!", copiedObject.getMetadata("was-i-updated")); // Move object convenience method - retain metadata objectOffset = 0; targetObject = new StorageObject(objectNames[objectOffset]); service.moveObject(sourceBucketName, objectNames[objectOffset], targetBucketName, targetObject, false); try { service.getObjectDetails( sourceBucketName, objectNames[objectOffset]); fail("Source object should be moved"); } catch (ServiceException e) { // Expected } copiedObject = service.getObjectDetails( targetBucketName, targetObject.getName()); assertEquals("" + objectOffset, copiedObject.getMetadata("object-offset")); // Move object convenience method - replace metadata objectOffset = 1; targetObject = new StorageObject(objectNames[objectOffset]); targetObject.addMetadata("was-i-moved-with-new-metadata", "yes!"); service.moveObject(sourceBucketName, objectNames[objectOffset], targetBucketName, targetObject, true); try { service.getObjectDetails( sourceBucketName, objectNames[objectOffset]); fail("Source object should be moved"); } catch (ServiceException e) { // Expected } copiedObject = service.getObjectDetails( targetBucketName, targetObject.getName()); assertNull(copiedObject.getMetadata("object-offset")); assertEquals("yes!", copiedObject.getMetadata("was-i-moved-with-new-metadata")); } finally { cleanupBucketForTest("testCopyObjects-source"); cleanupBucketForTest("testCopyObjects-target"); } } public void testUnicodeData() throws Exception { String bucketName = createBucketForTest("testUnicodeData").getName(); RestStorageService service = getStorageService(getCredentials()); try { // Unicode object name String unicodeText = "テストオブジェクト"; StorageObject requestObject = new StorageObject("1." + unicodeText); service.putObject(bucketName, requestObject); StorageObject resultObject = service.getObjectDetails(bucketName, requestObject.getKey()); assertEquals("1." + unicodeText, resultObject.getKey()); // Unicode data content requestObject = new StorageObject("2." + unicodeText, unicodeText); service.putObject(bucketName, requestObject); resultObject = service.getObject(bucketName, requestObject.getKey()); String data = ServiceUtils.readInputStreamToString( resultObject.getDataInputStream(), "UTF-8"); assertEquals(unicodeText, data); // Unicode metadata values are not supported requestObject = new StorageObject("3." + unicodeText); requestObject.addMetadata("testing", unicodeText); try { service.putObject(bucketName, requestObject); } catch (ServiceException e) { } // Unicode metadata values can be encoded requestObject = new StorageObject("4." + unicodeText); requestObject.addMetadata("testing", URLEncoder.encode(unicodeText, "UTF-8")); service.putObject(bucketName, requestObject); resultObject = service.getObjectDetails(bucketName, requestObject.getKey()); assertEquals(unicodeText, URLDecoder.decode( (String) resultObject.getMetadata("testing"), "UTF-8")); // Unicode metadata names are not possible with HTTP requestObject = new StorageObject("5." + unicodeText); requestObject.addMetadata(unicodeText, "value"); try { service.putObject(bucketName, requestObject); fail("Illegal to use non-ASCII characters in HTTP headers"); } catch (ServiceException e) { } // Unicode HTTP headers (via RFC 5987 encoding) -- not working... /* requestObject = new StorageObject("6." + unicodeText); requestObject.setContentDisposition( "attachment; filename*=UTF-8''" + RestUtils.encodeUrlString(unicodeText + ".txt")); service.putObject(bucketName, requestObject); resultObject = service.getObjectDetails(bucketName, requestObject.getKey()); assertEquals( "attachment; filename=" + unicodeText + "", resultObject.getContentDisposition()); */ } finally { cleanupBucketForTest("testUnicodeData"); } } public void testACLManagement() throws Exception { // Access public-readable third-party bucket: jets3t RestStorageService anonymousS3Service = getStorageService(null); boolean jets3tBucketAvailable = anonymousS3Service.isBucketAccessible("jets3t"); assertTrue("Cannot find public jets3t bucket", jets3tBucketAvailable); RestStorageService service = getStorageService(getCredentials()); // Use Google- or S3-specific URL endpoint to lookup objects, depending on the target service String linkUrlPrefix = null; if (TARGET_SERVICE_GS.equals(getTargetService())) { linkUrlPrefix = "https://commondatastorage.googleapis.com"; } else { linkUrlPrefix = "https://s3.amazonaws.com"; } // Use Google- or S3-specific ACL elements depending on which service class we're using GranteeInterface allUsersGrantee = null; if (service instanceof GoogleStorageService) { allUsersGrantee = new AllUsersGrantee(); } else { allUsersGrantee = GroupGrantee.ALL_USERS; } StorageBucket bucket = createBucketForTest("testACLManagement"); String bucketName = bucket.getName(); StorageObject object = null; try { // Create private object (default permissions). String privateKey = "Private Object - " + System.currentTimeMillis(); object = new StorageObject(privateKey, "Private object sample text"); service.putObject(bucketName, object); URL url = new URL(linkUrlPrefix + "/" + bucketName + "/" + RestUtils.encodeUrlString(privateKey)); assertEquals("Expected denied access (403) error", 403, ((HttpURLConnection) url .openConnection()).getResponseCode()); // Get ACL details for private object so we can determine the bucket owner. AccessControlList bucketACL = service.getBucketAcl(bucketName); StorageOwner bucketOwner = bucketACL.getOwner(); // Create a public object. String publicKey = "Public Object - " + System.currentTimeMillis(); object = new StorageObject(publicKey, "Public object sample text"); AccessControlList acl = buildAccessControlList(); acl.setOwner(bucketOwner); acl.grantPermission(allUsersGrantee, Permission.PERMISSION_READ); // TODO: Google Storage quirk: Must *always* explicitly grant owner full control in ACL if (TARGET_SERVICE_GS.equals(getTargetService())) { // Apply S3 or GS ACL object, depending on the service type we're using if (service instanceof GoogleStorageService) { acl.grantPermission( new UserByIdGrantee(bucketOwner.getId()), Permission.PERMISSION_FULL_CONTROL); } else { acl.grantPermission( new CanonicalGrantee(bucketOwner.getId()), Permission.PERMISSION_FULL_CONTROL); } } object.setAcl(acl); service.putObject(bucketName, object); url = new URL(linkUrlPrefix + "/" + bucketName + "/" + RestUtils.encodeUrlString(publicKey)); assertEquals("Expected access (200)", 200, ((HttpURLConnection)url.openConnection()).getResponseCode()); // Update ACL to make private object public. AccessControlList privateToPublicACL = service.getObjectAcl(bucketName, privateKey); privateToPublicACL.grantPermission(allUsersGrantee, Permission.PERMISSION_READ); object.setKey(privateKey); object.setAcl(privateToPublicACL); service.putObjectAcl(bucketName, object); url = new URL(linkUrlPrefix + "/" + bucketName + "/" + RestUtils.encodeUrlString(privateKey)); assertEquals("Expected access (200)", 200, ((HttpURLConnection) url.openConnection()) .getResponseCode()); // Create a non-standard uncanned public object. String publicKey2 = "Public Object - " + System.currentTimeMillis(); object = new StorageObject(publicKey2); object.setAcl(privateToPublicACL); // This ACL has ALL_USERS READ permission set above. service.putObject(bucketName, object); url = new URL(linkUrlPrefix + "/" + bucketName + "/" + RestUtils.encodeUrlString(publicKey2)); assertEquals("Expected access (200)", 200, ((HttpURLConnection) url.openConnection()) .getResponseCode()); // Update ACL to make public object private. AccessControlList publicToPrivateACL = service.getObjectAcl(bucketName, publicKey); publicToPrivateACL.revokeAllPermissions(allUsersGrantee); object.setKey(publicKey); object.setAcl(publicToPrivateACL); service.putObjectAcl(bucketName, object); // TODO: Google Storage quirk: It may take some time for public object to become private again if (TARGET_SERVICE_GS.equals(getTargetService())) { // Confirm changes were applied on object's ACL, because we don't know // how long to wait until the object will really become private again. AccessControlList updatedAcl = service.getObjectAcl(bucketName, object.getKey()); assertFalse(updatedAcl.hasGranteeAndPermission( allUsersGrantee, Permission.PERMISSION_READ)); assertEquals(0, updatedAcl.getPermissionsForGrantee(allUsersGrantee).size()); } else { // In S3, objects are made private immediately. url = new URL(linkUrlPrefix + "/" + bucketName + "/" + RestUtils.encodeUrlString(publicKey)); assertEquals("Expected denied access (403) error", 403, ((HttpURLConnection) url .openConnection()).getResponseCode()); } // Clean-up. service.deleteObject(bucketName, privateKey); service.deleteObject(bucketName, publicKey); service.deleteObject(bucketName, publicKey2); } finally { cleanupBucketForTest("testACLManagement"); } } public void testACLManagementViaRestHeaders() throws Exception { RestStorageService service = getStorageService(getCredentials()); StorageBucket bucket = createBucketForTest("testACLManagementViaRestHeaders"); AccessControlList publicHeaderAcl = null; if (service instanceof GoogleStorageService) { publicHeaderAcl = GSAccessControlList.REST_CANNED_PUBLIC_READ; } else { publicHeaderAcl = AccessControlList.REST_CANNED_PUBLIC_READ; } try { // Try to create public object using HTTP header ACL settings. String publicKey = "PublicObject"; StorageObject object = new StorageObject(publicKey); object.setAcl(publicHeaderAcl); object.setOwner(bucket.getOwner()); try { service.putObject(bucket.getName(), object); URL url = new URL("https://" + service.getEndpoint() + "/" + bucket.getName() + "/" + publicKey); assertEquals("Expected public access (200)", 200, ((HttpURLConnection)url.openConnection()).getResponseCode()); } finally { service.deleteObject(bucket.getName(), object.getKey()); } } finally { cleanupBucketForTest("testACLManagementViaRestHeaders"); } } public void testObjectListing() throws Exception { RestStorageService service = getStorageService(getCredentials()); StorageBucket bucket = createBucketForTest("testObjectListing"); String bucketName = bucket.getName(); try { // Represent a directory structure in S3. List objectsList = new ArrayList(); objectsList.add(new StorageObject("dir1")); objectsList.add(new StorageObject("dir1/doc1Level1")); objectsList.add(new StorageObject("dir1/doc2level1")); objectsList.add(new StorageObject("dir1/dir1Level1")); objectsList.add(new StorageObject("dir1/dir1Level1/doc1Level2")); objectsList.add(new StorageObject("dir1/dir1Level1/dir1Level2")); objectsList.add(new StorageObject("dir1/dir1Level1/dir1Level2/doc1Level3")); // Create objects for (StorageObject object: objectsList) { service.putObject(bucketName, object); } StorageObject[] objects = null; // List all items in directory. objects = service.listObjects(bucketName); assertEquals("Incorrect number of objects in directory structure", objectsList.size(), objects.length); // List items in chunks of size 2, ensure we get a total of seven. int chunkedObjectsCount = 0; int chunkedIterationsCount = 0; String priorLastKey = null; do { StorageObjectsChunk chunk = service.listObjectsChunked( bucketName, null, null, 2, priorLastKey); priorLastKey = chunk.getPriorLastKey(); chunkedObjectsCount += chunk.getObjects().length; chunkedIterationsCount++; } while (priorLastKey != null); assertEquals("Chunked bucket listing retreived incorrect number of objects", objectsList.size(), chunkedObjectsCount); assertEquals("Chunked bucket listing ran for an unexpected number of iterations", (objectsList.size() + 1) / 2, chunkedIterationsCount); // List objects with a prefix and delimiter to check common prefixes. StorageObjectsChunk chunk = service.listObjectsChunked( bucketName, "dir1/", "/", 100, null); assertEquals("Chunked bucket listing with prefix and delimiter retreived incorrect number of objects", 3, chunk.getObjects().length); assertEquals("Chunked bucket listing with prefix and delimiter retreived incorrect number of common prefixes", 1, chunk.getCommonPrefixes().length); // List the same items with a prefix. objects = service.listObjects(bucketName, "dir1", null); assertEquals("Incorrect number of objects matching prefix", 7, objects.length); // List items up one directory with a prefix (will include dir1Level1) objects = service.listObjects(bucketName, "dir1/dir1Level1", null); assertEquals("Incorrect number of objects matching prefix", 4, objects.length); // List items up one directory with a prefix (will not include dir1Level1) objects = service.listObjects(bucketName, "dir1/dir1Level1/", null); assertEquals("Incorrect number of objects matching prefix", 3, objects.length); // Try a prefix matching no object keys. objects = service.listObjects(bucketName, "dir1-NonExistent", null); assertEquals("Expected no results", 0, objects.length); // Use delimiter with an partial prefix. objects = service.listObjects(bucketName, "dir", "/"); assertEquals("Expected no results", 1, objects.length); // Use delimiter to find item dir1 only. objects = service.listObjects(bucketName, "dir1", "/"); assertEquals("Incorrect number of objects matching prefix and delimiter", 1, objects.length); // Use delimiter to find items within dir1 only. objects = service.listObjects(bucketName, "dir1/", "/"); assertEquals("Incorrect number of objects matching prefix and delimiter", 3, objects.length); // List items up one directory with prefix and delimiter (will include only dir1Level1) objects = service.listObjects(bucketName, "dir1/dir1Level1", "/"); assertEquals("Incorrect number of objects matching prefix", 1, objects.length); // List items up one directory with prefix and delimiter (will include only contents of dir1Level1) objects = service.listObjects(bucketName, "dir1/dir1Level1/", "/"); assertEquals("Incorrect number of objects matching prefix", 2, objects.length); // Clean up. for (StorageObject object: objectsList) { service.deleteObject(bucketName, object.getKey()); } } finally { cleanupBucketForTest("testObjectListing"); } } public void testHashVerifiedUploads() throws Exception { RestStorageService service = getStorageService(getCredentials()); StorageBucket bucket = createBucketForTest("testHashVerifiedUploads"); String bucketName = bucket.getName(); try { // Create test object with an MD5 hash of the data. String dataString = "Text for MD5 hashing..."; StorageObject object = new StorageObject("Testing MD5 Hashing", dataString); object.setContentType("text/plain"); // Calculate hash data for object. byte[] md5Hash = ServiceUtils.computeMD5Hash(dataString.getBytes()); // Ensure that using an invalid hash value fails. try { object.addMetadata("Content-MD5", "123"); service.putObject(bucketName, object); fail("Should have failed due to invalid hash value"); } catch (ServiceException e) { assertTrue("Expected error code indicating invalid md5 hash", "InvalidDigest".equals(e.getErrorCode()) // S3 error code || "BadDigest".equals(e.getErrorCode()) // GS error code ); } object = new StorageObject("Testing MD5 Hashing", dataString); // Ensure that using the wrong hash value fails. try { byte[] incorrectHash = new byte[md5Hash.length]; System.arraycopy(md5Hash, 0, incorrectHash, 0, incorrectHash.length); incorrectHash[0] = incorrectHash[1]; object.setMd5Hash(incorrectHash); service.putObject(bucketName, object); fail("Should have failed due to incorrect hash value"); } catch (ServiceException e) { assertEquals("Expected error code indicating invalid md5 hash", "BadDigest", e.getErrorCode()); } object = new StorageObject("Testing MD5 Hashing", dataString); // Ensure that correct hash value succeeds. object.setMd5Hash(md5Hash); StorageObject resultObject = service.putObject(bucketName, object); // Ensure the ETag result matches the hex-encoded MD5 hash. assertEquals("Hex-encoded MD5 hash should match ETag", resultObject.getETag(), ServiceUtils.toHex(md5Hash)); // Ensure we can convert the hex-encoded ETag to Base64 that matches the Base64 md5 hash. String md5HashBase64 = ServiceUtils.toBase64(md5Hash); String eTagBase64 = ServiceUtils.toBase64(ServiceUtils.fromHex(resultObject.getETag())); assertEquals("Could not convert ETag and MD5 hash to matching Base64-encoded strings", md5HashBase64, eTagBase64); // Clean up. service.deleteObject(bucketName, object.getKey()); } finally { cleanupBucketForTest("testHashVerifiedUploads"); } } public void testIsObjectInBucket() throws Exception { RestStorageService service = getStorageService(getCredentials()); StorageBucket bucket = createBucketForTest("testIsObjecInBucket"); String bucketName = bucket.getName(); try { service.putObject(bucketName, new StorageObject("does-exist")); assertTrue(service.isObjectInBucket(bucketName, "does-exist")); assertFalse(service.isObjectInBucket(bucketName, "does-not-exist")); } finally { cleanupBucketForTest("testIsObjecInBucket"); } } public void testThreadedStorageService() throws Exception { RestStorageService service = getStorageService(getCredentials()); StorageBucket bucket = createBucketForTest("testThreadedStorageService"); String bucketName = bucket.getName(); try { final int[] createObjectsEventCount = new int[] {0}; final int[] getObjectHeadsEventCount = new int[] {0}; final List getObjectsList = new ArrayList(); final int[] deleteObjectsEventCount = new int[] {0}; // Multi-threaded service with adaptor to count event occurrences. ThreadedStorageService threadedService = new ThreadedStorageService( service, new StorageServiceEventAdaptor() { @Override public void event(CreateObjectsEvent event) { if (CreateObjectsEvent.EVENT_IN_PROGRESS == event.getEventCode()) { createObjectsEventCount[0] += event.getCreatedObjects().length; } } @Override public void event(GetObjectHeadsEvent event) { if (GetObjectHeadsEvent.EVENT_IN_PROGRESS == event.getEventCode()) { getObjectHeadsEventCount[0] += event.getCompletedObjects().length; } } @Override public void event(GetObjectsEvent event) { if (GetObjectsEvent.EVENT_IN_PROGRESS == event.getEventCode()) { for (StorageObject object: event.getCompletedObjects()) { getObjectsList.add(object); } } } @Override public void event(DeleteObjectsEvent event) { if (DeleteObjectsEvent.EVENT_IN_PROGRESS == event.getEventCode()) { deleteObjectsEventCount[0] += event.getDeletedObjects().length; } } }); assertEquals(0, createObjectsEventCount[0]); assertEquals(0, getObjectHeadsEventCount[0]); assertEquals(0, getObjectsList.size()); assertEquals(0, deleteObjectsEventCount[0]); StorageObject[] objects = new StorageObject[] { new StorageObject("one.txt", "Some data"), new StorageObject("twö.txt", "Some data"), new StorageObject("thréè.txt", "Some data"), new StorageObject("fôür.txt", "Some data"), new StorageObject("fîvæ∫.txt", "Some data") }; // Upload multiple objects boolean success = threadedService.putObjects(bucketName, objects); assertTrue(success); assertEquals(objects.length, createObjectsEventCount[0]); assertEquals(0, getObjectHeadsEventCount[0]); assertEquals(0, getObjectsList.size()); assertEquals(0, deleteObjectsEventCount[0]); // Retrieve details for multiple objects success = threadedService.getObjectsHeads(bucketName, objects); assertTrue(success); assertEquals(objects.length, createObjectsEventCount[0]); assertEquals(objects.length, getObjectHeadsEventCount[0]); assertEquals(0, getObjectsList.size()); assertEquals(0, deleteObjectsEventCount[0]); // Retrieve data for multiple objects success = threadedService.getObjects(bucketName, objects); assertTrue(success); assertEquals(objects.length, createObjectsEventCount[0]); assertEquals(objects.length, getObjectHeadsEventCount[0]); assertEquals(objects.length, getObjectsList.size()); assertEquals(0, deleteObjectsEventCount[0]); // Check all objects retrieved have expected data content. for (StorageObject getObject: getObjectsList) { // TODO: Google Storage doesn't reliably return Content-Length in a GET if (!TARGET_SERVICE_GS.equals(getTargetService())) { assertEquals("Some data".length(), getObject.getContentLength()); } String objectData = ServiceUtils.readInputStreamToString( getObject.getDataInputStream(), Constants.DEFAULT_ENCODING); assertEquals("Some data", objectData); } // Delete multiple objects success = threadedService.deleteObjects(bucketName, objects); assertTrue(success); assertEquals(objects.length, createObjectsEventCount[0]); assertEquals(objects.length, getObjectHeadsEventCount[0]); assertEquals(objects.length, getObjectsList.size()); assertEquals(objects.length, deleteObjectsEventCount[0]); StorageObject[] listedObjects = service.listObjects(bucketName); assertEquals(0, listedObjects.length); } finally { cleanupBucketForTest("testThreadedStorageService"); } } public void testSimpleThreadedStorageService() throws Exception { RestStorageService service = getStorageService(getCredentials()); StorageBucket bucket = createBucketForTest("testSimpleThreadedStorageService"); String bucketName = bucket.getName(); try { SimpleThreadedStorageService simpleThreadedService = new SimpleThreadedStorageService(service); StorageObject[] objects = new StorageObject[] { new StorageObject("1-one.txt", "Some data"), new StorageObject("2-twö.txt", "Some data"), new StorageObject("3-thréè.txt", "Some data"), new StorageObject("4-fôür.txt", "Some data"), new StorageObject("5-fîvæ∫.txt", "Some data") }; // Upload multiple objects StorageObject[] putObjects = simpleThreadedService.putObjects(bucketName, objects); StorageObject[] listedObjects = service.listObjects(bucketName); assertEquals(objects.length, listedObjects.length); // Retrieve details for multiple objects StorageObject[] headObjects = simpleThreadedService.getObjectsHeads(bucketName, objects); assertEquals(objects.length, headObjects.length); Arrays.sort(headObjects, new Comparator() { public int compare(StorageObject o1, StorageObject o2) { return o1.getKey().compareTo(o2.getKey()); } }); for (int i = 0; i < objects.length; i++) { assertEquals(objects[i].getKey(), headObjects[i].getKey()); assertEquals("Some data".length(), headObjects[i].getContentLength()); } // Retrieve data for multiple objects StorageObject[] getObjects = simpleThreadedService.getObjects(bucketName, objects); assertEquals(objects.length, getObjects.length); for (int i = 0; i < objects.length; i++) { // TODO: Google Storage doesn't reliably return Content-Length in a GET if (!TARGET_SERVICE_GS.equals(getTargetService())) { assertEquals("Some data".length(), getObjects[i].getContentLength()); } // Check all objects retrieved have expected data content. assertEquals("Some data", ServiceUtils.readInputStreamToString( getObjects[i].getDataInputStream(), Constants.DEFAULT_ENCODING)); } // Delete multiple objects simpleThreadedService.deleteObjects(bucketName, objects); listedObjects = service.listObjects(bucketName); assertEquals(0, listedObjects.length); } finally { cleanupBucketForTest("testSimpleThreadedStorageService"); } } public void testRecognizeDnsFriendlyBucketNames() { // Valid DNS bucket names assertTrue(ServiceUtils.isBucketNameValidDNSName("test")); assertTrue(ServiceUtils.isBucketNameValidDNSName("test-name")); assertTrue(ServiceUtils.isBucketNameValidDNSName("test.domain.name")); assertTrue(ServiceUtils.isBucketNameValidDNSName("test-domain.name")); assertTrue(ServiceUtils.isBucketNameValidDNSName( "this-bucket-name-is-not-too-long-with-63-chars--less-than-limit")); // IP-like, but not actual IP address numbers allowed assertTrue(ServiceUtils.isBucketNameValidDNSName("1234")); assertTrue(ServiceUtils.isBucketNameValidDNSName("123.4.5.6789")); assertTrue(ServiceUtils.isBucketNameValidDNSName("123.456")); assertTrue(ServiceUtils.isBucketNameValidDNSName("123.456.789")); // Invalid DNS bucket names assertFalse(ServiceUtils.isBucketNameValidDNSName(null)); assertFalse(ServiceUtils.isBucketNameValidDNSName("Capitalized")); assertFalse(ServiceUtils.isBucketNameValidDNSName("ab")); // Too short assertFalse(ServiceUtils.isBucketNameValidDNSName( "this-bucket-name-is-too-long-with-64-chars--more-than-allowed-63")); assertFalse(ServiceUtils.isBucketNameValidDNSName("bad-ch@racter")); assertFalse(ServiceUtils.isBucketNameValidDNSName("empty..segment")); assertFalse(ServiceUtils.isBucketNameValidDNSName("dash.-starts.segment")); assertFalse(ServiceUtils.isBucketNameValidDNSName("dash.ends-.segment")); // IP address numbers not allowed assertFalse(ServiceUtils.isBucketNameValidDNSName("192.12.4.1")); assertFalse(ServiceUtils.isBucketNameValidDNSName("127.0.0.1")); assertFalse(ServiceUtils.isBucketNameValidDNSName("123.456.789.012")); assertFalse(ServiceUtils.isBucketNameValidDNSName("10.0.0.1")); } public void testFileComparer() throws Exception { RestStorageService service = getStorageService(getCredentials()); StorageBucket bucket = createBucketForTest("testFileComparer"); String bucketName = bucket.getName(); try { // Create temporary file and directory structure File dummy = File.createTempFile("dummy-", ".txt"); File rootDir = new File(dummy.getParentFile(), "jets3t-test-" + dummy.getName()); File parentDir1 = new File(rootDir, "dir1"); File parentDir2 = new File(rootDir, "dir2"); parentDir1.mkdirs(); parentDir2.mkdirs(); File local1 = File.createTempFile("one", ".txt", parentDir1); File local2 = File.createTempFile("two", ".txt", parentDir1); File local3 = File.createTempFile("three", " ثلاثة.txt", parentDir2); String local1Path = parentDir1.getName() + File.separator + local1.getName(); String local2Path = parentDir1.getName() + File.separator + local2.getName(); String local3Path = parentDir2.getName() + File.separator + local3.getName(); FileComparer comparer = new FileComparer(new Jets3tProperties()); // Build a file map of local files Map objectKeyToFilepathMap = comparer.buildObjectKeyToFilepathMap( new File[] {parentDir1, parentDir2}, "", true); assertEquals(5, objectKeyToFilepathMap.size()); assertTrue(objectKeyToFilepathMap.keySet().contains(local1Path)); // Upload local directories and files to storage service service.putObject(bucketName, ObjectUtils.createObjectForUpload( parentDir1.getName() + "/", parentDir1, null, false)); service.putObject(bucketName, ObjectUtils.createObjectForUpload( parentDir2.getName() + "/", parentDir2, null, false)); service.putObject(bucketName, ObjectUtils.createObjectForUpload( local1Path, local1, null, false)); service.putObject(bucketName, ObjectUtils.createObjectForUpload( local2Path, local2, null, false)); service.putObject(bucketName, ObjectUtils.createObjectForUpload( local3Path, local3, null, false)); // Build a map of objects in storage service Map objectMap = comparer.buildObjectMap( service, bucket.getName(), "", objectKeyToFilepathMap, null, null); assertEquals(5, objectMap.size()); assertTrue(objectMap.keySet().contains(local3Path)); // Compare local and remote objects -- should be identical FileComparerResults comparerResults = comparer.buildDiscrepancyLists(objectKeyToFilepathMap, objectMap); assertEquals(5, comparerResults.alreadySynchronisedKeys.size()); assertEquals(0, comparerResults.onlyOnClientKeys.size()); assertEquals(0, comparerResults.onlyOnServerKeys.size()); assertEquals(0, comparerResults.updatedOnClientKeys.size()); assertEquals(0, comparerResults.updatedOnServerKeys.size()); // Update 1 local and 1 remote file, then confirm discrepancies byte[] data = "Updated local file".getBytes("UTF-8"); FileOutputStream local1FOS = new FileOutputStream(local1); local1FOS.write(data); local1FOS.close(); // Ensure local file's timestamp differs by at least 1 sec local1.setLastModified(local1.lastModified() + 1000); StorageObject remoteObject = new StorageObject(local3Path); remoteObject.setDataInputStream(new ByteArrayInputStream(data)); remoteObject.setContentLength(data.length); service.putObject(bucketName, remoteObject); objectMap = comparer.buildObjectMap( service, bucket.getName(), "", objectKeyToFilepathMap, null, null); comparerResults = comparer.buildDiscrepancyLists(objectKeyToFilepathMap, objectMap); assertEquals(3, comparerResults.alreadySynchronisedKeys.size()); assertEquals(0, comparerResults.onlyOnClientKeys.size()); assertEquals(0, comparerResults.onlyOnServerKeys.size()); assertEquals(1, comparerResults.updatedOnClientKeys.size()); assertTrue(comparerResults.updatedOnClientKeys.contains(local1Path)); assertEquals(1, comparerResults.updatedOnServerKeys.size()); assertTrue(comparerResults.updatedOnServerKeys.contains(local3Path)); // Create new local and remote objects, then confirm discrepancies File local4 = File.createTempFile("four", ".txt", parentDir2); String local4Path = parentDir2.getName() + File.separator + local4.getName(); remoteObject = new StorageObject("new-on-service.txt"); service.putObject(bucketName, remoteObject); objectKeyToFilepathMap = comparer.buildObjectKeyToFilepathMap( new File[] {parentDir1, parentDir2}, "", true); objectMap = comparer.buildObjectMap( service, bucket.getName(), "", objectKeyToFilepathMap, null, null); comparerResults = comparer.buildDiscrepancyLists(objectKeyToFilepathMap, objectMap); assertEquals(3, comparerResults.alreadySynchronisedKeys.size()); assertTrue(comparerResults.alreadySynchronisedKeys.contains(local2Path)); assertEquals(1, comparerResults.onlyOnClientKeys.size()); assertTrue(comparerResults.onlyOnClientKeys.contains(local4Path)); assertEquals(1, comparerResults.onlyOnServerKeys.size()); assertTrue(comparerResults.onlyOnServerKeys.contains("new-on-service.txt")); assertEquals(1, comparerResults.updatedOnClientKeys.size()); assertTrue(comparerResults.updatedOnClientKeys.contains(local1Path)); assertEquals(1, comparerResults.updatedOnServerKeys.size()); assertTrue(comparerResults.updatedOnServerKeys.contains(local3Path)); // Clean up after prior test local4.delete(); service.deleteObject(bucketName, "new-on-service.txt"); // Remove local file and remote object, then confirm discrepancies local3.delete(); service.deleteObject(bucketName, local1Path); objectKeyToFilepathMap = comparer.buildObjectKeyToFilepathMap( new File[] {parentDir1, parentDir2}, "", true); objectMap = comparer.buildObjectMap( service, bucket.getName(), "", objectKeyToFilepathMap, null, null); comparerResults = comparer.buildDiscrepancyLists(objectKeyToFilepathMap, objectMap); assertEquals(1, comparerResults.onlyOnClientKeys.size()); assertTrue(comparerResults.onlyOnClientKeys.contains(local1Path)); assertEquals(1, comparerResults.onlyOnServerKeys.size()); assertTrue(comparerResults.onlyOnServerKeys.contains(local3Path)); } finally { cleanupBucketForTest("testFileComparer"); } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/servlets/0002755000000000000000000000000011332474152016145 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/servlets/gatekeeper/0002755000000000000000000000000011441613550020257 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/servlets/gatekeeper/GatekeeperServlet.java0000644000000000000000000003702711550442124024550 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.servlets.gatekeeper; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.lang.reflect.Constructor; import java.util.Properties; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.utils.gatekeeper.GatekeeperMessage; import org.jets3t.service.utils.gatekeeper.SignatureRequest; import org.jets3t.servlets.gatekeeper.impl.DefaultAuthorizer; import org.jets3t.servlets.gatekeeper.impl.DefaultBucketLister; import org.jets3t.servlets.gatekeeper.impl.DefaultTransactionIdProvider; import org.jets3t.servlets.gatekeeper.impl.DefaultUrlSigner; /** * A servlet implementation of an S3 Gatekeeper, as described in the document * * Gatekeeper Concepts. *

* This servlet offers an easily configurable and extensible approach, where key * steps in the authorization and signature generation process are performed by pluggable * interfaces: *

    *
  • {@link TransactionIdProvider}: Generate a transaction ID to uniquely identify a * request/response transaction
  • *
  • {@link Authorizer}: Allow or deny specific requested operations
  • *
  • {@link UrlSigner}: Generate signed URLs for each operation that has been allowed by the * Authorizer
  • *
*

* These pluggable interfaces are configured in the servlet's configuration file, or if left * unconfigured the default JetS3t implementations are used. *

* For more information about this servlet please refer to: * * JetS3t Gatekeeper * * @author James Murty */ public class GatekeeperServlet extends HttpServlet { private static final long serialVersionUID = 2054765427620529238L; private static final Log log = LogFactory.getLog(GatekeeperServlet.class); private ServletConfig servletConfig = null; private TransactionIdProvider transactionIdProvider = null; private UrlSigner urlSigner = null; private Authorizer authorizer = null; private BucketLister bucketLister = null; private boolean isInitCompleted = false; /** * Instantiates a class by locating and invoking the appropriate constructor. * * @param className * @param constructorParamClasses * @param constructorParams * @return */ private Object instantiateClass(String className, Class[] constructorParamClasses, Object[] constructorParams) throws ServletException { try { Class myClass = Class.forName(className); Constructor constructor = myClass.getConstructor(constructorParamClasses); Object instance = constructor.newInstance(constructorParams); return instance; } catch (ClassNotFoundException e) { if (log.isDebugEnabled()) { log.debug("Class does not exist for name: " + className); } } catch (Exception e) { throw new ServletException("Unable to instantiate class '" + className + "'", e); } return null; } /** * Initialises the pluggable implementation classes for {@link Authorizer}, * {@link TransactionIdProvider}, and {@link UrlSigner} */ @Override public void init(ServletConfig servletConfig) throws ServletException { if (log.isInfoEnabled()) { log.info("Initialising GatekeeperServlet"); } this.servletConfig = servletConfig; // Initialise required classes. transactionIdProvider = initTransactionIdProvider(); authorizer = initAuthorizer(); urlSigner = initUrlSigner(); bucketLister = initBucketLister(); isInitCompleted = true; } /** * Initialises the Authorizer implementation that will be used by the servlet. * * @return * @throws ServletException */ private Authorizer initAuthorizer() throws ServletException { String authorizerClass = servletConfig.getInitParameter("AuthorizerClass"); if (log.isDebugEnabled()) { log.debug("AuthorizerClass: " + authorizerClass); } if (authorizerClass != null) { if (log.isInfoEnabled()) { log.info("Loading Authorizer implementation class: " + authorizerClass); } return (Authorizer) instantiateClass(authorizerClass, new Class[] {ServletConfig.class}, new Object[] {servletConfig}); } if (log.isInfoEnabled()) { log.info("Loaded default Authorizer implementation class: " + DefaultAuthorizer.class.getName()); } return new DefaultAuthorizer(servletConfig); } /** * Initialises the UrlSigner implementation that will be used by the servlet. * * @return * @throws ServletException */ private UrlSigner initUrlSigner() throws ServletException { String urlSignerClass = servletConfig.getInitParameter("UrlSignerClass"); if (log.isDebugEnabled()) { log.debug("UrlSignerClass: " + urlSignerClass); } if (urlSignerClass != null) { if (log.isInfoEnabled()) { log.info("Loading UrlSigner implementation class: " + urlSignerClass); } return (UrlSigner) instantiateClass(urlSignerClass, new Class[] {ServletConfig.class}, new Object[] {servletConfig}); } if (log.isInfoEnabled()) { log.info("Loaded default UrlSigner implementation class: " + DefaultUrlSigner.class.getName()); } return new DefaultUrlSigner(servletConfig); } /** * Initialises the TransactionIdProvider implementation that will be used by the servlet. * * @return * @throws ServletException */ private TransactionIdProvider initTransactionIdProvider() throws ServletException { String transactionIdProviderClass = servletConfig.getInitParameter("TransactionIdProviderClass"); if (log.isDebugEnabled()) { log.debug("TransactionIdProviderClass: " + transactionIdProviderClass); } if (transactionIdProviderClass != null) { if (log.isInfoEnabled()) { log.info("Loading TransactionIdProvider implementation class: " + transactionIdProviderClass); } return (TransactionIdProvider) instantiateClass(transactionIdProviderClass, new Class[] {ServletConfig.class}, new Object[] {servletConfig}); } if (log.isInfoEnabled()) { log.info("Loaded default TransactionIdProvider implementation class: " + TransactionIdProvider.class.getName()); } return new DefaultTransactionIdProvider(servletConfig); } /** * Initialises the BucketLister implementation that will be used by the servlet. * * @return * @throws ServletException */ private BucketLister initBucketLister() throws ServletException { String bucketListerClass = servletConfig.getInitParameter("BucketListerClass"); if (log.isDebugEnabled()) { log.debug("BucketListerClass: " + bucketListerClass); } if (bucketListerClass != null) { if (log.isInfoEnabled()) { log.info("Loading BucketLister implementation class: " + bucketListerClass); } return (BucketLister) instantiateClass(bucketListerClass, new Class[] {ServletConfig.class}, new Object[] {servletConfig}); } if (log.isInfoEnabled()) { log.info("Loaded default BucketLister implementation class: " + TransactionIdProvider.class.getName()); } return new DefaultBucketLister(servletConfig); } /** * Sends a simple HTML page in response to GET requests, indicating that the servlet is running. */ @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { if (log.isDebugEnabled()) { log.debug("Handling GET request"); } response.setStatus(200); response.setContentType("text/html"); response.getWriter().println("JetS3t Gatekeeper"); response.getWriter().println("

JetS3t Gatekeeper is running " + (isInitCompleted? "and initialized successfully" : "but initialization failed") + "

"); } /** * Handles POST requests that contain Gatekeeper messages encoded as POST form properties, and * sends a plain text response document containing the Gatekeeper response message encoded as * a properties file. */ @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { if (log.isDebugEnabled()) { log.debug("Handling POST request"); } try { // Build Gatekeeper request from POST form parameters. GatekeeperMessage gatekeeperMessage = GatekeeperMessage.decodeFromProperties(request.getParameterMap()); // Obtain client information ClientInformation clientInformation = new ClientInformation( request.getRemoteAddr(), request.getRemoteHost(), request.getRemoteUser(), request.getRemotePort(), request.getSession(false), request.getUserPrincipal(), request.getHeader("User-Agent"), request); // Generate Transaction ID, and store it in the message. String transactionId = transactionIdProvider.getTransactionId(gatekeeperMessage, clientInformation); if (transactionId != null) { gatekeeperMessage.addMessageProperty(GatekeeperMessage.PROPERTY_TRANSACTION_ID, transactionId); } if (!isInitCompleted) { if (log.isWarnEnabled()) { log.warn("Cannot process POST request as Gatekeeper servlet did not initialize correctly"); } gatekeeperMessage.addApplicationProperty( GatekeeperMessage.APP_PROPERTY_GATEKEEPER_ERROR_CODE, "GatekeeperInitializationError"); } else if (gatekeeperMessage.getApplicationProperties().containsKey( GatekeeperMessage.LIST_OBJECTS_IN_BUCKET_FLAG)) { // Handle "limited listing" requests. if (log.isDebugEnabled()) { log.debug("Listing objects"); } boolean allowed = authorizer.allowBucketListingRequest(gatekeeperMessage, clientInformation); if (allowed) { bucketLister.listObjects(gatekeeperMessage, clientInformation); } } else { if (log.isDebugEnabled()) { log.debug("Processing " + gatekeeperMessage.getSignatureRequests().length + " object signature requests"); } // Process each signature request. for (int i = 0; i < gatekeeperMessage.getSignatureRequests().length; i++) { SignatureRequest signatureRequest = gatekeeperMessage.getSignatureRequests()[i]; // Determine whether the request will be allowed. If the request is not allowed, the // reason will be made available in the signature request object (with signatureRequest.declineRequest()) boolean allowed = authorizer.allowSignatureRequest(gatekeeperMessage, clientInformation, signatureRequest); // Sign requests when they are allowed. When a request is signed, the signed URL is made available // in the SignatureRequest object. if (allowed) { String signedUrl = null; if (SignatureRequest.SIGNATURE_TYPE_GET.equals(signatureRequest.getSignatureType())) { signedUrl = urlSigner.signGet(gatekeeperMessage, clientInformation, signatureRequest); } else if (SignatureRequest.SIGNATURE_TYPE_HEAD.equals(signatureRequest.getSignatureType())) { signedUrl = urlSigner.signHead(gatekeeperMessage, clientInformation, signatureRequest); } else if (SignatureRequest.SIGNATURE_TYPE_PUT.equals(signatureRequest.getSignatureType())) { signedUrl = urlSigner.signPut(gatekeeperMessage, clientInformation, signatureRequest); } else if (SignatureRequest.SIGNATURE_TYPE_DELETE.equals(signatureRequest.getSignatureType())) { signedUrl = urlSigner.signDelete(gatekeeperMessage, clientInformation, signatureRequest); } else if (SignatureRequest.SIGNATURE_TYPE_ACL_LOOKUP.equals(signatureRequest.getSignatureType())) { signedUrl = urlSigner.signGetAcl(gatekeeperMessage, clientInformation, signatureRequest); } else if (SignatureRequest.SIGNATURE_TYPE_ACL_UPDATE.equals(signatureRequest.getSignatureType())) { signedUrl = urlSigner.signPutAcl(gatekeeperMessage, clientInformation, signatureRequest); } signatureRequest.signRequest(signedUrl); } } } // Build response as a set of properties, and return this document. Properties responseProperties = gatekeeperMessage.encodeToProperties(); if (log.isDebugEnabled()) { log.debug("Sending response message as properties: " + responseProperties); } // Serialize properties to bytes. ByteArrayOutputStream baos = new ByteArrayOutputStream(); responseProperties.store(baos, ""); // Send successful response. response.setStatus(200); response.setContentType("text/plain"); response.getOutputStream().write(baos.toByteArray()); } catch (Exception e) { if (log.isErrorEnabled()) { log.error("Gatekeeper failed to send valid response", e); } response.setStatus(500); response.setContentType("text/plain"); response.getWriter().println(e.toString()); } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/servlets/gatekeeper/BucketLister.java0000644000000000000000000000401511441613550023520 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2007 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.servlets.gatekeeper; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import org.jets3t.service.utils.gatekeeper.GatekeeperMessage; /** * Provides a listing of objects in an S3 account to a client application that cannot query * the account for itself. *

* The object listing may contain all the objects in the bucket, or any subset as is * appropriate for the client application or user in question. * * @author James Murty */ public abstract class BucketLister { public BucketLister(ServletConfig servletConfig) throws ServletException { } /** * Create in the GatekeeperMessage object a list of SignatureRequest objects capturing * details about the S3 objects contained in a bucket. The client application will * interpret the SignatureRequest object details to reconstruct the objects. * * @param gatekeeperMessage * the message object that was received, and in which the object listing to be returned * is stored. * @param clientInformation * information about the client end-point this request was received from. * * @throws Exception */ public abstract void listObjects(GatekeeperMessage gatekeeperMessage, ClientInformation clientInformation) throws Exception; } jets3t-0.8.1+dfsg.orig/src/org/jets3t/servlets/gatekeeper/TransactionIdProvider.java0000644000000000000000000000362111427702124025377 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.servlets.gatekeeper; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import org.jets3t.service.utils.gatekeeper.GatekeeperMessage; /** * Provides a transaction ID that uniquely identifies a Gatekeeper transaction - that is, a request * and response interaction. *

* A transaction ID could be based on a user's session ID (available in the client information), * come from a database sequence, or any other mechanism that is likely to generate unique IDs. * * @author James Murty */ public abstract class TransactionIdProvider { /** * Constructs a TransactionIdProvider. * * @param servletConfig * @throws ServletException */ public TransactionIdProvider(ServletConfig servletConfig) throws ServletException { } /** * Returns a transaction ID to uniquely identify the Gatekeeper transaction - if transaction * tracking is not required this method can return an empty string. * * @param requestMessage * @param clientInformation * * @return * an ID unique to this transaction. */ public abstract String getTransactionId(GatekeeperMessage requestMessage, ClientInformation clientInformation); } jets3t-0.8.1+dfsg.orig/src/org/jets3t/servlets/gatekeeper/ClientInformation.java0000644000000000000000000000577511427702124024562 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.servlets.gatekeeper; import java.security.Principal; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; /** * Stores information about the HTTP client that submitted a request to the Gatekeeper. *

* The information available about a client will depend on the server and client configuration, * such as whether the client is identified with an existing HttpSession or Principal. It must * be assumed that much of the information stored in this class will have a null value in many * cases. *

* All information in this class is sourced from equivalent methods in * {@link javax.servlet.http.HttpServletRequest}. * * @author James Murty */ public class ClientInformation { private String remoteAddress = null; private String remoteHost = null; private String remoteUser = null; private int remotePort = -1; private HttpSession session = null; private Principal userPrincipal = null; private String userAgent = null; private HttpServletRequest httpServletRequest = null; public ClientInformation(String remoteAddress, String remoteHost, String remoteUser, int remotePort, HttpSession session, Principal userPrincipal, String userAgent, HttpServletRequest httpServletRequest) { this.remoteAddress = remoteAddress; this.remoteHost = remoteHost; this.remoteUser = remoteUser; this.remotePort = remotePort; this.session = session; this.userPrincipal = userPrincipal; this.userAgent = userAgent; this.httpServletRequest = httpServletRequest; } public String getRemoteAddress() { return remoteAddress; } public String getRemoteHost() { return remoteHost; } public int getRemotePort() { return remotePort; } public String getRemoteUser() { return remoteUser; } public HttpSession getSession() { return session; } public Principal getUserPrincipal() { return userPrincipal; } public String getUserAgent() { return userAgent; } /** * @return * the original servlet request, in case the specific information captured in this * class is not sufficient. */ public HttpServletRequest getHttpServletRequest() { return httpServletRequest; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/servlets/gatekeeper/impl/0002755000000000000000000000000011441613550021220 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/servlets/gatekeeper/impl/RenameToUuidUrlSigner.java0000644000000000000000000001215211427702124026256 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.servlets.gatekeeper.impl; import java.util.Map; import java.util.Properties; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.S3ServiceException; import org.jets3t.service.utils.gatekeeper.GatekeeperMessage; import org.jets3t.service.utils.gatekeeper.SignatureRequest; /** * UrlSigner implementation that extends the DefaultUrlSigner class to perform some additional * work - speficically this class renames the S3 objects keys based on the transaction ID. * * @author James Murty */ public class RenameToUuidUrlSigner extends DefaultUrlSigner { private final static Log log = LogFactory.getLog(RenameToUuidUrlSigner.class); private String lastTransactionId = ""; private int countOfRenamedObjects = 0; /** * Constructs the UrlSigner with the required parameters. *

* The required parameters that must be available in the servlet configuration are: *

    *
  • S3BucketName: The bucket all objects are stored in (regardless of what bucket * name the client provided).
  • *
  • SecondsToSign: How many seconds until the signed URLs will expire
    * Note: this setting must allow enough time for the operation to complete * before the expiry time is reached. For example, if uploads are expected over slow * connections the expiry time must be long enough for the uploads to finish otherwise the * uploaded file will be rejected after it has finished uploading.
  • *
* * @param servletConfig * @throws ServletException */ public RenameToUuidUrlSigner(ServletConfig servletConfig) throws ServletException { super(servletConfig); } /** * Overrides the implementation in DefaultUrlProvider to do everything that class does, but * also to rename objects based on the transaction ID. *

* Each object is renamed to the following format:
* transactionId.objectCount.objectExtension *

* Objects that arrive with the metadata property * {@link GatekeeperMessage#SUMMARY_DOCUMENT_METADATA_FLAG} as treated as special cases, as this * flag indicates that the object is an XML summary document provided by the JetS3t * {@link org.jets3t.apps.uploader.Uploader} application. In this case, the object should not * be renamed as it is already named according to the last transaction ID. *

* * @param signatureRequest * @param messageProperties * @throws S3ServiceException */ protected void updateObject(SignatureRequest signatureRequest, Properties messageProperties) throws S3ServiceException { super.updateObject(signatureRequest, messageProperties); String transactionId = messageProperties.getProperty(GatekeeperMessage.PROPERTY_TRANSACTION_ID); Map objectMetadata = signatureRequest.getObjectMetadata(); if (transactionId != null) { if (lastTransactionId.equals(transactionId)) { // No need to reset the object count, we are still working on the same transaction ID. } else { // This is a new transaction ID, reset the object count. countOfRenamedObjects = 0; lastTransactionId = transactionId; } String originalKey = signatureRequest.getObjectKey(); if (objectMetadata.containsKey(GatekeeperMessage.SUMMARY_DOCUMENT_METADATA_FLAG)) { if (log.isDebugEnabled()) { log.debug("Object with key '" + originalKey + "' is flagged as a Summary Document" + ", and will not be renamed"); } } else { String extension = null; int lastDotIndex = originalKey.lastIndexOf("."); if (lastDotIndex >= 0) { extension = originalKey.substring(lastDotIndex + 1); } String newKey = transactionId + "." + (++countOfRenamedObjects) + (extension != null? "." + extension : ""); if (log.isDebugEnabled()) { log.debug("Renamed object key '" + originalKey + "' to '" + newKey + "'"); } signatureRequest.setObjectKey(newKey); } } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/servlets/gatekeeper/impl/ExternalUuidProvider.java0000644000000000000000000000442311427702124026210 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.servlets.gatekeeper.impl; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import org.jets3t.service.utils.gatekeeper.GatekeeperMessage; import org.jets3t.servlets.gatekeeper.ClientInformation; import org.jets3t.servlets.gatekeeper.TransactionIdProvider; import org.safehaus.uuid.UUID; import org.safehaus.uuid.UUIDGenerator; /** * Uses an externally provided UUID obtained from an application property externalUUID * when this is available. If not, a random-based UUID is created. * * @author James Murty */ public class ExternalUuidProvider extends TransactionIdProvider { public ExternalUuidProvider(ServletConfig servletConfig) throws ServletException { super(servletConfig); } /** * If the application property externalUUID is available, the value of this property * is returned as the transaction ID. If the property is not availble a new random-based * UUID is generated using the JUG library. */ public String getTransactionId(GatekeeperMessage requestMessage, ClientInformation clientInformation) { // Use the external UUID as a transaction ID, if it's available. String externalUuid = requestMessage.getApplicationProperties().getProperty("externalUUID"); if (externalUuid != null && externalUuid.length() > 0) { return externalUuid; } // Use a generated UUID based on a random generation as a fallback if the external UUID isn't available. UUID uuid = UUIDGenerator.getInstance().generateRandomBasedUUID(); return uuid.toString(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/servlets/gatekeeper/impl/DefaultTransactionIdProvider.java0000644000000000000000000000365511427702124027654 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.servlets.gatekeeper.impl; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import org.jets3t.service.utils.gatekeeper.GatekeeperMessage; import org.jets3t.servlets.gatekeeper.ClientInformation; import org.jets3t.servlets.gatekeeper.TransactionIdProvider; import org.safehaus.uuid.UUID; import org.safehaus.uuid.UUIDGenerator; /** * Default TransactionIdProvider implementation that generated random-based UUIDs using the * Java Uuid Generator. * * @author James Murty */ public class DefaultTransactionIdProvider extends TransactionIdProvider { /** * Constructs the TransactionIdProvider - no configuration parameters are required. * * @param servletConfig * @throws ServletException */ public DefaultTransactionIdProvider(ServletConfig servletConfig) throws ServletException { super(servletConfig); } /** * Returns a random-based UUID. */ public String getTransactionId(GatekeeperMessage requestMessage, ClientInformation clientInformation) { // Generate a UUID based on a random generation. UUID uuid = UUIDGenerator.getInstance().generateRandomBasedUUID(); return uuid.toString(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/servlets/gatekeeper/impl/DefaultUrlSigner.java0000644000000000000000000002152211441613550025302 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.servlets.gatekeeper.impl; import java.util.Map; import java.util.Properties; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import org.jets3t.service.Constants; import org.jets3t.service.S3Service; import org.jets3t.service.S3ServiceException; import org.jets3t.service.impl.rest.httpclient.RestS3Service; import org.jets3t.service.security.AWSCredentials; import org.jets3t.service.security.ProviderCredentials; import org.jets3t.service.utils.gatekeeper.GatekeeperMessage; import org.jets3t.service.utils.gatekeeper.SignatureRequest; import org.jets3t.servlets.gatekeeper.ClientInformation; import org.jets3t.servlets.gatekeeper.UrlSigner; /** * Default UrlSigner implementation that signs all requests, putting all objects in a specific S3 * bucket and limiting the signature time to a configurable time period. *

* This implementation also demonstrates how objects may be modified, as it adds a metadata * item to each signed object to store the transaction ID in which the object was signed. The * transaction id is stored in the metadata name x-amx-gatekeeper-transaction-id * * @author James Murty */ public class DefaultUrlSigner extends UrlSigner { protected ProviderCredentials credentials = null; protected S3Service s3Service = null; protected String s3BucketName = null; protected int secondsUntilExpiry = 0; public static final String TRANSACTION_ID_METADATA_NAME = Constants.REST_HEADER_PREFIX + "gatekeeper-transaction-id"; /** * Constructs the UrlSigner with the required parameters. *

* The required parameters that must be available in the servlet configuration are: *

    *
  • AwsAccessKey: The AWS Access Key for an S3 account
  • *
  • AwsSecretKey: The AWS Secret Key for an S3 account
  • *
  • S3BucketName: The bucket all objects are stored in (regardless of what bucket * name the client provided).
  • *
  • SecondsToSign: How many seconds until the signed URLs will expire
    * Note: this setting must allow enough time for the operation to complete * before the expiry time is reached. For example, if uploads are expected over slow * connections the expiry time must be long enough for the uploads to finish otherwise the * uploaded file will be rejected after it has finished uploading.
  • *
* * @param servletConfig * @throws ServletException */ public DefaultUrlSigner(ServletConfig servletConfig) throws ServletException { super(servletConfig); String awsAccessKey = servletConfig.getInitParameter("AwsAccessKey"); String awsSecretKey = servletConfig.getInitParameter("AwsSecretKey"); // Fail with an exception if required init params are missing. boolean missingInitParam = false; String errorMessage = "Missing required servlet init parameters for UrlSigner: "; if (awsAccessKey == null || awsAccessKey.length() == 0) { errorMessage += "AwsAccessKey "; missingInitParam = true; } if (awsSecretKey == null || awsSecretKey.length() == 0) { errorMessage += "AwsSecretKey "; missingInitParam = true; } if (missingInitParam) { throw new ServletException(errorMessage); } this.credentials = new AWSCredentials(awsAccessKey, awsSecretKey); try { this.s3Service = new RestS3Service(credentials); } catch (S3ServiceException e) { throw new ServletException("Unable to initialize S3Service", e); } String secondsToSign = servletConfig.getInitParameter("SecondsToSign"); if (secondsToSign == null || secondsToSign.length() == 0) { throw new ServletException("Missing required servlet init parameters for DefaultUrlSigner: " + "SecondsToSign"); } try { secondsUntilExpiry = Integer.parseInt(secondsToSign); } catch (NumberFormatException e) { throw new ServletException("Invalid servlet init param: SecondsToSign", e); } s3BucketName = servletConfig.getInitParameter("S3BucketName"); if (s3BucketName == null || s3BucketName.length() == 0) { throw new ServletException("Missing required servlet init parameters for DefaultUrlSigner: " + "S3BucketName"); } } /** * Adds a metadata item containing the transaction ID to each object. * * @param signatureRequest * @param messageProperties * @throws S3ServiceException */ protected void updateObject(SignatureRequest signatureRequest, Properties messageProperties) throws S3ServiceException { signatureRequest.setBucketName(s3BucketName); Map objectMetadata = signatureRequest.getObjectMetadata(); if (!objectMetadata.containsKey(TRANSACTION_ID_METADATA_NAME)) { String transactionId = messageProperties.getProperty(TRANSACTION_ID_METADATA_NAME); if (transactionId != null) { objectMetadata.put(TRANSACTION_ID_METADATA_NAME, transactionId); } } } public String signDelete(GatekeeperMessage requestMessage, ClientInformation clientInformation,SignatureRequest signatureRequest) throws S3ServiceException { updateObject(signatureRequest, requestMessage.getMessageProperties()); return s3Service.createSignedDeleteUrl(signatureRequest.getBucketName(), signatureRequest.getObjectKey(), calculateExpiryTime(secondsUntilExpiry), false); } public String signGet(GatekeeperMessage requestMessage, ClientInformation clientInformation,SignatureRequest signatureRequest) throws S3ServiceException { updateObject(signatureRequest, requestMessage.getMessageProperties()); return s3Service.createSignedGetUrl(signatureRequest.getBucketName(), signatureRequest.getObjectKey(), calculateExpiryTime(secondsUntilExpiry), false); } public String signHead(GatekeeperMessage requestMessage, ClientInformation clientInformation,SignatureRequest signatureRequest) throws S3ServiceException { updateObject(signatureRequest, requestMessage.getMessageProperties()); return s3Service.createSignedHeadUrl(signatureRequest.getBucketName(), signatureRequest.getObjectKey(), calculateExpiryTime(secondsUntilExpiry), false); } public String signPut(GatekeeperMessage requestMessage, ClientInformation clientInformation,SignatureRequest signatureRequest) throws S3ServiceException { updateObject(signatureRequest, requestMessage.getMessageProperties()); return s3Service.createSignedPutUrl(signatureRequest.getBucketName(), signatureRequest.getObjectKey(), signatureRequest.getObjectMetadata(), calculateExpiryTime(secondsUntilExpiry), false); } public String signGetAcl(GatekeeperMessage requestMessage, ClientInformation clientInformation, SignatureRequest signatureRequest) throws S3ServiceException { updateObject(signatureRequest, requestMessage.getMessageProperties()); long secondsSinceEpoch = calculateExpiryTime(secondsUntilExpiry).getTime() / 1000; return s3Service.createSignedUrl("GET", signatureRequest.getBucketName(), signatureRequest.getObjectKey(), "acl", null, secondsSinceEpoch, false); } public String signPutAcl(GatekeeperMessage requestMessage, ClientInformation clientInformation, SignatureRequest signatureRequest) throws S3ServiceException { updateObject(signatureRequest, requestMessage.getMessageProperties()); long secondsSinceEpoch = calculateExpiryTime(secondsUntilExpiry).getTime() / 1000; return s3Service.createSignedUrl("PUT", signatureRequest.getBucketName(), signatureRequest.getObjectKey(), "acl", signatureRequest.getObjectMetadata(), secondsSinceEpoch, false); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/servlets/gatekeeper/impl/DefaultBucketLister.java0000644000000000000000000001254311441613550025773 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2007 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.servlets.gatekeeper.impl; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import org.jets3t.service.S3ServiceException; import org.jets3t.service.impl.rest.httpclient.RestS3Service; import org.jets3t.service.model.S3Object; import org.jets3t.service.security.AWSCredentials; import org.jets3t.service.security.ProviderCredentials; import org.jets3t.service.utils.ServiceUtils; import org.jets3t.service.utils.gatekeeper.GatekeeperMessage; import org.jets3t.service.utils.gatekeeper.SignatureRequest; import org.jets3t.servlets.gatekeeper.BucketLister; import org.jets3t.servlets.gatekeeper.ClientInformation; /** * Default BucketLister implementation that lists all objects in the configured bucket. * * @author James Murty */ public class DefaultBucketLister extends BucketLister { protected ProviderCredentials credentials = null; private String s3BucketName = null; /** * Constructs the Bucket lister with the required parameters. *

* The required parameters that must be available in the servlet configuration are: *

    *
  • AwsAccessKey: The AWS Access Key for an S3 account
  • *
  • AwsSecretKey: The AWS Secret Key for an S3 account
  • *
  • S3BucketName: The bucket all objects are stored in (regardless of what bucket * name the client provided).
  • *
* * @param servletConfig * @throws ServletException */ public DefaultBucketLister(ServletConfig servletConfig) throws ServletException { super(servletConfig); String awsAccessKey = servletConfig.getInitParameter("AwsAccessKey"); String awsSecretKey = servletConfig.getInitParameter("AwsSecretKey"); // Fail with an exception if required init params are missing. boolean missingInitParam = false; String errorMessage = "Missing required servlet init parameters for UrlSigner: "; if (awsAccessKey == null || awsAccessKey.length() == 0) { errorMessage += "AwsAccessKey "; missingInitParam = true; } if (awsSecretKey == null || awsSecretKey.length() == 0) { errorMessage += "AwsSecretKey "; missingInitParam = true; } if (missingInitParam) { throw new ServletException(errorMessage); } this.credentials = new AWSCredentials(awsAccessKey, awsSecretKey); s3BucketName = servletConfig.getInitParameter("S3BucketName"); if (s3BucketName == null || s3BucketName.length() == 0) { throw new ServletException("Missing required servlet init parameters for DefaultBucketLister: " + "S3BucketName"); } } public void listObjects(GatekeeperMessage gatekeeperMessage, ClientInformation clientInformation) throws S3ServiceException { // Build prefix based on user's path and any additional prefix provided. String prefix = null; if (gatekeeperMessage.getApplicationProperties().containsKey("Prefix")) { prefix = gatekeeperMessage.getApplicationProperties().getProperty("Prefix"); } // Construct an authorized service. RestS3Service service = new RestS3Service(credentials); // List objects in the configured bucket. S3Object[] objects = service.listObjects(s3BucketName, prefix, null, 1000); // Package object information in SignatureRequest objects. This data will be // automatically encoded and sent across the wire back to the client. for (int i = 0; i < objects.length; i++) { SignatureRequest sr = new SignatureRequest(); sr.setObjectMetadata(objects[i].getMetadataMap()); sr.addObjectMetadata(S3Object.METADATA_HEADER_LAST_MODIFIED_DATE, ServiceUtils.formatIso8601Date(objects[i].getLastModifiedDate())); sr.setObjectKey(objects[i].getKey()); gatekeeperMessage.addSignatureRequest(sr); } gatekeeperMessage.addApplicationProperty("AccountDescription", "Bucket: " + s3BucketName + ""); // Include an application property to inform Cockpit Lite of the user's bucket gatekeeperMessage.addApplicationProperty("S3BucketName", s3BucketName); gatekeeperMessage.addApplicationProperty("UserCanUpload", "true"); gatekeeperMessage.addApplicationProperty("UserCanDownload", "true"); gatekeeperMessage.addApplicationProperty("UserCanDelete", "true"); gatekeeperMessage.addApplicationProperty("UserCanACL", "true"); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/servlets/gatekeeper/impl/DefaultAuthorizer.java0000644000000000000000000000372011441613550025524 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.servlets.gatekeeper.impl; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import org.jets3t.service.utils.gatekeeper.GatekeeperMessage; import org.jets3t.service.utils.gatekeeper.SignatureRequest; import org.jets3t.servlets.gatekeeper.Authorizer; import org.jets3t.servlets.gatekeeper.ClientInformation; /** * Default Authorizer implementation that allows all signature requests. * * @author James Murty */ public class DefaultAuthorizer extends Authorizer { /** * Constructs the Authorizer - no configuration parameters are required. * * @param servletConfig * @throws ServletException */ public DefaultAuthorizer(ServletConfig servletConfig) throws ServletException { super(servletConfig); } /** * Returns true in all cases. */ public boolean allowSignatureRequest(GatekeeperMessage requestMessage, ClientInformation clientInformation, SignatureRequest signatureRequest) { return true; } /** * Returns true in all cases. */ public boolean allowBucketListingRequest( GatekeeperMessage requestMessage, ClientInformation clientInformation) { return true; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/servlets/gatekeeper/Authorizer.java0000644000000000000000000000625011441613550023257 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.servlets.gatekeeper; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import org.jets3t.service.utils.gatekeeper.GatekeeperMessage; import org.jets3t.service.utils.gatekeeper.SignatureRequest; /** * Authorizes or refuses operations on an S3 account - the decision can be based on information * in the request message, details about the client, or the signature request itself. *

* An example Authorizer implementation might check that a user has alread been authorized and * their Principal details are available from the client information, or it might check that the * correct password has been provided in an application property in the request message. * * @author James Murty */ public abstract class Authorizer { /** * Constructs an Authorizer. * * @param servletConfig * @throws ServletException */ public Authorizer(ServletConfig servletConfig) throws ServletException { } /** * Authorizes an operation represented by a signature request by returning true, or * disallows the operation by returned false (and optionally setting a decline reason * in the signature request). *

* Authorization decisions can be made based on any of the inputs provided to this method. * * @param requestMessage * the Gatekeeper request message. * @param clientInformation * information about the client end-point this request was received from. * @param signatureRequest * a signature request to allow or disallow. * * @return * true if the request is allowed, false otherwise. */ public abstract boolean allowSignatureRequest(GatekeeperMessage requestMessage, ClientInformation clientInformation, SignatureRequest signatureRequest); /** * Authorizes a bucket listing operation for a client as represented by a the gatekeeper * request message. *

* Authorization decisions can be made based on any of the inputs provided to this method. * * @param requestMessage * the Gatekeeper request message. * @param clientInformation * information about the client end-point this request was received from. * * @return * true if the request is allowed, false otherwise. */ public abstract boolean allowBucketListingRequest(GatekeeperMessage requestMessage, ClientInformation clientInformation); } jets3t-0.8.1+dfsg.orig/src/org/jets3t/servlets/gatekeeper/UrlSigner.java0000644000000000000000000001566511427702124023047 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.servlets.gatekeeper; import java.util.Calendar; import java.util.Date; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import org.jets3t.service.S3ServiceException; import org.jets3t.service.utils.gatekeeper.GatekeeperMessage; import org.jets3t.service.utils.gatekeeper.SignatureRequest; /** * Provides signed URLs that will allow a client to perform the operation requested on a specific * object in S3. *

* This sign methods in this class are not called for a signature request unless that * request has already been allowed by the {@link Authorizer}. *

* Implementations of this class need only generate the appropriate signed URL. However, more * advanced implementations may do other work such as renaming objects to comply with naming * rules for an S3 account. * * @author James Murty */ public abstract class UrlSigner { /** * Constructs a UrlSigner with the following required properties from the servlet configuration: * * @param servletConfig * @throws ServletException */ public UrlSigner(ServletConfig servletConfig) throws ServletException { } /** * Generate a signed GET URL for the signature request. * * @param requestMessage * the request message received from the client. * @param clientInformation * information about the client's end-point, and any Session or Principal associated with the client. * @param signatureRequest * a pre-approved signature request. * * @return * a signed URL string that will allow the operation specified in the signature request * on the object specified in the signature request. * * @throws S3ServiceException */ public abstract String signGet(GatekeeperMessage requestMessage, ClientInformation clientInformation, SignatureRequest signatureRequest) throws S3ServiceException; /** * Generate a signed HEAD URL for the signature request. * * @param requestMessage * the request message received from the client. * @param clientInformation * information about the client's end-point, and any Session or Principal associated with the client. * @param signatureRequest * a pre-approved signature request. * * @return * a signed URL string that will allow the operation specified in the signature request * on the object specified in the signature request. * * @throws S3ServiceException */ public abstract String signHead(GatekeeperMessage requestMessage, ClientInformation clientInformation, SignatureRequest signatureRequest) throws S3ServiceException; /** * Generate a signed PUT URL for the signature request. * * @param requestMessage * the request message received from the client. * @param clientInformation * information about the client's end-point, and any Session or Principal associated with the client. * @param signatureRequest * a pre-approved signature request. * * @return * a signed URL string that will allow the operation specified in the signature request * on the object specified in the signature request. * * @throws S3ServiceException */ public abstract String signPut(GatekeeperMessage requestMessage, ClientInformation clientInformation, SignatureRequest signatureRequest) throws S3ServiceException; /** * Generate a signed DELETE URL for the signature request. * * @param requestMessage * the request message received from the client. * @param clientInformation * information about the client's end-point, and any Session or Principal associated with the client. * @param signatureRequest * a pre-approved signature request. * * @return * a signed URL string that will allow the operation specified in the signature request * on the object specified in the signature request. * * @throws S3ServiceException */ public abstract String signDelete(GatekeeperMessage requestMessage, ClientInformation clientInformation, SignatureRequest signatureRequest) throws S3ServiceException; /** * Generate a signed GET URL for an ACL-based signature request. * * @param requestMessage * the request message received from the client. * @param clientInformation * information about the client's end-point, and any Session or Principal associated with the client. * @param signatureRequest * a pre-approved signature request. * * @return * a signed URL string that will allow the operation specified in the signature request * on the object specified in the signature request. * * @throws S3ServiceException */ public abstract String signGetAcl(GatekeeperMessage requestMessage, ClientInformation clientInformation, SignatureRequest signatureRequest) throws S3ServiceException; /** * Generate a signed PUT URL for an ACL-based signature request. * * @param requestMessage * the request message received from the client. * @param clientInformation * information about the client's end-point, and any Session or Principal associated with the client. * @param signatureRequest * a pre-approved signature request. * * @return * a signed URL string that will allow the operation specified in the signature request * on the object specified in the signature request. * * @throws S3ServiceException */ public abstract String signPutAcl(GatekeeperMessage requestMessage, ClientInformation clientInformation, SignatureRequest signatureRequest) throws S3ServiceException; /** * @return * the date and time when signed URLs should expire, calculated by adding the number of seconds * until expiry to the current time. */ protected Date calculateExpiryTime(int secondsUntilExpiry) { Calendar cal = Calendar.getInstance(); cal.add(Calendar.SECOND, secondsUntilExpiry); return cal.getTime(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/samples/0002755000000000000000000000000011550442512015737 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/samples/CodeSamples.java0000644000000000000000000013376611550441724021023 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.samples; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Map; import org.jets3t.service.Constants; import org.jets3t.service.S3Service; import org.jets3t.service.S3ServiceException; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.acl.CanonicalGrantee; import org.jets3t.service.acl.EmailAddressGrantee; import org.jets3t.service.acl.GroupGrantee; import org.jets3t.service.acl.Permission; import org.jets3t.service.impl.rest.httpclient.RestS3Service; import org.jets3t.service.model.BaseVersionOrDeleteMarker; import org.jets3t.service.model.S3Bucket; import org.jets3t.service.model.S3BucketVersioningStatus; import org.jets3t.service.model.S3Object; import org.jets3t.service.model.StorageObject; import org.jets3t.service.multithread.DownloadPackage; import org.jets3t.service.multithread.S3ServiceSimpleMulti; import org.jets3t.service.security.AWSCredentials; import org.jets3t.service.security.AWSDevPayCredentials; import org.jets3t.service.security.ProviderCredentials; import org.jets3t.service.utils.MultipartUtils; import org.jets3t.service.utils.ServiceUtils; /** * This class includes all the code samples as listed in the JetS3t * Programmer Guide. *

* This code is provided as a convenience for those who are reading through the guide and don't want * to type out the examples themselves. *

* * @author James Murty */ public class CodeSamples { private static final String BUCKET_NAME = "test-bucket"; private static final String TEST_OBJECT_NAME = "helloworld.txt"; public static void main(String[] args) throws Exception { /* ************ * Code Samples * ************ */ /* * Connecting to S3 */ // Your Amazon Web Services (AWS) login credentials are required to manage S3 accounts. // These credentials are stored in an AWSCredentials object: AWSCredentials awsCredentials = SamplesUtils.loadAWSCredentials(); // To communicate with S3 use the RestS3Service. RestS3Service s3Service = new RestS3Service(awsCredentials); // A good test to see if your S3Service can connect to S3 is to list all the buckets you own. // If a bucket listing produces no exceptions, all is well. S3Bucket[] myBuckets = s3Service.listAllBuckets(); System.out.println("How many buckets do I have in S3? " + myBuckets.length); /* * Create a bucket */ // To store data in S3 you must first create a bucket, a container for objects. S3Bucket testBucket = s3Service.createBucket(BUCKET_NAME); System.out.println("Created test bucket: " + testBucket.getName()); // If you try using a common name, you will probably not be able to create the // bucket as someone else will already have a bucket of that name. // To create a bucket in an S3 data center located somewhere other than // the United States, you can specify a location for your bucket as a // second parameter to the createBucket() method. Currently, the alternative // S3 locations are Europe (EU), US West - Northern California (us-west-1), // and Asia Pacific (Singapore) S3Bucket euBucket = s3Service.createBucket("eu-bucket", S3Bucket.LOCATION_EUROPE); S3Bucket usWestBucket = s3Service.createBucket("us-west-bucket", S3Bucket.LOCATION_US_WEST); S3Bucket asiaPacificBucket = s3Service.createBucket( "asia-pacific-bucket", S3Bucket.LOCATION_ASIA_PACIFIC); /* * Uploading data objects */ // We use S3Object classes to represent data objects in S3. To store some information in our // new test bucket, we must first create an object with a key/name then tell our // S3Service to upload it to S3. // In the example below, we print out information about the S3Object before and after // uploading it to S3. These print-outs demonstrate that the S3Object returned by the // putObject method contains extra information provided by S3, such as the date the // object was last modified on an S3 server. // Create an empty object with a key/name, and print the object's details. S3Object object = new S3Object("object"); System.out.println("S3Object before upload: " + object); // Upload the object to our test bucket in S3. object = s3Service.putObject(testBucket, object); // Print the details about the uploaded object, which contains more information. System.out.println("S3Object after upload: " + object); // The example above will create an empty object in S3, which isn't very useful. // To include data in the object you must provide some data for the object. // If you know the Content/Mime type of the data (e.g. text/plain) you should set this too. // S3Object's can contain any data available from an input stream, but JetS3t provides two // convenient object types to hold File or String data. These convenient constructors // automatically set the Content-Type and Content-Length of the object. // Create an S3Object based on a string, with Content-Length set automatically and // Content-Type set to "text/plain" String stringData = "Hello World!"; S3Object stringObject = new S3Object(TEST_OBJECT_NAME, stringData); // Create an S3Object based on a file, with Content-Length set automatically and // Content-Type set based on the file's extension (using the Mimetypes utility class) File fileData = new File("src/org/jets3t/samples/CodeSamples.java"); S3Object fileObject = new S3Object(fileData); // If your data isn't a File or String you can use any input stream as a data source, // but you must manually set the Content-Length. // Create an object containing a greeting string as input stream data. String greeting = "Hello World!"; S3Object helloWorldObject = new S3Object("HelloWorld2.txt"); ByteArrayInputStream greetingIS = new ByteArrayInputStream( greeting.getBytes(Constants.DEFAULT_ENCODING)); helloWorldObject.setDataInputStream(greetingIS); helloWorldObject.setContentLength( greeting.getBytes(Constants.DEFAULT_ENCODING).length); helloWorldObject.setContentType("text/plain"); // Upload the data objects. s3Service.putObject(testBucket, stringObject); s3Service.putObject(testBucket, fileObject); s3Service.putObject(testBucket, helloWorldObject); // Print details about the uploaded object. System.out.println("S3Object with data: " + helloWorldObject); // You may want to store your objects using a non-standard // "storage class" in some cases, such as if you are prepared to // accept a reduced level of redundancy in exchange for cheaper // storage. Here is how you store an object using the // Reduced Redundancy Storage (RRS) feature. S3Object rrsObject = new S3Object("reduced-redundancy-object"); // Apply the RRS storage class instead of the default STANDARD one. rrsObject.setStorageClass(S3Object.STORAGE_CLASS_REDUCED_REDUNDANCY); // Upload the object as usual. s3Service.putObject(testBucket, rrsObject); /* * Verifying Uploads */ // To be 100% sure that data you have uploaded to S3 has not been // corrupted in transit, you can verify that the hash value of the data // S3 received matches the hash value of your original data. // The easiest way to do this is to specify your data's hash value // in the Content-MD5 header before you upload the object. JetS3t will // do this for you automatically when you use the File- or String-based // S3Object constructors: S3Object objectWithHash = new S3Object(TEST_OBJECT_NAME, stringData); System.out.println("Hash value: " + objectWithHash.getMd5HashAsHex()); // If you do not use these constructors, you should *always* set the // Content-MD5 header value yourself before you upload an object. // JetS3t provides the ServiceUtils#computeMD5Hash method to calculate // the hash value of an input stream or byte array. ByteArrayInputStream dataIS = new ByteArrayInputStream( "Here is my data".getBytes(Constants.DEFAULT_ENCODING)); byte[] md5Hash = ServiceUtils.computeMD5Hash(dataIS); dataIS.reset(); stringObject = new S3Object("MyData"); stringObject.setDataInputStream(dataIS); stringObject.setMd5Hash(md5Hash); /* * Downloading data objects */ // To download data from S3 you retrieve an S3Object through the S3Service. // You may retrieve an object in one of two ways, with the data contents or without. // If you just want to know some details about an object and you don't need its contents, // it's faster to use the getObjectDetails method. This returns only the object's details, // also known as its 'HEAD'. Head information includes the object's size, date, and other // metadata associated with it such as the Content Type. // Retrieve the HEAD of the data object we created previously. S3Object objectDetailsOnly = s3Service.getObjectDetails(testBucket, TEST_OBJECT_NAME); System.out.println("S3Object, details only: " + objectDetailsOnly); // If you need the data contents of the object, the getObject method will return all the // object's details and will also set the object's DataInputStream variable from which // the object's data can be read. // Retrieve the whole data object we created previously S3Object objectComplete = s3Service.getObject(testBucket, TEST_OBJECT_NAME); System.out.println("S3Object, complete: " + objectComplete); // Read the data from the object's DataInputStream using a loop, and print it out. System.out.println("Greeting:"); BufferedReader reader = new BufferedReader( new InputStreamReader(objectComplete.getDataInputStream())); String data = null; while ((data = reader.readLine()) != null) { System.out.println(data); } /* * Verifying Downloads */ // To be 100% sure that data you have downloaded from S3 has not been // corrupted in transit, you can verify the data by calculating its hash // value and comparing this against the hash value returned by S3. // JetS3t provides convenient methods for verifying data that has been // downloaded to a File, byte array or InputStream. S3Object downloadedObject = s3Service.getObject(testBucket, TEST_OBJECT_NAME); String textData = ServiceUtils.readInputStreamToString( downloadedObject.getDataInputStream(), "UTF-8"); boolean valid = downloadedObject.verifyData(textData.getBytes("UTF-8")); System.out.println("Object verified? " + valid); /* * List your buckets and objects */ // Now that you have a bucket and some objects, it's worth listing them. Note that when // you list objects, the objects returned will not include much information compared to // what you get from the getObject and getObjectDetails methods. However, they will // include the size of each object // List all your buckets. S3Bucket[] buckets = s3Service.listAllBuckets(); // List the object contents of each bucket. for (int b = 0; b < buckets.length; b++) { System.out.println("Bucket '" + buckets[b].getName() + "' contains:"); // List the objects in this bucket. S3Object[] objects = s3Service.listObjects(buckets[b]); // Print out each object's key and size. for (int o = 0; o < objects.length; o++) { System.out.println(" " + objects[o].getKey() + " (" + objects[o].getContentLength() + " bytes)"); } } // When listing the objects in a bucket you can filter which objects to return based on // the names of those objects. This is useful when you are only interested in some // specific objects in a bucket and you don't need to list all the bucket's contents. // List only objects whose keys match a prefix. String prefix = "Reports"; String delimiter = null; // Refer to the S3 guide for more information on delimiters S3Object[] filteredObjects = s3Service.listObjects(testBucket, prefix, delimiter); /* * Copying objects */ // Objects can be copied within the same bucket and between buckets. // Create a target S3Object S3Object targetObject = new S3Object("targetObjectWithSourcesMetadata"); // Copy an existing source object to the target S3Object // This will copy the source's object data and metadata to the target object. boolean replaceMetadata = false; s3Service.copyObject(BUCKET_NAME, TEST_OBJECT_NAME, "destination-bucket", targetObject, replaceMetadata); // You can also copy an object and update its metadata at the same time. Perform a // copy-in-place (with the same bucket and object names for source and destination) // to update an object's metadata while leaving the object's data unchanged. targetObject = new S3Object(TEST_OBJECT_NAME); targetObject.addMetadata(S3Object.METADATA_HEADER_CONTENT_TYPE, "text/html"); replaceMetadata = true; s3Service.copyObject(BUCKET_NAME, TEST_OBJECT_NAME, BUCKET_NAME, targetObject, replaceMetadata); /* * Moving and Renaming objects */ // Objects can be moved within a bucket (to a different name) or to another S3 // bucket in the same region (eg US or EU). // A move operation is composed of a copy then a delete operation behind the scenes. // If the initial copy operation fails, the object is not deleted. If the final delete // operation fails, the object will exist in both the source and destination locations. // Here is a command that moves an object from one bucket to another. s3Service.moveObject(BUCKET_NAME, TEST_OBJECT_NAME, "destination-bucket", targetObject, false); // You can move an object to a new name in the same bucket. This is essentially a rename operation. s3Service.moveObject(BUCKET_NAME, TEST_OBJECT_NAME, BUCKET_NAME, new S3Object("NewName.txt"), false); // To make renaming easier, JetS3t has a shortcut method especially for this purpose. s3Service.renameObject(BUCKET_NAME, TEST_OBJECT_NAME, targetObject); /* * Deleting objects and buckets */ // Objects can be easily deleted. When they are gone they are gone for good so be careful. // Buckets may only be deleted when they are empty. // If you try to delete your bucket before it is empty, it will fail. try { // This will fail if the bucket isn't empty. s3Service.deleteBucket(testBucket.getName()); } catch (S3ServiceException e) { e.printStackTrace(); } // Delete all the objects in the bucket s3Service.deleteObject(testBucket, object.getKey()); s3Service.deleteObject(testBucket, helloWorldObject.getKey()); // Now that the bucket is empty, you can delete it. s3Service.deleteBucket(testBucket.getName()); System.out.println("Deleted bucket " + testBucket.getName()); /* *********************** * Multi-threaded Examples * *********************** */ // The JetS3t Toolkit includes utility services, S3ServiceMulti and S3ServiceSimpleMulti, that // can perform an S3 operation on many objects at a time. These services allow you to use more // of your available bandwidth and perform S3 operations much faster. They work with any // thread-safe S3Service implementation, such as the HTTP/REST implementation provided with // JetS3t. // The S3ServiceMulti service is intended for advanced developers. It is designed for use in // graphical applications and uses an event-notification approach to communicate its results // rather than standard method calls. This means the service can provide progress reports to // an application during long-running operations. However, this approach makes the service // complicated to use. See the code for the Cockpit application to see how this service is used // to display progress updates. // The S3ServiceSimpleMulti is a service that wraps around S3ServiceMulti and provides a // simplified interface, so developers can take advantage of multi-threading without any extra work. // The examples below demonstrate how to use some of the multi-threaded operations provided by // S3ServiceSimpleMulti. /* * Construct an S3ServiceSimpleMulti service */ // To use the S3ServiceSimpleMulti service you construct it by providing an existing // S3Service object. // Create a simple multi-threading service based on our existing S3Service S3ServiceSimpleMulti simpleMulti = new S3ServiceSimpleMulti(s3Service); /* * Upload multiple objects at once */ // To demonstrate multiple uploads, let's create some small text-data objects and a bucket to put them in. // First, create a bucket. S3Bucket bucket = new S3Bucket(awsCredentials.getAccessKey() + ".TestMulti"); bucket = s3Service.createBucket(bucket); // Create an array of data objects to upload. S3Object[] objects = new S3Object[5]; objects[0] = new S3Object("object1.txt", "Hello from object 1"); objects[1] = new S3Object("object2.txt", "Hello from object 2"); objects[2] = new S3Object("object3.txt", "Hello from object 3"); objects[3] = new S3Object("object4.txt", "Hello from object 4"); objects[4] = new S3Object("object5.txt", "Hello from object 5"); // Now we have some sample objects, we can upload them. // Upload multiple objects. S3Object[] createdObjects = simpleMulti.putObjects(bucket, objects); System.out.println("Uploaded " + createdObjects.length + " objects"); /* * Retrieve the HEAD information of multiple objects */ // Perform a Details/HEAD query for multiple objects. S3Object[] objectsWithHeadDetails = simpleMulti.getObjectsHeads(bucket, objects); // Print out details about all the objects. System.out.println("Objects with HEAD Details..."); for (int i = 0; i < objectsWithHeadDetails.length; i++) { System.out.println(objectsWithHeadDetails[i]); } /* * Download objects to local files */ // The multi-threading services provide a method to download multiple objects at a time, but // to use this you must first prepare somewhere to put the data associated with each object. // The most obvious place to put this data is into a file, so let's go through an example of // downloading object data into files. // To download our objects into files we first must create a DownloadPackage class for // each object. This class is a simple container which merely associates an object with a // file, to which the object's data will be written. // Create a DownloadPackage for each object, to associate the object with an output file. DownloadPackage[] downloadPackages = new DownloadPackage[5]; downloadPackages[0] = new DownloadPackage(objects[0], new File(objects[0].getKey())); downloadPackages[1] = new DownloadPackage(objects[1], new File(objects[1].getKey())); downloadPackages[2] = new DownloadPackage(objects[2], new File(objects[2].getKey())); downloadPackages[3] = new DownloadPackage(objects[3], new File(objects[3].getKey())); downloadPackages[4] = new DownloadPackage(objects[4], new File(objects[4].getKey())); // Download the objects. simpleMulti.downloadObjects(bucket, downloadPackages); System.out.println("Downloaded objects to current working directory"); /* * Delete multiple objects */ // It's time to clean up, so let's get rid of our multiple objects and test bucket. // Delete multiple objects, then the bucket too. simpleMulti.deleteObjects(bucket, objects); s3Service.deleteBucket(bucket); System.out.println("Deleted bucket: " + bucket); /* ***************** * Bucket Versioning * ***************** * S3 Buckets have a versioning feature which allows you to keep prior versions of * your objects when they are updated or deleted. This feature means you can be much * more confident that vital data will not be lost even if it is accidentally * overwritten or deleted. * * Versioning is not enabled for a bucket by default, you must explicitly enable * it. Once it is enabled you access and mange object versions using unique version * identifiers. */ // Create a bucket to test versioning S3Bucket versioningBucket = s3Service.getOrCreateBucket( "test-versioning"); String vBucketName = versioningBucket.getName(); // Check bucket versioning status for the bucket S3BucketVersioningStatus versioningStatus = s3Service.getBucketVersioningStatus(vBucketName); System.out.println("Versioning enabled ? " + versioningStatus.isVersioningEnabled()); // Suspend (disable) versioning for a bucket -- will have no // effect if bucket versioning is not yet enabled. // This will not delete any existing object versions. s3Service.suspendBucketVersioning(vBucketName); // Enable versioning for a bucket. s3Service.enableBucketVersioning(vBucketName); // Once versioning is enabled you can GET, PUT, copy and // delete objects as normal. Every change to an object will // cause a new version to be created. // Store and update and delete an object in the versioning bucket S3Object versionedObject = new S3Object("versioned-object", "Initial version"); s3Service.putObject(vBucketName, versionedObject); versionedObject = new S3Object("versioned-object", "Second version"); s3Service.putObject(vBucketName, versionedObject); versionedObject = new S3Object("versioned-object", "Final version"); s3Service.putObject(vBucketName, versionedObject); // If you retrieve an object with the standard method you will // get the latest version, and if the object is in a versioned // bucket its Version ID will be available versionedObject = s3Service.getObject(vBucketName, "versioned-object"); String finalVersionId = versionedObject.getVersionId(); System.out.println("Version ID: " + finalVersionId); // If you delete a versioned object it is no longer available using // standard methods... s3Service.deleteObject(vBucketName, "versioned-object"); try { s3Service.getObject(vBucketName, "versioned-object"); } catch (S3ServiceException e) { if (e.getResponseCode() == 404) { System.out.println("Is deleted object versioned? " + e.getResponseHeaders().get(Constants.AMZ_DELETE_MARKER)); System.out.println("Delete marker version ID: " + e.getResponseHeaders().get(Constants.AMZ_VERSION_ID)); } } // ... but you can use a versioning-aware method to retrieve any of // the prior versions by Version ID. versionedObject = s3Service.getVersionedObject(finalVersionId, vBucketName, "versioned-object"); String versionedData = ServiceUtils.readInputStreamToString( versionedObject.getDataInputStream(), "UTF-8"); System.out.println("Data from prior version of deleted document: " + versionedData); // List all the object versions in the bucket, with no prefix // or delimiter restrictions. Each result object will be one of // S3Version or S3DeleteMarker. BaseVersionOrDeleteMarker[] versions = s3Service.listVersionedObjects(vBucketName, null, null); for (int i = 0; i < versions.length; i++) { System.out.println(versions[i]); } // List versions of objects that match a prefix. String versionPrefix = "versioned-object"; versions = s3Service.listVersionedObjects(vBucketName, versionPrefix, null); // JetS3t includes a convenience method to list only the versions // for a specific object, even if it shares a prefix with other objects. versions = s3Service.getObjectVersions(vBucketName, "versioned-object"); // There are versioning-aware methods corresponding to all S3 operations versionedObject = s3Service.getVersionedObjectDetails( finalVersionId, vBucketName, "versioned-object"); // Confirm that S3 returned the versioned object you requested if (!finalVersionId.equals(versionedObject.getVersionId())) { throw new Exception("Incorrect version!"); } s3Service.copyVersionedObject(finalVersionId, vBucketName, "versioned-object", "destination-bucket", new S3Object("copied-from-version"), false, null, null, null, null); AccessControlList versionedObjectAcl = s3Service.getVersionedObjectAcl(finalVersionId, vBucketName, "versioned-object"); s3Service.putVersionedObjectAcl(finalVersionId, vBucketName, "versioned-object", versionedObjectAcl); // To delete an object version once-and-for-all you must use the // versioning-specific delete operation, and you can only do so // if you are the owner of the bucket containing the version. s3Service.deleteVersionedObject(finalVersionId, vBucketName, "versioned-object"); // You can easily delete all the versions of an object using // one of JetS3t's multi-threaded services. versions = s3Service.getObjectVersions(vBucketName, "versioned-object"); // Convert version and delete marker objects into versionId strings. String[] versionIds = BaseVersionOrDeleteMarker.toVersionIds(versions); (new S3ServiceSimpleMulti(s3Service)).deleteVersionsOfObject( versionIds, vBucketName, "versioned-object"); ////////////////////////////////////////////////////////////// // For additional data protection you can require multi-factor // authentication (MFA) to delete object versions. ////////////////////////////////////////////////////////////// // Require multi-factor authentication to delete versions. s3Service.enableBucketVersioningAndMFA(vBucketName); // Check MFA status for the bucket versioningStatus = s3Service.getBucketVersioningStatus(vBucketName); System.out.println("Multi-factor auth required to delete versions ? " + versioningStatus.isMultiFactorAuthDeleteRequired()); // If MFA is enabled for a bucket you must provide the serial number // for your multi-factor authentication device and a recent code to // delete object versions. String multiFactorSerialNumber = "#111222333"; String multiFactorAuthCode = "12345678"; s3Service.deleteVersionedObjectWithMFA(finalVersionId, multiFactorSerialNumber, multiFactorAuthCode, vBucketName, "versioned-object"); // With MFA enabled, you must provide your multi-factor auth credentials // to disable MFA. s3Service.disableMFAForVersionedBucket(vBucketName, multiFactorSerialNumber, multiFactorAuthCode); // With MFA enabled, you must provide your multi-factor auth credentials // to suspend S3 versioning altogether. However, the credentials will not // be needed if you have already disabled MFA. s3Service.suspendBucketVersioningWithMFA(vBucketName, multiFactorSerialNumber, multiFactorAuthCode); /* ***************** * Advanced Examples * ***************** */ /* * Managing Metadata */ // S3Objects can contain metadata stored as name/value pairs. This metadata is stored in // S3 and can be accessed when an object is retrieved from S3 using getObject // or getObjectDetails methods. To store metadata with an object, add your metadata to // the object prior to uploading it to S3. // Note that metadata cannot be updated in S3 without replacing the existing object, // and that metadata names must be strings without spaces. S3Object objectWithMetadata = new S3Object("metadataObject"); objectWithMetadata.addMetadata("favourite-colour", "blue"); objectWithMetadata.addMetadata("document-version", "0.3"); /* * Save and load encrypted AWS Credentials */ // AWS credentials are your means to login to and manage your S3 account, and should be // kept secure. The JetS3t toolkit stores these credentials in AWSCredentials objects. // The AWSCredentials class provides utility methods to allow credentials to be saved to // an encrypted file and loaded from a previously saved file with the right password. // Save credentials to an encrypted file protected with a password. File credFile = new File("awscredentials.enc"); awsCredentials.save("password", credFile); // Load encrypted credentials from a file. ProviderCredentials loadedCredentials = AWSCredentials.load("password", credFile); System.out.println("AWS Key loaded from file: " + loadedCredentials.getAccessKey()); // You won't get far if you use the wrong password... try { loadedCredentials = AWSCredentials.load("wrongPassword", credFile); } catch (S3ServiceException e) { System.err.println("Cannot load credentials from file with the wrong password!"); } /* * Manage Access Control Lists */ // S3 uses Access Control Lists to control who has access to buckets and objects in S3. // By default, any bucket or object you create will belong to you and will not be accessible // to anyone else. You can use JetS3t's support for access control lists to make buckets or // objects publicly accessible, or to allow other S3 members to access or manage your objects. // The ACL capabilities of S3 are quite involved, so to understand this subject fully please // consult Amazon's documentation. The code examples below show how to put your understanding // of the S3 ACL mechanism into practice. // ACL settings may be provided with a bucket or object when it is created, or the ACL of // existing items may be updated. Let's start by creating a bucket with default (i.e. private) // access settings, then making it public. // Create a bucket in S3. S3Bucket publicBucket = new S3Bucket(awsCredentials.getAccessKey() + ".publicBucket"); s3Service.createBucket(publicBucket); // Retrieve the bucket's ACL and modify it to grant public access, // ie READ access to the ALL_USERS group. AccessControlList bucketAcl = s3Service.getBucketAcl(publicBucket); bucketAcl.grantPermission(GroupGrantee.ALL_USERS, Permission.PERMISSION_READ); // Update the bucket's ACL. Now anyone can view the list of objects in this bucket. publicBucket.setAcl(bucketAcl); s3Service.putBucketAcl(publicBucket); System.out.println("View bucket's object listing here: http://s3.amazonaws.com/" + publicBucket.getName()); // Now let's create an object that is public from scratch. Note that we will use the bucket's // public ACL object created above, this works fine. Although it is possible to create an // AccessControlList object from scratch, this is more involved as you need to set the // ACL's Owner information which is only readily available from an existing ACL. // Create a public object in S3. Anyone can download this object. S3Object publicObject = new S3Object( "publicObject.txt", "This object is public"); publicObject.setAcl(bucketAcl); s3Service.putObject(publicBucket, publicObject); System.out.println("View public object contents here: http://s3.amazonaws.com/" + publicBucket.getName() + "/" + publicObject.getKey()); // The ALL_USERS Group is particularly useful, but there are also other grantee types // that can be used with AccessControlList. Please see Amazon's S3 technical documentation // for a fuller discussion of these settings. AccessControlList acl = new AccessControlList(); // Grant access by email address. Note that this only works email address of AWS S3 members. acl.grantPermission(new EmailAddressGrantee("someone@somewhere.com"), Permission.PERMISSION_FULL_CONTROL); // Grant control of ACL settings to a known AWS S3 member. acl.grantPermission(new CanonicalGrantee("AWS member's ID"), Permission.PERMISSION_READ_ACP); acl.grantPermission(new CanonicalGrantee("AWS member's ID"), Permission.PERMISSION_WRITE_ACP); /* * Bucket Policies -- offer a greater degree of access control for a bucket. */ // Set a bucket policy that allows public read access to all objects under // the virtual path "/public" String bucketNameForPolicy = publicBucket.getName(); String policyJSON = "{" + "\"Version\":\"2008-10-17\"" + ",\"Id\":\"EXAMPLE\"" + ",\"Statement\": [{" + "\"Effect\":\"Allow\"" + ",\"Action\":[\"s3:GetObject*\"]" + ",\"Principal\":{\"AWS\": [\"*\"]}" + ",\"Resource\":\"arn:aws:s3:::" + bucketNameForPolicy + "/public/*\"" + "}]}"; s3Service.setBucketPolicy(bucketNameForPolicy, policyJSON); // Retrieve the policy document applied to a bucket String policyDocument = s3Service.getBucketPolicy(bucketNameForPolicy); System.out.println(policyDocument); // Delete the policy document applied to a bucket s3Service.deleteBucketPolicy(bucketNameForPolicy); /* * Temporarily make an Object available to anyone */ // A private object stored in S3 can be made publicly available for a limited time using a // signed URL. The signed URL can be used by anyone to download the object, yet it includes // a date and time after which the URL will no longer work. // Create a private object in S3. S3Bucket privateBucket = new S3Bucket(awsCredentials.getAccessKey() + ".privateBucket"); S3Object privateObject = new S3Object( "privateObject.txt", "This object is private"); s3Service.createBucket(privateBucket); s3Service.putObject(privateBucket, privateObject); // Determine what the time will be in 5 minutes. Calendar cal = Calendar.getInstance(); cal.add(Calendar.MINUTE, 5); Date expiryDate = cal.getTime(); // Create a signed HTTP GET URL valid for 5 minutes. // If you use the generated URL in a web browser within 5 minutes, you will be able to view // the object's contents. After 5 minutes, the URL will no longer work and you will only // see an Access Denied message. String signedUrl = s3Service.createSignedGetUrl( privateBucket.getName(), privateObject.getKey(), expiryDate, false); System.out.println("Signed URL: " + signedUrl); /* * Multipart uploads */ // Amazon S3 offers an alternative method for uploading objects for // users with advanced requirements, called Multipart Uploads. This // mechanism involves uploading an object's data in parts instead of // all at once, which can give the following advantages: // * large files can be uploaded in smaller pieces to reduce the // impact of transient uploading/networking errors // * objects larger than 5 GB can be stored // * objects can be constructed from data that is uploaded over a // period of time, when it may not all be available in advance. // JetS3t's MultipartUtils class makes it easy to perform mutipart // uploads of your files. To upload a file in 20MB parts: S3Object largeFileObject = new S3Object(new File("/path/to/large/file")); List objectsToUploadAsMultipart = new ArrayList(); objectsToUploadAsMultipart.add(largeFileObject); long maxSizeForAPartInBytes = 20 * 1024 * 1024; MultipartUtils mpUtils = new MultipartUtils(maxSizeForAPartInBytes); mpUtils.uploadObjects(BUCKET_NAME, s3Service, objectsToUploadAsMultipart, null // eventListener : Provide one to monitor the upload progress ); // The S3Service API also provides the underlying low-level multipart operations // if you need more control over the process. See the method names that // start with "multipart", and the example code in // TestRestS3Service#testMultipartUploads // IMPORTANT: The objects in S3 created by a multipart upload process do not // have ETag header values that can be used to perform MD5 hash verification // of the object data. See https://forums.aws.amazon.com/thread.jspa?messageID=234579 /* * Create an S3 POST form */ // When you create and S3 POST form, anyone who accesses that form in // a web browser will be able to upload files to S3 directly from the // browser, without needing S3-compatible client software. // Refer to the S3 documentation for more information: // http://docs.amazonwebservices.com/AmazonS3/2006-03-01/UsingHTTPPOST.html // We will start by creating a POST form with no policy document, // meaning that the form will have no expiration date or usage // conditions. This form will only work if the target bucket has // public write access enabled. String unrestrictedForm = S3Service.buildPostForm("public-bucket", "${filename}"); // To use this form, save it in a UTF-8 encoded HTML page (ie with // the meta tag // ) // and load the page in a web browser. // We will now create a POST form with a range of policy conditions, // that will allow users to upload image files to a protected bucket. String key = "uploads/images/pic.jpg"; // Specify input fields to set the access permissions and content type // of the object created by the form. We will also redirect the user to // another web site after they have successfully uploaded a file. String[] inputFields = new String[] { "", "", "" }; // We then specify policy conditions for at least the mandatory // 'bucket' and 'key' fields that will be included in the POST request. // In addition to the mandatory fields, we will add a condition to // control the size of the file the user can upload. // Note that our list of conditions must include a condition // corresponding to each of the additional input fields we specified above. String[] conditions = { S3Service.generatePostPolicyCondition_Equality("bucket", BUCKET_NAME), S3Service.generatePostPolicyCondition_Equality("key", key), S3Service.generatePostPolicyCondition_Range(10240, 204800), // Conditions to allow the additional fields specified above S3Service.generatePostPolicyCondition_Equality("acl", "public-read"), S3Service.generatePostPolicyCondition_Equality("Content-Type", "image/jpeg"), S3Service.generatePostPolicyCondition_Equality("success_action_redirect", "http://localhost/post_upload") }; // Form will expire in 24 hours cal = Calendar.getInstance(); cal.add(Calendar.HOUR, 24); Date expiration = cal.getTime(); // Generate the form. String restrictedForm = S3Service.buildPostForm( BUCKET_NAME, key, awsCredentials, expiration, conditions, inputFields, null, true); /* * Activate Requester Pays for a bucket. */ // A bucket in S3 is normally configured such that the bucket's owner // pays all the service fees for accessing, sharing and storing objects. // The Requester Pays feature of S3 allows a bucket to be configured // such that the individual who sends requests to a bucket is charged // the S3 request and data transfer fees, instead of the bucket's owner. // Set a bucket to be Requester Pays s3Service.setRequesterPaysBucket(BUCKET_NAME, true); // Set a bucket to be Owner pays (the default value for S3 buckets) s3Service.setRequesterPaysBucket(BUCKET_NAME, false); // Find out whether a bucket is configured as Requester pays s3Service.isRequesterPaysBucket(BUCKET_NAME); /* * Access a Requester Pays bucket when you are not the bucket's owner */ // When a bucket is configured as Requester Pays, other AWS users can // upload objects to the bucket or retrieve them provided the user: // - has the necessary Access Control List permissions, and // - indicates that he/she is willing to pay the Requester Pays fees, // by including a special flag in the request. // Indicate that you will accept any Requester Pays fees by setting // the RequesterPaysEnabled flag to true in your RestS3Service class. // You can then use the service to list, upload, or download objects as // normal. // Support for Requester Pays buckets is disabled by default in JetS3t // with the jets3t.properties setting // 'httpclient.requester-pays-buckets-enabled=false' s3Service.setRequesterPaysEnabled(true); /* * Generate a Signed URL for a Requester Pays bucket */ // Third party users of a Requester Pays bucket can generate Signed // URLs that permit public access to objects. To generate such a URL, // these users call the S3Service#createSignedUrl method with a flag to // indicate that the he/she is willing to pay the Requester Pays fees // incurred by the use of the signed URL. // Generate a signed GET URL for Map httpHeaders = null; long expirySecsAfterEpoch = System.currentTimeMillis() / 1000 + 300; boolean isVirtualHost = false; boolean isHttpsUrl = false; boolean isDnsBucketNamingDisabled = false; String requesterPaysSignedGetUrl = s3Service.createSignedUrl("GET", BUCKET_NAME, "object-name", Constants.REQUESTER_PAYS_BUCKET_FLAG, // Include Requester Pays flag httpHeaders, expirySecsAfterEpoch, isVirtualHost, isHttpsUrl, isDnsBucketNamingDisabled); /* * Accessing Amazon DevPay S3 accounts */ // Amazon's DevPay service allows vendors to sell user-pays S3 accounts. // To access the S3 portions of a DevPay product, JetS3t needs // additional credentials that include the DevPay User Token, and the // DevPay Product Token. AWSDevPayCredentials devPayCredentials = new AWSDevPayCredentials( "YOUR_AWS_ACCESSS_KEY", "YOUR_AWS_SECRET_KEY", "DEVPAY_USER_TOKEN", "DEVPAY_PRODUCT_TOKEN"); // Once you have defined your DevPay S3 credentials, you can create an // S3Service class based on these and access the DevPay account as usual. S3Service devPayService = new RestS3Service(devPayCredentials); devPayService.listAllBuckets(); // You can also generate signed URLs for DevPay S3 accounts. Here is the // code to generate a link that makes an object in a DevPay account // temporary available for public download. cal = Calendar.getInstance(); cal.add(Calendar.MINUTE, 5); String signedDevPayUrl = devPayService.createSignedGetUrl( "devpay-bucket-name", "devpay-object-name", cal.getTime()); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/samples/SamplesUtils.java0000644000000000000000000001107411441613550021231 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.samples; import java.io.IOException; import java.io.InputStream; import java.util.Properties; import org.jets3t.service.security.AWSCredentials; import org.jets3t.service.security.GSCredentials; /** * Utilities used by all Sample code, collected in one place for convenience. * * @author James Murty */ public class SamplesUtils { public static final String SAMPLES_PROPERTIES_NAME = "samples.properties"; public static final String AWS_ACCESS_KEY_PROPERTY_NAME = "awsAccessKey"; public static final String AWS_SECRET_KEY_PROPERTY_NAME = "awsSecretKey"; public static final String GS_ACCESS_KEY_PROPERTY_NAME = "gsAccessKey"; public static final String GS_SECRET_KEY_PROPERTY_NAME = "gsSecretKey"; /** * Loads AWS Credentials from the file samples.properties * ({@link #SAMPLES_PROPERTIES_NAME}) that must be available in the * classpath, and must contain settings awsAccessKey and * awsSecretKey. * * @return * the AWS credentials loaded from the samples properties file. */ public static AWSCredentials loadAWSCredentials() throws IOException { InputStream propertiesIS = ClassLoader.getSystemResourceAsStream(SAMPLES_PROPERTIES_NAME); if (propertiesIS == null) { throw new RuntimeException("Unable to load test properties file from classpath: " + SAMPLES_PROPERTIES_NAME); } Properties testProperties = new Properties(); testProperties.load(propertiesIS); if (!testProperties.containsKey(AWS_ACCESS_KEY_PROPERTY_NAME)) { throw new RuntimeException( "Properties file '" + SAMPLES_PROPERTIES_NAME + "' does not contain required property: " + AWS_ACCESS_KEY_PROPERTY_NAME); } if (!testProperties.containsKey(AWS_SECRET_KEY_PROPERTY_NAME)) { throw new RuntimeException( "Properties file '" + SAMPLES_PROPERTIES_NAME + "' does not contain required property: " + AWS_SECRET_KEY_PROPERTY_NAME); } AWSCredentials awsCredentials = new AWSCredentials( testProperties.getProperty(AWS_ACCESS_KEY_PROPERTY_NAME), testProperties.getProperty(AWS_SECRET_KEY_PROPERTY_NAME)); return awsCredentials; } /** * Loads Google Storage Credentials from the file samples.properties * ({@link #SAMPLES_PROPERTIES_NAME}) that must be available in the * classpath, and must contain settings gsAccessKey and * gsSecretKey. * * @return * the Google Storage credentials loaded from the samples properties file. */ public static GSCredentials loadGSCredentials() throws IOException { InputStream propertiesIS = ClassLoader.getSystemResourceAsStream(SAMPLES_PROPERTIES_NAME); if (propertiesIS == null) { throw new RuntimeException("Unable to load test properties file from classpath: " + SAMPLES_PROPERTIES_NAME); } Properties testProperties = new Properties(); testProperties.load(propertiesIS); if (!testProperties.containsKey(GS_ACCESS_KEY_PROPERTY_NAME)) { throw new RuntimeException( "Properties file '" + SAMPLES_PROPERTIES_NAME + "' does not contain required property: " + GS_ACCESS_KEY_PROPERTY_NAME); } if (!testProperties.containsKey(GS_SECRET_KEY_PROPERTY_NAME)) { throw new RuntimeException( "Properties file '" + SAMPLES_PROPERTIES_NAME + "' does not contain required property: " + GS_SECRET_KEY_PROPERTY_NAME); } GSCredentials gsCredentials = new GSCredentials( testProperties.getProperty(GS_ACCESS_KEY_PROPERTY_NAME), testProperties.getProperty(GS_SECRET_KEY_PROPERTY_NAME)); return gsCredentials; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/samples/GSCodeSamples.java0000644000000000000000000004365511546514260021253 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.samples; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; import java.io.InputStreamReader; import org.jets3t.service.Constants; import org.jets3t.service.ServiceException; import org.jets3t.service.acl.Permission; import org.jets3t.service.acl.gs.AllUsersGrantee; import org.jets3t.service.acl.gs.GSAccessControlList; import org.jets3t.service.acl.gs.GroupByDomainGrantee; import org.jets3t.service.acl.gs.UserByEmailAddressGrantee; import org.jets3t.service.acl.gs.UserByIdGrantee; import org.jets3t.service.impl.rest.httpclient.GoogleStorageService; import org.jets3t.service.model.GSBucket; import org.jets3t.service.model.GSObject; import org.jets3t.service.security.GSCredentials; import org.jets3t.service.utils.ServiceUtils; /** * This class includes all the code samples as listed in the Google Storage * Developer's Guide. *

* This code is provided as a convenience for those who are reading through the guide and don't want * to type out the examples themselves. *

* * @author Google Developers */ public class GSCodeSamples { private static final String BUCKET_NAME = "test-bucket"; private static final String TEST_OBJECT_NAME = "helloworld.txt"; public static void main(String[] args) throws Exception { /* ************ * Code Samples * ************ */ /* * Connecting to Google Storage */ // Your Google Storage (GS) login credentials are required to manage GS accounts. // These credentials are stored in an GSCredentials object: GSCredentials gsCredentials = SamplesUtils.loadGSCredentials(); // To communicate with Google Storage use the GoogleStorageService. GoogleStorageService gsService = new GoogleStorageService(gsCredentials); // A good test to see if your GoogleStorageService can connect to GS is to list all the buckets you own. // If a bucket listing produces no exceptions, all is well. GSBucket[] myBuckets = gsService.listAllBuckets(); System.out.println("How many buckets to I have in GS? " + myBuckets.length); /* * Create a bucket */ // To store data in GS you must first create a bucket, a container for objects. GSBucket testBucket = gsService.createBucket(BUCKET_NAME); System.out.println("Created test bucket: " + testBucket.getName()); // If you try using a common name, you will probably not be able to create the // bucket as someone else will already have a bucket of that name. /* * Uploading data objects */ // We use GSObject classes to represent data objects in Google Storage. To store some // information in our new test bucket, we must first create an object with a key/name then // tell our GoogleStorageService to upload it to GS. // In the example below, we print out information about the GSObject before and after // uploading it to GS. These print-outs demonstrate that the GSObject returned by the // putObject method contains extra information provided by GS, such as the date the // object was last modified on a GS server. // Create an empty object with a key/name, and print the object's details. GSObject object = new GSObject("object"); System.out.println("GSObject before upload: " + object); // Upload the object to our test bucket in GS. object = gsService.putObject(BUCKET_NAME, object); // Print the details about the uploaded object, which contains more information. System.out.println("GSObject after upload: " + object); // The example above will create an empty object in GS, which isn't very useful. // To include data in the object you must provide some data for the object. // If you know the Content/Mime type of the data (e.g. text/plain) you should set this too. // GSObject's can contain any data available from an input stream, but JetS3t provides two // convenient object types to hold File or String data. These convenient constructors // automatically set the Content-Type and Content-Length of the object. // Create an GSObject based on a string, with Content-Length set automatically and // Content-Type set to "text/plain" String stringData = "Hello World!"; GSObject stringObject = new GSObject(TEST_OBJECT_NAME, stringData); // Create an GSObject based on a file, with Content-Length set automatically and // Content-Type set based on the file's extension (using the Mimetypes utility class) File fileData = new File("src/org/jets3t/samples/GSCodeSamples.java"); GSObject fileObject = new GSObject(fileData); // If your data isn't a File or String you can use any input stream as a data source, // but you must manually set the Content-Length. // Create an object containing a greeting string as input stream data. String greeting = "Hello World!"; GSObject helloWorldObject = new GSObject("HelloWorld2.txt"); ByteArrayInputStream greetingIS = new ByteArrayInputStream( greeting.getBytes(Constants.DEFAULT_ENCODING)); helloWorldObject.setDataInputStream(greetingIS); helloWorldObject.setContentLength( greeting.getBytes(Constants.DEFAULT_ENCODING).length); helloWorldObject.setContentType("text/plain"); // Upload the data objects. gsService.putObject(BUCKET_NAME, stringObject); gsService.putObject(BUCKET_NAME, fileObject); gsService.putObject(BUCKET_NAME, helloWorldObject); // Print details about the uploaded object. System.out.println("GSObject with data: " + helloWorldObject); /* * Verifying Uploads */ // To be 100% sure that data you have uploaded to GS has not been // corrupted in transit, you can verify that the hash value of the data // GS received matches the hash value of your original data. // The easiest way to do this is to specify your data's hash value // in the Content-MD5 header before you upload the object. JetS3t will // do this for you automatically when you use the File- or String-based // GSObject constructors: GSObject objectWithHash = new GSObject(TEST_OBJECT_NAME, stringData); System.out.println("Hash value: " + objectWithHash.getMd5HashAsHex()); // If you do not use these constructors, you should *always* set the // Content-MD5 header value yourself before you upload an object. // JetS3t provides the ServiceUtils#computeMD5Hash method to calculate // the hash value of an input stream or byte array. ByteArrayInputStream dataIS = new ByteArrayInputStream( "Here is my data".getBytes(Constants.DEFAULT_ENCODING)); byte[] md5Hash = ServiceUtils.computeMD5Hash(dataIS); dataIS.reset(); GSObject hashObject = new GSObject("MyData"); hashObject.setDataInputStream(dataIS); hashObject.setMd5Hash(md5Hash); /* * Downloading data objects */ // To download data from GS you retrieve an GSObject through the GSService. // You may retrieve an object in one of two ways, with the data contents or without. // If you just want to know some details about an object and you don't need its contents, // it's faster to use the getObjectDetails method. This returns only the object's details, // also known as its 'HEAD'. Head information includes the object's size, date, and other // metadata associated with it such as the Content Type. // Retrieve the HEAD of the data object we created previously. GSObject objectDetailsOnly = gsService.getObjectDetails(BUCKET_NAME, TEST_OBJECT_NAME); System.out.println("GSObject, details only: " + objectDetailsOnly); // If you need the data contents of the object, the getObject method will return all the // object's details and will also set the object's DataInputStream variable from which // the object's data can be read. // Retrieve the whole data object we created previously GSObject objectComplete = gsService.getObject(BUCKET_NAME, TEST_OBJECT_NAME); System.out.println("GSObject, complete: " + objectComplete); // Read the data from the object's DataInputStream using a loop, and print it out. System.out.println("Greeting:"); BufferedReader reader = new BufferedReader( new InputStreamReader(objectComplete.getDataInputStream())); String data; while ((data = reader.readLine()) != null) { System.out.println(data); } /* * Verifying Downloads */ // To be 100% sure that data you have downloaded from GS has not been // corrupted in transit, you can verify the data by calculating its hash // value and comparing this against the hash value returned by GS. // JetS3t provides convenient methods for verifying data that has been // downloaded to a File, byte array or InputStream. GSObject downloadedObject = gsService.getObject(BUCKET_NAME, TEST_OBJECT_NAME); String textData = ServiceUtils.readInputStreamToString( downloadedObject.getDataInputStream(), "UTF-8"); boolean valid = downloadedObject.verifyData(textData.getBytes("UTF-8")); System.out.println("Object verified? " + valid); /* * List your buckets and objects */ // Now that you have a bucket and some objects, it's worth listing them. Note that when // you list objects, the objects returned will not include much information compared to // what you get from the getObject and getObjectDetails methods. However, they will // include the size of each object // List all your buckets. GSBucket[] buckets = gsService.listAllBuckets(); // List the object contents of each bucket. for (int b = 0; b < buckets.length; b++) { System.out.println("Bucket '" + buckets[b].getName() + "' contains:"); // List the objects in this bucket. GSObject[] objects = gsService.listObjects(buckets[b].getName()); // Print out each object's key and size. for (int o = 0; o < objects.length; o++) { System.out.println(" " + objects[o].getKey() + " (" + objects[o].getContentLength() + " bytes)"); } } // When listing the objects in a bucket you can filter which objects to return based on // the names of those objects. This is useful when you are only interested in some // specific objects in a bucket and you don't need to list all the bucket's contents. // List only objects whose keys match a prefix. String prefix = "Reports"; String delimiter = null; // Refer to the service guide for more information on delimiters GSObject[] filteredObjects = gsService.listObjects(BUCKET_NAME, prefix, delimiter); /* * Copying objects */ // Objects can be copied within the same bucket and between buckets. // Create a target GSObject GSObject targetObject = new GSObject("target-object-with-sources-metadata"); // Copy an existing source object to the target GSObject // This will copy the source's object data and metadata to the target object. boolean replaceMetadata = false; gsService.copyObject(BUCKET_NAME, TEST_OBJECT_NAME, "target-bucket", targetObject, replaceMetadata); // You can also copy an object and update its metadata at the same time. Perform a // copy-in-place (with the same bucket and object names for source and destination) // to update an object's metadata while leaving the object's data unchanged. targetObject = new GSObject(TEST_OBJECT_NAME); targetObject.addMetadata(GSObject.METADATA_HEADER_CONTENT_TYPE, "text/html"); replaceMetadata = true; gsService.copyObject(BUCKET_NAME, TEST_OBJECT_NAME, BUCKET_NAME, targetObject, replaceMetadata); /* * Moving and Renaming objects */ // Objects can be moved within a bucket (to a different name) or to another bucket. // A move operation is composed of a copy then a delete operation behind the scenes. // If the initial copy operation fails, the object is not deleted. If the final delete // operation fails, the object will exist in both the source and destination locations. // Here is a command that moves an object from one bucket to another. gsService.moveObject(BUCKET_NAME, TEST_OBJECT_NAME, "target-bucket", targetObject, false); // You can move an object to a new name in the same bucket. This is essentially a rename operation. gsService.moveObject(BUCKET_NAME, TEST_OBJECT_NAME, BUCKET_NAME, new GSObject("newname.txt"), false); // To make renaming easier, JetS3t has a shortcut method especially for this purpose. gsService.renameObject(BUCKET_NAME, TEST_OBJECT_NAME, targetObject); /* * Deleting objects and buckets */ // Objects can be easily deleted. When they are gone they are gone for good so be careful. // Buckets may only be deleted when they are empty. // If you try to delete your bucket before it is empty, it will fail. try { // This will fail if the bucket isn't empty. gsService.deleteBucket(BUCKET_NAME); } catch (ServiceException e) { e.printStackTrace(); } // Delete all the objects in the bucket gsService.deleteObject(BUCKET_NAME, object.getKey()); gsService.deleteObject(BUCKET_NAME, helloWorldObject.getKey()); gsService.deleteObject(BUCKET_NAME, stringObject.getKey()); gsService.deleteObject(BUCKET_NAME, fileObject.getKey()); // Now that the bucket is empty, you can delete it. gsService.deleteBucket(BUCKET_NAME); System.out.println("Deleted bucket " + BUCKET_NAME); /* * Manage Access Control Lists */ // GS uses Access Control Lists to control who has access to buckets and objects in GS. // By default, any bucket or object you create will belong to you and will not be accessible // to anyone else. You can use JetS3t's support for access control lists to make buckets or // objects publicly accessible, or to allow other GS members to access or manage your objects. // The ACL capabilities of GS are quite involved, so to understand this subject fully please // consult Google's documentation. The code examples below show how to put your understanding // of the GS ACL mechanism into practice. // ACL settings may be provided with a bucket or object when it is created, or the ACL of // existing items may be updated. Let's start by creating a bucket with default (i.e. private) // access settings, then making it public. // Create a bucket. String publicBucketName = BUCKET_NAME + "-public"; GSBucket publicBucket = new GSBucket(publicBucketName); gsService.createBucket(publicBucketName); // Retrieve the bucket's ACL and modify it to grant public access, // ie READ access to the ALL_USERS group. GSAccessControlList bucketAcl = gsService.getBucketAcl(publicBucketName); bucketAcl.grantPermission(new AllUsersGrantee(), Permission.PERMISSION_READ); // Update the bucket's ACL. Now anyone can view the list of objects in this bucket. publicBucket.setAcl(bucketAcl); gsService.putBucketAcl(publicBucket); // Now let's create an object that is public from scratch. Note that we will use the bucket's // public ACL object created above, this works fine. Although it is possible to create an // AccessControlList object from scratch, this is more involved as you need to set the // ACL's Owner information which is only readily available from an existing ACL. // Create a public object in GS. Anyone can download this object. GSObject publicObject = new GSObject("publicObject.txt", "This object is public"); publicObject.setAcl(bucketAcl); gsService.putObject(publicBucketName, publicObject); // The ALL_USERS Group is particularly useful, but there are also other grantee types // that can be used with AccessControlList. Please see Google Storage technical documentation // for a fuller discussion of these settings. GSAccessControlList acl = new GSAccessControlList(); // Grant access by email address. Note that this only works email address of GS members. acl.grantPermission(new UserByEmailAddressGrantee("someone@somewhere.com"), Permission.PERMISSION_FULL_CONTROL); // Grant Read access by Goodle ID. acl.grantPermission(new UserByIdGrantee("Google member's ID"), Permission.PERMISSION_READ); // Grant Write access to a group by domain. acl.grantPermission(new GroupByDomainGrantee("yourdomain.com"), Permission.PERMISSION_WRITE); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/samples/UrlSigningExample.java0000644000000000000000000001141411427702124022177 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.samples; import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.Calendar; import java.util.Date; import org.jets3t.service.S3Service; import org.jets3t.service.impl.rest.httpclient.RestS3Service; import org.jets3t.service.model.S3Bucket; import org.jets3t.service.model.S3Object; import org.jets3t.service.security.AWSCredentials; import org.jets3t.service.utils.signedurl.SignedUrlHandler; /** * Demonstrates how to create and use Signed URLs. */ public class UrlSigningExample { /* * Change the name of this bucket to a bucket of your own. */ private static final String myBucketName = "test"; public static void main(String[] args) throws Exception { // Initialise a SignedUrlHandler, which is an interface implemented by classes able to // perform operations in S3 using signed URLs (no AWS Credentials required). // The RestS3Service provides an implementation of this interface in JetS3t. SignedUrlHandler signedUrlHandler = new RestS3Service(null); // Create a bucket to test reading and writing to S3Bucket bucket = new S3Bucket(myBucketName); // Create an object to use for testing. S3Object object = new S3Object(bucket, "urlSigningTestObject.txt", "Hello World!"); // Determine what the time will be in 5 minutes - our signed URLs will be valid for 5 minutes only. Calendar cal = Calendar.getInstance(); cal.add(Calendar.MINUTE, 5); Date expiryDate = cal.getTime(); /* * Generate the signed URL strings for PUT, GET, HEAD and DELETE operations, using the * AWS Credentials in the samples.properties file. */ AWSCredentials awsCredentials = SamplesUtils.loadAWSCredentials(); S3Service s3Service = new RestS3Service(awsCredentials); // Create an unsigned HTTP GET URL -- useful only for publicly-accessible objects. String unsignedGetUrl = s3Service.createUnsignedObjectUrl( bucket.getName(), object.getKey(), false, false, false); // Create a signed HTTP PUT URL valid for 5 minutes. String putUrl = s3Service.createSignedPutUrl(bucket.getName(), object.getKey(), object.getMetadataMap(), expiryDate, false); // Create a signed HTTP GET URL valid for 5 minutes. String getUrl = s3Service.createSignedGetUrl(bucket.getName(), object.getKey(), expiryDate, false); // Create a signed HTTP HEAD URL valid for 5 minutes. String headUrl = s3Service.createSignedHeadUrl(bucket.getName(), object.getKey(), expiryDate, false); // Create a signed HTTP DELETE URL valid for 5 minutes. String deleteUrl = s3Service.createSignedDeleteUrl(bucket.getName(), object.getKey(), expiryDate, false); System.out.println("Unsigned URL: " + unsignedGetUrl); System.out.println("Signed PUT URL: " + putUrl); System.out.println("Signed GET URL: " + getUrl); System.out.println("Signed HEAD URL: " + headUrl); System.out.println("Signed DELETE URL: " + deleteUrl); System.out.println("Performing PUT with signed URL"); S3Object putObject = signedUrlHandler.putObjectWithSignedUrl(putUrl, object); System.out.println(" Object has been uploaded to S3: " + putObject.getKey()); System.out.println("Performing HEAD with signed URL"); S3Object headObject = signedUrlHandler.getObjectDetailsWithSignedUrl(headUrl); System.out.println(" Size of object in S3: " + headObject.getContentLength()); System.out.println("Performing GET with signed URL"); S3Object getObject = signedUrlHandler.getObjectWithSignedUrl(getUrl); String contentData = (new BufferedReader( new InputStreamReader(getObject.getDataInputStream()))).readLine(); System.out.println(" Content of object in S3: " + contentData); System.out.println("Performing DELETE with signed URL"); signedUrlHandler.deleteObjectWithSignedUrl(deleteUrl); System.out.println(" Object deleted - the example is finished"); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/samples/ThreadedObjectListing.java0000644000000000000000000001322511441613550023005 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.samples; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; import org.jets3t.service.S3ObjectsChunk; import org.jets3t.service.S3Service; import org.jets3t.service.S3ServiceException; import org.jets3t.service.StorageObjectsChunk; import org.jets3t.service.impl.rest.httpclient.RestS3Service; import org.jets3t.service.multithread.ListObjectsEvent; import org.jets3t.service.multithread.S3ServiceEventAdaptor; import org.jets3t.service.multithread.S3ServiceMulti; import org.jets3t.service.security.AWSCredentials; /** * Demonstrates how to use the {@link S3ServiceMulti#listObjects(String, String[], String, long)} * method to list multiple "partitions" of an S3 bucket at once, using multiple * threads to list objects matching different prefixes. * * @author James Murty */ public class ThreadedObjectListing { public static String TEST_PROPERTIES_FILENAME = "test.properties"; public static void main(String[] args) throws Exception { /* * Set these values to test the multi-theaded listing. * * If you set delimiter to null, only a standard single-threaded listing * will be performed. If you set the delimiter to a string that will * identify a number of "subdirectory" partitions in your bucket, a * threaded listing will be performed for each such partition. */ final String bucketName = "jets3t"; final String delimiter = "/"; AWSCredentials awsCredentials = SamplesUtils.loadAWSCredentials(); S3Service restService = new RestS3Service(awsCredentials); final List allObjects = Collections.synchronizedList(new ArrayList()); final Exception s3ServiceExceptions[] = new Exception[1]; /* * Identify top-level "subdirectory" names in a bucket by performing a * standard object listing with a delimiter string. */ long startTime = System.currentTimeMillis(); // Find all the objects and common prefixes at the top level. StorageObjectsChunk initialChunk = restService.listObjectsChunked( bucketName, null, delimiter, 1000, null, true); long totalElapsedTime = System.currentTimeMillis() - startTime; // We will use the common prefix strings, if any, to perform sub-listings final String[] commonPrefixes = initialChunk.getCommonPrefixes(); if (commonPrefixes.length > 0) { System.out.println("Performing sub-listings for common prefixes: " + Arrays.asList(commonPrefixes)); /* * Create a S3ServiceMulti object with an event listener that responds to * ListObjectsEvent notifications and populates a complete object listing. */ final S3ServiceMulti s3Multi = new S3ServiceMulti(restService, new S3ServiceEventAdaptor() { @Override public void s3ServiceEventPerformed(ListObjectsEvent event) { if (ListObjectsEvent.EVENT_IN_PROGRESS == event.getEventCode()) { Iterator chunkIter = event.getChunkList().iterator(); while (chunkIter.hasNext()) { StorageObjectsChunk chunk = (StorageObjectsChunk) chunkIter.next(); System.out.println("Listed " + chunk.getObjects().length + " objects for sub-listing with prefix: '" + chunk.getPrefix() + "'"); allObjects.addAll(Arrays.asList(chunk.getObjects())); } } else if (ListObjectsEvent.EVENT_ERROR == event.getEventCode()) { s3ServiceExceptions[0] = new S3ServiceException( "Failed to list all objects in S3 bucket", event.getErrorCause()); } } }); startTime = System.currentTimeMillis(); /* * Perform a multi-threaded listing, where each common prefix string * will be used as the prefix for a separate listing thread. */ (new Thread() { @Override public void run() { s3Multi.listObjects(bucketName, commonPrefixes, null, 1000); }; }).run(); long threadedElapsedTime = System.currentTimeMillis() - startTime; totalElapsedTime += threadedElapsedTime; System.out.println("\nTime to list " + allObjects.size() + " objects with " + commonPrefixes.length + " sub-listings: " + threadedElapsedTime + " ms"); } // Add top-level objects to the complete listing allObjects.addAll(Arrays.asList(initialChunk.getObjects())); System.out.println("\nTotal time to list " + allObjects.size() + " objects: " + totalElapsedTime + " ms"); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/samples/CloudFrontSamples.java0000644000000000000000000005006311550427710022213 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008-2009 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.samples; import java.io.FileInputStream; import java.util.List; import org.jets3t.service.CloudFrontService; import org.jets3t.service.model.cloudfront.CustomOrigin; import org.jets3t.service.model.cloudfront.Invalidation; import org.jets3t.service.model.cloudfront.InvalidationSummary; import org.jets3t.service.model.cloudfront.OriginAccessIdentity; import org.jets3t.service.model.cloudfront.Distribution; import org.jets3t.service.model.cloudfront.DistributionConfig; import org.jets3t.service.model.cloudfront.LoggingStatus; import org.jets3t.service.model.cloudfront.OriginAccessIdentityConfig; import org.jets3t.service.model.cloudfront.S3Origin; import org.jets3t.service.model.cloudfront.StreamingDistribution; import org.jets3t.service.model.cloudfront.StreamingDistributionConfig; import org.jets3t.service.security.EncryptionUtil; import org.jets3t.service.utils.ServiceUtils; /** * Sample code for performing CloudFront service operations. */ public class CloudFrontSamples { public static void main(String[] args) throws Exception { // Construct a CloudFrontService object to interact with the service. CloudFrontService cloudFrontService = new CloudFrontService( SamplesUtils.loadAWSCredentials()); // List non-streaming distributions Distribution[] bucketDistributions = cloudFrontService.listDistributions(); for (int i = 0; i < bucketDistributions.length; i++) { System.out.println("Distribution " + (i + 1) + ": " + bucketDistributions[i]); } // List the distributions applied to a given S3 bucket bucketDistributions = cloudFrontService.listDistributions("jets3t"); for (int i = 0; i < bucketDistributions.length; i++) { System.out.println("Bucket distribution " + (i + 1) + ": " + bucketDistributions[i]); } // Create a new public distribution String originBucket = "jets3t.s3.amazonaws.com"; Distribution newDistribution = cloudFrontService.createDistribution( new S3Origin(originBucket), "" + System.currentTimeMillis(), // Caller reference - a unique string value new String[] {"test1.jamesmurty.com"}, // CNAME aliases for distribution "Testing", // Comment true, // Distribution is enabled? null // Logging status of distribution (null means disabled) ); System.out.println("New Distribution: " + newDistribution); // The ID of the new distribution we will use for testing String testDistributionId = newDistribution.getId(); // List information about a distribution Distribution distribution = cloudFrontService.getDistributionInfo(testDistributionId); System.out.println("Distribution: " + distribution); // List configuration information about a distribution DistributionConfig distributionConfig = cloudFrontService.getDistributionConfig(testDistributionId); System.out.println("Distribution Config: " + distributionConfig); // Update a distribution's configuration to add an extra CNAME alias and enable logging. DistributionConfig updatedDistributionConfig = cloudFrontService.updateDistributionConfig( testDistributionId, null, // origin -- null for no changes new String[] {"test1.jamesmurty.com", "test2.jamesmurty.com"}, // CNAME aliases for distribution "Another comment for testing", // Comment true, // Distribution enabled? new LoggingStatus("log-bucket.s3.amazonaws.com", "log-prefix/") // Distribution logging ); System.out.println("Updated Distribution Config: " + updatedDistributionConfig); // Update a distribution's configuration to require secure HTTPS // connections, using the RequiredProtocols feature updatedDistributionConfig = cloudFrontService.updateDistributionConfig( testDistributionId, null, // origin -- null for no changes new String[] {"test1.jamesmurty.com", "test2.jamesmurty.com"}, // CNAME aliases for distribution "HTTPS Only!", // Comment true, // Distribution enabled? new LoggingStatus("log-bucket.s3.amazonaws.com", "log-prefix/"), // Distribution logging false, // URLs self-signing disabled null, // No other AWS users can sign URLs new String[] {"https"}, // RequiredProtocols with HTTPS protocol "index.html" // Default Root Object ); System.out.println("HTTPS only distribution Config: " + updatedDistributionConfig); // Disable a distribution, e.g. so that it may be deleted. // The CloudFront service may take some time to disable and deploy the distribution. DistributionConfig disabledDistributionConfig = cloudFrontService.updateDistributionConfig( testDistributionId, null, new String[] {}, "Deleting distribution", false, null); System.out.println("Disabled Distribution Config: " + disabledDistributionConfig); // Check whether a distribution is deployed distribution = cloudFrontService.getDistributionInfo(testDistributionId); System.out.println("Distribution is deployed? " + distribution.isDeployed()); // Convenience method to disable a distribution prior to deletion cloudFrontService.disableDistributionForDeletion(testDistributionId); // Delete a distribution (the distribution must be disabled and deployed first) cloudFrontService.deleteDistribution(testDistributionId); // ----------------------------------------------------------- // CloudFront Private Distributions - Origin Access Identities // ----------------------------------------------------------- // Create a new origin access identity OriginAccessIdentity originAccessIdentity = cloudFrontService.createOriginAccessIdentity(null, "Testing"); System.out.println(originAccessIdentity.toString()); // List your origin access identities List originAccessIdentityList = cloudFrontService.getOriginAccessIdentityList(); System.out.println(originAccessIdentityList); // Obtain an origin access identity ID for future use OriginAccessIdentity identity = originAccessIdentityList.get(1); String originAccessIdentityId = identity.getId(); System.out.println("originAccessIdentityId: " + originAccessIdentityId); // Lookup information about a specific origin access identity originAccessIdentity = cloudFrontService.getOriginAccessIdentity(originAccessIdentityId); System.out.println(originAccessIdentity); // Lookup config details for an origin access identity OriginAccessIdentityConfig originAccessIdentityConfig = cloudFrontService.getOriginAccessIdentityConfig(originAccessIdentityId); System.out.println(originAccessIdentityConfig); // Update configuration for an origin access identity OriginAccessIdentityConfig updatedConfig = cloudFrontService.updateOriginAccessIdentityConfig( originAccessIdentityId, "New Comment"); System.out.println(updatedConfig); // Delete an origin access identity cloudFrontService.deleteOriginAccessIdentity(originAccessIdentityId); // -------------------------------------------------------- // CloudFront Private Distributions - Private Distributions // -------------------------------------------------------- // Create a new private distribution for which signed URLs are *not* required originBucket = "jets3t.s3.amazonaws.com"; Distribution privateDistribution = cloudFrontService.createDistribution( new S3Origin(originBucket, originAccessIdentityId), "" + System.currentTimeMillis(), // Caller reference - a unique string value new String[] {}, // CNAME aliases for distribution "New private distribution -- URL signing not required", // Comment true, // Distribution is enabled? null, // Logging status of distribution (null means disabled) false, // URLs self-signing disabled null, // No other AWS users can sign URLs null, // No required protocols null // No default root object ); System.out.println("New Private Distribution: " + privateDistribution); // Update an existing distribution to make it private and require URL signing updatedDistributionConfig = cloudFrontService.updateDistributionConfig( testDistributionId, new S3Origin(originBucket, originAccessIdentityId), new String[] {}, // CNAME aliases for distribution "Now a private distribution -- URL Signing required", // Comment true, // Distribution enabled? null, // No distribution logging true, // URLs can be self-signed null, // No other AWS users can sign URLs null, // No required protocols "index.html" //Default Root Object ); System.out.println("Made distribution private: " + updatedDistributionConfig); // List active trusted signers for a private distribution distribution = cloudFrontService.getDistributionInfo(testDistributionId); System.out.println("Active trusted signers: " + distribution.getActiveTrustedSigners()); // Obtain one of your own (Self) keypair ids that can sign URLs for the distribution List selfKeypairIds = (List) distribution.getActiveTrustedSigners().get("Self"); String keyPairId = (String) selfKeypairIds.get(0); System.out.println("Keypair ID: " + keyPairId); // ------------------------------------------------------------------------- // CloudFront Private Distributions - Signed URLs for a private distribution // ------------------------------------------------------------------------- String distributionDomain = "a1b2c3d4e5f6g7.cloudfront.net"; String privateKeyFilePath = "/path/to/rsa-private-key.pem"; String s3ObjectKey = "s3/object/key.txt"; String policyResourcePath = "http://" + distributionDomain + "/" + s3ObjectKey; // Convert an RSA PEM private key file to DER bytes byte[] derPrivateKey = EncryptionUtil.convertRsaPemToDer( new FileInputStream(privateKeyFilePath)); // Generate a "canned" signed URL to allow access to a specific distribution and object String signedUrlCanned = CloudFrontService.signUrlCanned( "http://" + distributionDomain + "/" + s3ObjectKey, // Resource URL or Path keyPairId, // Certificate identifier, an active trusted signer for the distribution derPrivateKey, // DER Private key data ServiceUtils.parseIso8601Date("2009-11-14T22:20:00.000Z") // DateLessThan ); System.out.println(signedUrlCanned); // Build a policy document to define custom restrictions for a signed URL String policy = CloudFrontService.buildPolicyForSignedUrl( policyResourcePath, // Resource path (optional, may include '*' and '?' wildcards) ServiceUtils.parseIso8601Date("2009-11-14T22:20:00.000Z"), // DateLessThan "0.0.0.0/0", // CIDR IP address restriction (optional, 0.0.0.0/0 means everyone) ServiceUtils.parseIso8601Date("2009-10-16T06:31:56.000Z") // DateGreaterThan (optional) ); // Generate a signed URL using a custom policy document String signedUrl = CloudFrontService.signUrl( "http://" + distributionDomain + "/" + s3ObjectKey, // Resource URL or Path keyPairId, // Certificate identifier, an active trusted signer for the distribution derPrivateKey, // DER Private key data policy // Access control policy ); System.out.println(signedUrl); // ------------------------------------------------------------ // CloudFront Streaming Distributions // // The methods for interacting with streaming distributions are // very similar to those for standard distributions // ------------------------------------------------------------ // List your streaming distributions StreamingDistribution[] streamingDistributions = cloudFrontService.listStreamingDistributions(); for (int i = 0; i < streamingDistributions.length; i++) { System.out.println("Streaming distribution " + (i + 1) + ": " + streamingDistributions[i]); } // Create a new streaming distribution String streamingBucket = "jets3t-streaming.s3.amazonaws.com"; StreamingDistribution newStreamingDistribution = cloudFrontService.createStreamingDistribution( new S3Origin(streamingBucket), "" + System.currentTimeMillis(), // Caller reference - a unique string value null, // CNAME aliases for distribution "Test streaming distribution", // Comment true, // Distribution is enabled? null // Logging status ); System.out.println("New Streaming Distribution: " + newStreamingDistribution); // Streaming distributions can be made private just like standard non-streaming // distributions. Create a new private streaming distribution for which signed // URLs are *not* required StreamingDistribution newPrivateStreamingDistribution = cloudFrontService.createStreamingDistribution( new S3Origin(streamingBucket, originAccessIdentityId), "" + System.currentTimeMillis(), // Caller reference - a unique string value new String[] {}, // CNAME aliases for distribution "New private streaming distribution -- URL signing not required", // Comment true, // Distribution is enabled? null, // Logging status true, // URLs self-signing enabled null // No other AWS users can sign URLs ); System.out.println("New Private Streaming Distribution: " + newPrivateStreamingDistribution); // The ID of the streaming distribution we will use for testing String testStreamingDistributionId = newStreamingDistribution.getId(); // List information about a streaming distribution StreamingDistribution streamingDistribution = cloudFrontService.getStreamingDistributionInfo(testStreamingDistributionId); System.out.println("Streaming Distribution: " + streamingDistribution); // List configuration information about a streaming distribution StreamingDistributionConfig streamingDistributionConfig = cloudFrontService.getStreamingDistributionConfig(testStreamingDistributionId); System.out.println("Streaming Distribution Config: " + streamingDistributionConfig); // Update a streaming distribution's configuration to add an extra CNAME alias // and to enable access logging -- logs will be written to ' StreamingDistributionConfig updatedStreamingDistributionConfig = cloudFrontService.updateStreamingDistributionConfig( testStreamingDistributionId, null, // origin -- null for no changes new String[] {"cname.jets3t-streaming.com"}, // CNAME aliases for distribution "Updated this streaming distribution", // Comment true, // Distribution enabled? new LoggingStatus("jets3t-streaming-logs.s3.amazonaws.com", "sdlog-") // Logging ); System.out.println("Updated Streaming Distribution Config: " + updatedStreamingDistributionConfig); // Disable a streaming distribution, e.g. so that it may be deleted. // The CloudFront service may take some time to disable and deploy the distribution. StreamingDistributionConfig disabledStreamingDistributionConfig = cloudFrontService.updateStreamingDistributionConfig( testStreamingDistributionId, null, // origin -- null for no changes new String[] {}, "Deleting distribution", false, // Distribution enabled? null // Logging status ); System.out.println("Disabled Streaming Distribution Config: " + disabledStreamingDistributionConfig); // Check whether a streaming distribution is deployed StreamingDistribution streamingDistributionCheck = cloudFrontService.getStreamingDistributionInfo(testStreamingDistributionId); System.out.println("Streaming Distribution is deployed? " + streamingDistributionCheck.isDeployed()); // Convenience method to disable a streaming distribution prior to deletion cloudFrontService.disableStreamingDistributionForDeletion(testStreamingDistributionId); // Delete a streaming distribution (the distribution must be disabled and deployed first) cloudFrontService.deleteStreamingDistribution(testStreamingDistributionId); // ------------------------------------------------------------ // Object Invalidation // ------------------------------------------------------------ // Invalidate objects in a distribution to force CloudFront to fetch the // latest object data from the S3 origin. String[] objectKeys = new String[] {"downloads.html"}; Invalidation invalidation = cloudFrontService.invalidateObjects( testDistributionId, objectKeys, "" + System.currentTimeMillis() // Caller reference - a unique string value ); System.out.println(invalidation); // Retrieve details about a prior invalidation operation String invalidationId = invalidation.getId(); Invalidation priorInvalidation = cloudFrontService.getInvalidation( testDistributionId, invalidationId); System.out.println(priorInvalidation); // List summary information about all invalidations performed // on a distribution. List invalidationSummaries = cloudFrontService.listInvalidations(testDistributionId); System.out.println(invalidationSummaries); // ------------------------------------------------------------ // Non-S3 origin // ------------------------------------------------------------ // Create a new distribution with a non-S3 (custom) origin CustomOrigin customOrigin = new CustomOrigin( "www.jamesmurty.com", // DNS name CustomOrigin.OriginProtocolPolicy.HTTP_ONLY // Access content over HTTP only // To distribute content over HTTPS use: // CustomOrigin.OriginProtocolPolicy.MATCH_VIEWER ); Distribution customOriginDistribution = cloudFrontService.createDistribution( customOrigin, "" + System.currentTimeMillis(), // Caller reference - a unique string value null, // CNAME aliases for distribution "Distribution with a non-S3 origin", // Comment true, // Distribution is enabled? null // Logging status of distribution (null means disabled) ); System.out.println("Distribution with custom origin: " + customOriginDistribution); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/samples/StorePassphraseBasedLogin.java0000644000000000000000000001064111537563564023700 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.samples; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import org.jets3t.service.Constants; import org.jets3t.service.S3Service; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.impl.rest.httpclient.RestS3Service; import org.jets3t.service.model.S3Bucket; import org.jets3t.service.model.S3Object; import org.jets3t.service.security.AWSCredentials; import org.jets3t.service.security.ProviderCredentials; import org.jets3t.service.utils.ServiceUtils; /** * Demonstrates how Cockpit stores Passphrase-based login credentials in S3. *

* WARNING: Do not run this class until you have changed the * default values for passphrase and password in the code, or you risk making your real * AWS Credentials available online with a publicly known Passphrase and Password! * * @author James Murty */ public class StorePassphraseBasedLogin { /* * CHANGE THESE VALUES BEFORE TESTING, TO AVOID PUTTING YOUR CREDENTIALS * IN S3 IN AN OBVIOUS PLACE! */ private static final String passphrase = "Example passphrase"; private static final String password = "password"; public static void main(String[] args) throws Exception { AWSCredentials awsCredentials = SamplesUtils.loadAWSCredentials(); String combinedPassphraseAndPassword = passphrase + password; // Generate the S3 bucket name based on the passphrase hash. String bucketName = "jets3t-" + ServiceUtils.toHex( ServiceUtils.computeMD5Hash(passphrase.getBytes(Constants.DEFAULT_ENCODING))); // Generate the S3 object name based on the combined passphrase & password hash. String credentialObjectName = ServiceUtils.toHex( ServiceUtils.computeMD5Hash(combinedPassphraseAndPassword.getBytes(Constants.DEFAULT_ENCODING))) + "/jets3t.credentials"; S3Bucket bucket = new S3Bucket(bucketName); System.out.println("bucketName=" + bucketName); System.out.println("credentialObjectName=" + credentialObjectName); /* * Store credentials. */ // Initialise an S3 Service that knows the AWS credentials. S3Service s3Service = new RestS3Service(awsCredentials); // Encrypt credentials into InputStream ByteArrayOutputStream baos = new ByteArrayOutputStream(); awsCredentials.save(password, baos); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); // Create the target bucket bucket = s3Service.createBucket(bucketName); // Upload credentials object, which must be publicly readable. S3Object credsObject = new S3Object(credentialObjectName); credsObject.setDataInputStream(bais); credsObject.setAcl(AccessControlList.REST_CANNED_PUBLIC_READ); s3Service.putObject(bucket, credsObject); /* * Retrieve credentials. */ // Initialise an S3 Service that does not know the AWS credentials. s3Service = new RestS3Service(null); // Check whether the passphrase-based bucket exists and is accessible. System.out.println("Is bucket accessible? " + s3Service.isBucketAccessible(bucketName)); // Download the encrypted credentials object. S3Object retrievedCredsObject = s3Service.getObject(bucket, credentialObjectName); // Decrypt the credentials object. ProviderCredentials retrievedCreds = AWSCredentials.load(password, new BufferedInputStream(retrievedCredsObject.getDataInputStream())); System.out.println("Retrieved credentials from S3: " + retrievedCreds.getAccessKey() + " : " + retrievedCreds.getSecretKey()); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/samples/S3PostFormBuilder.java0000644000000000000000000000543611340664276022110 0ustar package org.jets3t.samples; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; public class S3PostFormBuilder { public static void main(String[] args) throws Exception { String aws_access_key = "YOUR AWS ACCESS KEY GOES HERE"; String aws_secret_key = "YOUR AWS SECRET KEY GOES HERE"; String policy_document = "{\"expiration\": \"2009-01-01T00:00:00Z\"," + "\"conditions\": [" + "{\"bucket\": \"s3-bucket\"}," + "[\"starts-with\", \"$key\", \"uploads/\"]," + "{\"acl\": \"private\"}," + "{\"success_action_redirect\": \"http://localhost/\"}," + "[\"starts-with\", \"$Content-Type\", \"\"]," + "[\"content-length-range\", 0, 1048576]" + "]" + "}"; // Calculate policy and signature values from the given policy document and AWS credentials. String policy = new String( Base64.encodeBase64(policy_document.getBytes("UTF-8")), "ASCII"); Mac hmac = Mac.getInstance("HmacSHA1"); hmac.init(new SecretKeySpec( aws_secret_key.getBytes("UTF-8"), "HmacSHA1")); String signature = new String( Base64.encodeBase64(hmac.doFinal(policy.getBytes("UTF-8"))), "ASCII"); // Build an S3 POST HTML document String html_document = "\n" + "\n" + " S3 POST Form\n" + " \n" + "\n" + "\n" + "

\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " File to upload to S3:\n" + " \n" + "
\n" + " \n" + "
\n" + "\n" + ""; System.out.print(html_document); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/0002755000000000000000000000000011550421156015734 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/0002755000000000000000000000000011550421156017034 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/AWSDevPayProduct.java0000644000000000000000000001176711427702124023015 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 Zmanda Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model; import java.io.InputStream; import java.io.IOException; import java.io.Serializable; import java.util.Collections; import java.util.Enumeration; import java.util.Properties; import java.util.Vector; import org.jets3t.service.Constants; /** * Class to contain information about an Amazon Web Services (AWS) S3 DevPay product. * * @author Nikolas Coukouma */ public class AWSDevPayProduct implements Serializable, Comparable { private static final long serialVersionUID = 7581378683354747125L; private String productName = null; private String productToken = null; public AWSDevPayProduct(String productToken) { this.productToken = productToken; } public AWSDevPayProduct(String productToken, String productName) { this(productToken); this.productName = productName; } /** * @return * the name of the DevPay product */ public String getProductName() { return this.productName; } /** * @return * the product token of the DevPay product */ public String getProductToken() { return this.productToken; } /** * @return * the name of the DevPay product */ public String toString() { return getProductName(); } /** * Compare two products by their names (using string comparision) */ public int compareTo(Object o) { return getProductName().compareTo(((AWSDevPayProduct) o).getProductName()); } /** * Loads the products listed in * {@link Constants#DEVPAY_PRODUCTS_PROPERTIES_FILENAME} * * @return the Vector of AWSDevPayProducts */ public static Vector load() throws IOException { InputStream pin = AWSDevPayProduct.class.getResourceAsStream("/" + Constants.DEVPAY_PRODUCTS_PROPERTIES_FILENAME); Vector ret = new Vector(); if (pin != null) { try { ret = load(pin); } finally { pin.close(); } } return ret; } /** * Loads the products listed in the {@link java.util.Properties} file * represented by the input stream. * * @param pin the input stream * * @return the Vector of AWSDevPayProducts */ public static Vector load(InputStream pin) throws IOException { if (pin == null) { return new Vector(); } else { Properties prodProps = new Properties(); prodProps.load(pin); return load(prodProps); } } /** * Loads the products listed in the {@link java.util.Properties}. * Specifically, any properties ending in {@link Constants#DEVPAY_PRODUCT_NAME_PROP_SUFFIX} * (the product's name) * have that ending removed and replaced with {@link Constants#DEVPAY_PRODUCT_NAME_PROP_SUFFIX} * (to form name of the property for the product's token). * If the token exists, then a AWSDevPayProduct is constructed * with that name and token, and then is added to the Vector. For example, * (with the current constants) "foo.name" would become "foo.token"; * if both properties exist, then a product is constructed with the values of * the "foo.name" and "foo.token" properties (e.g. "Foo" and "{ProductToken}AAA..."). * * @param prodProps the properties * * @return the Vector of AWSDevPayProducts, sorted by name */ public static Vector load(Properties prodProps) { Vector ret = new Vector(); Enumeration propEnum = prodProps.propertyNames(); while (propEnum.hasMoreElements()) { String propName = (String) propEnum.nextElement(); if (propName.endsWith(Constants.DEVPAY_PRODUCT_NAME_PROP_SUFFIX)) { String tokenPropName = propName.substring(0, propName.length()-Constants.DEVPAY_PRODUCT_NAME_PROP_SUFFIX.length()) + Constants.DEVPAY_PRODUCT_TOKEN_PROP_SUFFIX; String prodName = prodProps.getProperty(propName); String prodToken = prodProps.getProperty(tokenPropName); if (prodToken != null) { ret.add(new AWSDevPayProduct(prodToken, prodName)); } } } Collections.sort(ret); return ret; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/GSOwner.java0000644000000000000000000000202011452167624021223 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model; /** * Represents a Google Storage owner object with a canonical ID and, optionally, a display name. * * @author James Murty */ public class GSOwner extends StorageOwner { public GSOwner() { super(); } public GSOwner(String id, String displayName) { super(id, displayName); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/S3DeleteMarker.java0000644000000000000000000000250011441613550022444 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model; import java.util.Date; /** * @author James Murty */ public class S3DeleteMarker extends BaseVersionOrDeleteMarker { public S3DeleteMarker(String key, String versionId, boolean isLatest, Date lastModified, S3Owner owner) { super(key, versionId, isLatest, lastModified, owner); } public boolean isDeleteMarker() { return true; } public String toString() { return "S3DeleteMarker [key=" + getKey() + ", versionId=" + getVersionId() + ", isLatest=" + isLatest() + ", lastModified=" + getLastModified() + ", owner=" + getOwner() + "]"; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/StorageOwner.java0000644000000000000000000000306611452167756022337 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model; /** * Represents an owner object with a canonical ID and, optionally, a display name. * * @author James Murty */ public class StorageOwner { private String displayName; private String id; public StorageOwner() { } public StorageOwner(String id, String displayName) { this.id = id; this.displayName = displayName; } @Override public String toString() { return this.getClass().getName() + " [" + "id=" + getId() + (getDisplayName() != null ? ", name=" + getDisplayName(): "") + "]"; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getDisplayName() { return displayName; } public void setDisplayName(String name) { this.displayName = name; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/S3Owner.java0000644000000000000000000000211511441613550021174 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model; /** * Represents an S3 owner object with a canonical ID and, optionally, a display name. * * @author James Murty */ public class S3Owner extends StorageOwner { private static final long serialVersionUID = 3895047011353549858L; public S3Owner() { super(); } public S3Owner(String id, String displayName) { super(id, displayName); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/CreateBucketConfiguration.java0000644000000000000000000000403511441613550024770 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.jets3t.service.Constants; import com.jamesmurty.utils.XMLBuilder; /** * Represents the location configuraton to be applied to a newly * created Bucket. * * @author James Murty * */ public class CreateBucketConfiguration { private String location = null; public CreateBucketConfiguration() { } public CreateBucketConfiguration(String location) { this.location = location; } public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } /** * * @return * An XML representation of the object suitable for use as an input to the REST/HTTP interface. * * @throws FactoryConfigurationError * @throws ParserConfigurationException * @throws TransformerException */ public String toXml() throws ParserConfigurationException, FactoryConfigurationError, TransformerException { XMLBuilder builder = XMLBuilder.create("CreateBucketConfiguration") .attr("xmlns", Constants.XML_NAMESPACE) .elem("LocationConstraint").text(location); return builder.asString(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/cloudfront/0002755000000000000000000000000011537563564021232 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/cloudfront/StreamingDistribution.java0000644000000000000000000000255011537563564026426 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model.cloudfront; import java.util.Date; import java.util.Map; public class StreamingDistribution extends Distribution { public StreamingDistribution(String id, String status, Date lastModifiedDate, String domainName, Origin origin, String[] cnames, String comment, boolean enabled) { super(id, status, lastModifiedDate, domainName, origin, cnames, comment, enabled); } public StreamingDistribution(String id, String status, Date lastModifiedDate, String domainName, Map activeTrustedSigners, DistributionConfig config) { super(id, status, lastModifiedDate, domainName, activeTrustedSigners, config); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/cloudfront/S3Origin.java0000644000000000000000000000551411537563564023535 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model.cloudfront; import org.jets3t.service.CloudFrontService; public class S3Origin extends Origin { public static final String ORIGIN_ACCESS_IDENTITY_PREFIX = "origin-access-identity/cloudfront/"; private String originAccessIdentity = null; /** * An S3 bucket origin. * * @param dnsName * a full S3 sub-domain path (e.g. 'jets3t.s3.amazonaws.com' for the 'jets3t' bucket) * @param originAccessIdentity * Identifier of the origin access identity that can authorize access to * S3 objects via a private distribution. If provided the distribution will be * private, if null the distribution will be be public. */ public S3Origin(String dnsName, String originAccessIdentity) { super(dnsName); // Ensure origin access identity has required prefix if (originAccessIdentity != null && !originAccessIdentity.startsWith(ORIGIN_ACCESS_IDENTITY_PREFIX)) { this.originAccessIdentity = ORIGIN_ACCESS_IDENTITY_PREFIX + originAccessIdentity; } else { this.originAccessIdentity = originAccessIdentity; } } /** * An S3 bucket origin. * * @param dnsName * a full S3 sub-domain path (e.g. 'jets3t.s3.amazonaws.com' for the 'jets3t' bucket) */ public S3Origin(String dnsName) { this(dnsName, null); } public String getOriginAccessIdentity() { return this.originAccessIdentity; } /** * @return * the origin bucket's name, without the suffix ".s3.amazonaws.com" */ public String getOriginAsBucketName() { String bucketName = getDnsName(); if (bucketName.endsWith(CloudFrontService.DEFAULT_BUCKET_SUFFIX)) { return bucketName.substring(0, bucketName.length() - CloudFrontService.DEFAULT_BUCKET_SUFFIX.length()); } else { return bucketName; } } @Override public String toString() { return "S3Origin: dnsName=" + getDnsName() + (getOriginAccessIdentity() != null ? ", originAccessIdentity=" + getOriginAccessIdentity() : ""); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/cloudfront/CustomOrigin.java0000644000000000000000000000512711537563564024522 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model.cloudfront; public class CustomOrigin extends Origin { public enum OriginProtocolPolicy { HTTP_ONLY ("http-only"), MATCH_VIEWER ("match-viewer"); private final String textValue; OriginProtocolPolicy(String textValue) { this.textValue = textValue; } public String toText() { return textValue; } public static OriginProtocolPolicy fromText(String text) { for (OriginProtocolPolicy e: OriginProtocolPolicy.values()) { if (e.toText().equalsIgnoreCase(text)) { return e; } } throw new IllegalArgumentException("Invalid OriginProtocolPolicy: " + text); } }; private OriginProtocolPolicy originProtocolPolicy = null; private int httpPort = 80; // Not customizable in 2010-11-01 API private int httpsPort = 443; // Not customizable in 2010-11-01 API public CustomOrigin(String dnsName, OriginProtocolPolicy originProtocolPolicy) { super(dnsName); this.originProtocolPolicy = originProtocolPolicy; } public CustomOrigin(String dnsName, OriginProtocolPolicy originProtocolPolicy, int httpPort, int httpsPort) { super(dnsName); this.originProtocolPolicy = originProtocolPolicy; this.httpPort = httpPort; this.httpsPort = httpsPort; } public OriginProtocolPolicy getOriginProtocolPolicy() { return this.originProtocolPolicy; } public int getHttpPort() { return this.httpPort; } public int getHttpsPort() { return this.httpsPort; } @Override public String toString() { return "CustomOrigin: dnsName=" + getDnsName() + ", originProtocolPolicy=" + getOriginProtocolPolicy() + ", httpPort=" + getHttpPort() + ", httpsPort=" + getHttpsPort(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/cloudfront/OriginAccessIdentity.java0000644000000000000000000000364011441613550026142 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2009 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model.cloudfront; public class OriginAccessIdentity { private String id = null; private String s3CanonicalUserId = null; private String comment = null; private OriginAccessIdentityConfig config = null; public OriginAccessIdentity(String id, String s3CanonicalUserId, String comment) { this.id = id; this.s3CanonicalUserId = s3CanonicalUserId; this.comment = comment; } public OriginAccessIdentity(String id, String s3CanonicalUserId, OriginAccessIdentityConfig config) { this.id = id; this.s3CanonicalUserId = s3CanonicalUserId; this.config = config; } public OriginAccessIdentityConfig getConfig() { return this.config; } public boolean isSummary() { return getConfig() == null; } public String getId() { return id; } public String getS3CanonicalUserId() { return s3CanonicalUserId; } public String toString() { return "CloudFrontOriginAccessIdentity: id=" + id + ", s3CanonicalUserId=" + s3CanonicalUserId + (isSummary() ? ", comment=" + comment : ", config=[" + config + "]"); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/cloudfront/DistributionConfig.java0000644000000000000000000001357311537563564025711 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model.cloudfront; import java.util.Arrays; public class DistributionConfig { private Origin origin = null; private String callerReference = null; private String[] cnames = new String[0]; private String comment = null; private boolean enabled = false; private String etag = null; private LoggingStatus loggingStatus = null; // Private distribution settings private boolean trustedSignerSelf = false; private String[] trustedSignerAwsAccountNumbers = new String[0]; private String[] requiredProtocols = new String[0]; private String defaultRootObject = null; public DistributionConfig(Origin origin, String callerReference, String[] cnames, String comment, boolean enabled, LoggingStatus loggingStatus, boolean trustedSignerSelf, String[] trustedSignerAwsAccountNumbers, String[] requiredProtocols, String defaultRootObject) { this.origin = origin; this.callerReference = callerReference; this.cnames = cnames; this.comment = comment; this.enabled = enabled; this.loggingStatus = loggingStatus; this.trustedSignerSelf = trustedSignerSelf; this.trustedSignerAwsAccountNumbers = trustedSignerAwsAccountNumbers; this.requiredProtocols = requiredProtocols; this.defaultRootObject = defaultRootObject; } public DistributionConfig(Origin origin, String callerReference, String[] cnames, String comment, boolean enabled, LoggingStatus loggingStatus) { this(origin, callerReference, cnames, comment, enabled, loggingStatus, false, null, null, null); } public Origin getOrigin() { return origin; } public String getCallerReference() { return callerReference; } public String[] getCNAMEs() { return this.cnames; } public String getComment() { return comment; } public boolean isEnabled() { return enabled; } public String getEtag() { return etag; } public void setEtag(String etag) { this.etag = etag; } public LoggingStatus getLoggingStatus() { return loggingStatus; } public boolean isLoggingEnabled() { return this.loggingStatus != null; } public boolean isPrivate() { return (this.getOrigin() instanceof S3Origin && ((S3Origin)this.getOrigin()).getOriginAccessIdentity() != null); } public String[] getTrustedSignerAwsAccountNumbers() { return this.trustedSignerAwsAccountNumbers; } public boolean isTrustedSignerSelf() { return this.trustedSignerSelf; } public boolean hasTrustedSignerAwsAccountNumbers() { return getTrustedSignerAwsAccountNumbers() != null && getTrustedSignerAwsAccountNumbers().length > 0; } public boolean isUrlSigningRequired() { return isTrustedSignerSelf() || hasTrustedSignerAwsAccountNumbers(); } public boolean isStreamingDistributionConfig() { return (this instanceof StreamingDistributionConfig); } public void setRequiredProtocols(String[] protocols) { this.requiredProtocols = protocols; } public String[] getRequiredProtocols() { return this.requiredProtocols; } public boolean isHttpsProtocolRequired() { return this.requiredProtocols != null && this.requiredProtocols.length > 0 && "https".equals(this.requiredProtocols[0]); } public void setHttpsProtocolRequired(boolean value) { if (value) { this.requiredProtocols = new String[] {"https"}; } else { this.requiredProtocols = new String[0]; } } public String getDefaultRootObject() { return defaultRootObject; } @Override public String toString() { return (isStreamingDistributionConfig() ? "StreamingDistributionConfig" : "DistributionConfig") + ": origin=" + origin + ", callerReference=" + callerReference + ", comment=" + comment + ", enabled=" + enabled + (isPrivate() ? ", Private:originAccessIdentity=" + ((S3Origin)getOrigin()).getOriginAccessIdentity() : ", Public") + (isUrlSigningRequired() ? ", TrustedSigners:self=" + isTrustedSignerSelf() + (hasTrustedSignerAwsAccountNumbers() ? ":awsAccountNumbers=" + Arrays.asList(getTrustedSignerAwsAccountNumbers()) : "") : "") + (etag != null ? ", etag=" + etag : "") + (!isLoggingEnabled() ? "" : ", LoggingStatus: bucket=" + loggingStatus.getBucket() + ", prefix=" + loggingStatus.getPrefix()) + (getRequiredProtocols() == null || getRequiredProtocols().length == 0 ? "" : ", RequiredProtocols=" + Arrays.asList(getRequiredProtocols())) + ", CNAMEs=" + Arrays.asList(cnames) + ", DefaultRootObject=" + defaultRootObject; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/cloudfront/Distribution.java0000644000000000000000000000735311537563564024562 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model.cloudfront; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.Map; import org.jets3t.service.CloudFrontService; public class Distribution { private String id = null; private String status = null; private Date lastModifiedTime = null; private String domainName = null; private Map activeTrustedSigners = new HashMap(); private Origin origin = null; private String cnames[] = new String[0]; private String comment = null; private boolean enabled = false; private DistributionConfig config = null; public Distribution(String id, String status, Date lastModifiedDate, String domainName, Origin origin, String[] cnames, String comment, boolean enabled) { this.id = id; this.status = status; this.lastModifiedTime = lastModifiedDate; this.domainName = domainName; this.origin = origin; this.cnames = cnames; this.comment = comment; this.enabled = enabled; } public Distribution(String id, String status, Date lastModifiedDate, String domainName, Map activeTrustedSigners, DistributionConfig config) { this.id = id; this.status = status; this.lastModifiedTime = lastModifiedDate; this.domainName = domainName; this.activeTrustedSigners = activeTrustedSigners; this.config = config; } public boolean isSummary() { return getConfig() == null; } public String getComment() { return comment; } public String getDomainName() { return domainName; } public Map getActiveTrustedSigners() { return activeTrustedSigners; } public String getId() { return id; } public Date getLastModifiedTime() { return lastModifiedTime; } public Origin getOrigin() { return origin; } public String[] getCNAMEs() { return cnames; } public boolean isEnabled() { return enabled; } public String getStatus() { return status; } /** * @return * true if this distribution's status is "Deployed". */ public boolean isDeployed() { return "Deployed".equals(getStatus()); } public DistributionConfig getConfig() { return config; } public boolean isStreamingDistribution() { return (this instanceof StreamingDistribution); } @Override public String toString() { return (isStreamingDistribution() ? "CloudFrontStreamingDistribution" : "CloudFrontDistribution") + ": id=" + id + ", status=" + status + ", domainName=" + domainName + ", activeTrustedSigners=" + activeTrustedSigners + ", lastModifiedTime=" + lastModifiedTime + (isSummary() ? ", origin=" + origin + ", comment=" + comment + ", enabled=" + enabled + ", CNAMEs=" + Arrays.asList(cnames) : ", config=[" + config + "]"); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/cloudfront/OriginAccessIdentityConfig.java0000644000000000000000000000302211441613550027262 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2009 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model.cloudfront; public class OriginAccessIdentityConfig { private String callerReference = null; private String comment = null; private String etag = null; public OriginAccessIdentityConfig(String callerReference, String comment) { this.callerReference = callerReference; this.comment = comment; } public String getCallerReference() { return callerReference; } public String getComment() { return comment; } public String getEtag() { return etag; } public void setEtag(String etag) { this.etag = etag; } public String toString() { return "CloudFrontOriginAccessIdentityConfig: " + "callerReference=" + callerReference + ", comment=" + comment + (etag != null ? ", etag=" + etag : ""); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/cloudfront/InvalidationSummary.java0000644000000000000000000000250611445214110026047 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model.cloudfront; public class InvalidationSummary { private String id = null; private String status = null; public InvalidationSummary(String id, String status) { this.id = id; this.status = status; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } @Override public String toString() { return "InvalidationSummary" + ": id=" + id + ", status=" + status; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/cloudfront/StreamingDistributionConfig.java0000644000000000000000000000305211537563564027552 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model.cloudfront; public class StreamingDistributionConfig extends DistributionConfig { public StreamingDistributionConfig(Origin origin, String callerReference, String[] cnames, String comment, boolean enabled, LoggingStatus loggingStatus, boolean trustedSignerSelf, String[] trustedSignerAwsAccountNumbers, String[] requiredProtocols) { super(origin, callerReference, cnames, comment, enabled, loggingStatus, trustedSignerSelf, trustedSignerAwsAccountNumbers, requiredProtocols, null); } public StreamingDistributionConfig(Origin origin, String callerReference, String[] cnames, String comment, boolean enabled, LoggingStatus loggingStatus) { super(origin, callerReference, cnames, comment, enabled, loggingStatus, false, null, null, null); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/cloudfront/Invalidation.java0000644000000000000000000000407511445212446024506 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model.cloudfront; import java.util.ArrayList; import java.util.Date; import java.util.List; public class Invalidation { private String id = null; private String status = null; private Date createTime = null; private String callerReference = null; private List objectKeys = new ArrayList(); public String getId() { return id; } public void setId(String id) { this.id = id; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public List getObjectKeys() { return objectKeys; } public void setObjectKeys(List objectKeys) { this.objectKeys = objectKeys; } public String getCallerReference() { return callerReference; } public void setCallerReference(String callerReference) { this.callerReference = callerReference; } @Override public String toString() { return "Invalidation" + ": id=" + id + ", status=" + status + ", createTime=" + createTime + ", callerReference=" + callerReference + ", objectKeys=" + objectKeys; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/cloudfront/InvalidationList.java0000644000000000000000000000407411445215264025342 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model.cloudfront; import java.util.ArrayList; import java.util.List; public class InvalidationList { private String marker = null; private String nextMarker = null; private int maxItems = 1000; private boolean isTruncated = false; private List invalidationSummaries = new ArrayList(); public InvalidationList(String marker, String nextMarker, int maxItems, boolean isTruncated, List invalidationSummaries) { this.marker = marker; this.nextMarker = nextMarker; this.maxItems = maxItems; this.isTruncated = isTruncated; this.invalidationSummaries = invalidationSummaries; } public String getMarker() { return marker; } public String getNextMarker() { return nextMarker; } public int getMaxItems() { return maxItems; } public boolean isTruncated() { return isTruncated; } public List getInvalidationSummaries() { return invalidationSummaries; } @Override public String toString() { return "InvalidationList" + ": marker=" + marker + ", nextMarker=" + nextMarker + ", maxItems=" + maxItems + ", isTruncated=" + isTruncated() + ", invalidationSummaries=" + invalidationSummaries; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/cloudfront/LoggingStatus.java0000644000000000000000000000511311427702124024646 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2009 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model.cloudfront; import org.jets3t.service.CloudFrontService; /** * Represents the logging status of a CloudFront distribution. *

* For logging to be enabled, both the bucket and prefix * properties must be non-null and the named bucket must exist. * * @author James Murty */ public class LoggingStatus { private String bucket = null; private String prefix = null; public LoggingStatus() { this.prefix = ""; } /** * @param bucket * the Amazon S3 bucket in which log files will be stored, specified as a full * S3 sub-domain path (e.g. 'jets3t.s3.amazonaws.com' for the 'jets3t' bucket) * @param prefix * a prefix to apply to log file names. May be an empty string, but cannot * be null. */ public LoggingStatus(String bucket, String prefix) { this.bucket = bucket; this.prefix = prefix; } public String getPrefix() { return prefix; } /** * @param prefix * a prefix to apply to log file names. May be an empty string, but cannot * be null. */ public void setPrefix(String prefix) { this.prefix = prefix; } public String getBucket() { return bucket; } /** * @return * the logging bucket name, without the suffix ".s3.amazonaws.com". */ public String getShortBucketName() { if (bucket.endsWith(CloudFrontService.DEFAULT_BUCKET_SUFFIX)) { return bucket.substring(0, bucket.length() - CloudFrontService.DEFAULT_BUCKET_SUFFIX.length()); } else { return bucket; } } /** * @param bucket * the Amazon S3 bucket in which log files will be stored, specified as a full * S3 sub-domain path (e.g. 'jets3t.s3.amazonaws.com' for the 'jets3t' bucket) */ public void setBucket(String bucket) { this.bucket = bucket; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/cloudfront/Origin.java0000644000000000000000000000165611537563564023332 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model.cloudfront; public abstract class Origin { private String dnsName = null; public Origin(String dnsName) { this.dnsName = dnsName; } public String getDnsName() { return dnsName; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/MultipartUpload.java0000644000000000000000000000672211537563564023051 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; /** * Represents a MultipartUpload operation. * * @author James Murty */ public class MultipartUpload { private String uploadId; private String bucketName; private String objectKey; private Map metadata = null; private String storageClass; private S3Owner initiator; private S3Owner owner; private Date initiatedDate; private List multipartsPartsUploaded = new ArrayList(); public MultipartUpload(String uploadId, String bucketName, String objectKey) { this.uploadId = uploadId; this.objectKey = objectKey; this.bucketName = bucketName; } public MultipartUpload(String uploadId, String objectKey, String storageClass, S3Owner initiator, S3Owner owner, Date initiatedDate) { this.uploadId = uploadId; this.objectKey = objectKey; this.storageClass = storageClass; this.initiator = initiator; this.owner = owner; this.initiatedDate = initiatedDate; } @Override public String toString() { return this.getClass().getName() + " [" + "uploadId=" + getUploadId() + ", bucketName=" + getBucketName() + ", objectKey=" + getObjectKey() + (metadata != null ? ", metadata=" + getMetadata() : "") + (storageClass != null ? ", storageClass=" + getStorageClass() : "") + (initiator != null ? ", initiator=" + getInitiator() : "") + (owner != null ? ", owner=" + getOwner() : "") + (initiatedDate != null ? ", initiatedDate=" + getInitiatedDate() : "") + ", multipartsPartsUploaded=" + multipartsPartsUploaded + "]"; } public String getBucketName() { return bucketName; } public String getObjectKey() { return objectKey; } public String getUploadId() { return uploadId; } public Map getMetadata() { return metadata; } public S3Owner getOwner() { return owner; } public Date getInitiatedDate() { return initiatedDate; } public void setMetadata(Map metadata) { this.metadata = metadata; } public void setBucketName(String name) { this.bucketName = name; } public String getStorageClass() { return storageClass; } public S3Owner getInitiator() { return initiator; } public void addMultipartPartToUploadedList(MultipartPart part) { this.multipartsPartsUploaded.add(part); } public List getMultipartPartsUploaded() { return this.multipartsPartsUploaded; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/StorageObject.java0000644000000000000000000006352711550421156022445 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.security.NoSuchAlgorithmException; import java.text.ParseException; import java.util.Date; import java.util.HashMap; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.Constants; import org.jets3t.service.ServiceException; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.io.RepeatableFileInputStream; import org.jets3t.service.utils.Mimetypes; import org.jets3t.service.utils.ServiceUtils; /** * A generic storage object. * * @author James Murty */ public class StorageObject extends BaseStorageItem implements Cloneable { private static final Log log = LogFactory.getLog(StorageObject.class); /* * Metadata names used by JetS3t. */ public static final String METADATA_HEADER_HASH_MD5 = "md5-hash"; public static final String METADATA_HEADER_ORIGINAL_HASH_MD5 = "original-md5-hash"; protected AccessControlList acl = null; protected transient InputStream dataInputStream = null; protected boolean isMetadataComplete = false; protected String bucketName = null; protected String storageClass = null; /** * Store references to files when the object's data comes from a file, to allow for lazy * opening of the file's input streams. */ protected File dataInputFile = null; /** * Create an object representing a file. The object is initialised with the file's name * as its key, the file's content as its data, a content type based on the file's extension * (see {@link Mimetypes}), and a content length matching the file's size. * The file's MD5 hash value is also calculated and provided to the destination service, * so the service can verify that no data are corrupted in transit. *

* NOTE: The automatic calculation of a file's MD5 hash digest as performed by * this constructor could take some time for large files, or for many small ones. * * @param file * the file the object will represent. This file must exist and be readable. * * @throws IOException when an i/o error occurred reading the file * @throws NoSuchAlgorithmException when this JRE doesn't support the MD5 hash algorithm */ public StorageObject(File file) throws NoSuchAlgorithmException, IOException { this(file.getName()); setContentLength(file.length()); setContentType(Mimetypes.getInstance().getMimetype(file)); if (!file.exists()) { throw new FileNotFoundException("Cannot read from file: " + file.getAbsolutePath()); } setDataInputFile(file); setMd5Hash(ServiceUtils.computeMD5Hash(new FileInputStream(file))); } /** * Create an object representing text data. The object is initialized with the given * key, the given string as its data content (encoded as UTF-8), a content type of * text/plain; charset=utf-8, and a content length matching the * string's length. * The given string's MD5 hash value is also calculated and provided to the target * service, so the service can verify that no data are corrupted in transit. *

* NOTE: The automatic calculation of the MD5 hash digest as performed by * this constructor could take some time for large strings, or for many small ones. * * @param key * the key name for the object. * @param dataString * the text data the object will contain. Text data will be encoded as UTF-8. * This string cannot be null. * * @throws IOException * @throws NoSuchAlgorithmException when this JRE doesn't support the MD5 hash algorithm */ public StorageObject(String key, String dataString) throws NoSuchAlgorithmException, IOException { this(key); ByteArrayInputStream bais = new ByteArrayInputStream( dataString.getBytes(Constants.DEFAULT_ENCODING)); setDataInputStream(bais); setContentLength(bais.available()); setContentType("text/plain; charset=utf-8"); setMd5Hash(ServiceUtils.computeMD5Hash(dataString.getBytes(Constants.DEFAULT_ENCODING))); } /** * Create an object representing binary data. The object is initialized with the given * key, the bytes as its data content, a content type of * application/octet-stream, and a content length matching the * byte array's length. * The MD5 hash value of the byte data is also calculated and provided to the target * service, so the service can verify that no data are corrupted in transit. * * @param key * the key name for the object. * @param data * the byte data the object will contain, cannot be null. * * @throws IOException * @throws NoSuchAlgorithmException when this JRE doesn't support the MD5 hash algorithm */ public StorageObject(String key, byte[] data) throws NoSuchAlgorithmException, IOException { this(key); ByteArrayInputStream bais = new ByteArrayInputStream(data); setDataInputStream(bais); setContentLength(bais.available()); setContentType(Mimetypes.MIMETYPE_OCTET_STREAM); setMd5Hash(ServiceUtils.computeMD5Hash(data)); } /** * Create an object without any associated data. * * @param key * the key name for the object. */ public StorageObject(String key) { super(key); } @Override public Object clone() { StorageObject clone = new StorageObject(getKey()); clone.dataInputStream = dataInputStream; clone.acl = acl; clone.isMetadataComplete = isMetadataComplete; clone.dataInputFile = dataInputFile; clone.setOwner(this.getOwner()); clone.addAllMetadata(getMetadataMap()); return clone; } @Override public String toString() { return "StorageObject [key=" + getKey() + ", lastModified=" + getLastModifiedDate() + ", dataInputStream=" + dataInputStream + ", Metadata=" + getMetadataMap() + "]"; } /** * Create an object without any associated information whatsoever. */ public StorageObject() { super(); } /** * @return * the name of the bucket this object belongs to or will be placed into, or null if none is set. */ public String getBucketName() { return bucketName; } /** * Set the name of the bucket this object belongs to or will be placed into. * @param bucketName the name for the bucket. */ public void setBucketName(String bucketName) { this.bucketName = bucketName; } /** * Returns an input stream containing this object's data, or null if there is * no data associated with the object. *

* If you are downloading data from a service, you should consider verifying the * integrity of the data you read from this stream using one of the * {@link #verifyData(InputStream)} methods. * * @return * input stream containing the object's service-side data, or null if no data. * * @throws ServiceException */ public InputStream getDataInputStream() throws ServiceException { if (dataInputStream == null && dataInputFile != null) { try { // Use a repeatable file data input stream, so transmissions can be retried if necessary. dataInputStream = new RepeatableFileInputStream(dataInputFile); } catch (FileNotFoundException e) { throw new ServiceException("Cannot open file input stream", e); } } return dataInputStream; } /** * Sets an input stream containing the data content to associate with this object. *

* Note: If the data content comes from a file, use the alternate method * {@link #setDataInputFile(File)} which allows objects to lazily open files and avoid any * Operating System limits on the number of files that may be opened simultaneously. *

* Note 2: This method does not calculate an MD5 hash of the input data, * which means the target service will not be able to recognize if data are corrupted in transit. * To allow the target service to verify data you upload, you should set the MD5 hash value of * your data using {@link #setMd5Hash(byte[])}. *

* This method will set the object's file data reference to null. * * @param dataInputStream * an input stream containing the object's data. */ public void setDataInputStream(InputStream dataInputStream) { this.dataInputFile = null; this.dataInputStream = dataInputStream; } /** * Sets the file containing the data content to associate with this object. This file will * be automatically opened as an input stream only when absolutely necessary, that is when * {@link #getDataInputStream()} is called. *

* Note 2: This method does not calculate an MD5 hash of the input data, * which means the target service will not be able to recognize if data are corrupted in transit. * To allow the target service to verify data you upload, you should set the MD5 hash value of * your data using {@link #setMd5Hash(byte[])}. *

* This method will set the object's input stream data reference to null. * * @param dataInputFile * a file containing the object's data. */ public void setDataInputFile(File dataInputFile) { this.dataInputStream = null; this.dataInputFile = dataInputFile; } /** * @return * Return the file that contains this object's data, if such a file has been * provided. Null otherwise. */ public File getDataInputFile() { return this.dataInputFile; } /** * Closes the object's data input stream if it exists. * * @throws IOException */ public void closeDataInputStream() throws IOException { if (this.dataInputStream != null) { this.dataInputStream.close(); this.dataInputStream = null; } } /** * @return * the ETag value of the object as returned by the service when an object is created. The ETag * value does not include quote (") characters. This value will be null if the object's ETag value * is not known, such as when an object has not yet been uploaded to the service. */ public String getETag() { String etag = (String) getMetadata(METADATA_HEADER_ETAG); if (etag != null) { if (etag.startsWith("\"") && etag.endsWith("\"")) { return etag.substring(1, etag.length() -1); } } return etag; } /** * Set the ETag value of the object based on information returned from the service. * This method should only by used by code that reads service responses. * * @param etag * the ETag value as provided by the service. */ public void setETag(String etag) { addMetadata(METADATA_HEADER_ETAG, etag); } /** * @return * the hex-encoded MD5 hash of an object's data contents as stored in the JEtS3t-specific * metadata item md5-hash, or null if the hash value is not available. */ public String getMd5HashAsHex() { return (String) getMetadata(METADATA_HEADER_HASH_MD5); } /** * @return * the Base64-encoded MD5 hash of an object's data contents as stored in the metadata * item Content-MD5, or as derived from an ETag or * md5-hash hex-encoded version of the hash. Returns null if the hash value is not * available. */ public String getMd5HashAsBase64() { String md5HashBase64 = (String) getMetadata(METADATA_HEADER_CONTENT_MD5); if (md5HashBase64 == null) { // Try converting the object's ETag (a hex-encoded md5 hash). final String eTag = getETag(); if (eTag != null && ServiceUtils.isEtagAlsoAnMD5Hash(eTag)) { return ServiceUtils.toBase64(ServiceUtils.fromHex(eTag)); } // Try converting the object's md5-hash (another hex-encoded md5 hash). if (getMd5HashAsHex() != null) { return ServiceUtils.toBase64(ServiceUtils.fromHex(getMd5HashAsHex())); } } return md5HashBase64; } /** * Set the MD5 hash value of this object's data. * The hash value is stored as metadata under Content-MD5 (Base64-encoded) * and the JetS3t-specific md5-hash (Hex-encoded). * * @param md5Hash * the MD5 hash value of the object's data. */ public void setMd5Hash(byte[] md5Hash) { addMetadata(METADATA_HEADER_HASH_MD5, ServiceUtils.toHex(md5Hash)); addMetadata(METADATA_HEADER_CONTENT_MD5, ServiceUtils.toBase64(md5Hash)); } /** * @return * the last modified date of this object, as provided by the service. If the last modified date is not * available (e.g. if the object has only just been created) the object's creation date is * returned instead. If both last modified and creation dates are unavailable, null is returned. */ public Date getLastModifiedDate() { Date lastModifiedDate = (Date) getMetadata(METADATA_HEADER_LAST_MODIFIED_DATE); if (lastModifiedDate == null) { // Perhaps this object has just been created, in which case we can use the Date metadata. lastModifiedDate = (Date) getMetadata(METADATA_HEADER_DATE); } return lastModifiedDate; } /** * Set this object's last modified date based on information returned from the service. * This method should only by used internally by code that reads the last modified date * from a service response; it must not be set prior to uploading data to the service. * * @param lastModifiedDate */ public void setLastModifiedDate(Date lastModifiedDate) { addMetadata(METADATA_HEADER_LAST_MODIFIED_DATE, lastModifiedDate); } /** * @return * the content length, or size, of this object's data, or 0 if it is unknown. */ public long getContentLength() { Object contentLength = getMetadata(METADATA_HEADER_CONTENT_LENGTH); if (contentLength == null) { return 0; } else { return Long.parseLong(contentLength.toString()); } } /** * Set this object's content length. The content length is set internally by JetS3t for * objects that are retrieved from a service. For objects that are uploaded, JetS3t * automatically calculates the content length if the data is provided to the String- or * File-based object constructor. If you manually provide data to this object via the * {@link #setDataInputStream(InputStream)} or {@link #setDataInputFile(File)} methods, * you must also set the content length value. * @param size */ public void setContentLength(long size) { addMetadata(METADATA_HEADER_CONTENT_LENGTH, String.valueOf(size)); } /** * @return * the content type of the object */ public String getContentType() { return (String) getMetadata(METADATA_HEADER_CONTENT_TYPE); } /** * Set the content type of the object. JetS3t can help you determine the * content type when the associated data is a File (see {@link Mimetypes}). * You should set the content type for associated String or InputStream data. * * @param contentType */ public void setContentType(String contentType) { addMetadata(METADATA_HEADER_CONTENT_TYPE, contentType); } /** * @return * the content language of this object, or null if it is unknown. */ public String getContentLanguage() { return (String) getMetadata(METADATA_HEADER_CONTENT_LANGUAGE); } /** * Set the content language of the object. * @param contentLanguage */ public void setContentLanguage(String contentLanguage) { addMetadata(METADATA_HEADER_CONTENT_LANGUAGE, contentLanguage); } /** * @return * the content disposition of this object, or null if it is unknown. */ public String getContentDisposition() { return (String) getMetadata(METADATA_HEADER_CONTENT_DISPOSITION); } /** * Set the content disposition of the object. * @param contentDisposition */ public void setContentDisposition(String contentDisposition) { addMetadata(METADATA_HEADER_CONTENT_DISPOSITION, contentDisposition); } /** * @return * the content encoding of this object, or null if it is unknown. */ public String getContentEncoding() { return (String) getMetadata(METADATA_HEADER_CONTENT_ENCODING); } /** * Set the content encoding of this object. * @param contentEncoding */ public void setContentEncoding(String contentEncoding) { addMetadata(METADATA_HEADER_CONTENT_ENCODING, contentEncoding); } /** * @return * the key of this object. */ public String getKey() { return super.getName(); } /** * Set the key of this object. * @param key the key for this object. */ public void setKey(String key) { super.setName(key); } /** * @return * the object's ACL, or null if it is unknown. */ public AccessControlList getAcl() { return acl; } /** * Set the object's ACL. * * @param acl */ public void setAcl(AccessControlList acl) { this.acl = acl; } /** * @return * the storage class of the object. */ public String getStorageClass() { return this.storageClass; } /** * Set the storage class for this object. * * @param storageClass */ public void setStorageClass(String storageClass) { this.storageClass = storageClass; } /** * @return * true if the object's metadata are considered complete, such as when the object's metadata * has been retrieved from the service by a HEAD request. If this value is not true, the metadata * information in this object should not be considered authoritative. */ public boolean isMetadataComplete() { return isMetadataComplete; } /** * Object metadata are only complete when it is populated with all values following * a HEAD or GET request. * This method should only by used by code that reads service responses. * * @param isMetadataComplete */ public void setMetadataComplete(boolean isMetadataComplete) { this.isMetadataComplete = isMetadataComplete; } /** * Add metadata information to the object. If date metadata items (as recognized by name) * are added and the value is not a date the value is parsed as an RFC 822 or * ISO 8601 string. * @param name * @param value */ @Override public void addMetadata(String name, String value) { if (METADATA_HEADER_LAST_MODIFIED_DATE.equals(name) || METADATA_HEADER_DATE.equals(name)) { try { Date parsedDate = null; // We shouldn't get ISO 8601 dates here but let's be paranoid... if (value.toString().indexOf("-") >= 0) { parsedDate = ServiceUtils.parseIso8601Date(value); } else { parsedDate = ServiceUtils.parseRfc822Date(value); } super.addMetadata(name, parsedDate); return; } catch (ParseException e) { if (log.isErrorEnabled()) { log.error("Unable to parse value we expect to be a valid date: " + name + "=" + value, e); } } } super.addMetadata(name, value); } /** * Add all the metadata information to the object from the provided map. * * @param metadata */ @Override public void addAllMetadata(Map metadata) { for (Map.Entry entry: metadata.entrySet()) { Object value = entry.getValue(); if (value instanceof String) { addMetadata(entry.getKey().toString(), (String) value); } else if (value instanceof Date) { addMetadata(entry.getKey().toString(), (Date) value); } else if (value instanceof S3Owner) { addMetadata(entry.getKey().toString(), (S3Owner) value); } } } /** * Returns only those object metadata items that can be modified in * a service. This list excludes those that are set by the the service, and * those that are specific to a particular HTTP request/response * session (such as request identifiers). * * @return * the limited set of metadata items that users can control. */ public Map getModifiableMetadata() { Map objectMetadata = new HashMap(getMetadataMap()); objectMetadata.remove(METADATA_HEADER_CONTENT_LENGTH); objectMetadata.remove(METADATA_HEADER_DATE); objectMetadata.remove(METADATA_HEADER_ETAG); objectMetadata.remove(METADATA_HEADER_LAST_MODIFIED_DATE); objectMetadata.remove("id-2"); // HTTP request-specific information objectMetadata.remove("request-id"); // HTTP request-specific information return objectMetadata; } @SuppressWarnings("deprecation") public boolean isDirectoryPlaceholder() { // Recognize "standard" directory place-holder indications used by // Amazon's AWS Console and Panic's Transmit. if (this.getKey().endsWith("/") && this.getContentLength() == 0) { return true; } // Recognize s3sync.rb directory placeholders by MD5/ETag value. if ("d66759af42f282e1ba19144df2d405d0".equals(this.getETag())) { return true; } // Recognize place-holder objects created by the Google Storage console // or S3 Organizer Firefox extension. if (this.getKey().endsWith("_$folder$") && this.getContentLength() == 0) { return true; } // Recognize legacy JetS3t directory place-holder objects, only gives // accurate results if an object's metadata is populated. if (this.getContentLength() == 0 && Mimetypes.MIMETYPE_JETS3T_DIRECTORY.equals(this.getContentType())) { return true; } return false; } /** * Calculates the MD5 hash value of the given data object, and compares it * against this object's hash (as stored in the Content-MD5 header for * uploads, or the ETag header for downloads). * * @param downloadedFile * @return * true if the calculated MD5 hash value of the file matches this object's * hash value, false otherwise. * * @throws NoSuchAlgorithmException * @throws FileNotFoundException * @throws IOException */ public boolean verifyData(File downloadedFile) throws NoSuchAlgorithmException, FileNotFoundException, IOException { return getMd5HashAsBase64().equals( ServiceUtils.toBase64( ServiceUtils.computeMD5Hash( new FileInputStream(downloadedFile)))); } /** * Calculates the MD5 hash value of the given data object, and compares it * against this object's hash (as stored in the Content-MD5 header for * uploads, or the ETag header for downloads). * * @param downloadedData * @return * true if the calculated MD5 hash value of the bytes matches this object's * hash value, false otherwise. * * @throws NoSuchAlgorithmException * @throws FileNotFoundException * @throws IOException */ public boolean verifyData(byte[] downloadedData) throws NoSuchAlgorithmException, FileNotFoundException, IOException { return getMd5HashAsBase64().equals( ServiceUtils.toBase64( ServiceUtils.computeMD5Hash(downloadedData))); } /** * Calculates the MD5 hash value of the given data object, and compares it * against this object's hash (as stored in the Content-MD5 header for * uploads, or the ETag header for downloads). * * @param downloadedDataStream * the input stream of a downloaded object. * * @return * true if the calculated MD5 hash value of the input stream matches this * object's hash value, false otherwise. * * @throws NoSuchAlgorithmException * @throws FileNotFoundException * @throws IOException */ public boolean verifyData(InputStream downloadedDataStream) throws NoSuchAlgorithmException, FileNotFoundException, IOException { return getMd5HashAsBase64().equals( ServiceUtils.toBase64( ServiceUtils.computeMD5Hash(downloadedDataStream))); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/BaseVersionOrDeleteMarker.java0000644000000000000000000000401011452170402024672 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * @author James Murty */ public abstract class BaseVersionOrDeleteMarker { private String key = null; private String versionId = null; private boolean isLatest = false; private Date lastModified = null; private S3Owner owner = null; public BaseVersionOrDeleteMarker(String key, String versionId, boolean isLatest, Date lastModified, S3Owner owner) { this.key = key; this.versionId = versionId; this.isLatest = isLatest; this.lastModified = lastModified; this.owner = owner; } public abstract boolean isDeleteMarker(); public String getKey() { return key; } public String getVersionId() { return versionId; } public boolean isLatest() { return isLatest; } public Date getLastModified() { return lastModified; } public S3Owner getOwner() { return owner; } public static String[] toVersionIds(BaseVersionOrDeleteMarker[] items) { List versionsList = new ArrayList(); for (int i = 0; i < items.length; i++) { versionsList.add(items[i].getVersionId()); } return versionsList.toArray(new String[versionsList.size()]); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/WebsiteConfig.java0000644000000000000000000000500311537563564022442 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2011 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.jets3t.service.Constants; import com.jamesmurty.utils.XMLBuilder; /** * Represents the website configuraton of a bucket * * @author James Murty */ public class WebsiteConfig { private String indexDocumentSuffix = null; private String errorDocumentKey = null; public WebsiteConfig(String indexDocumentSuffix, String errorDocumentKey) { this.indexDocumentSuffix = indexDocumentSuffix; this.errorDocumentKey = errorDocumentKey; } public WebsiteConfig(String indexDocumentSuffix) { this(indexDocumentSuffix, null); } public String getIndexDocumentSuffix() { return indexDocumentSuffix; } public String getErrorDocumentKey() { return errorDocumentKey; } public boolean isWebsiteConfigActive() { return (indexDocumentSuffix != null); } /** * * @return * An XML representation of the object suitable for use as an input to the REST/HTTP interface. * * @throws FactoryConfigurationError * @throws ParserConfigurationException * @throws TransformerException */ public String toXml() throws ParserConfigurationException, FactoryConfigurationError, TransformerException { XMLBuilder builder = XMLBuilder.create("WebsiteConfiguration") .attr("xmlns", Constants.XML_NAMESPACE) .elem("IndexDocument").elem("Suffix").text(this.indexDocumentSuffix) .up().up(); if (this.errorDocumentKey != null && this.errorDocumentKey.length() > 0) { builder.elem("ErrorDocument").elem("Key").text(this.errorDocumentKey); } return builder.asString(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/MultipartPart.java0000644000000000000000000000606111537563564022527 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model; import java.util.Comparator; import java.util.Date; /** * Represents a Part of a MultipartUpload operation. * * @author James Murty */ public class MultipartPart { private Integer partNumber; private Date lastModified; private String etag; private Long size; public MultipartPart(Integer partNumber, Date lastModified, String etag, Long size) { if (partNumber == null) { throw new IllegalArgumentException("Null part number not allowed."); } if (lastModified == null) { throw new IllegalArgumentException("Null last modified not allowed."); } if (etag == null) { throw new IllegalArgumentException("Null etag not allowed."); } if (size == null) { throw new IllegalArgumentException("Null size not allowed."); } this.partNumber = partNumber; this.lastModified = lastModified; this.size = size; // Strip quote characters from etag value this.etag = etag.replaceAll("\"", ""); } @Override public boolean equals(Object other) { if (other == this) { return true; } if (other instanceof MultipartPart) { MultipartPart p = (MultipartPart) other; return this.partNumber.equals(p.partNumber) && this.lastModified.equals(p.lastModified) && this.size.equals(p.size) && this.etag.equals(p.etag); } return false; } @Override public String toString() { return this.getClass().getName() + " [" + "partNumber=" + getPartNumber() + ", lastModified=" + getLastModified() + ", etag=" + getEtag() + ", size=" + getSize() + "]"; } public String getEtag() { return etag; } public Long getSize() { return size; } public Integer getPartNumber() { return partNumber; } public Date getLastModified() { return lastModified; } public static class PartNumberComparator implements Comparator { public int compare(MultipartPart o1, MultipartPart o2) { if (o1 == o2) { return 0; } else { return o1.getPartNumber().compareTo(o2.getPartNumber()); } } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/StorageBucket.java0000644000000000000000000000442011441613550022437 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model; import java.util.Date; import org.jets3t.service.acl.AccessControlList; /** * A generic storage bucket. * * @author James Murty */ public class StorageBucket extends BaseStorageItem { private AccessControlList acl = null; /** * Create a bucket without any name or location specified */ public StorageBucket() { super(); } /** * Create a bucket with a name. */ public StorageBucket(String name) { super(name); } @Override public String toString() { return "StorageBucket [name=" + getName() + "] Metadata=" + getMetadataMap(); } /** * @return * the bucket's creation date, or null if it is unknown. */ public Date getCreationDate() { return (Date) getMetadata(METADATA_HEADER_CREATION_DATE); } /** * Sets the bucket's creation date - this should only be used internally by JetS3t * methods that retrieve information directly from a service. * * @param creationDate */ public void setCreationDate(Date creationDate) { addMetadata(METADATA_HEADER_CREATION_DATE, creationDate); } /** * @return * the bucket's Access Control List, or null if it is unknown. */ public AccessControlList getAcl() { return acl; } /** * Sets the bucket's Access Control List in S3 - this should only be used internally by J3tS3t * methods that retrieve information directly from S3. * * @param acl */ public void setAcl(AccessControlList acl) { this.acl = acl; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/S3Bucket.java0000644000000000000000000001301011537563564021332 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model; import java.util.ArrayList; import java.util.List; /** * Represents an S3 bucket. * * @author James Murty */ public class S3Bucket extends StorageBucket { public static final String LOCATION_US = null; public static final String LOCATION_US_STANDARD = null; public static final String LOCATION_US_WEST = "us-west-1"; public static final String LOCATION_EUROPE = "EU"; public static final String LOCATION_ASIA_PACIFIC_SOUTHEAST = "ap-southeast-1"; /** * Alias of {@link #LOCATION_ASIA_PACIFIC_SOUTHEAST} */ public static final String LOCATION_ASIA_PACIFIC = LOCATION_ASIA_PACIFIC_SOUTHEAST; /** * Alias of {@link #LOCATION_ASIA_PACIFIC_SOUTHEAST} */ public static final String LOCATION_ASIA_PACIFIC_SINGAPORE = LOCATION_ASIA_PACIFIC_SOUTHEAST; public static final String LOCATION_ASIA_PACIFIC_NORTHEAST = "ap-northeast-1"; /** * Alias of {@link #LOCATION_ASIA_PACIFIC_NORTHEAST} */ public static final String LOCATION_ASIA_PACIFIC_TOKYO = LOCATION_ASIA_PACIFIC_NORTHEAST; private String location = LOCATION_US; private boolean isLocationKnown = false; private boolean requesterPays = false; private boolean isRequesterPaysKnown = false; /** * Create a bucket without any name or location specified */ public S3Bucket() { super(); } /** * Create a bucket with a name. All buckets in S3 share a single namespace, * so choose a unique name for your bucket. * @param name the name for the bucket */ public S3Bucket(String name) { super(name); } /** * Create a bucket with a name and a location. All buckets in S3 share a single namespace, * so choose a unique name for your bucket. * @param name the name for the bucket * @param location A string representing the location. Legal values include * {@link #LOCATION_US} and null (which are equivalent), or * {@link #LOCATION_EUROPE}. */ public S3Bucket(String name, String location) { this(name); this.location = location; this.isLocationKnown = true; } @Override public String toString() { return "S3Bucket [name=" + getName() + ",location=" + getLocation() + ",creationDate=" + getCreationDate() + ",owner=" + getOwner() + "] Metadata=" + getMetadataMap(); } /** * Set's the bucket's location. This method should only be used internally by * JetS3t methods that retrieve information directly from S3. * * @param location * A string representing the location. Legal values include * {@link #LOCATION_US} and null (which are equivalent), or * {@link #LOCATION_EUROPE}. */ public void setLocation(String location) { this.location = location; this.isLocationKnown = true; } /** * @return * true if this object knows the bucket's location, false otherwise. */ public boolean isLocationKnown() { return this.isLocationKnown; } /** * @return * the bucket's location represented as a string. "EU" * denotes a bucket located in Europe, while null denotes a bucket located * in the US. */ public String getLocation() { return location; } /** * Set's the bucket's Requester Pays Configuration setting. * This method should only be used internally by JetS3t methods that * retrieve information directly from S3. * * @param requesterPays * true if the bucket is configured for Requester Pays, false if it is * configured for Owner pays. */ public void setRequesterPays(boolean requesterPays) { this.requesterPays = requesterPays; this.isRequesterPaysKnown = true; } /** * @return * true if this bucket object knows its Requester Pays status, false otherwise. */ public boolean isRequesterPaysKnown() { return this.isRequesterPaysKnown; } /** * Return the Requester Pays status of this bucket, if it is known. *

* WARNING: * Before you use this method, always check with the {@link #isRequesterPaysKnown} * method to ensure that the Requester Pays status has been set, otherwise * the result of this method is meaningless. * * @return * true if the bucket is configured for Requester Pays, false if it is * configured for Owner pays or the Request Pays configuration status is * unknown. */ public boolean isRequesterPays() { return requesterPays; } public static S3Bucket[] cast(StorageBucket[] buckets) { List results = new ArrayList(); for (StorageBucket bucket: buckets) { results.add((S3Bucket)bucket); } return results.toArray(new S3Bucket[results.size()]); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/BaseStorageItem.java0000644000000000000000000001267211441613550022723 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Map; /** * Base class to represent storage items that can contain metadata: both objects and buckets. * * @author James Murty */ public abstract class BaseStorageItem { /* * Standard HTTP metadata/header names. */ public static final String METADATA_HEADER_CREATION_DATE = "Date"; public static final String METADATA_HEADER_LAST_MODIFIED_DATE = "Last-Modified"; public static final String METADATA_HEADER_DATE = "Date"; public static final String METADATA_HEADER_CONTENT_MD5 = "Content-MD5"; public static final String METADATA_HEADER_CONTENT_LENGTH = "Content-Length"; public static final String METADATA_HEADER_CONTENT_TYPE = "Content-Type"; public static final String METADATA_HEADER_CONTENT_ENCODING = "Content-Encoding"; public static final String METADATA_HEADER_CONTENT_DISPOSITION = "Content-Disposition"; public static final String METADATA_HEADER_CONTENT_LANGUAGE = "Content-Language"; public static final String METADATA_HEADER_ETAG = "ETag"; /* * Metadata names common to S3 and Google Storage. */ private String name = null; private StorageOwner owner = null; /** * Map to metadata associated with this object. */ private final Map metadata = new HashMap(); protected BaseStorageItem(String name) { this.name = name; } protected BaseStorageItem() { } /** * @return * the name of the bucket. */ public String getName() { return name; } /** * Set the name of the bucket. * @param name the name for the bucket */ public void setName(String name) { this.name = name; } /** * @return * an immutable map containing all the metadata associated with this object. */ public Map getMetadataMap() { return Collections.unmodifiableMap(metadata); } /** * @param name * the metadata item name. * * @return * the value of the metadata with the given name, or null if no such metadata item exists. */ public Object getMetadata(String name) { return this.metadata.get(name); } /** * @param name * the metadata item name. * * @return * true if this object contains a metadata item with the given name, false otherwise. */ public boolean containsMetadata(String name) { return this.metadata.keySet().contains(name); } /** * Adds a metadata item to the object. * * @param name * the metadata item name. * @param value * the metadata item value. */ public void addMetadata(String name, String value) { this.metadata.put(name, value); } /** * Adds a Date metadata item to the object. * * @param name * the metadata item name. * @param value * the metadata item's date value. */ public void addMetadata(String name, Date value) { this.metadata.put(name, value); } /** * Adds an owner metadata item to the object. * * @param name * the metadata item name. * @param value * the metadata item's owner value. */ public void addMetadata(String name, StorageOwner value) { this.metadata.put(name, value); } /** * Adds all the items in the provided map to this object's metadata. * * @param metadata * metadata items to add. */ public void addAllMetadata(Map metadata) { this.metadata.putAll(metadata); } /** * Removes a metadata item from the object. * * @param name * the name of the metadata item to remove. */ public void removeMetadata(String name) { this.metadata.remove(name); } /** * Removes all the metadata items associated with this object, then adds all the items * in the provided map. After performing this operation, the metadata list will contain * only those items in the provided map. * * @param metadata * metadata items to add. */ public void replaceAllMetadata(Map metadata) { this.metadata.clear(); addAllMetadata(metadata); } /** * @return * this object's owner, or null if the owner is not available. */ public StorageOwner getOwner() { return this.owner; } /** * Set this object's owner object based on information returned from the service. * This method should only by used by code that reads service responses. * * @param owner */ public void setOwner(StorageOwner owner) { this.owner = owner; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/S3Object.java0000644000000000000000000002236111537563564021334 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model; import java.io.File; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; import org.jets3t.service.Constants; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.utils.Mimetypes; /** * An S3 object. * * @author James Murty */ public class S3Object extends StorageObject implements Cloneable { public static final String STORAGE_CLASS_STANDARD = "STANDARD"; public static final String STORAGE_CLASS_REDUCED_REDUNDANCY = "REDUCED_REDUNDANCY"; /* * S3-specific metadata/header names. */ public static final String S3_VERSION_ID = "version-id"; /** * Create an object representing a file. The object is initialised with the file's name * as its key, the file's content as its data, a content type based on the file's extension * (see {@link Mimetypes}), and a content length matching the file's size. * The file's MD5 hash value is also calculated and provided to S3, so the service * can verify that no data are corrupted in transit. *

* NOTE: The automatic calculation of a file's MD5 hash digest as performed by * this constructor could take some time for large files, or for many small ones. * * @param bucket * the bucket the object belongs to, or will be placed in. * @param file * the file the object will represent. This file must exist and be readable. * * @throws IOException when an i/o error occurred reading the file * @throws NoSuchAlgorithmException when this JRE doesn't support the MD5 hash algorithm */ public S3Object(S3Bucket bucket, File file) throws NoSuchAlgorithmException, IOException { super(file); if (bucket != null) { this.bucketName = bucket.getName(); } } /** * Create an object representing a file. The object is initialised with the file's name * as its key, the file's content as its data, a content type based on the file's extension * (see {@link Mimetypes}), and a content length matching the file's size. * The file's MD5 hash value is also calculated and provided to S3, so the service * can verify that no data are corrupted in transit. *

* NOTE: The automatic calculation of a file's MD5 hash digest as performed by * this constructor could take some time for large files, or for many small ones. * * @param file * the file the object will represent. This file must exist and be readable. * * @throws IOException when an i/o error occurred reading the file * @throws NoSuchAlgorithmException when this JRE doesn't support the MD5 hash algorithm */ public S3Object(File file) throws NoSuchAlgorithmException, IOException { super(file); } /** * Create an object representing text data. The object is initialized with the given * key, the given string as its data content (encoded as UTF-8), a content type of * text/plain; charset=utf-8, and a content length matching the * string's length. * The given string's MD5 hash value is also calculated and provided to S3, so the service * can verify that no data are corrupted in transit. *

* NOTE: The automatic calculation of the MD5 hash digest as performed by * this constructor could take some time for large strings, or for many small ones. * * @param bucket * the bucket the object belongs to, or will be placed in. * @param key * the key name for the object. * @param dataString * the text data the object will contain. Text data will be encoded as UTF-8. * This string cannot be null. * * @throws IOException * @throws NoSuchAlgorithmException when this JRE doesn't support the MD5 hash algorithm */ public S3Object(S3Bucket bucket, String key, String dataString) throws NoSuchAlgorithmException, IOException { super(key, dataString); if (bucket != null) { this.bucketName = bucket.getName(); } } /** * Create an object representing text data. The object is initialized with the given * key, the given string as its data content (encoded as UTF-8), a content type of * text/plain; charset=utf-8, and a content length matching the * string's length. * The given string's MD5 hash value is also calculated and provided to S3, so the service * can verify that no data are corrupted in transit. *

* NOTE: The automatic calculation of the MD5 hash digest as performed by * this constructor could take some time for large strings, or for many small ones. * * @param key * the key name for the object. * @param dataString * the text data the object will contain. Text data will be encoded as UTF-8. * This string cannot be null. * * @throws IOException * @throws NoSuchAlgorithmException when this JRE doesn't support the MD5 hash algorithm */ public S3Object(String key, String dataString) throws NoSuchAlgorithmException, IOException { super(key, dataString); } /** * Create an object representing binary data. The object is initialized with the given * key, the bytes as its data content, a content type of * application/octet-stream, and a content length matching the * byte array's length. * The MD5 hash value of the byte data is also calculated and provided to the target * service, so the service can verify that no data are corrupted in transit. * * @param key * the key name for the object. * @param data * the byte data the object will contain, cannot be null. * * @throws IOException * @throws NoSuchAlgorithmException when this JRE doesn't support the MD5 hash algorithm */ public S3Object(String key, byte[] data) throws NoSuchAlgorithmException, IOException { super(key, data); } /** * Create an object without any associated data, and no associated bucket. * * @param key * the key name for the object. */ public S3Object(String key) { super(key); } /** * Create an object without any associated data. * * @param bucket * the bucket the object belongs to, or will be placed in. * @param key * the key name for the object. */ public S3Object(S3Bucket bucket, String key) { super(key); if (bucket != null) { this.bucketName = bucket.getName(); } } /** * Create an object without any associated information whatsoever. */ public S3Object() { super(); } @Override public String toString() { return "S3Object [key=" + getKey() + ", bucket=" + (bucketName == null ? "" : bucketName) + ", lastModified=" + getLastModifiedDate() + ", dataInputStream=" + dataInputStream + (getStorageClass() != null ? ", storageClass=" + getStorageClass() : "") + ", Metadata=" + getMetadataMap() + "]"; } /** * Set the object's ACL. If a pre-canned REST ACL is used, the plain-text representation * of the canned ACL is also added as a metadata header x-amz-acl. * * @param acl */ @Override public void setAcl(AccessControlList acl) { this.acl = acl; if (acl != null) { String restHeaderAclValue = acl.getValueForRESTHeaderACL(); if (restHeaderAclValue != null) { addMetadata(Constants.REST_HEADER_PREFIX + "acl", restHeaderAclValue); } else { // Non-REST canned ACLs are not added as headers... } } } public String getVersionId() { return (String) getMetadata(S3_VERSION_ID); } @Override public Object clone() { S3Object clone = new S3Object(getKey()); clone.bucketName = bucketName; clone.dataInputStream = dataInputStream; clone.acl = acl; clone.isMetadataComplete = isMetadataComplete; clone.dataInputFile = dataInputFile; clone.storageClass = storageClass; clone.setOwner(this.getOwner()); clone.addAllMetadata(getMetadataMap()); return clone; } public static S3Object[] cast(StorageObject[] objects) { List results = new ArrayList(); for (StorageObject object: objects) { results.add((S3Object)object); } return results.toArray(new S3Object[results.size()]); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/GSBucket.java0000644000000000000000000000431211452167160021347 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model; import java.util.ArrayList; import java.util.List; import org.jets3t.service.acl.gs.GSAccessControlList; /** * Represents a bucket in the Google Storage service. * * @author James Murty */ public class GSBucket extends StorageBucket { private GSAccessControlList acl = null; /** * Create a bucket without any name or location specified */ public GSBucket() { } /** * Create a bucket with a name. All buckets share a single namespace, * so choose a unique name for your bucket. * @param name the name for the bucket */ public GSBucket(String name) { super(name); } @Override public String toString() { return "GSBucket [name=" + getName() + "] Metadata=" + getMetadataMap(); } /** * @return * the bucket's Access Control List, or null if it is unknown. */ @Override public GSAccessControlList getAcl() { return acl; } /** * Sets the bucket's Access Control List - this should only be used internally * by JetS3t methods that retrieve information directly from the service. * * @param acl */ public void setAcl(GSAccessControlList acl) { this.acl = acl; } public static GSBucket[] cast(StorageBucket[] buckets) { List results = new ArrayList(); for (StorageBucket bucket: buckets) { results.add((GSBucket)bucket); } return results.toArray(new GSBucket[results.size()]); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/S3BucketVersioningStatus.java0000644000000000000000000000275311441613550024577 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model; /** * @author James Murty * */ public class S3BucketVersioningStatus { private boolean versioningEnabled = false; private boolean multiFactorAuthDeleteEnabled = false; public S3BucketVersioningStatus(boolean versioningEnabled, boolean multiFactorAuthEnabled) { this.versioningEnabled = versioningEnabled; this.multiFactorAuthDeleteEnabled = multiFactorAuthEnabled; } public boolean isVersioningEnabled() { return versioningEnabled; } public boolean isMultiFactorAuthDeleteRequired() { return multiFactorAuthDeleteEnabled; } public String toString() { return "VersioningStatus enabled=" + isVersioningEnabled() + ", multiFactorAuthDeleteEnabled=" + isMultiFactorAuthDeleteRequired(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/NotificationConfig.java0000644000000000000000000000531611537563564023475 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2011 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model; import java.util.ArrayList; import java.util.List; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import com.jamesmurty.utils.XMLBuilder; /** * Represents the notification configuraton of a bucket * * @author James Murty */ public class NotificationConfig { public static final String EVENT_REDUCED_REDUNDANCY_LOST_OBJECT = "s3:ReducedRedundancyLostObject"; private List topicConfigs = new ArrayList(); public NotificationConfig(List topicConfigs) { this.topicConfigs = topicConfigs; } public NotificationConfig() { } public List getTopicConfigs() { return topicConfigs; } public void addTopicConfig(TopicConfig config) { this.topicConfigs.add(config); } /** * * @return * An XML representation of the object suitable for use as an input to the REST/HTTP interface. * * @throws FactoryConfigurationError * @throws ParserConfigurationException * @throws TransformerException */ public String toXml() throws ParserConfigurationException, FactoryConfigurationError, TransformerException { XMLBuilder builder = XMLBuilder.create("NotificationConfiguration"); for (TopicConfig topicConfig: this.topicConfigs) { builder .elem("TopicConfiguration") .elem("Topic").text(topicConfig.topic).up() .elem("Event").text(topicConfig.event); } return builder.asString(); } public class TopicConfig { protected String topic; protected String event; public TopicConfig(String topic, String event) { this.topic = topic; this.event = event; } public String getTopic() { return topic; } public String getEvent() { return event; } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/GSObject.java0000644000000000000000000001134011452167230021335 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model; import java.io.File; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; import org.jets3t.service.acl.gs.GSAccessControlList; import org.jets3t.service.utils.Mimetypes; /** * A Google Storage object. * * @author James Murty */ public class GSObject extends StorageObject implements Cloneable { private GSAccessControlList acl = null; /** * Create an object representing a file. The object is initialised with the file's name * as its key, the file's content as its data, a content type based on the file's extension * (see {@link Mimetypes}), and a content length matching the file's size. * The file's MD5 hash value is also calculated and provided to the service so it * can verify that no data are corrupted in transit. *

* NOTE: The automatic calculation of a file's MD5 hash digest as performed by * this constructor could take some time for large files, or for many small ones. * * @param file * the file the object will represent. This file must exist and be readable. * * @throws IOException when an i/o error occurred reading the file * @throws NoSuchAlgorithmException when this JRE doesn't support the MD5 hash algorithm */ public GSObject(File file) throws NoSuchAlgorithmException, IOException { super(file); } /** * Create an object representing text data. The object is initialized with the given * key, the given string as its data content (encoded as UTF-8), a content type of * text/plain; charset=utf-8, and a content length matching the * string's length. * The given string's MD5 hash value is also calculated and provided to the service * so it can verify that no data are corrupted in transit. *

* NOTE: The automatic calculation of the MD5 hash digest as performed by * this constructor could take some time for large strings, or for many small ones. * * @param key * the key name for the object. * @param dataString * the text data the object will contain. Text data will be encoded as UTF-8. * This string cannot be null. * * @throws IOException * @throws NoSuchAlgorithmException when this JRE doesn't support the MD5 hash algorithm */ public GSObject(String key, String dataString) throws NoSuchAlgorithmException, IOException { super(key, dataString); } /** * Create an object without any associated data, and no associated bucket. * * @param key * the key name for the object. */ public GSObject(String key) { super(key); } /** * Create an object without any associated information whatsoever. */ public GSObject() { super(); } @Override public String toString() { return "GSObject [key=" + getKey() + ", lastModified=" + getLastModifiedDate() + ", dataInputStream=" + dataInputStream + ", Metadata=" + getMetadataMap() + "]"; } /** * @return * the object's ACL, or null if it is unknown. */ @Override public GSAccessControlList getAcl() { return acl; } /** * Set the object's ACL. * * @param acl */ public void setAcl(GSAccessControlList acl) { this.acl = acl; } @Override public Object clone() { GSObject clone = new GSObject(getKey()); clone.dataInputStream = dataInputStream; clone.acl = acl; clone.isMetadataComplete = isMetadataComplete; clone.dataInputFile = dataInputFile; clone.setOwner(this.getOwner()); clone.addAllMetadata(getMetadataMap()); return clone; } public static GSObject[] cast(StorageObject[] objects) { List results = new ArrayList(); for (StorageObject object: objects) { results.add((GSObject)object); } return results.toArray(new GSObject[results.size()]); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/S3Version.java0000644000000000000000000000421411441613550021531 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model; import java.util.Date; /** * An S3 version. * * @author James Murty */ public class S3Version extends BaseVersionOrDeleteMarker { private String etag = null; private long size = 0; private String storageClass = null; public S3Version(String key, String versionId, boolean isLatest, Date lastModified, S3Owner owner, String etag, long size, String storageClass) { this(key, versionId, isLatest, lastModified, owner); this.etag = etag; this.size = size; this.storageClass = storageClass; } public S3Version(String key, String versionId, boolean isLatest, Date lastModified, S3Owner owner) { super(key, versionId, isLatest, lastModified, owner); } public S3Version(String key, String versionId) { super(key, versionId, false, null, null); } public boolean isDeleteMarker() { return false; } public String getEtag() { return etag; } public long getSize() { return size; } public String getStorageClass() { return storageClass; } public String toString() { return "S3Version [key=" + getKey() + ", versionId=" + getVersionId() + ", isLatest=" + isLatest() + ", lastModified=" + getLastModified() + ", owner=" + getOwner() + ", etag=" + getEtag() + ", size=" + getSize() + ", storageClass=" + getStorageClass() + "]"; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/MultipartCompleted.java0000644000000000000000000000375711537563564023546 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model; /** * Represents a completed object resulting from a MultipartUpload operation. * * @author James Murty */ public class MultipartCompleted { private String location; private String bucketName; private String objectKey; private String etag; private String versionId; public MultipartCompleted(String location, String bucketName, String objectKey, String etag) { this.location = location; this.bucketName = bucketName; this.etag = etag; this.objectKey = objectKey; } @Override public String toString() { return this.getClass().getName() + " [" + "location=" + getLocation() + ", bucketName=" + getBucketName() + ", objectKey=" + getObjectKey() + ", etag=" + getEtag() + (versionId != null ? ", etag=" + getEtag() : "") + "]"; } public String getEtag() { return etag; } public String getObjectKey() { return objectKey; } public String getLocation() { return location; } public String getBucketName() { return bucketName; } public String getVersionId() { return versionId; } public void setVersionId(String versionId) { this.versionId = versionId; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/model/S3BucketLoggingStatus.java0000644000000000000000000001264311550421156024041 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.model; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.jets3t.service.Constants; import org.jets3t.service.S3ServiceException; import org.jets3t.service.acl.GrantAndPermission; import com.jamesmurty.utils.XMLBuilder; /** * Represents Bucket Logging Status settings used to control bucket-based Server Access Logging in S3. *

* For logging to be enabled for a bucket both the targetBucketName and logfilePrefix must be * non-null, and the named bucket must exist. When both variables are non-null, this object * represents an enabled logging status (as indicated by {@link #isLoggingEnabled()}) and * the XML document generated by {@link #toXml()} will enable logging for the named bucket when * provided to {@link org.jets3t.service.S3Service#setBucketLoggingStatus(String, S3BucketLoggingStatus, boolean)}. *

* If either the targetBucketName or logfilePrefix are null, this object will represent a * disabled logging status (as indicated by {@link #isLoggingEnabled()}) and * the XML document generated by {@link #toXml()} will disable logging for the named bucket when * provided to {@link org.jets3t.service.S3Service#setBucketLoggingStatus(String, S3BucketLoggingStatus, boolean)}. * * @author James Murty * */ public class S3BucketLoggingStatus { private String targetBucketName = null; private String logfilePrefix = null; private final List targetGrantsList = new ArrayList(); public S3BucketLoggingStatus() { } public S3BucketLoggingStatus(String targetBucketName, String logfilePrefix) { this.targetBucketName = targetBucketName; this.logfilePrefix = logfilePrefix; } public boolean isLoggingEnabled() { return targetBucketName != null && logfilePrefix != null; } public String getLogfilePrefix() { return logfilePrefix; } public void setLogfilePrefix(String logfilePrefix) { this.logfilePrefix = logfilePrefix; } public String getTargetBucketName() { return targetBucketName; } public void setTargetBucketName(String targetBucketName) { this.targetBucketName = targetBucketName; } public GrantAndPermission[] getTargetGrants() { return targetGrantsList.toArray( new GrantAndPermission[targetGrantsList.size()]); } public void setTargetGrants(GrantAndPermission[] targetGrants) { targetGrantsList.clear(); targetGrantsList.addAll(Arrays.asList(targetGrants)); } public void addTargetGrant(GrantAndPermission targetGrant) { targetGrantsList.add(targetGrant); } @Override public String toString() { String result = "LoggingStatus enabled=" + isLoggingEnabled(); if (isLoggingEnabled()) { result += ", targetBucketName=" + getTargetBucketName() + ", logfilePrefix=" + getLogfilePrefix(); } result += ", targetGrants=[" + targetGrantsList + "]"; return result; } /** * * @return * An XML representation of the object suitable for use as an input to the REST/HTTP interface. * * @throws S3ServiceException */ public String toXml() throws S3ServiceException { try { return toXMLBuilder().asString(); } catch (Exception e) { throw new S3ServiceException("Failed to build XML document for ACL", e); } } public XMLBuilder toXMLBuilder() throws ParserConfigurationException, FactoryConfigurationError, TransformerException { XMLBuilder builder = XMLBuilder.create("BucketLoggingStatus") .attr("xmlns", Constants.XML_NAMESPACE); if (isLoggingEnabled()) { XMLBuilder enabledBuilder = builder.elem("LoggingEnabled") .elem("TargetBucket").text(getTargetBucketName()).up() .elem("TargetPrefix").text(getLogfilePrefix()).up(); if (targetGrantsList.size() > 0) { Iterator targetGrantsIter = targetGrantsList.iterator(); XMLBuilder grantsBuilder = enabledBuilder.elem("TargetGrants"); while (targetGrantsIter.hasNext()) { GrantAndPermission gap = targetGrantsIter.next(); grantsBuilder.elem("Grant") .importXMLBuilder(gap.getGrantee().toXMLBuilder()) .elem("Permission").text(gap.getPermission().toString()); } } } return builder; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/S3ObjectsChunk.java0000644000000000000000000000306311441613550021367 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service; import org.jets3t.service.model.S3Object; /** * Stores a "chunk" of S3Objects returned from a list command - this particular chunk may or may * not include all the objects available in a bucket. * * This class contains an array of objects and a the last key name returned by a prior * call to the method {@link S3Service#listObjectsChunked(String, String, String, long, String)}. * * @author James Murty * * @deprecated 0.8.0 use {@link StorageObjectsChunk} instead. */ @Deprecated public class S3ObjectsChunk extends StorageObjectsChunk { public S3ObjectsChunk(String prefix, String delimiter, S3Object[] objects, String[] commonPrefixes, String priorLastKey) { super(prefix, delimiter, objects, commonPrefixes, priorLastKey); } @Override public S3Object[] getObjects() { return S3Object.cast(objects); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/CloudFrontService.java0000644000000000000000000026375211550442052022212 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 - 2009 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.apache.commons.httpclient.HostConfiguration; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.auth.CredentialsProvider; import org.apache.commons.httpclient.methods.DeleteMethod; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.PutMethod; import org.apache.commons.httpclient.methods.StringRequestEntity; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.impl.rest.CloudFrontXmlResponsesSaxParser; import org.jets3t.service.impl.rest.CloudFrontXmlResponsesSaxParser.DistributionConfigHandler; import org.jets3t.service.impl.rest.CloudFrontXmlResponsesSaxParser.DistributionHandler; import org.jets3t.service.impl.rest.CloudFrontXmlResponsesSaxParser.ErrorHandler; import org.jets3t.service.impl.rest.CloudFrontXmlResponsesSaxParser.InvalidationHandler; import org.jets3t.service.impl.rest.CloudFrontXmlResponsesSaxParser.InvalidationListHandler; import org.jets3t.service.impl.rest.CloudFrontXmlResponsesSaxParser.DistributionListHandler; import org.jets3t.service.impl.rest.CloudFrontXmlResponsesSaxParser.OriginAccessIdentityConfigHandler; import org.jets3t.service.impl.rest.CloudFrontXmlResponsesSaxParser.OriginAccessIdentityHandler; import org.jets3t.service.impl.rest.CloudFrontXmlResponsesSaxParser.OriginAccessIdentityListHandler; import org.jets3t.service.impl.rest.httpclient.AWSRequestAuthorizer; import org.jets3t.service.impl.rest.httpclient.HttpClientAndConnectionManager; import org.jets3t.service.model.S3Object; import org.jets3t.service.model.cloudfront.CustomOrigin; import org.jets3t.service.model.cloudfront.Distribution; import org.jets3t.service.model.cloudfront.DistributionConfig; import org.jets3t.service.model.cloudfront.Invalidation; import org.jets3t.service.model.cloudfront.InvalidationList; import org.jets3t.service.model.cloudfront.InvalidationSummary; import org.jets3t.service.model.cloudfront.LoggingStatus; import org.jets3t.service.model.cloudfront.Origin; import org.jets3t.service.model.cloudfront.OriginAccessIdentity; import org.jets3t.service.model.cloudfront.OriginAccessIdentityConfig; import org.jets3t.service.model.cloudfront.S3Origin; import org.jets3t.service.model.cloudfront.StreamingDistribution; import org.jets3t.service.model.cloudfront.StreamingDistributionConfig; import org.jets3t.service.security.EncryptionUtil; import org.jets3t.service.security.ProviderCredentials; import org.jets3t.service.utils.RestUtils; import org.jets3t.service.utils.ServiceUtils; import com.jamesmurty.utils.XMLBuilder; /** * A service that handles communication with the Amazon CloudFront REST API, offering * all the operations that can be performed on CloudFront distributions. *

* This class uses properties obtained through {@link Jets3tProperties}. For more information on * these properties please refer to * JetS3t Configuration *

* * @author James Murty */ public class CloudFrontService implements AWSRequestAuthorizer { private static final Log log = LogFactory.getLog(CloudFrontService.class); public static final String ENDPOINT = "https://cloudfront.amazonaws.com/"; public static final String VERSION = "2010-11-01"; public static final String XML_NAMESPACE = "http://cloudfront.amazonaws.com/doc/" + VERSION + "/"; public static final String DEFAULT_BUCKET_SUFFIX = ".s3.amazonaws.com"; public static final String ORIGIN_ACCESS_IDENTITY_URI_PATH = "/origin-access-identity/cloudfront"; public static final String ORIGIN_ACCESS_IDENTITY_PREFIX = "origin-access-identity/cloudfront/"; private HttpClient httpClient = null; private CredentialsProvider credentialsProvider = null; private ProviderCredentials credentials = null; protected Jets3tProperties jets3tProperties = null; private String invokingApplicationDescription = null; protected int internalErrorRetryMax = 5; /** * The approximate difference in the current time between your computer and * Amazon's servers, measured in milliseconds. * * This value is 0 by default. Use the {@link #getCurrentTimeWithOffset()} * to obtain the current time with this offset factor included, and the * {@link RestUtils#getAWSTimeAdjustment()} method to calculate an offset value for your * computer based on a response from an AWS server. */ protected long timeOffset = 0; /** * Constructs the service and initialises its properties. * * @param credentials * the Storage Provider user credentials to use when communicating with CloudFront * @param invokingApplicationDescription * a short description of the application using the service, suitable for inclusion in a * user agent string for REST/HTTP requests. Ideally this would include the application's * version number, for example: Cockpit/0.7.3 or My App Name/1.0. * May be null. * @param credentialsProvider * an implementation of the HttpClient CredentialsProvider interface, to provide a means for * prompting for credentials when necessary. May be null. * @param jets3tProperties * JetS3t properties that will be applied within this service. May be null. * @param hostConfig * Custom HTTP host configuration; e.g to register a custom Protocol Socket Factory. * May be null. * * @throws CloudFrontServiceException */ public CloudFrontService(ProviderCredentials credentials, String invokingApplicationDescription, CredentialsProvider credentialsProvider, Jets3tProperties jets3tProperties, HostConfiguration hostConfig) throws CloudFrontServiceException { this.credentials = credentials; this.invokingApplicationDescription = invokingApplicationDescription; this.credentialsProvider = credentialsProvider; if (jets3tProperties == null) { jets3tProperties = Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME); } this.jets3tProperties = jets3tProperties; // Configure the InetAddress DNS caching times to work well with CloudFront. The cached DNS will // timeout after 5 minutes, while failed DNS lookups will be retried after 1 second. System.setProperty("networkaddress.cache.ttl", "300"); System.setProperty("networkaddress.cache.negative.ttl", "1"); this.internalErrorRetryMax = jets3tProperties.getIntProperty("cloudfront-service.internal-error-retry-max", 5); if (hostConfig == null) { hostConfig = new HostConfiguration(); } HttpClientAndConnectionManager initHttpResult = RestUtils.initHttpConnection( this, hostConfig, jets3tProperties, this.invokingApplicationDescription, this.credentialsProvider); this.httpClient = initHttpResult.getHttpClient(); // Retrieve Proxy settings. if (this.jets3tProperties.getBoolProperty("httpclient.proxy-autodetect", true)) { RestUtils.initHttpProxy(this.httpClient, this.jets3tProperties); } else { String proxyHostAddress = this.jets3tProperties.getStringProperty("httpclient.proxy-host", null); int proxyPort = this.jets3tProperties.getIntProperty("httpclient.proxy-port", -1); String proxyUser = this.jets3tProperties.getStringProperty("httpclient.proxy-user", null); String proxyPassword = this.jets3tProperties.getStringProperty("httpclient.proxy-password", null); String proxyDomain = this.jets3tProperties.getStringProperty("httpclient.proxy-domain", null); RestUtils.initHttpProxy(this.httpClient, this.jets3tProperties, proxyHostAddress, proxyPort, proxyUser, proxyPassword, proxyDomain); } /* TODO: CloudFront service does not seem to support 100-continue protocol for 2009-04-02 * DistributionConfig updates, causing unnecessary timeouts when updating these settings. * This will probably be fixed, remove the following line when full support returns. */ this.httpClient.getParams().setBooleanParameter("http.protocol.expect-continue", false); } /** * Constructs the service with default properties. * * @param credentials * the Storage Provider user credentials to use when communicating with CloudFront * * @throws CloudFrontServiceException */ public CloudFrontService(ProviderCredentials credentials) throws CloudFrontServiceException { this(credentials, null, null, null, null); } /** * @return the Storage Provider Credentials identifying the AWS user. */ public ProviderCredentials getAWSCredentials() { return credentials; } /** * Returns the current date and time, adjusted according to the time * offset between your computer and an AWS server (as set by the * {@link RestUtils#getAWSTimeAdjustment()} method). * * @return * the current time, or the current time adjusted to match the AWS time * if the service has experienced a RequestExpired error. */ protected Date getCurrentTimeWithOffset() { return new Date(System.currentTimeMillis() + timeOffset); } /** * Sign the given HTTP method object using the AWS credentials provided * by {@link #getAWSCredentials()}. * * @param httpMethod * the request object * @throws Exception */ public void authorizeHttpRequest(HttpMethod httpMethod) throws Exception { String date = ServiceUtils.formatRfc822Date(getCurrentTimeWithOffset()); // Set/update the date timestamp to the current time // Note that this will be over-ridden if an "x-amz-date" header is present. httpMethod.setRequestHeader("Date", date); // Sign the date to authenticate the request. // Sign the canonical string. String signature = ServiceUtils.signWithHmacSha1( getAWSCredentials().getSecretKey(), date); // Add encoded authorization to connection as HTTP Authorization header. String authorizationString = "AWS " + getAWSCredentials().getAccessKey() + ":" + signature; httpMethod.setRequestHeader("Authorization", authorizationString); } /** * Performs an HTTP/S request by invoking the provided HttpMethod object. If the HTTP * response code doesn't match the expected value, an exception is thrown. * * @param httpMethod * the object containing a request target and all other information necessary to * perform the request * @param expectedResponseCode * the HTTP response code that indicates a successful request. If the response code received * does not match this value an error must have occurred, so an exception is thrown. * @throws CloudFrontServiceException * all exceptions are wrapped in a CloudFrontServiceException. Depending on the kind of error that * occurred, this exception may contain additional error information available from an XML * error response document. */ protected void performRestRequest(HttpMethod httpMethod, int expectedResponseCode) throws CloudFrontServiceException { // Set mandatory Request headers. if (httpMethod.getRequestHeader("Date") == null) { httpMethod.setRequestHeader("Date", ServiceUtils.formatRfc822Date( getCurrentTimeWithOffset())); } boolean completedWithoutRecoverableError = true; int internalErrorCount = 0; try { do { completedWithoutRecoverableError = true; authorizeHttpRequest(httpMethod); int responseCode = httpClient.executeMethod(httpMethod); if (responseCode != expectedResponseCode) { if (responseCode == 500) { // Retry on Internal Server errors, up to the defined limit. long delayMs = 1000; if (++internalErrorCount < this.internalErrorRetryMax) { log.warn("Encountered " + internalErrorCount + " CloudFront Internal Server error(s), will retry in " + delayMs + "ms"); Thread.sleep(delayMs); completedWithoutRecoverableError = false; } else { throw new CloudFrontServiceException("Encountered too many CloudFront Internal Server errors (" + internalErrorCount + "), aborting request."); } } else { // Parse XML error message. ErrorHandler handler = (new CloudFrontXmlResponsesSaxParser(this.jets3tProperties)) .parseErrorResponse(httpMethod.getResponseBodyAsStream()); CloudFrontServiceException exception = new CloudFrontServiceException( "Request failed with CloudFront Service error", responseCode, handler.getType(), handler.getCode(), handler.getMessage(), handler.getDetail(), handler.getRequestId()); if ("RequestExpired".equals(exception.getErrorCode())) { // Retry on time skew errors. this.timeOffset = RestUtils.getAWSTimeAdjustment(); if (log.isWarnEnabled()) { log.warn("Adjusted time offset in response to RequestExpired error. " + "Local machine and CloudFront server disagree on the time by approximately " + (this.timeOffset / 1000) + " seconds. Retrying connection."); } completedWithoutRecoverableError = false; } else { throw exception; } } } // End responseCode check } while (!completedWithoutRecoverableError); } catch (CloudFrontServiceException e) { httpMethod.releaseConnection(); throw e; } catch (Throwable t) { httpMethod.releaseConnection(); throw new CloudFrontServiceException("CloudFront Request failed", t); } } /** * List streaming or non-streaming Distributions in a CloudFront account. * @param isStreaming * @param pagingSize * @return * A list of {@link Distribution}s. * @throws CloudFrontServiceException */ protected List listDistributionsImpl(boolean isStreaming, int pagingSize) throws CloudFrontServiceException { if (log.isDebugEnabled()) { log.debug("Listing " + (isStreaming ? "streaming" : "") + " distributions for AWS user: " + getAWSCredentials().getAccessKey()); } try { List distributions = new ArrayList(); String nextMarker = null; boolean incompleteListing = true; do { String uri = ENDPOINT + VERSION + (isStreaming ? "/streaming-distribution" : "/distribution") + "?MaxItems=" + pagingSize; if (nextMarker != null) { uri += "&Marker=" + nextMarker; } HttpMethod httpMethod = new GetMethod(uri); performRestRequest(httpMethod, 200); DistributionListHandler handler = (new CloudFrontXmlResponsesSaxParser(this.jets3tProperties)) .parseDistributionListResponse(httpMethod.getResponseBodyAsStream()); distributions.addAll(handler.getDistributions()); incompleteListing = handler.isTruncated(); nextMarker = handler.getNextMarker(); // Sanity check for valid pagination values. if (incompleteListing && nextMarker == null) { throw new CloudFrontServiceException("Unable to retrieve paginated " + "DistributionList results without a valid NextMarker value."); } } while (incompleteListing); return distributions; } catch (CloudFrontServiceException e) { throw e; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new CloudFrontServiceException(e); } } /** * List all your standard CloudFront distributions, with a given maximum * number of Distribution items in each "page" of results. * * @param pagingSize * the maximum number of distributions the CloudFront service will * return in each response message. * @return * a list of your distributions. * * @throws CloudFrontServiceException */ public Distribution[] listDistributions(int pagingSize) throws CloudFrontServiceException { List distributions = listDistributionsImpl(false, pagingSize); return distributions.toArray(new Distribution[distributions.size()]); } /** * List all your streaming CloudFront distributions, with a given maximum * number of Distribution items in each "page" of results. * * @param pagingSize * the maximum number of distributions the CloudFront service will * return in each response message. * @return * a list of your distributions. * * @throws CloudFrontServiceException */ public StreamingDistribution[] listStreamingDistributions(int pagingSize) throws CloudFrontServiceException { List distributions = listDistributionsImpl(true, pagingSize); return distributions.toArray( new StreamingDistribution[distributions.size()]); } /** * List all your standard CloudFront distributions. * * @return * a list of your distributions. * * @throws CloudFrontServiceException */ public Distribution[] listDistributions() throws CloudFrontServiceException { return listDistributions(100); } /** * List all your streaming CloudFront distributions. * * @return * a list of your streaming distributions. * * @throws CloudFrontServiceException */ public StreamingDistribution[] listStreamingDistributions() throws CloudFrontServiceException { return listStreamingDistributions(100); } /** * List streaming or non-stream distributions whose origin is the given S3 bucket name. * * @param bucketName * the name of the S3 bucket whose distributions will be returned. * @return * a list of distributions applied to the given S3 bucket, or an empty list * if there are no such distributions. * * @throws CloudFrontServiceException */ public List listDistributionsByBucketName(boolean isStreaming, String bucketName) throws CloudFrontServiceException { String s3Endpoint = this.jets3tProperties.getStringProperty( "s3service.s3-endpoint", Constants.S3_DEFAULT_HOSTNAME); if (log.isDebugEnabled()) { log.debug("Listing " + (isStreaming ? "streaming" : "") + " distributions for the S3 bucket '" + bucketName + "' for AWS user: " + getAWSCredentials().getAccessKey()); } ArrayList bucketDistributions = new ArrayList(); Distribution[] allDistributions = (isStreaming ? listStreamingDistributions() : listDistributions()); for (int i = 0; i < allDistributions.length; i++) { Origin origin = allDistributions[i].getOrigin(); if (!(origin instanceof S3Origin)) { continue; } S3Origin s3Origin = (S3Origin) origin; if (s3Origin.getDnsName().equals(bucketName) || bucketName.equals(ServiceUtils.findBucketNameInHostname(s3Origin.getDnsName(), s3Endpoint))) { bucketDistributions.add(allDistributions[i]); } } return bucketDistributions; } /** * List the distributions whose origin is the given S3 bucket name. * * @param bucketName * the name of the S3 bucket whose distributions will be returned. * @return * a list of distributions applied to the given S3 bucket, or an empty list * if there are no such distributions. * * @throws CloudFrontServiceException */ public Distribution[] listDistributions(String bucketName) throws CloudFrontServiceException { List bucketDistributions = listDistributionsByBucketName(false, bucketName); return bucketDistributions.toArray( new Distribution[bucketDistributions.size()]); } /** * List the streaming distributions whose origin is the given S3 bucket name. * * @param bucketName * the name of the S3 bucket whose distributions will be returned. * @return * a list of distributions applied to the given S3 bucket, or an empty list * if there are no such distributions. * * @throws CloudFrontServiceException */ public StreamingDistribution[] listStreamingDistributions(String bucketName) throws CloudFrontServiceException { List streamingDistributions = listDistributionsByBucketName(true, bucketName); return streamingDistributions.toArray( new StreamingDistribution[streamingDistributions.size()]); } /** * Generate XML representing an S3 or non-S3 (custom) origin. * * @param origin * @return * XML document representing an origin * * @throws TransformerException * @throws ParserConfigurationException * @throws FactoryConfigurationError */ protected XMLBuilder buildOrigin(Origin origin) throws TransformerException, ParserConfigurationException, FactoryConfigurationError { if (origin instanceof S3Origin) { S3Origin o = (S3Origin) origin; XMLBuilder builder = XMLBuilder.create("S3Origin") .e("DNSName").t(sanitizeS3BucketName(origin.getDnsName())).up(); if (o.getOriginAccessIdentity() != null) { builder.e("OriginAccessIdentity").t(o.getOriginAccessIdentity()); } return builder; } else { CustomOrigin o = (CustomOrigin) origin; return XMLBuilder.create("CustomOrigin") .e("DNSName").t(origin.getDnsName()).up() .e("HTTPPort").t("" + o.getHttpPort()).up() .e("HTTPSPort").t("" + o.getHttpsPort()).up() .e("OriginProtocolPolicy").t(o.getOriginProtocolPolicy().toText()); } } /** * Generate a DistributionConfig or StreamingDistributionConfig XML document. * * @param isStreamingDistribution * @param origin * @param callerReference * @param cnames * @param comment * @param enabled * @param loggingStatus * @param trustedSignerSelf * @param trustedSignerAwsAccountNumbers * @param requiredProtocols * @param defaultRootObject * @return * XML document representing a Distribution Configuration * @throws TransformerException * @throws ParserConfigurationException * @throws FactoryConfigurationError */ protected String buildDistributionConfigXmlDocument(boolean isStreamingDistribution, Origin origin, String callerReference, String[] cnames, String comment, boolean enabled, LoggingStatus loggingStatus, boolean trustedSignerSelf, String[] trustedSignerAwsAccountNumbers, String[] requiredProtocols, String defaultRootObject) throws TransformerException, ParserConfigurationException, FactoryConfigurationError { XMLBuilder builder = XMLBuilder.create( isStreamingDistribution ? "StreamingDistributionConfig" : "DistributionConfig") .a("xmlns", XML_NAMESPACE); builder.importXMLBuilder(buildOrigin(origin)); builder.e("CallerReference").t(callerReference).up(); for (int i = 0; i < cnames.length; i++) { builder.e("CNAME").t(cnames[i]).up(); } builder .e("Comment").t(comment).up() .e("Enabled").t("" + enabled); if (defaultRootObject != null) { builder.e("DefaultRootObject").t(defaultRootObject).up(); } if (trustedSignerSelf || (trustedSignerAwsAccountNumbers != null && trustedSignerAwsAccountNumbers.length > 0)) { XMLBuilder trustedSigners = builder.e("TrustedSigners"); if (trustedSignerSelf) { trustedSigners.e("Self"); } for (int i = 0; trustedSignerAwsAccountNumbers != null && i < trustedSignerAwsAccountNumbers.length; i++) { trustedSigners.e("AWSAccountNumber") .t(trustedSignerAwsAccountNumbers[i]); } builder.up(); } if (loggingStatus != null) { builder.e("Logging") .e("Bucket").t(loggingStatus.getBucket()).up() .e("Prefix").t(loggingStatus.getPrefix()).up() .up(); } if (requiredProtocols != null && requiredProtocols.length > 0) { XMLBuilder rpsBuilder = builder.e("RequiredProtocols"); for (int i = 0; i < requiredProtocols.length; i++) { rpsBuilder.e("Protocol").t(requiredProtocols[i]).up(); } } return builder.asString(null); } /** * Create a streaming or non-streaming distribution. * @param isStreaming * @param origin * @param callerReference * @param cnames * @param comment * @param enabled * @param loggingStatus * @param trustedSignerSelf * @param trustedSignerAwsAccountNumbers * @param requiredProtocols * @param defaultRootObject * * @return * Information about the newly-created distribution. * @throws CloudFrontServiceException */ protected Distribution createDistributionImpl( boolean isStreaming, Origin origin, String callerReference, String[] cnames, String comment, boolean enabled, LoggingStatus loggingStatus, boolean trustedSignerSelf, String[] trustedSignerAwsAccountNumbers, String[] requiredProtocols, String defaultRootObject) throws CloudFrontServiceException { if (log.isDebugEnabled()) { log.debug("Creating " + (isStreaming ? "streaming" : "") + " distribution for origin: " + origin); } // Sanitize parameters. if (callerReference == null) { callerReference = "" + System.currentTimeMillis(); } if (cnames == null) { cnames = new String[] {}; } if (comment == null) { comment = ""; } PostMethod httpMethod = new PostMethod(ENDPOINT + VERSION + (isStreaming ? "/streaming-distribution" : "/distribution")); try { String distributionConfigXml = buildDistributionConfigXmlDocument( isStreaming, origin, callerReference, cnames, comment, enabled, loggingStatus, trustedSignerSelf, trustedSignerAwsAccountNumbers, requiredProtocols, defaultRootObject); httpMethod.setRequestEntity( new StringRequestEntity(distributionConfigXml, "text/xml", Constants.DEFAULT_ENCODING)); performRestRequest(httpMethod, 201); DistributionHandler handler = (new CloudFrontXmlResponsesSaxParser(this.jets3tProperties)) .parseDistributionResponse(httpMethod.getResponseBodyAsStream()); return handler.getDistribution(); } catch (CloudFrontServiceException e) { throw e; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new CloudFrontServiceException(e); } } /** * Create a public or private CloudFront distribution for an S3 bucket. * * @param origin * the origin to associate with the distribution, either an Amazon S3 bucket or * a custom HTTP/S-accessible location. * @param callerReference * A user-set unique reference value that ensures the request can't be replayed * (max UTF-8 encoding size 128 bytes). This parameter may be null, in which * case your computer's local epoch time in milliseconds will be used. * @param cnames * A list of up to 10 CNAME aliases to associate with the distribution. This * parameter may be a null or empty array. * @param comment * An optional comment to describe the distribution in your own terms * (max 128 characters). May be null. * @param enabled * Should the distribution should be enabled and publicly accessible upon creation? * @param loggingStatus * Logging status settings (bucket, prefix) for the distribution. If this value * is null, logging will be disabled for the distribution. * @param trustedSignerSelf * If true the owner of the distribution (you) will be be allowed to generate * signed URLs for a private distribution. Note: If either trustedSignerSelf or * trustedSignerAwsAccountNumbers parameters are provided the private distribution * will require signed URLs to access content. * @param trustedSignerAwsAccountNumbers * Account Number identifiers for AWS account holders other than the * distribution's owner who will be allowed to generate signed URLs for a private * distribution. If null or empty, no additional AWS account holders may generate * signed URLs. Note: If either trustedSignerSelf or * trustedSignerAwsAccountNumbers parameters are provided the private distribution * will require signed URLs to access content. * @param requiredProtocols * List of protocols that must be used by clients to retrieve content from the * distribution. If this value is null or is an empty array, all protocols will be * supported. * @param defaultRootObject * The name of an object that will be served when someone visits the root of a * distribution. * * @return * an object that describes the newly-created distribution, in particular the * distribution's identifier and domain name values. * * @throws CloudFrontServiceException */ public Distribution createDistribution(Origin origin, String callerReference, String[] cnames, String comment, boolean enabled, LoggingStatus loggingStatus, boolean trustedSignerSelf, String[] trustedSignerAwsAccountNumbers, String[] requiredProtocols, String defaultRootObject) throws CloudFrontServiceException { return createDistributionImpl(false, origin, callerReference, cnames, comment, enabled, loggingStatus, trustedSignerSelf, trustedSignerAwsAccountNumbers, requiredProtocols, defaultRootObject); } /** * Create a minimally-configured CloudFront distribution for an S3 bucket that will * be publicly available once created. * * @param origin * the origin to associate with the distribution, either an Amazon S3 bucket or * a custom HTTP/S-accessible location. * * @return * an object that describes the newly-created distribution, in particular the * distribution's identifier and domain name values. * * @throws CloudFrontServiceException */ public Distribution createDistribution(Origin origin) throws CloudFrontServiceException { return this.createDistribution(origin, null, null, null, true, null); } /** * Create a public CloudFront distribution for an S3 bucket. * * @param origin * the origin to associate with the distribution, either an Amazon S3 bucket or * a custom HTTP/S-accessible location. * @param callerReference * A user-set unique reference value that ensures the request can't be replayed * (max UTF-8 encoding size 128 bytes). This parameter may be null, in which * case your computer's local epoch time in milliseconds will be used. * @param cnames * A list of up to 10 CNAME aliases to associate with the distribution. This * parameter may be a null or empty array. * @param comment * An optional comment to describe the distribution in your own terms * (max 128 characters). May be null. * @param enabled * Should the distribution should be enabled and publicly accessible upon creation? * @param loggingStatus * Logging status settings (bucket, prefix) for the distribution. If this value * is null, logging will be disabled for the distribution. * * @return * an object that describes the newly-created distribution, in particular the * distribution's identifier and domain name values. * * @throws CloudFrontServiceException */ public Distribution createDistribution(Origin origin, String callerReference, String[] cnames, String comment, boolean enabled, LoggingStatus loggingStatus) throws CloudFrontServiceException { return createDistribution(origin, callerReference, cnames, comment, enabled, loggingStatus, false, null, null, null); } /** * Create a public or private CloudFront distribution for an S3 bucket based * on a pre-configured {@link DistributionConfig}. * * @param config * Configuration settings to apply to the distribution. * * @return * an object that describes the newly-created distribution, in particular the * distribution's identifier and domain name values. * * @throws CloudFrontServiceException */ public Distribution createDistribution(DistributionConfig config) throws CloudFrontServiceException { return createDistribution(config.getOrigin(), config.getCallerReference(), config.getCNAMEs(), config.getComment(), config.isEnabled(), config.getLoggingStatus(), config.isTrustedSignerSelf(), config.getTrustedSignerAwsAccountNumbers(), config.getRequiredProtocols(), config.getDefaultRootObject()); } /** * Create a public or private streaming CloudFront distribution for an S3 bucket. * * @param origin * the origin to associate with the distribution, either an Amazon S3 bucket or * a custom HTTP/S-accessible location. * @param callerReference * A user-set unique reference value that ensures the request can't be replayed * (max UTF-8 encoding size 128 bytes). This parameter may be null, in which * case your computer's local epoch time in milliseconds will be used. * @param cnames * A list of up to 10 CNAME aliases to associate with the distribution. This * parameter may be a null or empty array. * @param comment * An optional comment to describe the distribution in your own terms * (max 128 characters). May be null. * @param enabled * Should the distribution should be enabled and publicly accessible upon creation? * @param loggingStatus * Logging status settings (bucket, prefix) for the distribution. If this value * is null, logging will be disabled for the distribution. * @param trustedSignerSelf * If true the owner of the distribution (you) will be be allowed to generate * signed URLs for a private distribution. Note: If either trustedSignerSelf or * trustedSignerAwsAccountNumbers parameters are provided the private distribution * will require signed URLs to access content. * @param trustedSignerAwsAccountNumbers * Account Number identifiers for AWS account holders other than the * distribution's owner who will be allowed to generate signed URLs for a private * distribution. If null or empty, no additional AWS account holders may generate * signed URLs. Note: If either trustedSignerSelf or * trustedSignerAwsAccountNumbers parameters are provided the private distribution * will require signed URLs to access content. * * @return * an object that describes the newly-created distribution, in particular the * distribution's identifier and domain name values. * * @throws CloudFrontServiceException */ public StreamingDistribution createStreamingDistribution(Origin origin, String callerReference, String[] cnames, String comment, boolean enabled, LoggingStatus loggingStatus, boolean trustedSignerSelf, String[] trustedSignerAwsAccountNumbers) throws CloudFrontServiceException { return (StreamingDistribution) createDistributionImpl(true, origin, callerReference, cnames, comment, enabled, loggingStatus, trustedSignerSelf, trustedSignerAwsAccountNumbers, null, null); } /** * Create a public streaming CloudFront distribution for an S3 bucket. * * @param origin * the origin to associate with the distribution, either an Amazon S3 bucket or * a custom HTTP/S-accessible location. * @param callerReference * A user-set unique reference value that ensures the request can't be replayed * (max UTF-8 encoding size 128 bytes). This parameter may be null, in which * case your computer's local epoch time in milliseconds will be used. * @param cnames * A list of up to 10 CNAME aliases to associate with the distribution. This * parameter may be a null or empty array. * @param comment * An optional comment to describe the distribution in your own terms * (max 128 characters). May be null. * @param enabled * Should the distribution should be enabled and publicly accessible upon creation? * @param loggingStatus * Logging status settings (bucket, prefix) for the distribution. If this value * is null, logging will be disabled for the distribution. * * @return * an object that describes the newly-created distribution, in particular the * distribution's identifier and domain name values. * * @throws CloudFrontServiceException */ public StreamingDistribution createStreamingDistribution(Origin origin, String callerReference, String[] cnames, String comment, boolean enabled, LoggingStatus loggingStatus) throws CloudFrontServiceException { return (StreamingDistribution) createDistributionImpl(true, origin, callerReference, cnames, comment, enabled, loggingStatus, false, null, null, null); } /** * @param isStreaming * @param id * @return * Information about a streaming or non-streaming distribution. * @throws CloudFrontServiceException */ protected Distribution getDistributionInfoImpl(boolean isStreaming, String id) throws CloudFrontServiceException { if (log.isDebugEnabled()) { log.debug("Getting information for " + (isStreaming ? "streaming" : "") + " distribution with id: " + id); } GetMethod httpMethod = new GetMethod(ENDPOINT + VERSION + (isStreaming ? "/streaming-distribution/" : "/distribution/") + id); try { performRestRequest(httpMethod, 200); DistributionHandler handler = (new CloudFrontXmlResponsesSaxParser(this.jets3tProperties)) .parseDistributionResponse(httpMethod.getResponseBodyAsStream()); return handler.getDistribution(); } catch (CloudFrontServiceException e) { throw e; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new CloudFrontServiceException(e); } } /** * Lookup information for a standard distribution. * * @param id * the distribution's unique identifier. * * @return * an object that describes the distribution, including its identifier and domain * name values as well as its configuration details. * * @throws CloudFrontServiceException */ public Distribution getDistributionInfo(String id) throws CloudFrontServiceException { return getDistributionInfoImpl(false, id); } /** * Lookup information for a streaming distribution. * * @param id * the distribution's unique identifier. * * @return * an object that describes the distribution, including its identifier and domain * name values as well as its configuration details. * * @throws CloudFrontServiceException */ public StreamingDistribution getStreamingDistributionInfo(String id) throws CloudFrontServiceException { return (StreamingDistribution) getDistributionInfoImpl(true, id); } /** * @param isStreaming * @param id * @return * Information about a streaming or non-streaming distribution configuration. * @throws CloudFrontServiceException */ protected DistributionConfig getDistributionConfigImpl(boolean isStreaming, String id) throws CloudFrontServiceException { if (log.isDebugEnabled()) { log.debug("Getting configuration for " + (isStreaming ? "streaming" : "") + " distribution with id: " + id); } GetMethod httpMethod = new GetMethod(ENDPOINT + VERSION + (isStreaming ? "/streaming-distribution/" : "/distribution/") + id + "/config"); try { performRestRequest(httpMethod, 200); DistributionConfigHandler handler = (new CloudFrontXmlResponsesSaxParser(this.jets3tProperties)) .parseDistributionConfigResponse(httpMethod.getResponseBodyAsStream()); DistributionConfig config = handler.getDistributionConfig(); config.setEtag(httpMethod.getResponseHeader("ETag").getValue()); return config; } catch (CloudFrontServiceException e) { throw e; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new CloudFrontServiceException(e); } } /** * Lookup configuration information for a standard distribution. The configuration * information is a subset of the information available from the * {@link #getDistributionInfo(String)} method. * * @param id * the distribution's unique identifier. * * @return * an object that describes the distribution's configuration, including its origin bucket * and CNAME aliases. * * @throws CloudFrontServiceException */ public DistributionConfig getDistributionConfig(String id) throws CloudFrontServiceException { return getDistributionConfigImpl(false, id); } /** * Lookup configuration information for a streaming distribution. The configuration * information is a subset of the information available from the * {@link #getDistributionInfo(String)} method. * * @param id * the distribution's unique identifier. * * @return * an object that describes the distribution's configuration, including its origin bucket * and CNAME aliases. * * @throws CloudFrontServiceException */ public StreamingDistributionConfig getStreamingDistributionConfig(String id) throws CloudFrontServiceException { return (StreamingDistributionConfig) getDistributionConfigImpl(true, id); } /** * Update a streaming or non-streaming distribution. * @param isStreaming * @param id * @param cnames * @param comment * @param enabled * @param loggingStatus * @param trustedSignerSelf * @param trustedSignerAwsAccountNumbers * @param requiredProtocols * @param defaultRootObject * @return * Information about the updated distribution configuration. * @throws CloudFrontServiceException */ protected DistributionConfig updateDistributionConfigImpl( boolean isStreaming, String id, Origin origin, String[] cnames, String comment, boolean enabled, LoggingStatus loggingStatus, boolean trustedSignerSelf, String[] trustedSignerAwsAccountNumbers, String[] requiredProtocols, String defaultRootObject) throws CloudFrontServiceException { if (log.isDebugEnabled()) { log.debug("Updating configuration of " + (isStreaming ? "streaming" : "") + "distribution with id: " + id); } // Retrieve the old configuration. DistributionConfig oldConfig = (isStreaming ? getStreamingDistributionConfig(id) : getDistributionConfig(id)); // Sanitize parameters. if (cnames == null) { cnames = oldConfig.getCNAMEs(); } if (comment == null) { comment = oldConfig.getComment(); } if (origin == null) { origin = oldConfig.getOrigin(); } PutMethod httpMethod = new PutMethod(ENDPOINT + VERSION + (isStreaming ? "/streaming-distribution/" : "/distribution/") + id + "/config"); try { String distributionConfigXml = buildDistributionConfigXmlDocument(isStreaming, origin, oldConfig.getCallerReference(), cnames, comment, enabled, loggingStatus, trustedSignerSelf, trustedSignerAwsAccountNumbers, requiredProtocols, defaultRootObject); httpMethod.setRequestEntity( new StringRequestEntity(distributionConfigXml, "text/xml", Constants.DEFAULT_ENCODING)); httpMethod.setRequestHeader("If-Match", oldConfig.getEtag()); performRestRequest(httpMethod, 200); DistributionConfigHandler handler = (new CloudFrontXmlResponsesSaxParser(this.jets3tProperties)) .parseDistributionConfigResponse(httpMethod.getResponseBodyAsStream()); DistributionConfig config = handler.getDistributionConfig(); config.setEtag(httpMethod.getResponseHeader("ETag").getValue()); return config; } catch (CloudFrontServiceException e) { throw e; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new CloudFrontServiceException(e); } } /** * Update the configuration of an existing distribution to change its properties * or public/private status. The new configuration properties provided * replace any existing configuration, and may take some time * to be fully applied. *

* This method performs all the steps necessary to update the configuration. It * first performs lookup on the distribution using * {@link #getDistributionConfig(String)} to find its origin and caller reference * values, then uses this information to apply your configuration changes. * * @param id * the distribution's unique identifier. * @param cnames * A list of up to 10 CNAME aliases to associate with the distribution. This * parameter may be null, in which case the original CNAME aliases are retained. * @param comment * An optional comment to describe the distribution in your own terms * (max 128 characters). May be null, in which case the original comment is retained. * @param enabled * Should the distribution should be enabled and publicly accessible after the * configuration update? * @param loggingStatus * Logging status settings (bucket, prefix) for the distribution. If this value * is null, logging will be disabled for the distribution. * @param trustedSignerSelf * If true the owner of the distribution (you) will be be allowed to generate * signed URLs for a private distribution. Note: If either trustedSignerSelf or * trustedSignerAwsAccountNumbers parameters are provided the private distribution * will require signed URLs to access content. * @param trustedSignerAwsAccountNumbers * Account Number identifiers for AWS account holders other than the * distribution's owner who will be allowed to generate signed URLs for a private * distribution. If null or empty, no additional AWS account holders may generate * signed URLs. Note: If either trustedSignerSelf or * trustedSignerAwsAccountNumbers parameters are provided the private distribution * will require signed URLs to access content. * @param requiredProtocols * List of protocols that must be used by clients to retrieve content from the * distribution. If this value is null or is an empty array all protocols will be * permitted. * @param defaultRootObject * The name of an object that will be served when someone visits the root of a * distribution. * * @return * an object that describes the distribution's updated configuration, including its * origin bucket and CNAME aliases. * * @throws CloudFrontServiceException */ public DistributionConfig updateDistributionConfig(String id, Origin origin, String[] cnames, String comment, boolean enabled, LoggingStatus loggingStatus, boolean trustedSignerSelf, String[] trustedSignerAwsAccountNumbers, String[] requiredProtocols, String defaultRootObject) throws CloudFrontServiceException { return updateDistributionConfigImpl(false, id, origin, cnames, comment, enabled, loggingStatus, trustedSignerSelf, trustedSignerAwsAccountNumbers, requiredProtocols, defaultRootObject); } /** * Update the configuration of an existing streaming distribution to change its * properties. The new configuration properties provided replace * any existing configuration, and may take some time to be fully applied. *

* This method performs all the steps necessary to update the configuration. It * first performs lookup on the distribution using * {@link #getDistributionConfig(String)} to find its origin and caller reference * values, then uses this information to apply your configuration changes. * * @param id * the distribution's unique identifier. * @param cnames * A list of up to 10 CNAME aliases to associate with the distribution. This * parameter may be null, in which case the original CNAME aliases are retained. * @param comment * An optional comment to describe the distribution in your own terms * (max 128 characters). May be null, in which case the original comment is retained. * @param enabled * Should the distribution should be enabled and publicly accessible after the * configuration update? * @param loggingStatus * Logging status settings (bucket, prefix) for the distribution. If this value * is null, logging will be disabled for the distribution. * * @return * an object that describes the distribution's updated configuration, including its * origin bucket and CNAME aliases. * * @throws CloudFrontServiceException */ public StreamingDistributionConfig updateStreamingDistributionConfig( String id, Origin origin, String[] cnames, String comment, boolean enabled, LoggingStatus loggingStatus) throws CloudFrontServiceException { return (StreamingDistributionConfig) updateDistributionConfigImpl( true, id, origin, cnames, comment, enabled, loggingStatus, false, null, null, null); } /** * Update the configuration of an existing streaming distribution to change its * properties. The new configuration properties provided replace * any existing configuration, and may take some time to be fully applied. *

* This method performs all the steps necessary to update the configuration. It * first performs lookup on the distribution using * {@link #getDistributionConfig(String)} to find its origin and caller reference * values, then uses this information to apply your configuration changes. * * @param id * the distribution's unique identifier. * @param cnames * A list of up to 10 CNAME aliases to associate with the distribution. This * parameter may be null, in which case the original CNAME aliases are retained. * @param comment * An optional comment to describe the distribution in your own terms * (max 128 characters). May be null, in which case the original comment is retained. * @param enabled * Should the distribution should be enabled and publicly accessible after the * configuration update? * @param loggingStatus * Logging status settings (bucket, prefix) for the distribution. If this value * is null, logging will be disabled for the distribution. * @param origin * the origin to associate with the distribution, either an Amazon S3 bucket or * a custom HTTP/S-accessible location. * @param trustedSignerSelf * If true the owner of the distribution (you) will be be allowed to generate * signed URLs for a private distribution. Note: If either trustedSignerSelf or * trustedSignerAwsAccountNumbers parameters are provided the private distribution * will require signed URLs to access content. * @param trustedSignerAwsAccountNumbers * Account Number identifiers for AWS account holders other than the * distribution's owner who will be allowed to generate signed URLs for a private * distribution. If null or empty, no additional AWS account holders may generate * signed URLs. Note: If either trustedSignerSelf or * trustedSignerAwsAccountNumbers parameters are provided the private distribution * will require signed URLs to access content. * * @return * an object that describes the distribution's updated configuration, including its * origin bucket and CNAME aliases. * * @throws CloudFrontServiceException */ public StreamingDistributionConfig updateStreamingDistributionConfig( String id, Origin origin, String[] cnames, String comment, boolean enabled, LoggingStatus loggingStatus, boolean trustedSignerSelf, String[] trustedSignerAwsAccountNumbers) throws CloudFrontServiceException { return (StreamingDistributionConfig) updateDistributionConfigImpl( true, id, origin, cnames, comment, enabled, loggingStatus, trustedSignerSelf, trustedSignerAwsAccountNumbers, null, null); } /** * Update the configuration of an existing distribution to change its properties. * If the original distribution is private this method will make it public instead. * The new configuration properties provided replace any existing * configuration, and may take some time to be fully applied. *

* This method performs all the steps necessary to update the configuration. It * first performs lookup on the distribution using * {@link #getDistributionConfig(String)} to find its origin and caller reference * values, then uses this information to apply your configuration changes. * * @param id * the distribution's unique identifier. * @param cnames * A list of up to 10 CNAME aliases to associate with the distribution. This * parameter may be null, in which case the original CNAME aliases are retained. * @param comment * An optional comment to describe the distribution in your own terms * (max 128 characters). May be null, in which case the original comment is retained. * @param enabled * Should the distribution should be enabled and publicly accessible after the * configuration update? * @param loggingStatus * Logging status settings (bucket, prefix) for the distribution. If this value * is null, logging will be disabled for the distribution. * * @return * an object that describes the distribution's updated configuration, including its * origin bucket and CNAME aliases. * * @throws CloudFrontServiceException */ public DistributionConfig updateDistributionConfig(String id, Origin origin, String[] cnames, String comment, boolean enabled, LoggingStatus loggingStatus) throws CloudFrontServiceException { return updateDistributionConfig(id, origin, cnames, comment, enabled, loggingStatus, false, null, null, null); } /** * Update the configuration of an existing distribution to change its properties * or public/private status. The new configuration properties provided * replace any existing configuration, and may take some time * to be fully applied. *

* This method performs all the steps necessary to update the configuration. It * first performs lookup on the distribution using * {@link #getDistributionConfig(String)} to find its origin and caller reference * values, then uses this information to apply your configuration changes. * * @param id * the distribution's unique identifier. * @param config * Configuration properties to apply to the distribution. * * @return * an object that describes the distribution's updated configuration, including its * origin bucket and CNAME aliases. * * @throws CloudFrontServiceException */ public DistributionConfig updateDistributionConfig(String id, DistributionConfig config) throws CloudFrontServiceException { return updateDistributionConfig(id, config.getOrigin(), config.getCNAMEs(), config.getComment(), config.isEnabled(), config.getLoggingStatus(), config.isTrustedSignerSelf(), config.getTrustedSignerAwsAccountNumbers(), config.getRequiredProtocols(), config.getDefaultRootObject()); } /** * Convenience method to disable a distribution that you intend to delete. * This method merely calls the * {@link #updateDistributionConfig(String, Origin, String[], String, boolean, LoggingStatus)} * method with default values for most of the distribution's configuration * settings. *

* Warning: Do not use this method on distributions you * intend to keep, because it will reset most of the distribution's * configuration settings such as CNAMEs and logging status. * * @param id * the distribution's unique identifier. * * @throws CloudFrontServiceException */ public void disableDistributionForDeletion(String id) throws CloudFrontServiceException { updateDistributionConfig(id, null, new String[] {}, "Disabled prior to deletion", false, null); } /** * Convenience method to disable a streaming distribution that you intend to delete. * This method merely calls the * {@link #updateStreamingDistributionConfig(String, Origin, String[], String, boolean, LoggingStatus)} * method with default values for most of the distribution's configuration * settings. *

* Warning: Do not use this method on distributions you * intend to keep, because it will reset most of the distribution's * configuration settings such as CNAMEs and logging status. * * @param id * the distribution's unique identifier. * * @throws CloudFrontServiceException */ public void disableStreamingDistributionForDeletion(String id) throws CloudFrontServiceException { updateStreamingDistributionConfig(id, null, new String[] {}, "Disabled prior to deletion", false, // enabled? null // LoggingStatus ); } /** * Delete a streaming or non-streaming distribution. * @param isStreaming * @param id * @throws CloudFrontServiceException */ protected void deleteDistributionImpl(boolean isStreaming, String id) throws CloudFrontServiceException { if (log.isDebugEnabled()) { log.debug("Deleting " + (isStreaming ? "streaming" : "") + "distribution with id: " + id); } // Get the distribution's current config. DistributionConfig currentConfig = (isStreaming ? getStreamingDistributionConfig(id) : getDistributionConfig(id)); DeleteMethod httpMethod = new DeleteMethod(ENDPOINT + VERSION + (isStreaming ? "/streaming-distribution/" : "/distribution/") + id); try { httpMethod.setRequestHeader("If-Match", currentConfig.getEtag()); performRestRequest(httpMethod, 204); } catch (CloudFrontServiceException e) { throw e; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new CloudFrontServiceException(e); } } /** * Delete a disabled distribution. You can only delete a distribution that is * already disabled, if you delete an enabled distribution this operation will * fail with a DistributionNotDisabled error. *

* This method performs many of the steps necessary to delete a disabled * distribution. It first performs lookup on the distribution using * {@link #getDistributionConfig(String)} to find its ETag value, then uses * this information to delete the distribution. *

* Because it can take a long time (minutes) to disable a distribution, this * task is not performed automatically by this method. In your own code, you * need to verify that a distribution is disabled with a status of * Deployed before you invoke this method. * * @param id * the distribution's unique identifier. * * @throws CloudFrontServiceException */ public void deleteDistribution(String id) throws CloudFrontServiceException { deleteDistributionImpl(false, id); } /** * Delete a disabled streaming distribution. You can only delete a distribution * that is already disabled, if you delete an enabled distribution this operation * will fail with a DistributionNotDisabled error. *

* This method performs many of the steps necessary to delete a disabled * distribution. It first performs lookup on the distribution using * {@link #getDistributionConfig(String)} to find its ETag value, then uses * this information to delete the distribution. *

* Because it can take a long time (minutes) to disable a distribution, this * task is not performed automatically by this method. In your own code, you * need to verify that a distribution is disabled with a status of * Deployed before you invoke this method. * * @param id * the distribution's unique identifier. * * @throws CloudFrontServiceException */ public void deleteStreamingDistribution(String id) throws CloudFrontServiceException { deleteDistributionImpl(true, id); } /** * Create a new Origin Access Identity * * @param callerReference * A user-set unique reference value that ensures the request can't be replayed * (max UTF-8 encoding size 128 bytes). This parameter may be null, in which * case your computer's local epoch time in milliseconds will be used. * @param comment * An optional comment to describe the identity (max 128 characters). May be null. * * @return * The origin access identity's properties. * * @throws CloudFrontServiceException */ public OriginAccessIdentity createOriginAccessIdentity( String callerReference, String comment) throws CloudFrontServiceException { if (log.isDebugEnabled()) { log.debug("Creating origin access identity"); } PostMethod httpMethod = new PostMethod(ENDPOINT + VERSION + ORIGIN_ACCESS_IDENTITY_URI_PATH); if (callerReference == null) { callerReference = "" + System.currentTimeMillis(); } try { XMLBuilder builder = XMLBuilder.create( "CloudFrontOriginAccessIdentityConfig") .a("xmlns", XML_NAMESPACE) .e("CallerReference").t(callerReference).up() .e("Comment").t(comment); httpMethod.setRequestEntity(new StringRequestEntity( builder.asString(null), "text/xml", Constants.DEFAULT_ENCODING)); performRestRequest(httpMethod, 201); OriginAccessIdentityHandler handler = (new CloudFrontXmlResponsesSaxParser(this.jets3tProperties)) .parseOriginAccessIdentity(httpMethod.getResponseBodyAsStream()); return handler.getOriginAccessIdentity(); } catch (CloudFrontServiceException e) { throw e; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new CloudFrontServiceException(e); } } /** * List the Origin Access Identities in a CloudFront account. * * @return * List of {@link OriginAccessIdentity} objects describing the identities. * * @throws CloudFrontServiceException */ public List getOriginAccessIdentityList() throws CloudFrontServiceException { if (log.isDebugEnabled()) { log.debug("Getting list of origin access identities"); } GetMethod httpMethod = new GetMethod(ENDPOINT + VERSION + ORIGIN_ACCESS_IDENTITY_URI_PATH); try { performRestRequest(httpMethod, 200); OriginAccessIdentityListHandler handler = (new CloudFrontXmlResponsesSaxParser(this.jets3tProperties)) .parseOriginAccessIdentityListResponse(httpMethod.getResponseBodyAsStream()); return handler.getOriginAccessIdentityList(); } catch (CloudFrontServiceException e) { throw e; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new CloudFrontServiceException(e); } } /** * Obtain the complete properties of an Origin Access Identity. * * @param id * The identifier of the Origin Access Identity. * * @return * The origin access identity's properties. * * @throws CloudFrontServiceException */ public OriginAccessIdentity getOriginAccessIdentity(String id) throws CloudFrontServiceException { if (log.isDebugEnabled()) { log.debug("Getting information for origin access identity with id: " + id); } GetMethod httpMethod = new GetMethod(ENDPOINT + VERSION + ORIGIN_ACCESS_IDENTITY_URI_PATH + "/" + id); try { performRestRequest(httpMethod, 200); OriginAccessIdentityHandler handler = (new CloudFrontXmlResponsesSaxParser(this.jets3tProperties)) .parseOriginAccessIdentity(httpMethod.getResponseBodyAsStream()); return handler.getOriginAccessIdentity(); } catch (CloudFrontServiceException e) { throw e; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new CloudFrontServiceException(e); } } /** * Obtain the configuration properties of an Origin Access Identity. * * @param id * The identifier of the Origin Access Identity. * * @return * The origin access identity's configuration properties. * * @throws CloudFrontServiceException */ public OriginAccessIdentityConfig getOriginAccessIdentityConfig(String id) throws CloudFrontServiceException { if (log.isDebugEnabled()) { log.debug("Getting config for origin access identity with id: " + id); } GetMethod httpMethod = new GetMethod(ENDPOINT + VERSION + ORIGIN_ACCESS_IDENTITY_URI_PATH + "/" + id + "/config"); try { performRestRequest(httpMethod, 200); OriginAccessIdentityConfigHandler handler = (new CloudFrontXmlResponsesSaxParser(this.jets3tProperties)) .parseOriginAccessIdentityConfig(httpMethod.getResponseBodyAsStream()); OriginAccessIdentityConfig config = handler.getOriginAccessIdentityConfig(); config.setEtag(httpMethod.getResponseHeader("ETag").getValue()); return config; } catch (CloudFrontServiceException e) { throw e; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new CloudFrontServiceException(e); } } /** * Update the properties of an Origin Access Identity. * * @param id * The identifier of the Origin Access Identity. * @param comment * A new comment to apply to the identity. * * @return * The origin access identity's configuration properties. * * @throws CloudFrontServiceException */ public OriginAccessIdentityConfig updateOriginAccessIdentityConfig( String id, String comment) throws CloudFrontServiceException { if (log.isDebugEnabled()) { log.debug("Updating configuration of origin access identity with id: " + id); } // Retrieve the old configuration. OriginAccessIdentityConfig oldConfig = getOriginAccessIdentityConfig(id); // Sanitize parameters. if (comment == null) { comment = oldConfig.getComment(); } PutMethod httpMethod = new PutMethod(ENDPOINT + VERSION + ORIGIN_ACCESS_IDENTITY_URI_PATH + "/" + id + "/config"); try { XMLBuilder builder = XMLBuilder.create( "CloudFrontOriginAccessIdentityConfig") .a("xmlns", XML_NAMESPACE) .e("CallerReference").t(oldConfig.getCallerReference()).up() .e("Comment").t(comment); httpMethod.setRequestEntity(new StringRequestEntity( builder.asString(null), "text/xml", Constants.DEFAULT_ENCODING)); httpMethod.setRequestHeader("If-Match", oldConfig.getEtag()); performRestRequest(httpMethod, 200); OriginAccessIdentityConfigHandler handler = (new CloudFrontXmlResponsesSaxParser(this.jets3tProperties)) .parseOriginAccessIdentityConfig(httpMethod.getResponseBodyAsStream()); OriginAccessIdentityConfig config = handler.getOriginAccessIdentityConfig(); config.setEtag(httpMethod.getResponseHeader("ETag").getValue()); return config; } catch (CloudFrontServiceException e) { throw e; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new CloudFrontServiceException(e); } } /** * Delete an Origin Access Identity. * * @param id * The identifier of the Origin Access Identity. * * @throws CloudFrontServiceException */ public void deleteOriginAccessIdentity(String id) throws CloudFrontServiceException { if (log.isDebugEnabled()) { log.debug("Deleting origin access identity with id: " + id); } // Get the identity's current config. OriginAccessIdentityConfig currentConfig = getOriginAccessIdentityConfig(id); DeleteMethod httpMethod = new DeleteMethod(ENDPOINT + VERSION + ORIGIN_ACCESS_IDENTITY_URI_PATH + "/" + id); try { httpMethod.setRequestHeader("If-Match", currentConfig.getEtag()); performRestRequest(httpMethod, 204); } catch (CloudFrontServiceException e) { throw e; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new CloudFrontServiceException(e); } } /** * Remove distribution objects from a CloudFront edge server cache to force * a refresh of the object data from the S3 origin. * * @param distributionId * @param objectKeys * S3 object key names of object(s) to invalidate. * @param callerReference * @return * invalidation object * @throws CloudFrontServiceException */ public Invalidation invalidateObjects(String distributionId, String[] objectKeys, String callerReference) throws CloudFrontServiceException { PostMethod httpMethod = new PostMethod(ENDPOINT + VERSION + "/distribution/" + distributionId + "/invalidation"); try { XMLBuilder builder = XMLBuilder.create("InvalidationBatch"); for (String objectPath: objectKeys) { String encodedPath = RestUtils.encodeUrlPath(objectPath, "/"); if (!encodedPath.startsWith("/")) { encodedPath = "/" + encodedPath; } builder.e("Path").t(encodedPath); } builder.e("CallerReference").t(callerReference); httpMethod.setRequestEntity(new StringRequestEntity( builder.asString(null), "text/xml", Constants.DEFAULT_ENCODING)); performRestRequest(httpMethod, 201); InvalidationHandler handler = (new CloudFrontXmlResponsesSaxParser(this.jets3tProperties)) .parseInvalidationResponse(httpMethod.getResponseBodyAsStream()); return handler.getInvalidation(); } catch (CloudFrontServiceException e) { throw e; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new CloudFrontServiceException(e); } } /** * Remove distribution objects from a CloudFront edge server cache to force * a refresh of the object data from the S3 origin. * * @param distributionId * @param objects * S3 object(s) to invalidate. * @param callerReference * @return * invalidation object * * @throws CloudFrontServiceException */ public Invalidation invalidateObjects(String distributionId, S3Object[] objects, String callerReference) throws CloudFrontServiceException { String[] objectKeys = new String[objects.length]; for (int i = 0; i < objects.length; i++) { objectKeys[i] = objects[i].getKey(); } return invalidateObjects(distributionId, objectKeys, callerReference); } /** * @param distributionId * @param invalidationId * @return * Details of a prior invalidation operation. * @throws CloudFrontServiceException */ public Invalidation getInvalidation(String distributionId, String invalidationId) throws CloudFrontServiceException { GetMethod httpMethod = new GetMethod(ENDPOINT + VERSION + "/distribution/" + distributionId + "/invalidation/" + invalidationId); try { performRestRequest(httpMethod, 200); InvalidationHandler handler = (new CloudFrontXmlResponsesSaxParser(this.jets3tProperties)) .parseInvalidationResponse(httpMethod.getResponseBodyAsStream()); return handler.getInvalidation(); } catch (CloudFrontServiceException e) { throw e; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new CloudFrontServiceException(e); } } /** * List a single page of up to pagingSize past invalidation summaries, ordered from * most recent to oldest. If there are more prior invalidations than will fit on the * page you must perform follow-up calls to this method to obtain a complete listing. * * @param distributionId * @param nextMarker * a marker string indicating where to begin the next page of listing results. * Start with null for an initial listing page, then set to the NextMarker value * of each subsequent page returned. * @param pagingSize * maximum number of invalidation summaries to include in each result page, up to 100. * @return * invalidation listing * @throws CloudFrontServiceException */ public InvalidationList listInvalidations(String distributionId, String nextMarker, int pagingSize) throws CloudFrontServiceException { try { String uri = ENDPOINT + VERSION + "/distribution/" + distributionId + "/invalidation" + "?MaxItems=" + pagingSize; if (nextMarker != null) { uri += "&Marker=" + nextMarker; } HttpMethod httpMethod = new GetMethod(uri); performRestRequest(httpMethod, 200); InvalidationListHandler handler = (new CloudFrontXmlResponsesSaxParser(this.jets3tProperties)) .parseInvalidationListResponse(httpMethod.getResponseBodyAsStream()); return handler.getInvalidationList(); } catch (CloudFrontServiceException e) { throw e; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new CloudFrontServiceException(e); } } /** * List all past invalidation summaries, ordered from most recent to oldest. * * @param distributionId * @return * list of invalidation objects * @throws CloudFrontServiceException */ public List listInvalidations(String distributionId) throws CloudFrontServiceException { try { List invalidationSummaries = new ArrayList(); String nextMarker = null; boolean incompleteListing = true; do { InvalidationList invalidationList = listInvalidations( distributionId, nextMarker, 100); invalidationSummaries.addAll(invalidationList.getInvalidationSummaries()); incompleteListing = invalidationList.isTruncated(); nextMarker = invalidationList.getNextMarker(); // Sanity check for valid pagination values. if (incompleteListing && nextMarker == null) { throw new CloudFrontServiceException("Unable to retrieve paginated " + "InvalidationList results without a valid NextMarker value."); } } while (incompleteListing); return invalidationSummaries; } catch (CloudFrontServiceException e) { throw e; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new CloudFrontServiceException(e); } } /** * Sanitizes a proposed bucket name to ensure it is fully-specified rather than * merely the bucket's short name. A fully specified bucket name looks like * "jets3t.s3.amazonaws.com". * * @param proposedBucketName * the proposed S3 bucket name that will be sanitized. * * @return * the bucket name with the {@link #DEFAULT_BUCKET_SUFFIX} added, if necessary. */ public static String sanitizeS3BucketName(String proposedBucketName) { if (!proposedBucketName.endsWith(DEFAULT_BUCKET_SUFFIX)) { log.warn("Bucket names used within the CloudFront service should be specified as " + "full S3 subdomain paths like 'jets3t.s3.amazonaws.com'. Repairing " + "faulty bucket name value \"" + proposedBucketName + "\" by adding suffix " + "'" + DEFAULT_BUCKET_SUFFIX + "'."); return proposedBucketName + DEFAULT_BUCKET_SUFFIX; } else { return proposedBucketName; } } /** * Convert the given string to be safe for use in signed URLs for a private distribution. * @param str * @return * a URL-safe Base64 encoded version of the data. * @throws UnsupportedEncodingException */ protected static String makeStringUrlSafe(String str) throws UnsupportedEncodingException { return ServiceUtils.toBase64(str.getBytes("UTF-8")) .replace('+', '-') .replace('=', '_') .replace('/', '~'); } /** * Convert the given data to be safe for use in signed URLs for a private distribution by * using specialized Base64 encoding. * @param bytes * @return * a URL-safe Base64 encoded version of the data. * @throws UnsupportedEncodingException */ protected static String makeBytesUrlSafe(byte[] bytes) throws UnsupportedEncodingException { return ServiceUtils.toBase64(bytes) .replace('+', '-') .replace('=', '_') .replace('/', '~'); } /** * Generate a policy document that describes custom access permissions to apply * via a private distribution's signed URL. * * @param resourcePath * An optional HTTP/S or RTMP resource path that restricts which distribution and S3 objects * will be accessible in a signed URL. For standard distributions the resource URL will be * "http://" + distributionName + "/" + objectKey (may also include URL * parameters. For distributions with the HTTPS required protocol, the resource URL * must start with "https://". RTMP resources do not take the form of a URL, * and instead the resource path is nothing but the stream's name. * * The '*' and '?' characters can be used as a wildcards to allow multi-character or * single-character matches respectively: *

    *
  • * : All distributions/objects will be accessible
  • *
  • a1b2c3d4e5f6g7.cloudfront.net/* : All objects within the distribution * a1b2c3d4e5f6g7 will be accessible
  • *
  • a1b2c3d4e5f6g7.cloudfront.net/path/to/object.txt : Only the S3 object * named path/to/object.txt in the distribution a1b2c3d4e5f6g7 will be * accessible.
  • *
* If this parameter is null the policy will permit access to all distributions and S3 * objects associated with the certificate keypair used to generate the signed URL. * @param epochDateLessThan * The time and date when the signed URL will expire. REQUIRED. * @param limitToIpAddressCIDR * An optional range of client IP addresses that will be allowed to access the distribution, * specified as a CIDR range. If null, the CIDR will be 0.0.0.0/0 and any * client will be permitted. * @param epochDateGreaterThan * An optional time and date when the signed URL will become active. If null, the signed * URL will be active as soon as it is created. * * @return * A policy document describing the access permission to apply when generating a signed URL. * * @throws CloudFrontServiceException */ public static String buildPolicyForSignedUrl( String resourcePath, Date epochDateLessThan, String limitToIpAddressCIDR, Date epochDateGreaterThan) throws CloudFrontServiceException { if (epochDateLessThan == null) { throw new CloudFrontServiceException( "epochDateLessThan must be provided to sign CloudFront URLs"); } if (resourcePath == null) { resourcePath = "*"; } String ipAddress = (limitToIpAddressCIDR == null ? "0.0.0.0/0" // No IP restriction : limitToIpAddressCIDR); String policy = "{\"Statement\": [{" + "\"Resource\":\"" + resourcePath + "\"" + ",\"Condition\":{" + "\"DateLessThan\":{\"AWS:EpochTime\":" + epochDateLessThan.getTime() / 1000 + "}" + ",\"IpAddress\":{\"AWS:SourceIp\":\"" + ipAddress + "\"}" + (epochDateGreaterThan == null ? "" : ",\"DateGreaterThan\":{\"AWS:EpochTime\":" + epochDateGreaterThan.getTime() / 1000 + "}") + "}}]}"; return policy; } /** * Generate a signed URL that allows access to distribution and S3 objects by * applying access restrictions specified in a custom policy document. * * @param resourceUrlOrPath * The URL or path that uniquely identifies a resource within a distribution. * For standard distributions the resource URL will be * "http://" + distributionName + "/" + objectKey (may also include URL * parameters. For distributions with the HTTPS required protocol, the resource URL * must start with "https://". RTMP resources do not take the form of a URL, * and instead the resource path is nothing but the stream's name. * @param keyPairId * Identifier of a public/private certificate keypair already configured in your * Amazon Web Services account. * @param derPrivateKey * The RSA private key data that corresponding to the certificate keypair identified by * keyPairId, in DER format. To convert a standard PEM private key file into this format * use the utility method {@link EncryptionUtil#convertRsaPemToDer(java.io.InputStream)} * @param policy * A policy document that describes the access permissions that will be applied by the * signed URL. To generate a custom policy use * {@link #buildPolicyForSignedUrl(String, Date, String, Date)}. * * @return * A signed URL that will permit access to distribution and S3 objects as specified * in the policy document. * * @throws CloudFrontServiceException */ public static String signUrl(String resourceUrlOrPath, String keyPairId, byte[] derPrivateKey, String policy) throws CloudFrontServiceException { try { byte[] signatureBytes = EncryptionUtil.signWithRsaSha1(derPrivateKey, policy.getBytes("UTF-8")); String urlSafePolicy = makeStringUrlSafe(policy); String urlSafeSignature = makeBytesUrlSafe(signatureBytes); String signedUrl = resourceUrlOrPath + (resourceUrlOrPath.indexOf('?') >= 0 ? "&" : "?") + "Policy=" + urlSafePolicy + "&Signature=" + urlSafeSignature + "&Key-Pair-Id=" + keyPairId; return signedUrl; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new CloudFrontServiceException(e); } } /** * Generate a signed URL that allows access to a specific distribution and * S3 object by applying a access restrictions from a "canned" (simplified) * policy document. * * @param resourceUrlOrPath * The URL or path that uniquely identifies a resource within a distribution. * For standard distributions the resource URL will be * "http://" + distributionName + "/" + objectKey (may also include URL * parameters. For distributions with the HTTPS required protocol, the resource URL * must start with "https://". RTMP resources do not take the form of a URL, * and instead the resource path is nothing but the stream's name. * @param keyPairId * Identifier of a public/private certificate keypair already configured in your * Amazon Web Services account. * @param derPrivateKey * The RSA private key data that corresponding to the certificate keypair identified by * keyPairId, in DER format. To convert a standard PEM private key file into this format * use the utility method {@link EncryptionUtil#convertRsaPemToDer(java.io.InputStream)} * @param epochDateLessThan * The time and date when the signed URL will expire. REQUIRED. * * @return * A signed URL that will permit access to a specific distribution and S3 object. * * @throws CloudFrontServiceException */ public static String signUrlCanned(String resourceUrlOrPath, String keyPairId, byte[] derPrivateKey, Date epochDateLessThan) throws CloudFrontServiceException { try { String cannedPolicy = "{\"Statement\":[{\"Resource\":\"" + resourceUrlOrPath + "\",\"Condition\":{\"DateLessThan\":{\"AWS:EpochTime\":" + epochDateLessThan.getTime() / 1000 + "}}}]}"; byte[] signatureBytes = EncryptionUtil.signWithRsaSha1(derPrivateKey, cannedPolicy.getBytes("UTF-8")); String urlSafeSignature = makeBytesUrlSafe(signatureBytes); String signedUrl = resourceUrlOrPath + (resourceUrlOrPath.indexOf('?') >= 0 ? "&" : "?") + "Expires=" + epochDateLessThan.getTime() / 1000 + "&Signature=" + urlSafeSignature + "&Key-Pair-Id=" + keyPairId; return signedUrl; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new CloudFrontServiceException(e); } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/ServiceException.java0000644000000000000000000002753411550421156022067 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service; import java.io.IOException; import java.io.StringReader; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.xml.parsers.ParserConfigurationException; import org.jets3t.service.mx.MxDelegate; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import com.jamesmurty.utils.XMLBuilder; /** * Exception for use by {@link StorageService} and related utilities. * This exception can hold useful additional information about errors that occur * when communicating with a service. * * @author James Murty */ public class ServiceException extends Exception { private static final long serialVersionUID = -757626557833455141L; private String xmlMessage = null; // Fields from error messages. private String errorCode = null; private String errorMessage = null; private String errorRequestId = null; private String errorHostId = null; // Map - name => value pairs of response headers. private Map responseHeaders = null; private int responseCode = -1; private String responseStatus = null; private String responseDate = null; private String requestVerb = null; private String requestPath = null; private String requestHost = null; /** * Create a service exception that includes the XML error document returned by service. * * @param message * @param xmlMessage */ public ServiceException(String message, String xmlMessage) { this(message, xmlMessage, null); } /** * Create a service exception that includes a specific message, an optional XML error * document returned by service, and an optional underlying cause exception. * * @param message * @param xmlMessage * @param cause */ public ServiceException(String message, String xmlMessage, Throwable cause) { super(message, cause); if (xmlMessage != null) { parseXmlMessage(xmlMessage); } MxDelegate.getInstance().registerS3ServiceExceptionEvent(getErrorCode()); } /** * Create a service exception without any useful information. */ public ServiceException() { super(); } /** * Create a service exception that includes a specific message and an * optional underlying cause exception. * * @param message * @param cause */ public ServiceException(String message, Throwable cause) { super(message, cause); } /** * Create a service exception that includes a specific message. * * @param message */ public ServiceException(String message) { super(message); } /** * Create a service exception that includes an underlying cause exception. * * @param cause */ public ServiceException(Throwable cause) { super(cause); } @Override public String toString() { String myString = super.toString(); // Add request-specific information, if it's available. if (requestVerb != null) { myString += " " + requestVerb + " '" + requestPath + "'" + (requestHost != null ? " on Host '" + requestHost + "'" : "") + (responseDate != null ? " @ '" + responseDate + "'" : ""); } if (responseCode != -1) { myString += " -- ResponseCode: " + responseCode + ", ResponseStatus: " + responseStatus; } if (isParsedFromXmlMessage()) { myString += ", XML Error Message: " + xmlMessage; } else { if (errorRequestId != null) { myString += ", RequestId: " + errorRequestId + ", HostId: " + errorHostId; } } return myString; } private String findXmlElementText(String xmlMessage, String elementName) { Pattern pattern = Pattern.compile(".*<" + elementName + ">(.*).*"); Matcher matcher = pattern.matcher(xmlMessage); if (matcher.matches() && matcher.groupCount() == 1) { return matcher.group(1); } else { return null; } } private void parseXmlMessage(String xmlMessage) { xmlMessage = xmlMessage.replaceAll("\n", ""); this.xmlMessage = xmlMessage; this.errorCode = findXmlElementText(xmlMessage, "Code"); this.errorMessage = findXmlElementText(xmlMessage, "Message"); this.errorRequestId = findXmlElementText(xmlMessage, "RequestId"); this.errorHostId = findXmlElementText(xmlMessage, "HostId"); // Add Details element present in some Google Storage error // messages to Message field. String errorDetails = findXmlElementText(xmlMessage, "Details"); if (errorDetails != null && errorDetails.length() > 0) { this.errorMessage += " " + errorDetails; } } /** * @return The service-specific Error Code returned by the service, if a response is available. * For example "AccessDenied", "InternalError" * Null otherwise. */ public String getErrorCode() { return this.errorCode; } /** * Set the exception's error code; for internal use only. * @param code */ public void setErrorCode(String code) { this.errorCode = code; } /** * @return The service-specific Error Message returned by the service, if a response is available. * For example: "Access Denied", "We encountered an internal error. Please try again." */ public String getErrorMessage() { return this.errorMessage; } /** * Set the exception's error message; for internal use only. * @param message */ public void setErrorMessage(String message) { this.errorMessage= message; } /** * @return The Error Host ID returned by the service, if a response is available. * Null otherwise. */ public String getErrorHostId() { return errorHostId; } /** * Set the exception's host ID; for internal use only. * @param hostId */ public void setErrorHostId(String hostId) { this.errorHostId = hostId; } /** * @return The Error Request ID returned by the service, if a response is available. * Null otherwise. */ public String getErrorRequestId() { return errorRequestId; } /** * Set the exception's request ID; for internal use only. * @param requestId */ public void setErrorRequestId(String requestId) { this.errorRequestId = requestId; } /** * @return The XML Error message returned by the service, if a response is available. * Null otherwise. */ public String getXmlMessage() { return xmlMessage; } /** * @return * an XML error message returned by the services as an XMLBuilder * object that allows for simple XPath querying via {@link XMLBuilder#xpathFind(String)}, * or null if no XML error document is available. * * @throws IOException * @throws ParserConfigurationException * @throws SAXException */ public XMLBuilder getXmlMessageAsBuilder() throws IOException, ParserConfigurationException, SAXException { if (this.xmlMessage == null) { return null; } XMLBuilder builder = XMLBuilder.parse( new InputSource(new StringReader(this.xmlMessage))); return builder; } /** * @return * true if this exception contains information from an XML error * document returned by a service, e.g. with error code details. */ public boolean isParsedFromXmlMessage() { return (xmlMessage != null); } /** * @return The HTTP Response Code returned by the service, if an HTTP response is available. * For example: 401, 404, 500 */ public int getResponseCode() { return responseCode; } /** * Set the exception's HTTP response code; for internal use only. * @param responseCode */ public void setResponseCode(int responseCode) { this.responseCode = responseCode; } /** * @return * The HTTP Status message returned by the service, if an HTTP response is available. * For example: "Forbidden", "Not Found", "Internal Server Error" */ public String getResponseStatus() { return responseStatus; } /** * Set the exception's HTTP response status; for internal use only. * @param responseStatus */ public void setResponseStatus(String responseStatus) { this.responseStatus = responseStatus; } /** * @return * The exception's HTTP response date, if any. */ public String getResponseDate() { return responseDate; } /** * Set the exception's HTTP response date; for internal use only. * @param responseDate */ public void setResponseDate(String responseDate) { this.responseDate = responseDate; } /** * @return The HTTP Verb used in the request, if available. * For example: "GET", "PUT", "DELETE" */ public String getRequestVerb() { return requestVerb; } /** * Set the exception's HTTP request verb; for internal use only. * @param requestVerb */ public void setRequestVerb(String requestVerb) { this.requestVerb = requestVerb; } /** * @return * the exception's HTTP request path; if any. */ public String getRequestPath() { return requestPath; } /** * Set the exception's HTTP request path; for internal use only. * @param requestPath */ public void setRequestPath(String requestPath) { this.requestPath = requestPath; } /** * @return * the exception's HTTP request hostname; if any. */ public String getRequestHost() { return requestHost; } /** * Set the exception's HTTP request hostname; for internal use only. * @param requestHost */ public void setRequestHost(String requestHost) { this.requestHost = requestHost; } /** * Allow the Request and Host Id fields to be populated in situations where * this information is not available from an XML response error document. * If there is no XML error response document, the RequestId and HostId will * generally be available as the HTTP response headers * x-amz-request-id and x-amz-id-2 respectively. * * @param errorRequestId * @param errorHostId */ public void setRequestAndHostIds(String errorRequestId, String errorHostId) { this.errorRequestId = errorRequestId; this.errorHostId = errorHostId; } /** * @return * the exception's HTTP response headers, if any. */ public Map getResponseHeaders() { return responseHeaders; } /** * Set the exception's HTTP response headers; for internal use only. * @param responseHeaders */ public void setResponseHeaders(Map responseHeaders) { this.responseHeaders = responseHeaders; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/StorageObjectsChunk.java0000644000000000000000000000612311441613550022506 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service; import org.jets3t.service.model.StorageObject; /** * Stores a "chunk" of StorageObjects returned from a list command - this particular chunk may or may * not include all the objects available in a bucket. * * This class contains an array of objects and a the last key name returned by a prior * call to the method {@link S3Service#listObjectsChunked(String, String, String, long, String)}. * * @author James Murty */ public class StorageObjectsChunk { protected String prefix = null; protected String delimiter = null; protected StorageObject[] objects = null; protected String[] commonPrefixes = null; protected String priorLastKey = null; public StorageObjectsChunk(String prefix, String delimiter, StorageObject[] objects, String[] commonPrefixes, String priorLastKey) { this.prefix = prefix; this.delimiter = delimiter; this.objects = objects; this.commonPrefixes = commonPrefixes; this.priorLastKey = priorLastKey; } /** * @return * the objects in this chunk. */ public StorageObject[] getObjects() { return objects; } /** * @return * the common prefixes in this chunk. */ public String[] getCommonPrefixes() { return commonPrefixes; } /** * @return * the last key returned by the previous chunk if that chunk was incomplete, null otherwise. */ public String getPriorLastKey() { return priorLastKey; } /** * @return * the prefix applied when this object chunk was generated. If no prefix was * applied, this method will return null. */ public String getPrefix() { return prefix; } /** * @return * the delimiter applied when this object chunk was generated. If no * delimiter was applied, this method will return null. */ public String getDelimiter() { return delimiter; } /** * A convenience method to check whether a listing of objects is complete * (true) or there are more objects available (false). Just a synonym for * {@link #getPriorLastKey()} == null. * * @return * true if the listing is complete and there are no more unlisted * objects, false if follow-up requests will return more objects. */ public boolean isListingComplete() { return (priorLastKey == null); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/Constants.java0000644000000000000000000001353411550443546020566 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty, 2008 Zmanda Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service; import java.io.File; /** * Constants used by the S3Service and its implementation classes. * * @author James Murty * @author Nikolas Coukouma */ public class Constants { /** * The JetS3t suite version number implemented by this service. */ public static final String JETS3T_VERSION = "0.8.1"; public static String S3_DEFAULT_HOSTNAME = "s3.amazonaws.com"; public static String GS_DEFAULT_HOSTNAME = "commondatastorage.googleapis.com"; //////////////////////////////////// // Default file names and locations. //////////////////////////////////// /** * The name of the JetS3t properties * file: jets3t.properties */ public static String JETS3T_PROPERTIES_FILENAME = "jets3t.properties"; /** * The file containing local Cockpit preferences. */ public static String COCKPIT_PROPERTIES_FILENAME = "jets3t-cockpit.properties"; /** * The file containing the list of AWS DevPay Products */ public static String DEVPAY_PRODUCTS_PROPERTIES_FILENAME = "devpay_products.properties"; /** * The property name suffix for the names of products */ public static String DEVPAY_PRODUCT_NAME_PROP_SUFFIX = ".name"; /** * The property name suffix for the tokens of products */ public static String DEVPAY_PRODUCT_TOKEN_PROP_SUFFIX = ".token"; /** * The name of the JetS3t ignore * file: .jets3t-ignore */ public static String JETS3T_IGNORE_FILENAME = ".jets3t-ignore"; /** * The default preferences directory: <user.home>/.jets3t */ public static File DEFAULT_PREFERENCES_DIRECTORY = new File(System.getProperty("user.home") + "/.jets3t"); /** * The file delimiter used by JetS3t is the '/' character, which is compatible with standard * browser access to S3 files. */ public static String FILE_PATH_DELIM = "/"; /** * The default encoding used for text data: UTF-8 */ public static String DEFAULT_ENCODING = "UTF-8"; /** * HMAC/SHA1 Algorithm per RFC 2104, used when generating S3 signatures. */ public static final String HMAC_SHA1_ALGORITHM = "HmacSHA1"; /////////////////////////////////////// // JetS3t-specific metadata item names. /////////////////////////////////////// /** * Metadata header for storing the original date of a local file uploaded to S3, so it can * be used subsequently to compare files instead of relying on the S3 upload date. */ public static final String METADATA_JETS3T_LOCAL_FILE_DATE = "jets3t-original-file-date-iso8601"; /** * Metadata header for storing information about the data encryption algorithm applied by JetS3t tools. */ public static final String METADATA_JETS3T_CRYPTO_ALGORITHM = "jets3t-crypto-alg"; /** * Metadata header for storing information about the JetS3t version of encryption applied * (to keep encryption compatibility between versions). */ public static final String METADATA_JETS3T_CRYPTO_VERSION = "jets3t-crypto-ver"; /** * Metadata header for storing information about data compression applied by jets3t tools. */ public static final String METADATA_JETS3T_COMPRESSED = "jets3t-compression"; /////////////////////////////////// // Settings used by all S3 Services /////////////////////////////////// /** * Default number of objects to include in each chunk of an object listing. */ public static final long DEFAULT_OBJECT_LIST_CHUNK_SIZE = 1000; /////////////////////////////////// // Headers used by REST S3 Services /////////////////////////////////// /** * Header prefix for general Amazon headers: x-amz- */ public static final String REST_HEADER_PREFIX = "x-amz-"; /** * Header prefix for Amazon metadata headers: x-amz-meta- */ public static final String REST_METADATA_PREFIX = "x-amz-meta-"; /** * Header prefix for Amazon's alternative date header: x-amz-date */ public static final String REST_METADATA_ALTERNATE_DATE = "x-amz-date"; /** * XML namespace URL used when generating S3-compatible XML documents: * http://s3.amazonaws.com/doc/2006-03-01/ */ public static final String XML_NAMESPACE = "http://s3.amazonaws.com/doc/2006-03-01/"; /** * A flag used to indicate that the sender is willing to accept any Requester Pays * bucket fees imposed by the request. This flag may be used in request Headers, * or as a parameter. */ public static final String REQUESTER_PAYS_BUCKET_FLAG = "x-amz-request-payer=requester"; public static final String AMZ_REQUEST_ID_1 = "x-amz-request-id"; public static final String AMZ_REQUEST_ID_2 = "x-amz-id-2"; public static final String AMZ_SECURITY_TOKEN = "x-amz-security-token"; public static final String AMZ_VERSION_ID = "x-amz-version-id"; public static final String AMZ_DELETE_MARKER = "x-amz-delete-marker"; public static final String AMZ_MULTI_FACTOR_AUTH_CODE = "x-amz-mfa"; } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/Jets3tProperties.java0000644000000000000000000003222711550442074022036 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Utility class to load and store JetS3t-specific properties. *

* Properties are initially loaded via getInstance methods from a named properties file, * which must be available at the root of the classpath, or from an input stream. * In either case the properties are cached according to a name, such that subsequent calls to * get a properties instance with the same name will return the same properties object. *

*

* For more information about JetS3t properties please see: * JetS3t Configuration * * @author James Murty */ public class Jets3tProperties implements Serializable { private static final long serialVersionUID = -822234326095333142L; private static final Log log = LogFactory.getLog(Jets3tProperties.class); /** * Stores the jets3t properties. */ private static final Hashtable propertiesHashtable = new Hashtable(); private Properties properties = new Properties(); private boolean loaded = false; /** * Return a properties instance based on properties read from an input stream, and stores * the properties object in a cache referenced by the propertiesIdentifier. * * @param inputStream * an input stream containing property name/value pairs in a format that can be read by * {@link Properties#load(InputStream)}. * @param propertiesIdentifer * the name under which the properties are cached * * @return * a properties object initialised with property values from the input stream * * @throws IOException */ public static Jets3tProperties getInstance(InputStream inputStream, String propertiesIdentifer) throws IOException { Jets3tProperties jets3tProperties = null; // Keep static references to properties classes by propertiesIdentifer. if (propertiesHashtable.containsKey(propertiesIdentifer)) { jets3tProperties = propertiesHashtable.get(propertiesIdentifer); } else { jets3tProperties = new Jets3tProperties(); propertiesHashtable.put(propertiesIdentifer, jets3tProperties); } jets3tProperties.loadAndReplaceProperties(inputStream, propertiesIdentifer); return jets3tProperties; } /** * Return a properties instance based on properties read from a properties file, and stores * the properties object in a cache referenced by the properties file name. * * @param propertiesFileName * the name of a properties file that exists in the root of the classpath, such that it can * be loaded with the code getClass().getResourceAsStream("/" + propertiesFileName);. * * @return * a properties object initialised with property values from the properties file */ public static Jets3tProperties getInstance(String propertiesFileName) { Jets3tProperties jets3tProperties = null; // Keep static references to properties classes by filename. if (propertiesHashtable.containsKey(propertiesFileName)) { jets3tProperties = propertiesHashtable.get(propertiesFileName); return jets3tProperties; } else { jets3tProperties = new Jets3tProperties(); propertiesHashtable.put(propertiesFileName, jets3tProperties); } // Load properties from classpath. InputStream cpIS = jets3tProperties.getClass().getResourceAsStream("/" + propertiesFileName); if (cpIS != null) { if (log.isDebugEnabled()) { log.debug("Loading properties from resource in the classpath: " + propertiesFileName); } try { jets3tProperties.loadAndReplaceProperties(cpIS, "Resource '" + propertiesFileName + "' in classpath"); } catch (IOException e) { if (log.isErrorEnabled()) { log.error("Failed to load properties from resource in classpath: " + propertiesFileName, e); } } finally { try { cpIS.close(); } catch (Exception ignored) {} } } return jets3tProperties; } /** * Sets or removes a property value. * * @param propertyName * the name of the property to set or remove. * @param propertyValue * a new value for the property. If this value is null, the named property * will be removed. */ public void setProperty(String propertyName, String propertyValue) { if (propertyValue == null) { this.clearProperty(propertyName); } else { this.properties.put(propertyName, trim(propertyValue)); } } /** * Removes a property name and value. * * @param propertyName * the name of the property to remove. */ public void clearProperty(String propertyName) { this.properties.remove(propertyName); } /** * Clears (removes) all the property names and values used internally by * this object. Use this method in combination with * {@link #loadAndReplaceProperties(Properties, String)} to directly * manage the properties encapsulated in this class. */ public void clearAllProperties() { this.properties.clear(); } /** * Reads properties from an InputStream and stores them in this class's properties object. * If a new property already exists, the property value is replaced. * * @param inputStream * an input stream containing property name/value pairs in a format that can be read by * {@link Properties#load(InputStream)}. * @param propertiesSource * a name for the source of the properties, such as a properties file name or identifier. This * is only used to generate meaningful debug messages when properties are updated, so it is * possible to tell where the updated property value came from. * * @throws IOException */ public void loadAndReplaceProperties(InputStream inputStream, String propertiesSource) throws IOException { Properties newProperties = new Properties(); newProperties.load(inputStream); loadAndReplaceProperties(newProperties, propertiesSource); } /** * Merges properties from another JetS3tProperties object into this instance. * If a new property already exists, the property value is replaced. * * @param properties * the object containing properties that will be merged into this set of properties. * @param propertiesSource * a name for the source of the properties, such as a properties file name or identifier. This * is only used to generate meaningful debug messages when properties are updated, so it is * possible to tell where the updated property value came from. */ public void loadAndReplaceProperties(Jets3tProperties properties, String propertiesSource) { Properties newProperties = properties.getProperties(); loadAndReplaceProperties(newProperties, propertiesSource); } /** * Merges properties from another Properties object into this instance. * If a new property already exists, the property value is replaced. * * @param newProperties * the object containing properties that will be merged into this set of properties. * @param propertiesSource * a name for the source of the properties, such as a properties file name or identifier. This * is only used to generate meaningful debug messages when properties are updated, so it is * possible to tell where the updated property value came from. */ public void loadAndReplaceProperties(Properties newProperties, String propertiesSource) { Iterator> propsIter = newProperties.entrySet().iterator(); while (propsIter.hasNext()) { Map.Entry entry = propsIter.next(); String propertyName = (String) entry.getKey(); String propertyValue = (String) entry.getValue(); if (properties.containsKey(propertyName) && !properties.getProperty(propertyName).equals(propertyValue)) { if (log.isDebugEnabled()) { log.debug("Over-riding jets3t property [" + propertyName + "=" + propertyValue + "] with value from properties source " + propertiesSource + ". New value: [" + propertyName + "=" + trim(propertyValue) + "]"); } } properties.put(propertyName, trim(propertyValue)); } loaded = true; } /** * @return * a properties object containing all this object's properties, but cloned so changes to the * returned properties object are not reflected in this object. */ public Properties getProperties() { return (Properties) properties.clone(); } /** * @param propertyName * @param defaultValue * @return * the named Property value as a string if the property is set, otherwise returns the default value. */ public String getStringProperty(String propertyName, String defaultValue) { String stringValue = trim(properties.getProperty(propertyName, defaultValue)); if (log.isDebugEnabled()) { log.debug(propertyName + "=" + stringValue); } return stringValue; } /** * * @param propertyName * @param defaultValue * @return * the named Property value as a long if the property is set, otherwise returns the default value. * @throws NumberFormatException */ public long getLongProperty(String propertyName, long defaultValue) throws NumberFormatException { String longValue = trim(properties.getProperty(propertyName, String.valueOf(defaultValue))); if (log.isDebugEnabled()) { log.debug(propertyName + "=" + longValue); } return Long.parseLong(longValue); } /** * * @param propertyName * @param defaultValue * @return * the named Property value as an int if the property is set, otherwise returns the default value. * @throws NumberFormatException */ public int getIntProperty(String propertyName, int defaultValue) throws NumberFormatException { String intValue = trim(properties.getProperty(propertyName, String.valueOf(defaultValue))); if (log.isDebugEnabled()) { log.debug(propertyName + "=" + intValue); } return Integer.parseInt(intValue); } /** * * @param propertyName * @param defaultValue * @return * the named Property value as a boolean if the property is set, otherwise returns the default value. * @throws IllegalArgumentException */ public boolean getBoolProperty(String propertyName, boolean defaultValue) throws IllegalArgumentException { String boolValue = trim(properties.getProperty(propertyName, String.valueOf(defaultValue))); if (log.isDebugEnabled()) { log.debug(propertyName + "=" + boolValue); } if ("true".equalsIgnoreCase(boolValue)) { return true; } else if ("false".equalsIgnoreCase(boolValue)) { return false; } else { throw new IllegalArgumentException("Boolean value '" + boolValue + "' for jets3t property '" + propertyName + "' must be 'true' or 'false' (case-insensitive)"); } } /** * @param propertyName * the property name to check for. * @return * true if the property exists, false otherwise. */ public boolean containsKey(String propertyName) { return properties.containsKey(propertyName); } /** * @return * true if this properties object was successfully loaded from an input stream or a named * properties file, false otherwise. */ public boolean isLoaded() { return loaded; } private static String trim(String str) { if (str != null) { return str.trim(); } else { return null; } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/acl/0002755000000000000000000000000011463724214016477 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/acl/CanonicalGrantee.java0000644000000000000000000000630011441613550022530 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.acl; import com.jamesmurty.utils.XMLBuilder; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; /** * Represents a grantee identified by their canonical Amazon ID, which is something along the lines * of an Amazon-internal ID specific to a user. For example, Amazon can map a grantee identified * by an email address to a canonical ID. *

* Canonical grantees may have an associated Display Name, which is a human-friendly name that * Amazon has linked to the canonical ID (eg the user's login name). * * @author James Murty * */ public class CanonicalGrantee implements GranteeInterface { protected String id = null; protected String displayName = null; /** * Default constructor. *

* Warning! If created with this constructor this class will not * represent a valid grantee until the identifier is set. */ public CanonicalGrantee() { } /** * Constructs a grantee with the given canonical ID. * @param identifier */ public CanonicalGrantee(String identifier) { this.setIdentifier(identifier); } public String toXml() throws TransformerException, ParserConfigurationException, FactoryConfigurationError { return toXMLBuilder().asString(); } public XMLBuilder toXMLBuilder() throws TransformerException, ParserConfigurationException, FactoryConfigurationError { return (XMLBuilder.create("Grantee") .attr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance") .attr("xsi:type", "CanonicalUser") .element("ID").text(id) ); } public void setIdentifier(String id) { this.id = id; } public String getIdentifier() { return id; } public void setDisplayName(String displayName) { this.displayName = displayName; } public String getDisplayName() { return this.displayName; } public boolean equals(Object obj) { if (obj instanceof CanonicalGrantee) { CanonicalGrantee canonicalGrantee = (CanonicalGrantee) obj; return id.equals(canonicalGrantee.id); } return false; } public int hashCode() { return id.hashCode(); } public String toString() { return "CanonicalGrantee [id=" + id + (displayName != null ? ", displayName=" + displayName : "") + "]"; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/acl/AccessControlList.java0000644000000000000000000002104011447765354022747 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.acl; import java.io.Serializable; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.jets3t.service.Constants; import org.jets3t.service.ServiceException; import org.jets3t.service.model.StorageOwner; import com.jamesmurty.utils.XMLBuilder; /** * Represents an Amazon S3 Access Control List (ACL), including the ACL's set of grantees and the * permissions assigned to each grantee. * * @author James Murty * */ public class AccessControlList implements Serializable { private static final long serialVersionUID = -4616688515622838285L; /** * A pre-canned REST ACL to set an object's permissions to Private (only owner can read/write) */ public static final AccessControlList REST_CANNED_PRIVATE = new AccessControlList(); /** * A pre-canned REST ACL to set an object's permissions to Public Read (anyone can read, only owner * can write) */ public static final AccessControlList REST_CANNED_PUBLIC_READ = new AccessControlList(); /** * A pre-canned REST ACL to set an object's permissions to Public Read and Write (anyone can * read/write) */ public static final AccessControlList REST_CANNED_PUBLIC_READ_WRITE = new AccessControlList(); /** * A pre-canned REST ACL to set an object's permissions to Authenticated Read (authenticated Amazon * users can read, only owner can write) */ public static final AccessControlList REST_CANNED_AUTHENTICATED_READ = new AccessControlList(); protected final HashSet grants = new HashSet(); protected StorageOwner owner = null; /** * Returns a string representation of the ACL contents, useful for debugging. */ @Override public String toString() { return "AccessControlList [owner=" + owner + ", grants=" + getGrantAndPermissions() + "]"; } public StorageOwner getOwner() { return owner; } public void setOwner(StorageOwner owner) { this.owner = owner; } /** * @param grantee * @return list of permissions assigned to the given grantee in this ACL */ public List getPermissionsForGrantee(GranteeInterface grantee) { List permissions = new ArrayList(); for (GrantAndPermission gap: grants) { if (gap.getGrantee().equals(grantee)) { permissions.add(gap.getPermission()); } } return permissions; } /** * @param permission * @return list of grantees assigned the given permission in this ACL */ public List getGranteesWithPermission(Permission permission) { List grantees = new ArrayList(); for (GrantAndPermission gap: grants) { if (gap.getPermission().equals(permission)) { grantees.add(gap.getGrantee()); } } return grantees; } /** * @param grantee * @param permission * @return true if the given grantee has the given permission in this ACL */ public boolean hasGranteeAndPermission(GranteeInterface grantee, Permission permission) { return getPermissionsForGrantee(grantee).contains(permission); } /** * Adds a grantee to the ACL with the given permission. If this ACL already contains the grantee * (ie the same grantee object) the permission for the grantee will be updated. * * @param grantee * the grantee to whom the permission will apply * @param permission * the permission to apply to the grantee. */ public void grantPermission(GranteeInterface grantee, Permission permission) { grants.add(new GrantAndPermission(grantee, permission)); } /** * Adds a set of grantee/permission pairs to the ACL, where each item in the set is a * {@link GrantAndPermission} object. * * @param grantAndPermissions * the grant and permission combinations to add. */ public void grantAllPermissions(GrantAndPermission[] grantAndPermissions) { for (int i = 0; i < grantAndPermissions.length; i++) { GrantAndPermission gap = grantAndPermissions[i]; grantPermission(gap.getGrantee(), gap.getPermission()); } } /** * Revokes the permissions of a grantee by removing the grantee from the ACL. * * @param grantee * the grantee to remove from this ACL. */ public void revokeAllPermissions(GranteeInterface grantee) { List grantsToRemove = new ArrayList(); for (GrantAndPermission gap: grants) { if (gap.getGrantee().equals(grantee)) { grantsToRemove.add(gap); } } grants.removeAll(grantsToRemove); } /** * @return * the grant and permission collections in this ACL. */ public GrantAndPermission[] getGrantAndPermissions() { return grants.toArray( new GrantAndPermission[grants.size()]); } public XMLBuilder toXMLBuilder() throws ServiceException, ParserConfigurationException, FactoryConfigurationError, TransformerException { if (owner == null) { throw new ServiceException("Invalid AccessControlList: missing an owner"); } XMLBuilder builder = XMLBuilder.create("AccessControlPolicy") .attr("xmlns", Constants.XML_NAMESPACE) .elem("Owner") .elem("ID").text(owner.getId()).up() .elem("DisplayName").text(owner.getDisplayName()).up() .up(); XMLBuilder accessControlList = builder.elem("AccessControlList"); for (GrantAndPermission gap: grants) { GranteeInterface grantee = gap.getGrantee(); Permission permission = gap.getPermission(); accessControlList .elem("Grant") .importXMLBuilder(grantee.toXMLBuilder()) .elem("Permission").text(permission.toString()); } return builder; } /** * @return * an XML representation of the Access Control List object, suitable to send to * a storage service in the request body. */ public String toXml() throws ServiceException { try { return toXMLBuilder().asString(); } catch (Exception e) { throw new ServiceException("Failed to build XML document for ACL", e); } } /** * @return * true if this ACL is a REST pre-canned one, in which case REST/HTTP implementations can use * the x-amz-acl header as a short-cut to set permissions on upload rather than using * a full ACL XML document. * * @deprecated 0.8.0 */ @Deprecated public boolean isCannedRestACL() { return isRESTHeaderACL(); } /** * @return true if this ACL can be set via an HTTP header, rather than via an XML document. */ public boolean isRESTHeaderACL() { return getValueForRESTHeaderACL() != null; } /** * @return the header value string for this ACL if it is a canned ACL, otherwise return null; */ public String getValueForRESTHeaderACL() { if (AccessControlList.REST_CANNED_PRIVATE.equals(this)) { return "private"; } else if (AccessControlList.REST_CANNED_PUBLIC_READ.equals(this)) { return "public-read"; } else if (AccessControlList.REST_CANNED_PUBLIC_READ_WRITE.equals(this)) { return "public-read-write"; } else if (AccessControlList.REST_CANNED_AUTHENTICATED_READ.equals(this)) { return "authenticated-read"; } return null; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/acl/gs/0002755000000000000000000000000011452166202017103 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/acl/gs/AllAuthenticatedUsersGrantee.java0000644000000000000000000000341211441613550025510 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.acl.gs; import com.jamesmurty.utils.XMLBuilder; import org.jets3t.service.acl.GroupGrantee; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; /** * Represents a grant to all authenticated users. * * @author Google Developers * */ public class AllAuthenticatedUsersGrantee extends GroupGrantee { private final String id = "AllAuthenticatedUsers"; @Override public String toXml() throws TransformerException, ParserConfigurationException, FactoryConfigurationError { return toXMLBuilder().asString(); } @Override public XMLBuilder toXMLBuilder() throws TransformerException, ParserConfigurationException, FactoryConfigurationError { return XMLBuilder.create("Scope").attr("type", "AllAuthenticatedUsers"); } @Override public boolean equals(Object obj) { return (obj instanceof AllAuthenticatedUsersGrantee); } @Override public String toString() { return id; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/acl/gs/GroupByDomainGrantee.java0000644000000000000000000000375411441613550024003 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.acl.gs; import com.jamesmurty.utils.XMLBuilder; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.jets3t.service.acl.GroupGrantee; /** * Represents an Group By Domain Grantee, that is a group identified by their domain address. * * @author Google Developers * */ public class GroupByDomainGrantee extends GroupGrantee { public GroupByDomainGrantee() { super(); } /** * Constructs a group grantee object using the given domain address as an identifier. * * @param domain */ public GroupByDomainGrantee(String domain) { super(domain); } @Override public XMLBuilder toXMLBuilder() throws TransformerException, ParserConfigurationException, FactoryConfigurationError { return (XMLBuilder.create("Scope") .attr("type", "GroupByDomain") .element("Domain").text(id) ); } @Override public boolean equals(Object obj) { return (obj instanceof GroupByDomainGrantee && ((GroupByDomainGrantee)obj).getIdentifier() == this.getIdentifier()); } @Override public String toString() { return "GroupByDomain [" + id + "]"; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/acl/gs/AllUsersGrantee.java0000644000000000000000000000354711441613550023016 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.acl.gs; import com.jamesmurty.utils.XMLBuilder; import org.jets3t.service.acl.GroupGrantee; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; /** * Represents a grant to all users. * * @author Google Developers * */ public class AllUsersGrantee extends GroupGrantee { private final String id = "AllUsers"; @Override public String toXml() throws TransformerException, ParserConfigurationException, FactoryConfigurationError { return toXMLBuilder().asString(); } @Override public XMLBuilder toXMLBuilder() throws TransformerException, ParserConfigurationException, FactoryConfigurationError { return XMLBuilder.create("Scope").attr("type", "AllUsers"); } @Override public boolean equals(Object obj) { return (obj instanceof AllUsersGrantee && ((AllUsersGrantee)obj).getIdentifier() == this.getIdentifier()); } @Override public String getIdentifier() { return id; } @Override public String toString() { return id; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/acl/gs/UserByIdGrantee.java0000644000000000000000000000541211451026516022744 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.acl.gs; import com.jamesmurty.utils.XMLBuilder; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.jets3t.service.acl.CanonicalGrantee; /** * Represents a grantee identified by their canonical Google ID, which is something along the lines * of a Google-internal ID specific to a user. For example, Google can map a grantee identified * by an email address to a canonical ID. *

* Canonical grantees may have an associated Display Name, which is a human-friendly name that * Google has linked to the canonical ID (eg the user's login name). * * @author Google Developers * */ public class UserByIdGrantee extends CanonicalGrantee { /** * Default constructor. *

* Warning! If created with this constructor this class will not * represent a valid grantee until the identifier is set. */ public UserByIdGrantee() { super(); } /** * Constructs a grantee with the given canonical ID. * @param identifier */ public UserByIdGrantee(String identifier) { super(identifier); } public UserByIdGrantee(String identifier, String name) { super(identifier); setName(name); } public String getName() { return getDisplayName(); } public void setName(String name) { setDisplayName(name); } @Override public XMLBuilder toXMLBuilder() throws TransformerException, ParserConfigurationException, FactoryConfigurationError { return (XMLBuilder.create("Scope") .attr("type", "UserById") .element("ID").text(id) ); } @Override public boolean equals(Object obj) { return (obj instanceof UserByIdGrantee && ((UserByIdGrantee)obj).getIdentifier() == this.getIdentifier()); } @Override public String toString() { return "UserById [id=" + id + (displayName != null ? ", Name=" + displayName : "") + "]"; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/acl/gs/GroupByEmailAddressGrantee.java0000644000000000000000000000500211451026574025122 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.acl.gs; import com.jamesmurty.utils.XMLBuilder; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.jets3t.service.acl.GroupGrantee; /** * Represents an Group By Email Grantee, that is a group identified by their email address. * * @author Google Developers * */ public class GroupByEmailAddressGrantee extends GroupGrantee { private String name; public GroupByEmailAddressGrantee() { super(); } /** * Constructs a group grantee object using the given email address as an identifier. * * @param email */ public GroupByEmailAddressGrantee(String email) { super(email); } public GroupByEmailAddressGrantee(String email, String name) { super(email); setName(name); } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public XMLBuilder toXMLBuilder() throws TransformerException, ParserConfigurationException, FactoryConfigurationError { XMLBuilder builder = XMLBuilder.create("Scope") .attr("type", "GroupByEmail") .element("EmailAddress").text(getIdentifier()).up(); if (getName() != null) { builder.element("Name").text(getName()); } return builder; } @Override public boolean equals(Object obj) { return (obj instanceof GroupByEmailAddressGrantee && ((GroupByEmailAddressGrantee)obj).getIdentifier() == this.getIdentifier()); } @Override public String toString() { return "GroupByEmail [" + id + (name != null ? ", name=" + getName() : "") + "]"; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/acl/gs/UserByEmailAddressGrantee.java0000644000000000000000000000543011451026672024750 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.acl.gs; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.jets3t.service.acl.EmailAddressGrantee; import com.jamesmurty.utils.XMLBuilder; /** * Represents an User By Email Grantee, that is a grantee identified by their email address. * * @author Google Developers * */ public class UserByEmailAddressGrantee extends EmailAddressGrantee { private String name; /** * Default constructor. *

* Warning! If created with this constructor this class will not * represent a valid grantee until the identifier is set. */ public UserByEmailAddressGrantee() { super(); } /** * Constructs a grantee with the given email. * @param emailAddress * user's service-recognizable email address. */ public UserByEmailAddressGrantee(String emailAddress) { super(emailAddress); } public UserByEmailAddressGrantee(String emailAddress, String name) { super(emailAddress); setName(name); } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public XMLBuilder toXMLBuilder() throws TransformerException, ParserConfigurationException, FactoryConfigurationError { XMLBuilder builder = XMLBuilder.create("Scope") .attr("type", "UserByEmail") .element("EmailAddress").text(getIdentifier()).up(); if (getName() != null) { builder.element("Name").text(getName()); } return builder; } @Override public boolean equals(Object obj) { return (obj instanceof UserByEmailAddressGrantee && ((UserByEmailAddressGrantee)obj).getIdentifier() .equals(getIdentifier())); } @Override public String toString() { return "UserByEmail [email=" + getIdentifier() + (name != null ? ", name=" + getName() : "") + "]"; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/acl/gs/GSAccessControlList.java0000644000000000000000000001102411452167054023600 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.acl.gs; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.jets3t.service.ServiceException; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.acl.GrantAndPermission; import org.jets3t.service.acl.GranteeInterface; import org.jets3t.service.acl.Permission; import com.jamesmurty.utils.XMLBuilder; /** * Represents a Google Storage Access Control List (ACL), including the ACL's set of grantees and the * permissions assigned to each grantee. *

* *

* * @author Google Developers * */ public class GSAccessControlList extends AccessControlList { private static final long serialVersionUID = -3170938665076811564L; /* * Predefined ACLs that can be applied on creation of an object or bucket, * topic "Applying ACLs with an extension request header" at * http://code.google.com/apis/storage/docs/developer-guide.html#authentication */ public static final GSAccessControlList REST_CANNED_PRIVATE = new GSAccessControlList(); public static final GSAccessControlList REST_CANNED_PUBLIC_READ = new GSAccessControlList(); public static final GSAccessControlList REST_CANNED_PUBLIC_READ_WRITE = new GSAccessControlList(); public static final GSAccessControlList REST_CANNED_AUTHENTICATED_READ = new GSAccessControlList(); public static final GSAccessControlList REST_CANNED_BUCKET_OWNER_READ = new GSAccessControlList(); public static final GSAccessControlList REST_CANNED_BUCKET_OWNER_FULL_CONTROL = new GSAccessControlList(); /** * Returns a string representation of the ACL contents, useful for debugging. */ @Override public String toString() { return "GSAccessControlList [owner=" + owner + ", grants=" + getGrantAndPermissions() + "]"; } @Override public XMLBuilder toXMLBuilder() throws ServiceException, ParserConfigurationException, FactoryConfigurationError, TransformerException { if (owner == null) { throw new ServiceException("Invalid AccessControlList: missing an Owner"); } XMLBuilder builder = XMLBuilder.create("AccessControlList"); // Owner XMLBuilder ownerBuilder = builder.elem("Owner"); ownerBuilder.elem("ID").text(owner.getId()).up(); if (owner.getDisplayName() != null) { ownerBuilder.elem("Name").text(owner.getDisplayName()); } XMLBuilder accessControlList = builder.elem("Entries"); for (GrantAndPermission gap: grants) { GranteeInterface grantee = gap.getGrantee(); Permission permission = gap.getPermission(); accessControlList .elem("Entry") .importXMLBuilder(grantee.toXMLBuilder()) .elem("Permission").text(permission.toString()); } return builder; } /** * @return the header value string for this ACL if it is a predefined ACL, otherwise return null; */ @Override public String getValueForRESTHeaderACL() { if (GSAccessControlList.REST_CANNED_PRIVATE.equals(this)) { return "private"; } else if (GSAccessControlList.REST_CANNED_PUBLIC_READ.equals(this)) { return "public-read"; } else if (GSAccessControlList.REST_CANNED_PUBLIC_READ_WRITE.equals(this)) { return "public-read-write"; } else if (GSAccessControlList.REST_CANNED_AUTHENTICATED_READ.equals(this)) { return "authenticated-read"; } else if (GSAccessControlList.REST_CANNED_BUCKET_OWNER_READ.equals(this)) { return "bucket-owner-read"; } else if (GSAccessControlList.REST_CANNED_BUCKET_OWNER_FULL_CONTROL.equals(this)) { return "bucket-owner-full-control"; } return null; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/acl/gs/GroupByIdGrantee.java0000644000000000000000000000456311451026534023130 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.acl.gs; import com.jamesmurty.utils.XMLBuilder; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.jets3t.service.acl.GroupGrantee; /** * Represents a Group grantee. * * @author Google Developers * */ public class GroupByIdGrantee extends GroupGrantee { private String name; public GroupByIdGrantee() { super(); } /** * Constructs a group grantee object using the given group id as an identifier. * * @param id */ public GroupByIdGrantee(String id) { super(id); } public GroupByIdGrantee(String identifier, String name) { super(identifier); setName(name); } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public XMLBuilder toXMLBuilder() throws TransformerException, ParserConfigurationException, FactoryConfigurationError { XMLBuilder builder = XMLBuilder.create("Scope") .attr("type", "GroupById") .element("ID").text(getIdentifier()).up(); if (getName() != null) { builder.element("Name").text(getName()); } return builder; } @Override public boolean equals(Object obj) { return (obj instanceof GroupByIdGrantee && ((GroupByIdGrantee)obj).getIdentifier() == this.getIdentifier()); } @Override public String toString() { return "GroupById [" + id + (name != null ? ", name=" + getName() : "") + "]"; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/acl/Permission.java0000644000000000000000000000563411427702124021474 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.acl; /** * Represents an access permission, as granted to grantees in an {@link AccessControlList}. * Only a limited set of permissions are available, each one is available as a public static * variable in this class of the form PERMISSION_XYZ. * * @author James Murty */ public class Permission { public static final Permission PERMISSION_FULL_CONTROL = new Permission("FULL_CONTROL"); public static final Permission PERMISSION_READ = new Permission("READ"); public static final Permission PERMISSION_WRITE = new Permission("WRITE"); public static final Permission PERMISSION_READ_ACP = new Permission("READ_ACP"); public static final Permission PERMISSION_WRITE_ACP = new Permission("WRITE_ACP"); private String permissionString = ""; private Permission(String permissionString) { this.permissionString = permissionString; } /** * @param str * a string representation of a permission, eg FULL_CONTROL * @return * the Permission object represented by the given permission string */ public static Permission parsePermission(String str) { Permission permission = null; if (str == null) { // Do nothing } else if (str.equals(PERMISSION_FULL_CONTROL.toString())) { permission = PERMISSION_FULL_CONTROL; } else if (str.equals(PERMISSION_READ.toString())) { permission = PERMISSION_READ; } else if (str.equals(PERMISSION_WRITE.toString())) { permission = PERMISSION_WRITE; } else if (str.equals(PERMISSION_READ_ACP.toString())) { permission = PERMISSION_READ_ACP; } else if (str.equals(PERMISSION_WRITE_ACP.toString())) { permission = PERMISSION_WRITE_ACP; } else { permission = null; } return permission; } /** * @return * the string representation of a permission object, eg FULL_CONTROL */ public String toString() { return permissionString; } public int hashCode() { return permissionString.hashCode(); } public boolean equals(Object obj) { return (obj instanceof Permission) && toString().equals(obj.toString()); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/acl/GroupGrantee.java0000644000000000000000000000710611441613550021742 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.acl; import com.jamesmurty.utils.XMLBuilder; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; /** * Represents a Group grantee. *

* Only three groups are available in S3:
* ALL_USERS: The general public
* AUTHENTICATED_USERS: Authenticated Amazon S3 users
* LOG_DELIVERY: Amazon's S3 Log Delivery group, who deliver bucket log files
* * @author James Murty * */ public class GroupGrantee implements GranteeInterface { /** * The group of all users, represented in S3 by the URI: * http://acs.amazonaws.com/groups/global/AllUsers */ public static final GroupGrantee ALL_USERS = new GroupGrantee("http://acs.amazonaws.com/groups/global/AllUsers"); /** * The group of authenticated users, represented in S3 by the URI: * http://acs.amazonaws.com/groups/global/AuthenticatedUsers */ public static final GroupGrantee AUTHENTICATED_USERS = new GroupGrantee("http://acs.amazonaws.com/groups/global/AuthenticatedUsers"); /** * The group of Bucket Log delivery users, represented in S3 by the URI: * http://acs.amazonaws.com/groups/s3/LogDelivery */ public static final GroupGrantee LOG_DELIVERY = new GroupGrantee("http://acs.amazonaws.com/groups/s3/LogDelivery"); protected String id = null; public GroupGrantee() { } /** * Constructs a group grantee object using the given group URI as an identifier. *

* Note: All possible group types are available as public static variables from this class, * so this constructor should rarely be necessary. * * @param groupUri */ public GroupGrantee(String groupUri) { this.id = groupUri; } public String toXml() throws TransformerException, ParserConfigurationException, FactoryConfigurationError { return toXMLBuilder().asString(); } public XMLBuilder toXMLBuilder() throws TransformerException, ParserConfigurationException, FactoryConfigurationError { return (XMLBuilder.create("Grantee") .attr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance") .attr("xsi:type", "Group") .element("URI").text(id) ); } /** * Set the group grantee's URI. */ public void setIdentifier(String uri) { this.id = uri; } /** * Returns the group grantee's URI. */ public String getIdentifier() { return id; } public String toString() { return "GroupGrantee [" + id + "]"; } public boolean equals(Object obj) { if (obj instanceof GroupGrantee) { return id.equals(((GroupGrantee)obj).id); } return false; } public int hashCode() { return id.hashCode(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/acl/GranteeInterface.java0000644000000000000000000000333411441613550022545 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.acl; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import com.jamesmurty.utils.XMLBuilder; /** * Represents a grantee (entity) who can be assigned access permissions in an {@link AccessControlList}. * All grantees have an ID of some kind (though the format of the ID can differ depending on the kind * of grantee) and can be represented as an XML fragment suitable for use by the S3 REST implementation. * * @author James Murty */ public interface GranteeInterface { /** * @return * the grantee represented in an XML fragment compatible with the S3 REST interface. */ public String toXml() throws TransformerException, ParserConfigurationException, FactoryConfigurationError; public XMLBuilder toXMLBuilder() throws TransformerException, ParserConfigurationException, FactoryConfigurationError; public void setIdentifier(String id); public String getIdentifier(); } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/acl/EmailAddressGrantee.java0000644000000000000000000000540511451016022023173 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.acl; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import com.jamesmurty.utils.XMLBuilder; /** * Represents an Email Grantee, that is a grantee identified by their email address and * authenticated by an Amazon system. * * @author James Murty * */ public class EmailAddressGrantee implements GranteeInterface { private String emailAddress = null; /** * Default construtor. *

* Warning! If this constructor is used the class will not represent * a valid email grantee until the identifier has been set. */ public EmailAddressGrantee() { } /** * Constructs an email grantee with the given email address. * @param emailAddress */ public EmailAddressGrantee(String emailAddress) { this.setIdentifier(emailAddress); } public String toXml() throws TransformerException, ParserConfigurationException, FactoryConfigurationError { return toXMLBuilder().asString(); } public XMLBuilder toXMLBuilder() throws TransformerException, ParserConfigurationException, FactoryConfigurationError { return (XMLBuilder.create("Grantee") .attr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance") .attr("xsi:type", "AmazonCustomerByEmail") .element("EmailAddress").text(emailAddress) ); } /** * Set the email address as the grantee's ID. */ public void setIdentifier(String emailAddress) { this.emailAddress = emailAddress; } /** * Returns the grantee's email address (ID). */ public String getIdentifier() { return emailAddress; } @Override public boolean equals(Object obj) { if (obj instanceof EmailAddressGrantee) { return emailAddress.equals(((EmailAddressGrantee)obj).emailAddress); } return false; } @Override public int hashCode() { return emailAddress.hashCode(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/acl/GrantAndPermission.java0000644000000000000000000000336211441613550023107 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.acl; /** * Simple container object to combine a grantee object with a permission object. * * @author James Murty */ public class GrantAndPermission { private GranteeInterface grantee = null; private Permission permission = null; public GrantAndPermission(GranteeInterface grantee, Permission permission) { this.grantee = grantee; this.permission = permission; } public GranteeInterface getGrantee() { return grantee; } public Permission getPermission() { return permission; } public int hashCode() { return (grantee + ":" + permission.toString()).hashCode(); } public boolean equals(Object obj) { return (obj instanceof GrantAndPermission && this.getGrantee().equals(((GrantAndPermission)obj).getGrantee()) && this.getPermission().equals(((GrantAndPermission)obj).getPermission()) ); } public String toString() { return "GrantAndPermission [grantee=" + grantee + ", permission=" + permission + "]"; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/S3Service.java0000644000000000000000000046540311550442104020413 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008-2010 James Murty, 2008 Zmanda Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.httpclient.HostConfiguration; import org.apache.commons.httpclient.auth.CredentialsProvider; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.acl.GrantAndPermission; import org.jets3t.service.acl.GroupGrantee; import org.jets3t.service.acl.Permission; import org.jets3t.service.impl.rest.httpclient.RestS3Service; import org.jets3t.service.impl.rest.httpclient.RestStorageService; import org.jets3t.service.model.BaseVersionOrDeleteMarker; import org.jets3t.service.model.MultipartCompleted; import org.jets3t.service.model.MultipartPart; import org.jets3t.service.model.MultipartUpload; import org.jets3t.service.model.NotificationConfig; import org.jets3t.service.model.S3Bucket; import org.jets3t.service.model.S3BucketLoggingStatus; import org.jets3t.service.model.S3BucketVersioningStatus; import org.jets3t.service.model.S3DeleteMarker; import org.jets3t.service.model.S3Object; import org.jets3t.service.model.S3Version; import org.jets3t.service.model.StorageBucket; import org.jets3t.service.model.StorageObject; import org.jets3t.service.model.WebsiteConfig; import org.jets3t.service.mx.MxDelegate; import org.jets3t.service.security.AWSDevPayCredentials; import org.jets3t.service.security.ProviderCredentials; import org.jets3t.service.utils.MultipartUtils; import org.jets3t.service.utils.RestUtils; import org.jets3t.service.utils.ServiceUtils; import org.jets3t.service.utils.signedurl.SignedUrlHandler; /** * A service that handles communication with S3, offering all the operations that can be performed * on S3 accounts. *

* This class must be extended by implementation classes that perform the communication with S3 via * a particular interface, such as REST or SOAP. The JetS3t suite includes a REST implementation * in {@link org.jets3t.service.impl.rest.httpclient.RestS3Service}. *

*

* Implementations of S3Service must be thread-safe as they will probably be used by * the multi-threaded service class {@link org.jets3t.service.multithread.S3ServiceMulti}. *

*

* This class uses properties obtained through {@link Jets3tProperties}. For more information on * these properties please refer to * JetS3t Configuration *

* * @author James Murty * @author Nikolas Coukouma */ public abstract class S3Service extends RestStorageService implements SignedUrlHandler { private static final Log log = LogFactory.getLog(S3Service.class); protected S3Service(ProviderCredentials credentials, String invokingApplicationDescription, CredentialsProvider credentialsProvider, Jets3tProperties jets3tProperties, HostConfiguration hostConfig) { super(credentials, invokingApplicationDescription, credentialsProvider, jets3tProperties, hostConfig); } /** * Construct an S3Service identified by the given user credentials. * * @param credentials * the S3 user credentials to use when communicating with S3, may be null in which case the * communication is done as an anonymous user. * @param invokingApplicationDescription * a short description of the application using the service, suitable for inclusion in a * user agent string for REST/HTTP requests. Ideally this would include the application's * version number, for example: Cockpit/0.7.3 or My App Name/1.0 * @param jets3tProperties * JetS3t properties that will be applied within this service. */ protected S3Service(ProviderCredentials credentials, String invokingApplicationDescription, Jets3tProperties jets3tProperties) { super(credentials, invokingApplicationDescription, null, jets3tProperties); } /** * Construct an S3Service identified by the given user credentials. * * @param credentials * the S3 user credentials to use when communicating with S3, may be null in which case the * communication is done as an anonymous user. * @param invokingApplicationDescription * a short description of the application using the service, suitable for inclusion in a * user agent string for REST/HTTP requests. Ideally this would include the application's * version number, for example: Cockpit/0.7.3 or My App Name/1.0 */ protected S3Service(ProviderCredentials credentials, String invokingApplicationDescription) { this(credentials, invokingApplicationDescription, Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME)); } /** * Construct an S3Service identified by the given user credentials. * * @param credentials * the S3 user credentials to use when communicating with S3, may be null in which case the * communication is done as an anonymous user. */ protected S3Service(ProviderCredentials credentials) { this(credentials, null); } /** * @return the credentials identifying the service user, or null for anonymous. * @deprecated 0.8.0 use {@link #getProviderCredentials()} instead */ @Deprecated public ProviderCredentials getAWSCredentials() { return credentials; } /** * Returns the URL representing an object in S3 without a signature. This URL * can only be used to download publicly-accessible objects. * * @param bucketName * the name of the bucket that contains the object. * @param objectKey * the key name of the object. * @param isVirtualHost * if this parameter is true, the bucket name is treated as a virtual host name. To use * this option, the bucket name must be a valid DNS name that is an alias to an S3 bucket. * @param isHttps * if true, the signed URL will use the HTTPS protocol. If false, the signed URL will * use the HTTP protocol. * @param isDnsBucketNamingDisabled * if true, the signed URL will not use the DNS-name format for buckets eg. * jets3t.s3.amazonaws.com. Unless you have a specific reason to disable * DNS bucket naming, leave this value false. * * @return * the object's URL. * * @throws S3ServiceException */ public String createUnsignedObjectUrl(String bucketName, String objectKey, boolean isVirtualHost, boolean isHttps, boolean isDnsBucketNamingDisabled) throws S3ServiceException { // Create a signed GET URL then strip away the signature query components. String signedGETUrl = createSignedUrl("GET", bucketName, objectKey, null, null, 0, isVirtualHost, isHttps, isDnsBucketNamingDisabled); return signedGETUrl.split("\\?")[0]; } /** * Generates a signed URL string that will grant access to an S3 resource (bucket or object) * to whoever uses the URL up until the time specified. * * @param method * the HTTP method to sign, such as GET or PUT (note that S3 does not support POST requests). * @param bucketName * the name of the bucket to include in the URL, must be a valid bucket name. * @param objectKey * the name of the object to include in the URL, if null only the bucket name is used. * @param specialParamName * the name of a request parameter to add to the URL generated by this method. 'Special' * parameters may include parameters that specify the kind of S3 resource that the URL * will refer to, such as 'acl', 'torrent', 'logging', or 'location'. * @param headersMap * headers to add to the signed URL, may be null. * Headers that must match between the signed URL and the actual request include: * content-md5, content-type, and any header starting with 'x-amz-'. * @param secondsSinceEpoch * the time after which URL's signature will no longer be valid. This time cannot be null. * Note: This time is specified in seconds since the epoch, not milliseconds. * @param isVirtualHost * if this parameter is true, the bucket name is treated as a virtual host name. To use * this option, the bucket name must be a valid DNS name that is an alias to an S3 bucket. * @param isHttps * if true, the signed URL will use the HTTPS protocol. If false, the signed URL will * use the HTTP protocol. * @param isDnsBucketNamingDisabled * if true, the signed URL will not use the DNS-name format for buckets eg. * jets3t.s3.amazonaws.com. Unless you have a specific reason to disable * DNS bucket naming, leave this value false. * * @return * a URL signed in such a way as to grant access to an S3 resource to whoever uses it. * * @throws S3ServiceException */ public String createSignedUrl(String method, String bucketName, String objectKey, String specialParamName, Map headersMap, long secondsSinceEpoch, boolean isVirtualHost, boolean isHttps, boolean isDnsBucketNamingDisabled) throws S3ServiceException { try { String s3Endpoint = this.getEndpoint(); String uriPath = ""; String hostname = (isVirtualHost ? bucketName : ServiceUtils.generateS3HostnameForBucket( bucketName, isDnsBucketNamingDisabled, s3Endpoint)); if (headersMap == null) { headersMap = new HashMap(); } // If we are using an alternative hostname, include the hostname/bucketname in the resource path. String virtualBucketPath = ""; if (!s3Endpoint.equals(hostname)) { int subdomainOffset = hostname.lastIndexOf("." + s3Endpoint); if (subdomainOffset > 0) { // Hostname represents an S3 sub-domain, so the bucket's name is the CNAME portion virtualBucketPath = hostname.substring(0, subdomainOffset) + "/"; } else { // Hostname represents a virtual host, so the bucket's name is identical to hostname virtualBucketPath = hostname + "/"; } uriPath = (objectKey != null ? RestUtils.encodeUrlPath(objectKey, "/") : ""); } else { uriPath = bucketName + (objectKey != null ? "/" + RestUtils.encodeUrlPath(objectKey, "/") : ""); } if (specialParamName != null) { uriPath += "?" + specialParamName + "&"; } else { uriPath += "?"; } // Include any DevPay tokens in signed request if (credentials instanceof AWSDevPayCredentials) { AWSDevPayCredentials devPayCredentials = (AWSDevPayCredentials) credentials; if (devPayCredentials.getProductToken() != null) { String securityToken = devPayCredentials.getUserToken() + "," + devPayCredentials.getProductToken(); headersMap.put(Constants.AMZ_SECURITY_TOKEN, securityToken); } else { headersMap.put(Constants.AMZ_SECURITY_TOKEN, devPayCredentials.getUserToken()); } uriPath += Constants.AMZ_SECURITY_TOKEN + "=" + RestUtils.encodeUrlString((String) headersMap.get(Constants.AMZ_SECURITY_TOKEN)) + "&"; } uriPath += "AWSAccessKeyId=" + credentials.getAccessKey(); uriPath += "&Expires=" + secondsSinceEpoch; // Include Requester Pays header flag, if the flag is included as a request parameter. if (specialParamName != null && specialParamName.toLowerCase().indexOf(Constants.REQUESTER_PAYS_BUCKET_FLAG) >= 0) { String[] requesterPaysHeaderAndValue = Constants.REQUESTER_PAYS_BUCKET_FLAG.split("="); headersMap.put(requesterPaysHeaderAndValue[0], requesterPaysHeaderAndValue[1]); } String serviceEndpointVirtualPath = this.getVirtualPath(); String canonicalString = RestUtils.makeServiceCanonicalString(method, serviceEndpointVirtualPath + "/" + virtualBucketPath + uriPath, renameMetadataKeys(headersMap), String.valueOf(secondsSinceEpoch), this.getRestHeaderPrefix(), this.getResourceParameterNames()); if (log.isDebugEnabled()) { log.debug("Signing canonical string:\n" + canonicalString); } String signedCanonical = ServiceUtils.signWithHmacSha1(credentials.getSecretKey(), canonicalString); String encodedCanonical = RestUtils.encodeUrlString(signedCanonical); uriPath += "&Signature=" + encodedCanonical; if (isHttps) { int httpsPort = this.getHttpsPort(); return "https://" + hostname + (httpsPort != 443 ? ":" + httpsPort : "") + serviceEndpointVirtualPath + "/" + uriPath; } else { int httpPort = this.getHttpPort(); return "http://" + hostname + (httpPort != 80 ? ":" + httpPort : "") + serviceEndpointVirtualPath + "/" + uriPath; } } catch (ServiceException se) { throw new S3ServiceException(se); } catch (UnsupportedEncodingException e) { throw new S3ServiceException(e); } } /** * Generates a signed URL string that will grant access to an S3 resource (bucket or object) * to whoever uses the URL up until the time specified. The URL will use the default * JetS3t property settings in the jets3t.properties file to determine whether * to generate HTTP or HTTPS links (s3service.https-only), and whether to disable * DNS bucket naming (s3service.disable-dns-buckets). * * @param method * the HTTP method to sign, such as GET or PUT (note that S3 does not support POST requests). * @param bucketName * the name of the bucket to include in the URL, must be a valid bucket name. * @param objectKey * the name of the object to include in the URL, if null only the bucket name is used. * @param specialParamName * the name of a request parameter to add to the URL generated by this method. 'Special' * parameters may include parameters that specify the kind of S3 resource that the URL * will refer to, such as 'acl', 'torrent', 'logging' or 'location'. * @param headersMap * headers to add to the signed URL, may be null. * Headers that must match between the signed URL and the actual request include: * content-md5, content-type, and any header starting with 'x-amz-'. * @param secondsSinceEpoch * the time after which URL's signature will no longer be valid. This time cannot be null. * Note: This time is specified in seconds since the epoch, not milliseconds. * @param isVirtualHost * if this parameter is true, the bucket name is treated as a virtual host name. To use * this option, the bucket name must be a valid DNS name that is an alias to an S3 bucket. * * @return * a URL signed in such a way as to grant access to an S3 resource to whoever uses it. * * @throws S3ServiceException */ public String createSignedUrl(String method, String bucketName, String objectKey, String specialParamName, Map headersMap, long secondsSinceEpoch, boolean isVirtualHost) throws S3ServiceException { boolean isHttps = this.isHttpsOnly(); boolean disableDnsBuckets = this.getDisableDnsBuckets(); return createSignedUrl(method, bucketName, objectKey, specialParamName, headersMap, secondsSinceEpoch, isVirtualHost, isHttps, disableDnsBuckets); } /** * Generates a signed URL string that will grant access to an S3 resource (bucket or object) * to whoever uses the URL up until the time specified. * * @param method * the HTTP method to sign, such as GET or PUT (note that S3 does not support POST requests). * @param bucketName * the name of the bucket to include in the URL, must be a valid bucket name. * @param objectKey * the name of the object to include in the URL, if null only the bucket name is used. * @param specialParamName * the name of a request parameter to add to the URL generated by this method. 'Special' * parameters may include parameters that specify the kind of S3 resource that the URL * will refer to, such as 'acl', 'torrent', 'logging' or 'location'. * @param headersMap * headers to add to the signed URL, may be null. * Headers that must match between the signed URL and the actual request include: * content-md5, content-type, and any header starting with 'x-amz-'. * @param secondsSinceEpoch * the time after which URL's signature will no longer be valid. This time cannot be null. * Note: This time is specified in seconds since the epoch, not milliseconds. * * @return * a URL signed in such a way as to grant access to an S3 resource to whoever uses it. * * @throws S3ServiceException */ public String createSignedUrl(String method, String bucketName, String objectKey, String specialParamName, Map headersMap, long secondsSinceEpoch) throws S3ServiceException { return createSignedUrl(method, bucketName, objectKey, specialParamName, headersMap, secondsSinceEpoch, false); } /** * Generates a signed GET URL. * * @param bucketName * the name of the bucket to include in the URL, must be a valid bucket name. * @param objectKey * the name of the object to include in the URL, if null only the bucket name is used. * @param expiryTime * the time after which URL's signature will no longer be valid. This time cannot be null. * @param isVirtualHost * if this parameter is true, the bucket name is treated as a virtual host name. To use * this option, the bucket name must be a valid DNS name that is an alias to an S3 bucket. * * @return * a URL signed in such a way as to grant GET access to an S3 resource to whoever uses it. * @throws S3ServiceException */ public String createSignedGetUrl(String bucketName, String objectKey, Date expiryTime, boolean isVirtualHost) throws S3ServiceException { long secondsSinceEpoch = expiryTime.getTime() / 1000; return createSignedUrl("GET", bucketName, objectKey, null, null, secondsSinceEpoch, isVirtualHost); } /** * Generates a signed GET URL. * * @param bucketName * the name of the bucket to include in the URL, must be a valid bucket name. * @param objectKey * the name of the object to include in the URL, if null only the bucket name is used. * @param expiryTime * the time after which URL's signature will no longer be valid. This time cannot be null. * * @return * a URL signed in such a way as to grant GET access to an S3 resource to whoever uses it. * @throws S3ServiceException */ public String createSignedGetUrl(String bucketName, String objectKey, Date expiryTime) throws S3ServiceException { return createSignedGetUrl(bucketName, objectKey, expiryTime, false); } /** * Generates a signed PUT URL. * * @param bucketName * the name of the bucket to include in the URL, must be a valid bucket name. * @param objectKey * the name of the object to include in the URL, if null only the bucket name is used. * @param headersMap * headers to add to the signed URL, may be null. * Headers that must match between the signed URL and the actual request include: * content-md5, content-type, and any header starting with 'x-amz-'. * @param expiryTime * the time after which URL's signature will no longer be valid. This time cannot be null. * @param isVirtualHost * if this parameter is true, the bucket name is treated as a virtual host name. To use * this option, the bucket name must be a valid DNS name that is an alias to an S3 bucket. * * @return * a URL signed in such a way as to allow anyone to PUT an object into S3. * @throws S3ServiceException */ public String createSignedPutUrl(String bucketName, String objectKey, Map headersMap, Date expiryTime, boolean isVirtualHost) throws S3ServiceException { long secondsSinceEpoch = expiryTime.getTime() / 1000; return createSignedUrl("PUT", bucketName, objectKey, null, headersMap, secondsSinceEpoch, isVirtualHost); } /** * Generates a signed PUT URL. * * @param bucketName * the name of the bucket to include in the URL, must be a valid bucket name. * @param objectKey * the name of the object to include in the URL, if null only the bucket name is used. * @param headersMap * headers to add to the signed URL, may be null. * Headers that must match between the signed URL and the actual request include: * content-md5, content-type, and any header starting with 'x-amz-'. * @param expiryTime * the time after which URL's signature will no longer be valid. This time cannot be null. * * @return * a URL signed in such a way as to allow anyone to PUT an object into S3. * @throws S3ServiceException */ public String createSignedPutUrl(String bucketName, String objectKey, Map headersMap, Date expiryTime) throws S3ServiceException { return createSignedPutUrl(bucketName, objectKey, headersMap, expiryTime, false); } /** * Generates a signed DELETE URL. * * @param bucketName * the name of the bucket to include in the URL, must be a valid bucket name. * @param objectKey * the name of the object to include in the URL, if null only the bucket name is used. * @param expiryTime * the time after which URL's signature will no longer be valid. This time cannot be null. * @param isVirtualHost * if this parameter is true, the bucket name is treated as a virtual host name. To use * this option, the bucket name must be a valid DNS name that is an alias to an S3 bucket. * * @return * a URL signed in such a way as to allow anyone do DELETE an object in S3. * @throws S3ServiceException */ public String createSignedDeleteUrl(String bucketName, String objectKey, Date expiryTime, boolean isVirtualHost) throws S3ServiceException { long secondsSinceEpoch = expiryTime.getTime() / 1000; return createSignedUrl("DELETE", bucketName, objectKey, null, null, secondsSinceEpoch, isVirtualHost); } /** * Generates a signed DELETE URL. * * @param bucketName * the name of the bucket to include in the URL, must be a valid bucket name. * @param objectKey * the name of the object to include in the URL, if null only the bucket name is used. * @param expiryTime * the time after which URL's signature will no longer be valid. This time cannot be null. * * @return * a URL signed in such a way as to allow anyone do DELETE an object in S3. * @throws S3ServiceException */ public String createSignedDeleteUrl(String bucketName, String objectKey, Date expiryTime) throws S3ServiceException { return createSignedDeleteUrl(bucketName, objectKey, expiryTime, false); } /** * Generates a signed HEAD URL. * * @param bucketName * the name of the bucket to include in the URL, must be a valid bucket name. * @param objectKey * the name of the object to include in the URL, if null only the bucket name is used. * @param expiryTime * the time after which URL's signature will no longer be valid. This time cannot be null. * @param isVirtualHost * if this parameter is true, the bucket name is treated as a virtual host name. To use * this option, the bucket name must be a valid DNS name that is an alias to an S3 bucket. * * @return * a URL signed in such a way as to grant HEAD access to an S3 resource to whoever uses it. * @throws S3ServiceException */ public String createSignedHeadUrl(String bucketName, String objectKey, Date expiryTime, boolean isVirtualHost) throws S3ServiceException { long secondsSinceEpoch = expiryTime.getTime() / 1000; return createSignedUrl("HEAD", bucketName, objectKey, null, null, secondsSinceEpoch, isVirtualHost); } /** * Generates a signed HEAD URL. * * @param bucketName * the name of the bucket to include in the URL, must be a valid bucket name. * @param objectKey * the name of the object to include in the URL, if null only the bucket name is used. * @param expiryTime * the time after which URL's signature will no longer be valid. This time cannot be null. * * @return * a URL signed in such a way as to grant HEAD access to an S3 resource to whoever uses it. * @throws S3ServiceException */ public String createSignedHeadUrl(String bucketName, String objectKey, Date expiryTime) throws S3ServiceException { return createSignedHeadUrl(bucketName, objectKey, expiryTime, false); } /** * Generates a signed URL string that will grant access to an S3 resource (bucket or object) * to whoever uses the URL up until the time specified. * * @deprecated 0.7.4 * * @param method * the HTTP method to sign, such as GET or PUT (note that S3 does not support POST requests). * @param bucketName * the name of the bucket to include in the URL, must be a valid bucket name. * @param objectKey * the name of the object to include in the URL, if null only the bucket name is used. * @param specialParamName * the name of a request parameter to add to the URL generated by this method. 'Special' * parameters may include parameters that specify the kind of S3 resource that the URL * will refer to, such as 'acl', 'torrent', 'logging', or 'location'. * @param headersMap * headers to add to the signed URL, may be null. * Headers that must match between the signed URL and the actual request include: * content-md5, content-type, and any header starting with 'x-amz-'. * @param credentials * the credentials of someone with sufficient privileges to grant access to the bucket/object * @param secondsSinceEpoch * the time after which URL's signature will no longer be valid. This time cannot be null. * Note: This time is specified in seconds since the epoch, not milliseconds. * @param isVirtualHost * if this parameter is true, the bucket name is treated as a virtual host name. To use * this option, the bucket name must be a valid DNS name that is an alias to an S3 bucket. * @param isHttps * if true, the signed URL will use the HTTPS protocol. If false, the signed URL will * use the HTTP protocol. * @param isDnsBucketNamingDisabled * if true, the signed URL will not use the DNS-name format for buckets eg. * jets3t.s3.amazonaws.com. Unless you have a specific reason to disable * DNS bucket naming, leave this value false. * * @return * a URL signed in such a way as to grant access to an S3 resource to whoever uses it. * * @throws S3ServiceException */ @Deprecated public static String createSignedUrl(String method, String bucketName, String objectKey, String specialParamName, Map headersMap, ProviderCredentials credentials, long secondsSinceEpoch, boolean isVirtualHost, boolean isHttps, boolean isDnsBucketNamingDisabled) throws S3ServiceException { S3Service s3Service = new RestS3Service(credentials); return s3Service.createSignedUrl(method, bucketName, objectKey, specialParamName, headersMap, secondsSinceEpoch, isVirtualHost, isHttps, isDnsBucketNamingDisabled); } /** * Generates a signed URL string that will grant access to an S3 resource (bucket or object) * to whoever uses the URL up until the time specified. The URL will use the default * JetS3t property settings in the jets3t.properties file to determine whether * to generate HTTP or HTTPS links (s3service.https-only), and whether to disable * DNS bucket naming (s3service.disable-dns-buckets). * * @deprecated 0.7.4 * * @param method * the HTTP method to sign, such as GET or PUT (note that S3 does not support POST requests). * @param bucketName * the name of the bucket to include in the URL, must be a valid bucket name. * @param objectKey * the name of the object to include in the URL, if null only the bucket name is used. * @param specialParamName * the name of a request parameter to add to the URL generated by this method. 'Special' * parameters may include parameters that specify the kind of S3 resource that the URL * will refer to, such as 'acl', 'torrent', 'logging' or 'location'. * @param headersMap * headers to add to the signed URL, may be null. * Headers that must match between the signed URL and the actual request include: * content-md5, content-type, and any header starting with 'x-amz-'. * @param credentials * the credentials of someone with sufficient privileges to grant access to the bucket/object * @param secondsSinceEpoch * the time after which URL's signature will no longer be valid. This time cannot be null. * Note: This time is specified in seconds since the epoch, not milliseconds. * @param isVirtualHost * if this parameter is true, the bucket name is treated as a virtual host name. To use * this option, the bucket name must be a valid DNS name that is an alias to an S3 bucket. * * @return * a URL signed in such a way as to grant access to an S3 resource to whoever uses it. * * @throws S3ServiceException */ @Deprecated public String createSignedUrl(String method, String bucketName, String objectKey, String specialParamName, Map headersMap, ProviderCredentials credentials, long secondsSinceEpoch, boolean isVirtualHost) throws S3ServiceException { boolean isHttps = this.getHttpsOnly(); boolean disableDnsBuckets = this.getDisableDnsBuckets(); return createSignedUrl(method, bucketName, objectKey, specialParamName, headersMap, credentials, secondsSinceEpoch, isVirtualHost, isHttps, disableDnsBuckets); } /** * Generates a signed URL string that will grant access to an S3 resource (bucket or object) * to whoever uses the URL up until the time specified. * * @deprecated 0.7.4 * * @param method * the HTTP method to sign, such as GET or PUT (note that S3 does not support POST requests). * @param bucketName * the name of the bucket to include in the URL, must be a valid bucket name. * @param objectKey * the name of the object to include in the URL, if null only the bucket name is used. * @param specialParamName * the name of a request parameter to add to the URL generated by this method. 'Special' * parameters may include parameters that specify the kind of S3 resource that the URL * will refer to, such as 'acl', 'torrent', 'logging' or 'location'. * @param headersMap * headers to add to the signed URL, may be null. * Headers that must match between the signed URL and the actual request include: * content-md5, content-type, and any header starting with 'x-amz-'. * @param credentials * the credentials of someone with sufficient privileges to grant access to the bucket/object * @param secondsSinceEpoch * the time after which URL's signature will no longer be valid. This time cannot be null. * Note: This time is specified in seconds since the epoch, not milliseconds. * * @return * a URL signed in such a way as to grant access to an S3 resource to whoever uses it. * * @throws S3ServiceException */ @Deprecated public String createSignedUrl(String method, String bucketName, String objectKey, String specialParamName, Map headersMap, ProviderCredentials credentials, long secondsSinceEpoch) throws S3ServiceException { return createSignedUrl(method, bucketName, objectKey, specialParamName, headersMap, credentials, secondsSinceEpoch, false); } /** * Generates a signed GET URL. * * @deprecated 0.7.4 * * @param bucketName * the name of the bucket to include in the URL, must be a valid bucket name. * @param objectKey * the name of the object to include in the URL, if null only the bucket name is used. * @param credentials * the credentials of someone with sufficient privileges to grant access to the bucket/object * @param expiryTime * the time after which URL's signature will no longer be valid. This time cannot be null. * @param isVirtualHost * if this parameter is true, the bucket name is treated as a virtual host name. To use * this option, the bucket name must be a valid DNS name that is an alias to an S3 bucket. * * @return * a URL signed in such a way as to grant GET access to an S3 resource to whoever uses it. * @throws S3ServiceException */ @Deprecated public String createSignedGetUrl(String bucketName, String objectKey, ProviderCredentials credentials, Date expiryTime, boolean isVirtualHost) throws S3ServiceException { long secondsSinceEpoch = expiryTime.getTime() / 1000; return createSignedUrl("GET", bucketName, objectKey, null, null, credentials, secondsSinceEpoch, isVirtualHost); } /** * Generates a signed GET URL. * * @deprecated 0.7.4 * * @param bucketName * the name of the bucket to include in the URL, must be a valid bucket name. * @param objectKey * the name of the object to include in the URL, if null only the bucket name is used. * @param credentials * the credentials of someone with sufficient privileges to grant access to the bucket/object * @param expiryTime * the time after which URL's signature will no longer be valid. This time cannot be null. * * @return * a URL signed in such a way as to grant GET access to an S3 resource to whoever uses it. * @throws S3ServiceException */ @Deprecated public String createSignedGetUrl(String bucketName, String objectKey, ProviderCredentials credentials, Date expiryTime) throws S3ServiceException { return createSignedGetUrl(bucketName, objectKey, credentials, expiryTime, false); } /** * Generates a signed PUT URL. * * @deprecated 0.7.4 * * @param bucketName * the name of the bucket to include in the URL, must be a valid bucket name. * @param objectKey * the name of the object to include in the URL, if null only the bucket name is used. * @param headersMap * headers to add to the signed URL, may be null. * Headers that must match between the signed URL and the actual request include: * content-md5, content-type, and any header starting with 'x-amz-'. * @param credentials * the credentials of someone with sufficient privileges to grant access to the bucket/object * @param expiryTime * the time after which URL's signature will no longer be valid. This time cannot be null. * @param isVirtualHost * if this parameter is true, the bucket name is treated as a virtual host name. To use * this option, the bucket name must be a valid DNS name that is an alias to an S3 bucket. * * @return * a URL signed in such a way as to allow anyone to PUT an object into S3. * @throws S3ServiceException */ @Deprecated public String createSignedPutUrl(String bucketName, String objectKey, Map headersMap, ProviderCredentials credentials, Date expiryTime, boolean isVirtualHost) throws S3ServiceException { long secondsSinceEpoch = expiryTime.getTime() / 1000; return createSignedUrl("PUT", bucketName, objectKey, null, headersMap, credentials, secondsSinceEpoch, isVirtualHost); } /** * Generates a signed PUT URL. * * @deprecated 0.7.4 * * @param bucketName * the name of the bucket to include in the URL, must be a valid bucket name. * @param objectKey * the name of the object to include in the URL, if null only the bucket name is used. * @param headersMap * headers to add to the signed URL, may be null. * Headers that must match between the signed URL and the actual request include: * content-md5, content-type, and any header starting with 'x-amz-'. * @param credentials * the credentials of someone with sufficient privileges to grant access to the bucket/object * @param expiryTime * the time after which URL's signature will no longer be valid. This time cannot be null. * * @return * a URL signed in such a way as to allow anyone to PUT an object into S3. * @throws S3ServiceException */ @Deprecated public String createSignedPutUrl(String bucketName, String objectKey, Map headersMap, ProviderCredentials credentials, Date expiryTime) throws S3ServiceException { return createSignedPutUrl(bucketName, objectKey, headersMap, credentials, expiryTime, false); } /** * Generates a signed DELETE URL. * * @deprecated 0.7.4 * * @param bucketName * the name of the bucket to include in the URL, must be a valid bucket name. * @param objectKey * the name of the object to include in the URL, if null only the bucket name is used. * @param credentials * the credentials of someone with sufficient privileges to grant access to the bucket/object * @param expiryTime * the time after which URL's signature will no longer be valid. This time cannot be null. * @param isVirtualHost * if this parameter is true, the bucket name is treated as a virtual host name. To use * this option, the bucket name must be a valid DNS name that is an alias to an S3 bucket. * * @return * a URL signed in such a way as to allow anyone do DELETE an object in S3. * @throws S3ServiceException */ @Deprecated public String createSignedDeleteUrl(String bucketName, String objectKey, ProviderCredentials credentials, Date expiryTime, boolean isVirtualHost) throws S3ServiceException { long secondsSinceEpoch = expiryTime.getTime() / 1000; return createSignedUrl("DELETE", bucketName, objectKey, null, null, credentials, secondsSinceEpoch, isVirtualHost); } /** * Generates a signed DELETE URL. * * @deprecated 0.7.4 * * @param bucketName * the name of the bucket to include in the URL, must be a valid bucket name. * @param objectKey * the name of the object to include in the URL, if null only the bucket name is used. * @param credentials * the credentials of someone with sufficient privileges to grant access to the bucket/object * @param expiryTime * the time after which URL's signature will no longer be valid. This time cannot be null. * * @return * a URL signed in such a way as to allow anyone do DELETE an object in S3. * @throws S3ServiceException */ @Deprecated public String createSignedDeleteUrl(String bucketName, String objectKey, ProviderCredentials credentials, Date expiryTime) throws S3ServiceException { return createSignedDeleteUrl(bucketName, objectKey, credentials, expiryTime, false); } /** * Generates a signed HEAD URL. * * @deprecated 0.7.4 * * @param bucketName * the name of the bucket to include in the URL, must be a valid bucket name. * @param objectKey * the name of the object to include in the URL, if null only the bucket name is used. * @param credentials * the credentials of someone with sufficient privileges to grant access to the bucket/object * @param expiryTime * the time after which URL's signature will no longer be valid. This time cannot be null. * @param isVirtualHost * if this parameter is true, the bucket name is treated as a virtual host name. To use * this option, the bucket name must be a valid DNS name that is an alias to an S3 bucket. * * @return * a URL signed in such a way as to grant HEAD access to an S3 resource to whoever uses it. * @throws S3ServiceException */ @Deprecated public String createSignedHeadUrl(String bucketName, String objectKey, ProviderCredentials credentials, Date expiryTime, boolean isVirtualHost) throws S3ServiceException { long secondsSinceEpoch = expiryTime.getTime() / 1000; return createSignedUrl("HEAD", bucketName, objectKey, null, null, credentials, secondsSinceEpoch, isVirtualHost); } /** * Generates a signed HEAD URL. * * @deprecated 0.7.4 * * @param bucketName * the name of the bucket to include in the URL, must be a valid bucket name. * @param objectKey * the name of the object to include in the URL, if null only the bucket name is used. * @param credentials * the credentials of someone with sufficient privileges to grant access to the bucket/object * @param expiryTime * the time after which URL's signature will no longer be valid. This time cannot be null. * * @return * a URL signed in such a way as to grant HEAD access to an S3 resource to whoever uses it. * @throws S3ServiceException */ @Deprecated public String createSignedHeadUrl(String bucketName, String objectKey, ProviderCredentials credentials, Date expiryTime) throws S3ServiceException { return createSignedHeadUrl(bucketName, objectKey, credentials, expiryTime, false); } /** * Generates a URL string that will return a Torrent file for an object in S3, * which file can be downloaded and run in a BitTorrent client. * * @param bucketName * the name of the bucket containing the object. * @param objectKey * the name of the object. * @return * a URL to a Torrent file representing the object. */ public String createTorrentUrl(String bucketName, String objectKey) { String s3Endpoint = this.getEndpoint(); String serviceEndpointVirtualPath = this.getVirtualPath(); int httpPort = this.getHttpPort(); boolean disableDnsBuckets = this.getDisableDnsBuckets(); try { String bucketNameInPath = !disableDnsBuckets && ServiceUtils.isBucketNameValidDNSName(bucketName) ? "" : RestUtils.encodeUrlString(bucketName) + "/"; String urlPath = RestUtils.encodeUrlPath(serviceEndpointVirtualPath, "/") + "/" + bucketNameInPath + RestUtils.encodeUrlPath(objectKey, "/"); return "http://" + ServiceUtils.generateS3HostnameForBucket( bucketName, disableDnsBuckets, s3Endpoint) + (httpPort != 80 ? ":" + httpPort : "") + urlPath + "?torrent"; } catch (ServiceException e) { throw new RuntimeException(e); } } /** * Generates a policy document condition statement to represent an operation. * * @param operation * the name of the test operation this condition statement will apply. * @param name * the name of the data item the condition applies to. * @param value * the test value that will be used by the condition operation. * @return * a condition statement that can be included in the policy document * belonging to an S3 POST form. */ public static String generatePostPolicyCondition(String operation, String name, String value) { return "[\"" + operation + "\", \"$" + name + "\", \"" + value + "\"]"; } /** * Generates a policy document condition statement that will allow the named * data item in a POST request to take on any value. * * @param name * the name of the data item that will be allowed to take on any value. * @return * a condition statement that can be included in the policy document * belonging to an S3 POST form. */ public static String generatePostPolicyCondition_AllowAnyValue(String name) { return "[\"starts-with\", \"$" + name + "\", \"\"]"; } /** * Generates a policy document condition statement to represent an * equality test. * * @param name * the name of the data item that will be tested. * @param value * the value that the named data item must match. * @return * a condition statement that can be included in the policy document * belonging to an S3 POST form. */ public static String generatePostPolicyCondition_Equality(String name, String value) { return "{\"" + name + "\": \"" + value + "\"}"; } /** * Generates a policy document condition statement to represent an * equality test. * * @param name * the name of the data item that will be tested. * @param values * a list of values, one of which must match the named data item. * @return * a condition statement that can be included in the policy document * belonging to an S3 POST form. */ public static String generatePostPolicyCondition_Equality(String name, String[] values) { return "{\"" + name + "\": \"" + ServiceUtils.join(values, ",") + "\"}"; } /** * Generates a policy document condition statement to represent an * equality test. * * @param name * the name of the data item that will be tested. * @param values * a list of values, one of which must match the named data item. * @return * a condition statement that can be included in the policy document * belonging to an S3 POST form. */ public static String generatePostPolicyCondition_Equality(String name, List values) { return "{\"" + name + "\": \"" + ServiceUtils.join(values, ",") + "\"}"; } /** * Generates a policy document condition statement to represent a test that * imposes a limit on the minimum and maximum amount of data the user can * upload via a POST form. * * @param min * the minimum number of bytes the user must upload. This value should be * greater than or equal to zero. * @param max * the maximum number of bytes the user can upload. This value must be * greater than or equal to the min value. * @return * a condition statement that can be included in the policy document * belonging to an S3 POST form. */ public static String generatePostPolicyCondition_Range(int min, int max) { return "[\"content-length-range\", " + min + ", " + max + "]"; } /** * Generates an unauthenticated HTML POST form that can be used to * upload files or data to S3 from a standard web browser. *

* Because the generated form is unauthenticated, it will not contain a * policy document and will only allow uploads to be sent to S3 buckets * that are publicly writable. * * @param bucketName * the name of the target bucket to which the data will be uploaded. * @param key * the key name for the object that will store the data. The key name can * include the special variable ${filename} which expands to the * name of the file the user uploaded in the form. * @return * A form document that can be included in a UTF-8 encoded HTML web page * to allow uploads to a publicly-writable S3 bucket via a web browser. * * @throws S3ServiceException * @throws UnsupportedEncodingException */ public static String buildPostForm(String bucketName, String key) throws S3ServiceException, UnsupportedEncodingException { return buildPostForm(bucketName, key, null, null, null, null, null, true); } /** * Generates an HTML POST form that can be used to upload files or data to * S3 from a standard web browser. *

* Depending on the parameter values provided, this method will generate an * authenticated or unauthenticated form. If the form is unauthenticated, it * will not include a policy document and will therefore not have an * expiry date or any usage conditions. Unauthenticated forms may only be * used to upload data to a publicly writable bucket. *

* If both the expiration and conditions parameters are non-null, the form * will include a policy document and will be authenticated. In this case, * you must provide your AWS credentials to sign the authenticated form. * * @param bucketName * the name of the target bucket to which the data will be uploaded. * @param key * the key name for the object that will store the data. The key name can * include the special variable ${filename} which expands to the * name of the file the user uploaded in the form. * @param credentials * your Storage Provideer credentials. Credentials are only required if the form * includes policy document conditions, otherwise this can be null. * @param expiration * the expiration date beyond which the form will cease to work. If this * parameter is null, the generated form will not include a policy document * and will not have an expiry date. * @param conditions * the policy conditions applied to the form, specified as policy document * condition statements. These statements can be generated with the * convenience method {@link #generatePostPolicyCondition(String, String, String)} * and its siblings. If this parameter is null, the generated form will not * include a policy document and will not apply any usage conditions. * @param inputFields * optional input field strings that will be added to the form. Each string * must be a valid HTML form input field definition, such as * <input type="hidden" name="acl" value="public-read"> * @param textInput * an optional input field definition that is used instead of the default * file input field <input name=\"file\" type=\"file\">. If this * parameter is null, the default file input field will be used to allow * file uploads. If this parameter is non-null, the provided string must * define an input field named "file" that allows the user to provide input, * such as <textarea name="file" cols="60" rows="3"></textarea> * @param isSecureHttp * if this parameter is true the form will upload data to S3 using HTTPS, * otherwise it will use HTTP. * @return * A form document that can be included in a UTF-8 encoded HTML web page * to allow uploads to S3 via a web browser. * * @throws S3ServiceException * @throws UnsupportedEncodingException */ public static String buildPostForm(String bucketName, String key, ProviderCredentials credentials, Date expiration, String[] conditions, String[] inputFields, String textInput, boolean isSecureHttp) throws S3ServiceException, UnsupportedEncodingException { return buildPostForm(bucketName, key, credentials, expiration, conditions, inputFields, textInput, isSecureHttp, false, "Upload to Amazon S3"); } /** * Generates an HTML POST form that can be used to upload files or data to * S3 from a standard web browser. *

* Depending on the parameter values provided, this method will generate an * authenticated or unauthenticated form. If the form is unauthenticated, it * will not include a policy document and will therefore not have an * expiry date or any usage conditions. Unauthenticated forms may only be * used to upload data to a publicly writable bucket. *

* If both the expiration and conditions parameters are non-null, the form * will include a policy document and will be authenticated. In this case, * you must provide your AWS credentials to sign the authenticated form. * * @param bucketName * the name of the target bucket to which the data will be uploaded. * @param key * the key name for the object that will store the data. The key name can * include the special variable ${filename} which expands to the * name of the file the user uploaded in the form. * @param credentials * your Storage Provider credentials. Credentials are only required if the form * includes policy document conditions, otherwise this can be null. * @param expiration * the expiration date beyond which the form will cease to work. If this * parameter is null, the generated form will not include a policy document * and will not have an expiry date. * @param conditions * the policy conditions applied to the form, specified as policy document * condition statements. These statements can be generated with the * convenience method {@link #generatePostPolicyCondition(String, String, String)} * and its siblings. If this parameter is null, the generated form will not * include a policy document and will not apply any usage conditions. * @param inputFields * optional input field strings that will be added to the form. Each string * must be a valid HTML form input field definition, such as * <input type="hidden" name="acl" value="public-read"> * @param textInput * an optional input field definition that is used instead of the default * file input field <input name=\"file\" type=\"file\">. If this * parameter is null, the default file input field will be used to allow * file uploads. If this parameter is non-null, the provided string must * define an input field named "file" that allows the user to provide input, * such as <textarea name="file" cols="60" rows="3"></textarea> * @param isSecureHttp * if this parameter is true the form will upload data to S3 using HTTPS, * otherwise it will use HTTP. * @param usePathStyleUrl * if true the deprecated path style URL will be used to specify the bucket * name, for example: http://s3.amazon.com/BUCKET_NAME. If false, the * recommended sub-domain style will be used, for example: * http://BUCKET_NAME.s3.amazon.com/. * The path style can be useful for accessing US-based buckets with SSL, * however non-US buckets are inaccessible with this style URL. * @param submitButtonName * the name to display on the form's submit button. * * @return * A form document that can be included in a UTF-8 encoded HTML web page * to allow uploads to S3 via a web browser. * * @throws S3ServiceException * @throws UnsupportedEncodingException */ public static String buildPostForm(String bucketName, String key, ProviderCredentials credentials, Date expiration, String[] conditions, String[] inputFields, String textInput, boolean isSecureHttp, boolean usePathStyleUrl, String submitButtonName) throws S3ServiceException, UnsupportedEncodingException { List myInputFields = new ArrayList(); // Form is only authenticated if a policy is specified. if (expiration != null || conditions != null) { // Generate policy document String policyDocument = "{\"expiration\": \"" + ServiceUtils.formatIso8601Date(expiration) + "\", \"conditions\": [" + ServiceUtils.join(conditions, ",") + "]}"; if (log.isDebugEnabled()) { log.debug("Policy document for POST form:\n" + policyDocument); } // Add the base64-encoded policy document as the 'policy' form field String policyB64 = ServiceUtils.toBase64( policyDocument.getBytes(Constants.DEFAULT_ENCODING)); myInputFields.add(""); // Add the AWS access key as the 'AWSAccessKeyId' field myInputFields.add(""); // Add signature for encoded policy document as the 'AWSAccessKeyId' field String signature; try { signature = ServiceUtils.signWithHmacSha1( credentials.getSecretKey(), policyB64); } catch (ServiceException se) { throw new S3ServiceException(se); } myInputFields.add(""); } // Include any additional user-specified form fields if (inputFields != null) { myInputFields.addAll(Arrays.asList(inputFields)); } // Add the vital 'file' input item, which may be a textarea or file. if (textInput != null) { // Use a caller-specified string as the input field. myInputFields.add(textInput); } else { myInputFields.add(""); } // Construct a URL to refer to the target bucket using either the // deprecated path style, or the recommended sub-domain style. The // HTTPS protocol will be used if the secure HTTP option is enabled. String url = null; if (usePathStyleUrl) { url = "http" + (isSecureHttp? "s" : "") + "://s3.amazonaws.com/" + bucketName; } else { // Sub-domain URL style url = "http" + (isSecureHttp? "s" : "") + "://" + bucketName + ".s3.amazonaws.com/"; } // Construct the entire form. String form = "

\n" + "\n" + ServiceUtils.join(myInputFields, "\n") + "\n
\n" + "\n" + "
"; if (log.isDebugEnabled()) { log.debug("POST Form:\n" + form); } return form; } ///////////////////////////////////////////////// // Methods below this point perform actions in S3 ///////////////////////////////////////////////// @Override public S3Bucket[] listAllBuckets() throws S3ServiceException { try { StorageBucket[] buckets = super.listAllBuckets(); return S3Bucket.cast(buckets); } catch (ServiceException se) { throw new S3ServiceException(se); } } @Override public S3Object getObject(String bucketName, String objectKey) throws S3ServiceException { try { return (S3Object) super.getObject(bucketName, objectKey); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Lists the objects in a bucket. * * @deprecated 0.8.0 * *

* The objects returned by this method contain only minimal information * such as the object's size, ETag, and LastModified timestamp. To retrieve * the objects' metadata you must perform follow-up getObject * or getObjectDetails operations. *

* This method can be performed by anonymous services. Anonymous services * can only list the objects in a publicly-readable bucket. * * @param bucket * the bucket whose contents will be listed. * This must be a valid S3Bucket object that is non-null and contains a name. * @return * the set of objects contained in a bucket. * @throws S3ServiceException */ @Deprecated public S3Object[] listObjects(S3Bucket bucket) throws S3ServiceException { try { assertValidBucket(bucket, "listObjects"); return listObjects(bucket, null, null, Constants.DEFAULT_OBJECT_LIST_CHUNK_SIZE); } catch (ServiceException se) { throw new S3ServiceException(se); } } @Override public S3Object[] listObjects(String bucketName) throws S3ServiceException { try { return S3Object.cast(super.listObjects(bucketName)); } catch (ServiceException se) { throw new S3ServiceException(se); } } @Override public S3Object[] listObjects(String bucketName, String prefix, String delimiter, long maxListingLength) throws S3ServiceException { try { return S3Object.cast(super.listObjects(bucketName, prefix, delimiter, maxListingLength)); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Lists the objects in a bucket matching a prefix and delimiter. * * @deprecated 0.8.0 * *

* The objects returned by this method contain only minimal information * such as the object's size, ETag, and LastModified timestamp. To retrieve * the objects' metadata you must perform follow-up getObject * or getObjectDetails operations. *

* This method can be performed by anonymous services. Anonymous services * can only list the objects in a publicly-readable bucket. *

* NOTE: If you supply a delimiter value that could cause CommonPrefixes * ("subdirectory paths") to be included in the results from S3, use the * {@link #listObjectsChunked(String, String, String, long, String, boolean)} * method instead of this one to obtain both object and CommonPrefix values. * * @param bucket * the bucket whose contents will be listed. * This must be a valid S3Bucket object that is non-null and contains a name. * @param prefix * only objects with a key that starts with this prefix will be listed * @param delimiter * only list objects with key names up to this delimiter, may be null. * See note above. * Note: If a non-null delimiter is specified, the prefix must include enough text to * reach the first occurrence of the delimiter in the bucket's keys, or no results will be returned. * @return * the set of objects contained in a bucket whose keys start with the given prefix. * @throws S3ServiceException */ @Deprecated public S3Object[] listObjects(S3Bucket bucket, String prefix, String delimiter) throws S3ServiceException { try { assertValidBucket(bucket, "listObjects"); return listObjects(bucket, prefix, delimiter, Constants.DEFAULT_OBJECT_LIST_CHUNK_SIZE); } catch (ServiceException se) { throw new S3ServiceException(se); } } @Override public S3Object[] listObjects(String bucketName, String prefix, String delimiter) throws S3ServiceException { try { return S3Object.cast(super.listObjects(bucketName, prefix, delimiter)); } catch (ServiceException se) { throw new S3ServiceException(se); } } @Override public S3Bucket createBucket(String bucketName) throws S3ServiceException { try { return this.createBucket(bucketName, this.jets3tProperties.getStringProperty( "s3service.default-bucket-location", "US"), null); } catch (ServiceException se) { throw new S3ServiceException(se); } } @Override public S3Bucket getOrCreateBucket(String bucketName) throws S3ServiceException { try { return this.getOrCreateBucket(bucketName, this.jets3tProperties.getStringProperty( "s3service.default-bucket-location", "US")); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Creates a bucket in a specific location, without checking whether the bucket already * exists. Caution: Performing this operation unnecessarily when a bucket already * exists may cause OperationAborted errors with the message "A conflicting conditional * operation is currently in progress against this resource.". To avoid this error, use the * {@link #getOrCreateBucket(String)} in situations where the bucket may already exist. *

* Warning: Prior to version 0.7.0 this method did check whether a bucket already * existed using {@link #isBucketAccessible(String)}. After changes to the way S3 operates, * this check started to cause issues so it was removed. *

* This method cannot be performed by anonymous services. * * @param bucketName * the name of the bucket to create. * @param location * the location of the S3 data centre in which the bucket will be created, or null for the * default {@link S3Bucket#LOCATION_US_STANDARD} location. Valid values * include {@link S3Bucket#LOCATION_EUROPE}, {@link S3Bucket#LOCATION_US_WEST}, * {@link S3Bucket#LOCATION_ASIA_PACIFIC}, and the default US location that can be * expressed in two ways: * {@link S3Bucket#LOCATION_US_STANDARD} or {@link S3Bucket#LOCATION_US}. * @param acl * the access control settings to apply to the new bucket, or null for default ACL values. * * @return * the created bucket object. Note: the object returned has minimal information about * the bucket that was created, including only the bucket's name. * @throws S3ServiceException */ public S3Bucket createBucket(String bucketName, String location, AccessControlList acl) throws S3ServiceException { try { assertAuthenticatedConnection("createBucket"); return (S3Bucket) createBucketImpl(bucketName, location, acl); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Creates a bucket in a specific location, without checking whether the bucket already * exists. Caution: Performing this operation unnecessarily when a bucket already * exists may cause OperationAborted errors with the message "A conflicting conditional * operation is currently in progress against this resource.". To avoid this error, use the * {@link #getOrCreateBucket(String)} in situations where the bucket may already exist. *

* Warning: Prior to version 0.7.0 this method did check whether a bucket already * existed using {@link #isBucketAccessible(String)}. After changes to the way S3 operates, * this check started to cause issues so it was removed. *

* This method cannot be performed by anonymous services. * * @param bucketName * the name of the bucket to create. * @param location * the location of the S3 data centre in which the bucket will be created, or null for the * default {@link S3Bucket#LOCATION_US_STANDARD} location. Valid values * include {@link S3Bucket#LOCATION_EUROPE}, {@link S3Bucket#LOCATION_US_WEST}, * {@link S3Bucket#LOCATION_ASIA_PACIFIC}, and the default US location that can be * expressed in two ways: * {@link S3Bucket#LOCATION_US_STANDARD} or {@link S3Bucket#LOCATION_US}. * * @return * the created bucket object. Note: the object returned has minimal information about * the bucket that was created, including only the bucket's name. * @throws S3ServiceException */ public S3Bucket createBucket(String bucketName, String location) throws S3ServiceException { try { assertAuthenticatedConnection("createBucket"); return (S3Bucket) createBucketImpl(bucketName, location, null); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Returns an object representing the details and data of an item in S3, without applying any * preconditions. * * @deprecated 0.8.0 * *

* This method can be performed by anonymous services. Anonymous services * can get a publicly-readable object. *

* Important: It is the caller's responsibility to close the object's data input stream. * The data stream should be consumed and closed as soon as is practical as network connections * may be held open until the streams are closed. Excessive unclosed streams can lead to * connection starvation. * * @param bucket * the bucket containing the object. * This must be a valid S3Bucket object that is non-null and contains a name. * @param objectKey * the key identifying the object. * @return * the object with the given key in S3, including the object's data input stream. * @throws S3ServiceException */ @Deprecated public S3Object getObject(S3Bucket bucket, String objectKey) throws S3ServiceException { try { assertValidBucket(bucket, "getObject"); return getObject(bucket, objectKey, null, null, null, null, null, null); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Returns an object representing the details and data of an item in S3 with a specific * given version, without applying any preconditions. Versioned objects are only available * from buckets with versioning enabled, see {@link #enableBucketVersioning(String)}. *

* This method can be performed by anonymous services. Anonymous services * can get a publicly-readable object. *

* Important: It is the caller's responsibility to close the object's data input stream. * The data stream should be consumed and closed as soon as is practical as network connections * may be held open until the streams are closed. Excessive unclosed streams can lead to * connection starvation. * * @param versionId * identifier matching an existing object version that will be retrieved. * @param bucketName * the name of the versioned bucket containing the object. * @param objectKey * the key identifying the object. * @return * the object with the given key in S3, including the object's data input stream. * @throws S3ServiceException */ public S3Object getVersionedObject(String versionId, String bucketName, String objectKey) throws S3ServiceException { try { MxDelegate.getInstance().registerStorageObjectGetEvent(bucketName, objectKey); return (S3Object) getObjectImpl(bucketName, objectKey, null, null, null, null, null, null, versionId); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Returns an object representing the details of an item in S3 without the object's data, and * without applying any preconditions. * * @deprecated 0.8.0 * *

* This method can be performed by anonymous services. Anonymous services * can get a publicly-readable object's details. * * @param bucket * the bucket containing the object. * This must be a valid S3Bucket object that is non-null and contains a name. * @param objectKey * the key identifying the object. * @return * the object with the given key in S3, including only general details and metadata (not the data * input stream) * @throws S3ServiceException */ @Deprecated public S3Object getObjectDetails(S3Bucket bucket, String objectKey) throws S3ServiceException { try { assertValidBucket(bucket, "getObjectDetails"); return getObjectDetails(bucket, objectKey, null, null, null, null); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Returns an object representing the details of an item in S3 with a specific given version, * without the object's data and without applying any preconditions. Versioned objects are only * available from buckets with versioning enabled, see {@link #enableBucketVersioning(String)}. *

* This method can be performed by anonymous services. Anonymous services * can get a publicly-readable object's details. * * @param versionId * object's version identifier * @param bucketName * the name of the versioned bucket containing the object. * @param objectKey * the key identifying the object. * @return * the object with the given key in S3, including only general details and metadata (not the data * input stream) * @throws S3ServiceException */ public S3Object getVersionedObjectDetails(String versionId, String bucketName, String objectKey) throws S3ServiceException { try { MxDelegate.getInstance().registerStorageObjectHeadEvent(bucketName, objectKey); return (S3Object) getObjectDetailsImpl(bucketName, objectKey, null, null, null, null, versionId); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Lists the objects in a bucket matching a prefix, while instructing S3 to * send response messages containing no more than a given number of object * results. * * @deprecated 0.8.0 * *

* The objects returned by this method contain only minimal information * such as the object's size, ETag, and LastModified timestamp. To retrieve * the objects' metadata you must perform follow-up getObject * or getObjectDetails operations. *

* This method can be performed by anonymous services. Anonymous services * can list the contents of a publicly-readable bucket. *

* NOTE: If you supply a delimiter value that could cause CommonPrefixes * ("subdirectory paths") to be included in the results from S3, use the * {@link #listObjectsChunked(String, String, String, long, String, boolean)} * method instead of this one to obtain both object and CommonPrefix values. * * @param bucket * the bucket whose contents will be listed. * This must be a valid S3Bucket object that is non-null and contains a name. * @param prefix * only objects with a key that starts with this prefix will be listed * @param delimiter * only list objects with key names up to this delimiter, may be null. * See note above. * @param maxListingLength * the maximum number of objects to include in each result message sent by * S3. This value has no effect on the number of objects * that will be returned by this method, because it will always return all * the objects in the bucket. * @return * the set of objects contained in a bucket whose keys start with the given prefix. * @throws S3ServiceException */ @Deprecated public S3Object[] listObjects(S3Bucket bucket, String prefix, String delimiter, long maxListingLength) throws S3ServiceException { try { assertValidBucket(bucket, "List objects in bucket"); return listObjects(bucket.getName(), prefix, delimiter, maxListingLength); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Lists versioning information in a versioned bucket where the objects * match a given constraints. The S3 service will also be instructed to send * response messages containing no more than a given number of object results. *

* This operation can only be performed by the bucket owner. * * @param bucketName * the name of the the versioned bucket whose contents will be listed. * @param prefix * only objects with a key that starts with this prefix will be listed * @param delimiter * only list objects with key names up to this delimiter, may be null. * See note above. * @return * the set of objects contained in a bucket whose keys start with the given prefix. * @throws S3ServiceException */ public BaseVersionOrDeleteMarker[] listVersionedObjects(String bucketName, String prefix, String delimiter) throws S3ServiceException { return listVersionedObjectsImpl(bucketName, prefix, delimiter, null, null, 1000); } /** * Return version information for a specific object. *

* This is a convenience function that applies logic in addition to the LISTVERSIONS * S3 operation to simplify retrieval of an object's version history. This method * is *not* the most efficient way of retrieving version history in bulk, so if you * need version history for multiple objects you should use the * {@link #listVersionedObjects(String, String, String)} or * {@link #listVersionedObjectsChunked(String, String, String, long, String, String, boolean)} * methods instead. * * @param bucketName * the name of the versioned bucket containing the object. * @param objectKey * the key identifying the object. * @return * an array of {@link S3Version} and {@link S3DeleteMarker} objects that describe * the version history of the given object. * * @throws S3ServiceException */ public BaseVersionOrDeleteMarker[] getObjectVersions(String bucketName, String objectKey) throws S3ServiceException { BaseVersionOrDeleteMarker[] matchesForNamePrefix = listVersionedObjectsImpl(bucketName, objectKey, null, null, null, 1000); // Limit results to only matches for the exact object key name int exactMatchCount = 0; for (int i = 0; i < matchesForNamePrefix.length && i <= exactMatchCount; i++) { if (matchesForNamePrefix[i].getKey().equals(objectKey)) { exactMatchCount++; } } BaseVersionOrDeleteMarker[] exactMatches = new BaseVersionOrDeleteMarker[exactMatchCount]; System.arraycopy(matchesForNamePrefix, 0, exactMatches, 0, exactMatchCount); return exactMatches; } /** * Lists information for a versioned bucket where the items match given constarints. * Depending on the value of the completeListing variable, this method can be set to * automatically perform follow-up requests to build a complete object listing, or to * return only a partial listing. *

* The objects returned by this method contain only minimal information * such as the object's size, ETag, and LastModified timestamp. To retrieve * the objects' metadata you must perform follow-up getObject * or getObjectDetails operations. *

* This method can be performed by anonymous services. Anonymous services * can list the contents of a publicly-readable bucket. * * @param bucketName * the name of the versioned bucket whose contents will be listed. * @param prefix * only objects with a key that starts with this prefix will be listed * @param delimiter * only list objects with key names up to this delimiter, may be null. * @param maxListingLength * the maximum number of objects to include in each result chunk * @param priorLastKey * the last object key received in a prior call to this method. The next chunk of items * listed will start with the next object in the bucket after this key name. * This parameter may be null, in which case the listing will start at the beginning of the * bucket's object contents. * @param priorLastVersionId * the last version ID received in a prior call to this method. The next chunk of items * listed will start with the next object version after this version. * This parameter can only be used with a non-null priorLastKey. * @param completeListing * if true, the service class will automatically perform follow-up requests to * build a complete bucket object listing. * @return * the set of objects contained in a bucket whose keys start with the given prefix. * @throws S3ServiceException */ public VersionOrDeleteMarkersChunk listVersionedObjectsChunked(String bucketName, String prefix, String delimiter, long maxListingLength, String priorLastKey, String priorLastVersionId, boolean completeListing) throws S3ServiceException { return listVersionedObjectsChunkedImpl(bucketName, prefix, delimiter, maxListingLength, priorLastKey, priorLastVersionId, completeListing); } /** * Creates a bucket in S3 based on the provided bucket object, with the Access Control List * settings and location properties of the bucket object (if any). *

* Caution: Performing this operation unnecessarily when a bucket already * exists may cause OperationAborted errors with the message "A conflicting conditional * operation is currently in progress against this resource.". To avoid this error, use the * {@link #getOrCreateBucket(String)} in situations where the bucket may already exist. *

* This method cannot be performed by anonymous services. * * @param bucket * an object representing the bucket to create which must be valid, and which may contain * location and ACL settings that will be applied upon creation. * @return * the created bucket object, populated with all metadata made available by the creation operation. * @throws S3ServiceException */ public S3Bucket createBucket(S3Bucket bucket) throws S3ServiceException { try { assertAuthenticatedConnection("Create Bucket"); assertValidBucket(bucket, "Create Bucket"); return (S3Bucket) createBucketImpl(bucket.getName(), bucket.getLocation(), bucket.getAcl()); } catch (ServiceException se) { throw new S3ServiceException(se); } } @Override public S3Bucket getBucket(String bucketName) throws S3ServiceException { try { return (S3Bucket) super.getBucket(bucketName); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Returns a bucket in your S3 account, and creates the bucket in the given S3 location * if it does not yet exist. *

* Note: This method will not change the location of an existing bucket if you specify * a different location from a bucket's current location. To move a bucket between * locations you must first delete it in the original location, then re-create it * in the new location. * * @param bucketName * the name of the bucket to retrieve or create. * @param location * the location of the S3 data centre in which the bucket will be created. Valid values * include {@link S3Bucket#LOCATION_EUROPE}, {@link S3Bucket#LOCATION_US_WEST}, * {@link S3Bucket#LOCATION_ASIA_PACIFIC}, and the default US location that can be * expressed in two ways: * {@link S3Bucket#LOCATION_US_STANDARD} or {@link S3Bucket#LOCATION_US}. * @return * the bucket in your account. * * @throws S3ServiceException */ public S3Bucket getOrCreateBucket(String bucketName, String location) throws S3ServiceException { try { assertAuthenticatedConnection("Get or Create Bucket with location"); } catch (ServiceException se) { throw new S3ServiceException(se); } S3Bucket bucket = getBucket(bucketName); if (bucket == null) { // Bucket does not exist in this user's account, create it. bucket = createBucket(new S3Bucket(bucketName, location)); } return bucket; } /** * Deletes an S3 bucket. Only the owner of a bucket may delete it. * * @deprecated 0.8.0 * *

* This method cannot be performed by anonymous services. * * * @param bucket * the bucket to delete. * @throws S3ServiceException */ @Deprecated public void deleteBucket(S3Bucket bucket) throws S3ServiceException { try { assertValidBucket(bucket, "Delete bucket"); deleteBucketImpl(bucket.getName()); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Enable the S3 object versioning feature for a bucket. * Multi-factor authentication will not be required to delete versions. * * @param bucketName * the name of the bucket that will have versioning enabled. * @throws S3ServiceException */ public void enableBucketVersioning(String bucketName) throws S3ServiceException { updateBucketVersioningStatusImpl(bucketName, true, false, null, null); } /** * Enable the S3 object versioning feature and also enable the * multi-factor authentication (MFA) feature for a bucket which * does not yet have MFA enabled. * * @param bucketName * the name of the bucket that will have versioning enabled. * @throws S3ServiceException */ public void enableBucketVersioningAndMFA(String bucketName) throws S3ServiceException { updateBucketVersioningStatusImpl(bucketName, true, true, null, null); } /** * Enable the S3 object versioning feature for a bucket that * already has multi-factor authentication (MFA) enabled. * * @param bucketName * the name of the bucket that will have versioning enabled. * @param multiFactorSerialNumber * the serial number for a multi-factor authentication device. * @param multiFactorAuthCode * a multi-factor authentication code generated by a device. * @throws S3ServiceException */ public void enableBucketVersioningWithMFA(String bucketName, String multiFactorSerialNumber, String multiFactorAuthCode) throws S3ServiceException { updateBucketVersioningStatusImpl(bucketName, true, true, multiFactorSerialNumber, multiFactorAuthCode); } /** * Disable the multi-factor authentication (MFA) feature for a * bucket that already has S3 object versioning and MFA enabled. * * @param bucketName * the name of the bucket that will have versioning enabled. * versioning status of the bucket. * @param multiFactorSerialNumber * the serial number for a multi-factor authentication device. * @param multiFactorAuthCode * a multi-factor authentication code generated by a device. * @throws S3ServiceException */ public void disableMFAForVersionedBucket(String bucketName, String multiFactorSerialNumber, String multiFactorAuthCode) throws S3ServiceException { updateBucketVersioningStatusImpl(bucketName, true, false, multiFactorSerialNumber, multiFactorAuthCode); } /** * Suspend (disable) the S3 object versioning feature for a bucket. * The bucket must not have the multi-factor authentication (MFA) * feature enabled. * * @param bucketName * the name of the versioned bucket that will have versioning suspended. * @throws S3ServiceException */ public void suspendBucketVersioning(String bucketName) throws S3ServiceException { updateBucketVersioningStatusImpl(bucketName, false, false, null, null); } /** * Suspend (disable) the S3 object versioning feature for a bucket that * requires multi-factor authentication. * * @param bucketName * the name of the versioned bucket that will have versioning suspended. * @param multiFactorSerialNumber * the serial number for a multi-factor authentication device. * @param multiFactorAuthCode * a multi-factor authentication code generated by a device. * @throws S3ServiceException */ public void suspendBucketVersioningWithMFA(String bucketName, String multiFactorSerialNumber, String multiFactorAuthCode) throws S3ServiceException { updateBucketVersioningStatusImpl(bucketName, false, false, multiFactorSerialNumber, multiFactorAuthCode); } /** * Return versioning status of bucket, which reports on whether the given bucket * has S3 object versioning enabled and whether multi-factor authentication is * required to delete versions. * * @param bucketName * the name of the bucket. * @return * versioning status of bucket * @throws S3ServiceException */ public S3BucketVersioningStatus getBucketVersioningStatus(String bucketName) throws S3ServiceException { return getBucketVersioningStatusImpl(bucketName); } /** * Puts an object inside an existing bucket in S3, creating a new object or overwriting * an existing one with the same key. *

* This method can be performed by anonymous services. Anonymous services * can put objects into a publicly-writable bucket. * * @param bucketName * the name of the bucket inside which the object will be put. * @param object * the object containing all information that will be written to S3. At very least this object must * be valid. Beyond that it may contain: an input stream with the object's data content, metadata, * and access control settings.

* Note: It is very important to set the object's Content-Length to match the size of the * data input stream when possible, as this can remove the need to read data into memory to * determine its size. * * @return * the object populated with any metadata information made available by S3. * @throws S3ServiceException */ public S3Object putObject(String bucketName, S3Object object) throws S3ServiceException { try { return (S3Object) super.putObject(bucketName, object); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Copy an object with a specific version within your S3 account. You can copy an object * within a single bucket or between buckets, and can optionally update the object's * metadata at the same time. *

* This method cannot be performed by anonymous services. You must have read * access to the source object and write access to the destination bucket. *

* An object can be copied over itself, in which case you can update its * metadata without making any other changes. * * @param versionId * identifier matching an existing object version that will be copied. * @param sourceBucketName * the name of the versioned bucket that contains the original object. * @param sourceObjectKey * the key name of the original object. * @param destinationBucketName * the name of the destination bucket to which the object will be copied. * @param destinationObject * the object that will be created by the copy operation. If this item * includes an AccessControlList setting the copied object will be assigned * that ACL, otherwise the copied object will be assigned the default private * ACL setting. * @param replaceMetadata * If this parameter is true, the copied object will be assigned the metadata * values present in the destinationObject. Otherwise, the copied object will * have the same metadata as the original object. * @param ifModifiedSince * a precondition specifying a date after which the object must have been * modified, ignored if null. * @param ifUnmodifiedSince * a precondition specifying a date after which the object must not have * been modified, ignored if null. * @param ifMatchTags * a precondition specifying an MD5 hash the object must match, ignored if * null. * @param ifNoneMatchTags * a precondition specifying an MD5 hash the object must not match, ignored * if null. * * @return * a map of the header and result information returned by S3 after the object * copy. The map includes the object's MD5 hash value (ETag), its size * (Content-Length), and update timestamp (Last-Modified). * * @throws S3ServiceException */ public Map copyVersionedObject(String versionId, String sourceBucketName, String sourceObjectKey, String destinationBucketName, S3Object destinationObject, boolean replaceMetadata, Calendar ifModifiedSince, Calendar ifUnmodifiedSince, String[] ifMatchTags, String[] ifNoneMatchTags) throws S3ServiceException { try { assertAuthenticatedConnection("copyVersionedObject"); Map destinationMetadata = replaceMetadata ? destinationObject.getModifiableMetadata() : null; MxDelegate.getInstance().registerStorageObjectCopyEvent(sourceBucketName, sourceObjectKey); return copyObjectImpl(sourceBucketName, sourceObjectKey, destinationBucketName, destinationObject.getKey(), destinationObject.getAcl(), destinationMetadata, ifModifiedSince, ifUnmodifiedSince, ifMatchTags, ifNoneMatchTags, versionId, destinationObject.getStorageClass()); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Copy an object with a specific version within your S3 account. You can copy an object * within a single bucket or between buckets, and can optionally update the object's * metadata at the same time. *

* This method cannot be performed by anonymous services. You must have read * access to the source object and write access to the destination bucket. *

* An object can be copied over itself, in which case you can update its * metadata without making any other changes. * * @param versionId * identifier matching an existing object version that will be copied. * @param sourceBucketName * the name of the versioned bucket that contains the original object. * @param sourceObjectKey * the key name of the original object. * @param destinationBucketName * the name of the destination bucket to which the object will be copied. * @param destinationObject * the object that will be created by the copy operation. If this item * includes an AccessControlList setting the copied object will be assigned * that ACL, otherwise the copied object will be assigned the default private * ACL setting. * @param replaceMetadata * If this parameter is true, the copied object will be assigned the metadata * values present in the destinationObject. Otherwise, the copied object will * have the same metadata as the original object. * * @return * a map of the header and result information returned by S3 after the object * copy. The map includes the object's MD5 hash value (ETag), its size * (Content-Length), and update timestamp (Last-Modified). * * @throws S3ServiceException */ public Map copyVersionedObject(String versionId, String sourceBucketName, String sourceObjectKey, String destinationBucketName, S3Object destinationObject, boolean replaceMetadata) throws S3ServiceException { return copyVersionedObject(versionId, sourceBucketName, sourceObjectKey, destinationBucketName, destinationObject, replaceMetadata, null, null, null, null); } /** * Puts an object inside an existing bucket in S3, creating a new object or overwriting * an existing one with the same key. *

* This method can be performed by anonymous services. Anonymous services * can put objects into a publicly-writable bucket. * * @param bucket * the bucket inside which the object will be put, which must be valid. * @param object * the object containing all information that will be written to S3. At very least this object must * be valid. Beyond that it may contain: an input stream with the object's data content, metadata, * and access control settings.

* Note: It is very important to set the object's Content-Length to match the size of the * data input stream when possible, as this can remove the need to read data into memory to * determine its size. * * @return * the object populated with any metadata information made available by S3. * @throws S3ServiceException */ public S3Object putObject(S3Bucket bucket, S3Object object) throws S3ServiceException { try { assertValidBucket(bucket, "Create Object in bucket"); return putObject(bucket.getName(), object); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Deletes an object from a bucket in S3. *

* This method can be performed by anonymous services. Anonymous services * can delete objects from publicly-writable buckets. * * @param bucket * the bucket containing the object to be deleted. * @param objectKey * the key representing the object in S3. * @throws S3ServiceException */ public void deleteObject(S3Bucket bucket, String objectKey) throws S3ServiceException { try { assertValidBucket(bucket, "deleteObject"); assertValidObject(objectKey, "deleteObject"); deleteObject(bucket.getName(), objectKey); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Deletes a object version from a bucket in S3. This will delete only the specific * version identified and will not affect any other Version or DeleteMarkers related * to the object. *

* This operation can only be performed by the owner of the S3 bucket. * * @param versionId * the identifier of an object version that will be deleted. * @param multiFactorSerialNumber * the serial number for a multi-factor authentication device. * @param multiFactorAuthCode * a multi-factor authentication code generated by a device. * @param bucketName * the name of the versioned bucket containing the object to be deleted. * @param objectKey * the key representing the object in S3. * @throws S3ServiceException */ public void deleteVersionedObjectWithMFA(String versionId, String multiFactorSerialNumber, String multiFactorAuthCode, String bucketName, String objectKey) throws S3ServiceException { try { assertValidObject(objectKey, "deleteVersionedObjectWithMFA"); MxDelegate.getInstance().registerStorageObjectDeleteEvent(bucketName, objectKey); deleteObjectImpl(bucketName, objectKey, versionId, multiFactorSerialNumber, multiFactorAuthCode); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Deletes a object version from a bucket in S3. This will delete only the specific * version identified and will not affect any other Version or DeleteMarkers related * to the object. *

* This operation can only be performed by the owner of the S3 bucket. * * @param versionId * the identifier of an object version that will be deleted. * @param bucketName * the name of the versioned bucket containing the object to be deleted. * @param objectKey * the key representing the object in S3. * @throws S3ServiceException */ public void deleteVersionedObject(String versionId, String bucketName, String objectKey) throws S3ServiceException { try { assertValidObject(objectKey, "deleteVersionedObject"); MxDelegate.getInstance().registerStorageObjectDeleteEvent(bucketName, objectKey); deleteObjectImpl(bucketName, objectKey, versionId, null, null); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Returns an object representing the details of an item in S3 that meets any given preconditions. * The object is returned without the object's data. *

* An exception is thrown if any of the preconditions fail. * Preconditions are only applied if they are non-null. *

* This method can be performed by anonymous services. Anonymous services * can get details of publicly-readable objects. * * @param bucket * the bucket containing the object. * This must be a valid S3Bucket object that is non-null and contains a name. * @param objectKey * the key identifying the object. * @param ifModifiedSince * a precondition specifying a date after which the object must have been modified, ignored if null. * @param ifUnmodifiedSince * a precondition specifying a date after which the object must not have been modified, ignored if null. * @param ifMatchTags * a precondition specifying an MD5 hash the object must match, ignored if null. * @param ifNoneMatchTags * a precondition specifying an MD5 hash the object must not match, ignored if null. * @return * the object with the given key in S3, including only general details and metadata (not the data * input stream) * @throws S3ServiceException */ public S3Object getObjectDetails(S3Bucket bucket, String objectKey, Calendar ifModifiedSince, Calendar ifUnmodifiedSince, String[] ifMatchTags, String[] ifNoneMatchTags) throws S3ServiceException { try { assertValidBucket(bucket, "Get Object Details"); MxDelegate.getInstance().registerStorageObjectHeadEvent(bucket.getName(), objectKey); return (S3Object) getObjectDetailsImpl(bucket.getName(), objectKey, ifModifiedSince, ifUnmodifiedSince, ifMatchTags, ifNoneMatchTags, null); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Returns an object representing the details of a versioned object in S3 that also * meets any given preconditions. The object is returned without the object's data. *

* An exception is thrown if any of the preconditions fail. * Preconditions are only applied if they are non-null. *

* This method can be performed by anonymous services. Anonymous services * can get details of publicly-readable objects. * * @param versionId * the identifier of the object version to return. * @param bucket * the versioned bucket containing the object. * This must be a valid S3Bucket object that is non-null and contains a name. * @param objectKey * the key identifying the object. * @param ifModifiedSince * a precondition specifying a date after which the object must have been modified, ignored if null. * @param ifUnmodifiedSince * a precondition specifying a date after which the object must not have been modified, ignored if null. * @param ifMatchTags * a precondition specifying an MD5 hash the object must match, ignored if null. * @param ifNoneMatchTags * a precondition specifying an MD5 hash the object must not match, ignored if null. * @return * the object with the given key in S3, including only general details and metadata (not the data * input stream) * @throws S3ServiceException */ public S3Object getVersionedObjectDetails(String versionId, S3Bucket bucket, String objectKey, Calendar ifModifiedSince, Calendar ifUnmodifiedSince, String[] ifMatchTags, String[] ifNoneMatchTags) throws S3ServiceException { try { assertValidBucket(bucket, "Get Versioned Object Details"); MxDelegate.getInstance().registerStorageObjectHeadEvent(bucket.getName(), objectKey); return (S3Object) getObjectDetailsImpl(bucket.getName(), objectKey, ifModifiedSince, ifUnmodifiedSince, ifMatchTags, ifNoneMatchTags, versionId); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Returns an object representing the details of a versioned object in S3 that also meets * any given preconditions. The object is returned without the object's data. *

* An exception is thrown if any of the preconditions fail. * Preconditions are only applied if they are non-null. *

* This method can be performed by anonymous services. Anonymous services * can get details of publicly-readable objects. * * @param versionId * the identifier of the object version to return. * @param bucketName * the name of the versioned bucket containing the object. * @param objectKey * the key identifying the object. * @param ifModifiedSince * a precondition specifying a date after which the object must have been modified, ignored if null. * @param ifUnmodifiedSince * a precondition specifying a date after which the object must not have been modified, ignored if null. * @param ifMatchTags * a precondition specifying an MD5 hash the object must match, ignored if null. * @param ifNoneMatchTags * a precondition specifying an MD5 hash the object must not match, ignored if null. * @return * the object with the given key in S3, including only general details and metadata (not the data * input stream) * @throws S3ServiceException */ public S3Object getVersionedObjectDetails(String versionId, String bucketName, String objectKey, Calendar ifModifiedSince, Calendar ifUnmodifiedSince, String[] ifMatchTags, String[] ifNoneMatchTags) throws S3ServiceException { try { MxDelegate.getInstance().registerStorageObjectHeadEvent(bucketName, objectKey); return (S3Object) getObjectDetailsImpl(bucketName, objectKey, ifModifiedSince, ifUnmodifiedSince, ifMatchTags, ifNoneMatchTags, versionId); } catch (ServiceException se) { throw new S3ServiceException(se); } } @Override public S3Object getObject(String bucketName, String objectKey, Calendar ifModifiedSince, Calendar ifUnmodifiedSince, String[] ifMatchTags, String[] ifNoneMatchTags, Long byteRangeStart, Long byteRangeEnd) throws S3ServiceException { try { return (S3Object) super.getObject(bucketName, objectKey, ifModifiedSince, ifUnmodifiedSince, ifMatchTags, ifNoneMatchTags, byteRangeStart, byteRangeEnd); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Returns an object representing the details and data of an item in S3 that meets any given preconditions. *

* Important: It is the caller's responsibility to close the object's data input stream. * The data stream should be consumed and closed as soon as is practical as network connections * may be held open until the streams are closed. Excessive unclosed streams can lead to * connection starvation. *

* An exception is thrown if any of the preconditions fail. * Preconditions are only applied if they are non-null. *

* This method can be performed by anonymous services. Anonymous services * can get publicly-readable objects. *

* Implementation notes

* Implementations should use {@link #assertValidBucket} assertion. * * @param bucket * the bucket containing the object. * This must be a valid S3Bucket object that is non-null and contains a name. * @param objectKey * the key identifying the object. * @param ifModifiedSince * a precondition specifying a date after which the object must have been modified, ignored if null. * @param ifUnmodifiedSince * a precondition specifying a date after which the object must not have been modified, ignored if null. * @param ifMatchTags * a precondition specifying an MD5 hash the object must match, ignored if null. * @param ifNoneMatchTags * a precondition specifying an MD5 hash the object must not match, ignored if null. * @param byteRangeStart * include only a portion of the object's data - starting at this point, ignored if null. * @param byteRangeEnd * include only a portion of the object's data - ending at this point, ignored if null. * @return * the object with the given key in S3, including only general details and metadata (not the data * input stream) * @throws S3ServiceException */ public S3Object getObject(S3Bucket bucket, String objectKey, Calendar ifModifiedSince, Calendar ifUnmodifiedSince, String[] ifMatchTags, String[] ifNoneMatchTags, Long byteRangeStart, Long byteRangeEnd) throws S3ServiceException { try { assertValidBucket(bucket, "Get Object"); MxDelegate.getInstance().registerStorageObjectGetEvent(bucket.getName(), objectKey); return (S3Object) getObjectImpl(bucket.getName(), objectKey, ifModifiedSince, ifUnmodifiedSince, ifMatchTags, ifNoneMatchTags, byteRangeStart, byteRangeEnd, null); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Returns an object representing the details and data of a versioned object in S3 that * also meets any given preconditions. *

* Important: It is the caller's responsibility to close the object's data input stream. * The data stream should be consumed and closed as soon as is practical as network connections * may be held open until the streams are closed. Excessive unclosed streams can lead to * connection starvation. *

* An exception is thrown if any of the preconditions fail. * Preconditions are only applied if they are non-null. *

* This method can be performed by anonymous services. Anonymous services * can get publicly-readable objects. *

* Implementation notes

* Implementations should use {@link #assertValidBucket} assertion. * * @param versionId * the identifier of the object version to return. * @param bucket * the versioned bucket containing the object. * This must be a valid S3Bucket object that is non-null and contains a name. * @param objectKey * the key identifying the object. * @param ifModifiedSince * a precondition specifying a date after which the object must have been modified, ignored if null. * @param ifUnmodifiedSince * a precondition specifying a date after which the object must not have been modified, ignored if null. * @param ifMatchTags * a precondition specifying an MD5 hash the object must match, ignored if null. * @param ifNoneMatchTags * a precondition specifying an MD5 hash the object must not match, ignored if null. * @param byteRangeStart * include only a portion of the object's data - starting at this point, ignored if null. * @param byteRangeEnd * include only a portion of the object's data - ending at this point, ignored if null. * @return * the object with the given key in S3, including only general details and metadata (not the data * input stream) * @throws S3ServiceException */ public S3Object getVersionedObject(String versionId, S3Bucket bucket, String objectKey, Calendar ifModifiedSince, Calendar ifUnmodifiedSince, String[] ifMatchTags, String[] ifNoneMatchTags, Long byteRangeStart, Long byteRangeEnd) throws S3ServiceException { try { assertValidBucket(bucket, "Get Versioned Object"); MxDelegate.getInstance().registerStorageObjectGetEvent(bucket.getName(), objectKey); return (S3Object) getObjectImpl(bucket.getName(), objectKey, ifModifiedSince, ifUnmodifiedSince, ifMatchTags, ifNoneMatchTags, byteRangeStart, byteRangeEnd, versionId); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Returns an object representing the details and data of a versioned object in S3 that * also meets any given preconditions. *

* Important: It is the caller's responsibility to close the object's data input stream. * The data stream should be consumed and closed as soon as is practical as network connections * may be held open until the streams are closed. Excessive unclosed streams can lead to * connection starvation. *

* An exception is thrown if any of the preconditions fail. * Preconditions are only applied if they are non-null. *

* This method can be performed by anonymous services. Anonymous services * can get a publicly-readable object. *

* Implementation notes

* Implementations should use {@link #assertValidBucket} assertion. * * @param versionId * the identifier of the object version to return. * @param bucketName * the name of the versioned bucket containing the object. * @param objectKey * the key identifying the object. * @param ifModifiedSince * a precondition specifying a date after which the object must have been modified, ignored if null. * @param ifUnmodifiedSince * a precondition specifying a date after which the object must not have been modified, ignored if null. * @param ifMatchTags * a precondition specifying an MD5 hash the object must match, ignored if null. * @param ifNoneMatchTags * a precondition specifying an MD5 hash the object must not match, ignored if null. * @param byteRangeStart * include only a portion of the object's data - starting at this point, ignored if null. * @param byteRangeEnd * include only a portion of the object's data - ending at this point, ignored if null. * @return * the object with the given key in S3, including only general details and metadata (not the data * input stream) * @throws S3ServiceException */ public S3Object getVersionedObject(String versionId, String bucketName, String objectKey, Calendar ifModifiedSince, Calendar ifUnmodifiedSince, String[] ifMatchTags, String[] ifNoneMatchTags, Long byteRangeStart, Long byteRangeEnd) throws S3ServiceException { try { MxDelegate.getInstance().registerStorageObjectGetEvent(bucketName, objectKey); return (S3Object) getObjectImpl(bucketName, objectKey, ifModifiedSince, ifUnmodifiedSince, ifMatchTags, ifNoneMatchTags, byteRangeStart, byteRangeEnd, versionId); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Applies access control settings to an object. The ACL settings must be included * with the object. * * This method can be performed by anonymous services, but can only succeed if the * object's existing ACL already allows write access by the anonymous user. * In general, you can only access the ACL of an object if the ACL already in place * for that object (in S3) allows you to do so. See * * the S3 documentation on ACLs for more details on access to ACLs. * * @param bucket * the bucket containing the object to modify. * @param object * the object with ACL settings that will be applied. * @throws S3ServiceException */ public void putObjectAcl(S3Bucket bucket, S3Object object) throws S3ServiceException { try { assertValidBucket(bucket, "Put Object Access Control List"); assertValidObject(object, "Put Object Access Control List"); putObjectAcl(bucket.getName(), object.getKey(), object.getAcl()); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Applies access control settings to an object. The ACL settings must be included * with the object. * * This method can be performed by anonymous services, but can only succeed if the * object's existing ACL already allows write access by the anonymous user. * In general, you can only access the ACL of an object if the ACL already in place * for that object (in S3) allows you to do so. See * * the S3 documentation on ACLs for more details on access to ACLs. * * @param bucketName * the name of the bucket containing the object to modify. * @param object * the object with ACL settings that will be applied. * @throws S3ServiceException */ public void putObjectAcl(String bucketName, S3Object object) throws S3ServiceException { try { assertValidObject(object, "Put Object Access Control List"); putObjectAcl(bucketName, object.getKey(), object.getAcl()); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Applies access control settings to a versioned object. * * This method can be performed by anonymous services, but can only succeed if the * object's existing ACL already allows write access by the anonymous user. * In general, you can only access the ACL of an object if the ACL already in place * for that object (in S3) allows you to do so. See * * the S3 documentation on ACLs for more details on access to ACLs. * * @param versionId * the identifier of the object version whose ACL will be updated. * @param bucketName * the name of the versioned bucket containing the object to modify. * @param objectKey * the key name of the object to which ACL settings will be applied. * @param acl * ACL settings to apply. * @throws S3ServiceException */ public void putVersionedObjectAcl(String versionId, String bucketName, String objectKey, AccessControlList acl) throws S3ServiceException { try { putObjectAclImpl(bucketName, objectKey, acl, versionId); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Applies access control settings to a versioned object. * The ACL settings must be included with the object. * * This method can be performed by anonymous services, but can only succeed if the * object's existing ACL already allows write access by the anonymous user. * In general, you can only access the ACL of an object if the ACL already in place * for that object (in S3) allows you to do so. See * * the S3 documentation on ACLs for more details on access to ACLs. * * @param versionId * the identifier of the object version whose ACL will be updated. * @param bucket * the bucket containing the object to modify. * @param object * the object with ACL settings that will be applied. * * @throws S3ServiceException */ public void putVersionedObjectAcl(String versionId, S3Bucket bucket, S3Object object) throws S3ServiceException { try { assertValidBucket(bucket, "Put Versioned Object Access Control List"); assertValidObject(object, "Put Versioned Object Access Control List"); String objectKey = object.getKey(); AccessControlList acl = object.getAcl(); if (acl == null) { throw new S3ServiceException("The object '" + objectKey + "' does not include ACL information"); } putObjectAclImpl(bucket.getName(), objectKey, acl, versionId); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Retrieves the access control settings of an object. * * This method can be performed by anonymous services, but can only succeed if the * object's existing ACL already allows read access by the anonymous user. * In general, you can only access the ACL of an object if the ACL already in place * for that object (in S3) allows you to do so. See * * the S3 documentation on ACLs for more details on access to ACLs. * * @param bucket * the bucket whose ACL settings will be retrieved (if objectKey is null) or the bucket containing the * object whose ACL settings will be retrieved (if objectKey is non-null). * @param objectKey * if non-null, the key of the object whose ACL settings will be retrieved. Ignored if null. * @return * the ACL settings of the bucket or object. * @throws S3ServiceException */ public AccessControlList getObjectAcl(S3Bucket bucket, String objectKey) throws S3ServiceException { try { assertValidBucket(bucket, "Get Object Access Control List"); return getObjectAclImpl(bucket.getName(), objectKey, null); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Retrieves the access control settings of a versioned object. * * This method can be performed by anonymous services, but can only succeed if the * object's existing ACL already allows read access by the anonymous user. * In general, you can only access the ACL of an object if the ACL already in place * for that object (in S3) allows you to do so. See * * the S3 documentation on ACLs for more details on access to ACLs. * * @param versionId * the identifier of the object version whose ACL will be returned. * @param bucket * the versioned bucket whose ACL settings will be retrieved (if objectKey is null) or the bucket * containing the object whose ACL settings will be retrieved (if objectKey is non-null). * @param objectKey * if non-null, the key of the object whose ACL settings will be retrieved. Ignored if null. * @return * the ACL settings of the bucket or object. * @throws S3ServiceException */ public AccessControlList getVersionedObjectAcl(String versionId, S3Bucket bucket, String objectKey) throws S3ServiceException { try { assertValidBucket(bucket, "Get versioned Object Access Control List"); return getObjectAclImpl(bucket.getName(), objectKey, versionId); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Retrieves the access control settings of a versioned object. * * This method can be performed by anonymous services, but can only succeed if the * object's existing ACL already allows write access by the anonymous user. * In general, you can only access the ACL of an object if the ACL already in place * for that object (in S3) allows you to do so. See * * the S3 documentation on ACLs for more details on access to ACLs. * * @param versionId * the identifier of the object version whose ACL will be returned. * @param bucketName * the name of the versioned bucket containing the object whose ACL settings will be retrieved. * @param objectKey * if non-null, the key of the object whose ACL settings will be retrieved. Ignored if null. * @return * the ACL settings of the bucket or object. * @throws S3ServiceException */ public AccessControlList getVersionedObjectAcl(String versionId, String bucketName, String objectKey) throws S3ServiceException { try { return getObjectAclImpl(bucketName, objectKey, versionId); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Retrieves the access control settings of a bucket. * * This method can be performed by anonymous services, but can only succeed if the * bucket's existing ACL already allows write access by the anonymous user. * In general, you can only access the ACL of a bucket if the ACL already in place * for that bucket (in S3) allows you to do so. See * * the S3 documentation on ACLs for more details on access to ACLs. * * @param bucket * the bucket whose access control settings will be returned. * This must be a valid S3Bucket object that is non-null and contains a name. * @return * the ACL settings of the bucket. * @throws S3ServiceException */ public AccessControlList getBucketAcl(S3Bucket bucket) throws S3ServiceException { try { assertValidBucket(bucket, "Get Bucket Access Control List"); return getBucketAclImpl(bucket.getName()); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Retrieves the location of a bucket. Only the owner of a bucket may retrieve its location. * * @param bucketName * the name of the bucket whose location will be returned. * @return * a string representing the location of the bucket, such as "EU" for a bucket * located in Europe or null for a bucket in the default US location. * @throws S3ServiceException */ public String getBucketLocation(String bucketName) throws S3ServiceException { return getBucketLocationImpl(bucketName); } /** * Retrieves the logging status settings of a bucket. Only the owner of a bucket may retrieve * its logging status. * * @param bucketName * the name of the bucket whose logging status settings will be returned. * @return * the Logging Status settings of the bucket. * @throws S3ServiceException */ public S3BucketLoggingStatus getBucketLoggingStatus(String bucketName) throws S3ServiceException { return getBucketLoggingStatusImpl(bucketName); } /** * Applies logging settings to a bucket, optionally modifying the ACL permissions for the * logging target bucket to ensure log files can be written to it. Only the owner of * a bucket may change its logging status. * * @param bucketName * the name of the bucket the logging settings will apply to. * @param status * the logging status settings to apply to the bucket. * @param updateTargetACLifRequired * if true, when logging is enabled the method will check the target bucket to ensure it has the * necessary ACL permissions set to allow logging (that is, WRITE and READ_ACP for the group * http://acs.amazonaws.com/groups/s3/LogDelivery). If the target bucket does not * have the correct permissions the bucket's ACL will be updated to have the correct * permissions. If this parameter is false, no ACL checks or updates will occur. * * @throws S3ServiceException */ public void setBucketLoggingStatus(String bucketName, S3BucketLoggingStatus status, boolean updateTargetACLifRequired) throws S3ServiceException { try { if (status.isLoggingEnabled() && updateTargetACLifRequired) { // Check whether the target bucket has the ACL permissions necessary for logging. if (log.isDebugEnabled()) { log.debug("Checking whether the target logging bucket '" + status.getTargetBucketName() + "' has the appropriate ACL settings"); } boolean isSetLoggingGroupWrite = false; boolean isSetLoggingGroupReadACP = false; String groupIdentifier = GroupGrantee.LOG_DELIVERY.getIdentifier(); AccessControlList logBucketACL = getBucketAcl(status.getTargetBucketName()); for (GrantAndPermission gap: logBucketACL.getGrantAndPermissions()) { if (groupIdentifier.equals(gap.getGrantee().getIdentifier())) { // Found a Group Grantee. if (gap.getPermission().equals(Permission.PERMISSION_WRITE)) { isSetLoggingGroupWrite = true; if (log.isDebugEnabled()) { log.debug("Target bucket '" + status.getTargetBucketName() + "' has ACL " + "permission " + Permission.PERMISSION_WRITE + " for group " + groupIdentifier); } } else if (gap.getPermission().equals(Permission.PERMISSION_READ_ACP)) { isSetLoggingGroupReadACP = true; if (log.isDebugEnabled()) { log.debug("Target bucket '" + status.getTargetBucketName() + "' has ACL " + "permission " + Permission.PERMISSION_READ_ACP + " for group " + groupIdentifier); } } } } // Update target bucket's ACL if necessary. if (!isSetLoggingGroupWrite || !isSetLoggingGroupReadACP) { if (log.isWarnEnabled()) { log.warn("Target logging bucket '" + status.getTargetBucketName() + "' does not have the necessary ACL settings, updating ACL now"); } logBucketACL.grantPermission(GroupGrantee.LOG_DELIVERY, Permission.PERMISSION_WRITE); logBucketACL.grantPermission(GroupGrantee.LOG_DELIVERY, Permission.PERMISSION_READ_ACP); putBucketAcl(status.getTargetBucketName(), logBucketACL); } else { if (log.isDebugEnabled()) { log.debug("Target logging bucket '" + status.getTargetBucketName() + "' has the necessary ACL settings"); } } } setBucketLoggingStatusImpl(bucketName, status); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * Apply a JSON access control policy document to a bucket. * * @param bucketName * @param policyDocument * @throws S3ServiceException */ public void setBucketPolicy(String bucketName, String policyDocument) throws S3ServiceException { setBucketPolicyImpl(bucketName, policyDocument); } /** * Retrieve the JSON access control policy document for a bucket, * or null if the bucket does not have a policy. * * @param bucketName * @return * JSON policy document for bucket, or null if the bucket has no policy. * @throws S3ServiceException */ public String getBucketPolicy(String bucketName) throws S3ServiceException { try { return getBucketPolicyImpl(bucketName); } catch (S3ServiceException e) { if (e.getResponseCode() == 404) { return null; } else { throw e; } } } /** * Delete the acces control policy document for a bucket. * * @param bucketName * @throws S3ServiceException */ public void deleteBucketPolicy(String bucketName) throws S3ServiceException { deleteBucketPolicyImpl(bucketName); } /** * Return true if the given bucket is configured as a * * Requester Pays bucket, in which case the requester must supply their own AWS * credentials when accessing objects in the bucket, and will be responsible for request * and data transfer fees. * * @param bucketName * the name of the bucket whose request payment configuration setting will be returned. * * @return * true if the given bucket is configured to be Requester Pays, false if it is has the * default Owner pays configuration. * * @throws S3ServiceException */ public boolean isRequesterPaysBucket(String bucketName) throws S3ServiceException { return isRequesterPaysBucketImpl(bucketName); } /** * Applies * request payment configuration settings to a bucket, setting the bucket to * be either Requester Pays or Bucket Owner pays. Only the owner of a bucket may change * its request payment status. * * @param bucketName * the name of the bucket to which the request payment configuration settings will be applied. * @param requesterPays * if true, the bucket will be configured to be Requester Pays. If false, the bucket will * be configured to be Owner pays (the default configuration setting). * * @throws S3ServiceException */ public void setRequesterPaysBucket(String bucketName, boolean requesterPays) throws S3ServiceException { setRequesterPaysBucketImpl(bucketName, requesterPays); } /** * Convenience method that uploads a file-based object to a storage service using * the regular {@link #putObject(String, StorageObject)} mechanism, or as a * multipart upload if the object's file data is larger than the given maximum * part size parameter. * * If a multipart upload is performed this method will perform all the necessary * steps, including: *

    *
  1. Start a new multipart upload process, based on the object's key name, * metadata, ACL etc.
  2. *
  3. Poll the service for a little while to ensure the just-started upload * is actually available for use before proceeding -- this can take some * time, we give up after 5 seconds (with 1 lookup attempt per second)
  4. *
  5. Divide the object's underlying file into parts with size <= the given * maximum part size
  6. *
  7. Upload each of these parts in turn, with part numbers 1..n
  8. *
  9. Complete the upload once all the parts have been uploaded, or...
  10. *
  11. If there was a failure uploading parts or completing the upload, attempt * to clean up by calling {@link #multipartAbortUpload(MultipartUpload)} * then throw the original exception
  12. *
* This means that any multipart upload will involve sending around 2 + n separate * HTTP requests, where n is ceil(objectDataSize / maxPartSize). * * @param bucketName * the name of the bucket in which the object will be stored. * @param object * a file-based object containing all information that will be written to the service. * If the object provided is not file-based -- i.e. it returns null from * {@link StorageObject#getDataInputFile()} -- an exception will be thrown immediately. * @param maxPartSize * the maximum size in bytes for any single upload part. If the given object's data is * less than this value it will be uploaded using a regular PUT. If the object has more * data than this value it will be uploaded using a multipart upload. * The maximum part size value should be <= 5 GB and >= 5 MB. * * @throws ServiceException */ public void putObjectMaybeAsMultipart(String bucketName, StorageObject object, long maxPartSize) throws ServiceException { // Only file-based objects are supported if (object.getDataInputFile() == null) { throw new ServiceException( "multipartUpload method only supports file-based objects"); } MultipartUtils multipartUtils = new MultipartUtils(maxPartSize); // Upload object normally if it doesn't exceed maxPartSize if (!multipartUtils.isFileLargerThanMaxPartSize(object.getDataInputFile())) { log.debug("Performing normal PUT upload for object with data <= " + maxPartSize); putObject(bucketName, object); } else { log.debug("Performing multipart upload for object with data > " + maxPartSize); // Start upload MultipartUpload upload = multipartStartUpload(bucketName, object.getKey(), object.getMetadataMap(), object.getAcl(), object.getStorageClass()); // Ensure upload is present on service-side, might take a little time boolean foundUpload = false; int maxTries = 5; // Allow up to 5 lookups for upload before we give up int tries = 0; do { try { multipartListParts(upload); foundUpload = true; } catch (S3ServiceException e) { if ("NoSuchUpload".equals(e.getErrorCode())) { tries++; try { Thread.sleep(1000); // Wait for a second } catch (InterruptedException ie) { tries = maxTries; } } else { // Bail out if we get a (relatively) unexpected exception throw e; } } } while (!foundUpload && tries < maxTries); if (!foundUpload) { throw new ServiceException( "Multipart upload was started but unavailable for use after " + tries + " attempts, giving up"); } // Will attempt to delete multipart upload upon failure. try { List partObjects = multipartUtils.splitFileIntoObjectsByMaxPartSize( object.getKey(), object.getDataInputFile()); List parts = new ArrayList(); int partNumber = 1; for (S3Object partObject: partObjects) { MultipartPart part = multipartUploadPart(upload, partNumber, partObject); parts.add(part); partNumber++; } multipartCompleteUpload(upload, parts); } catch (RuntimeException e) { throw e; } catch (Exception e) { // If upload fails for any reason after the upload was started, try to clean up. log.warn("Multipart upload failed, attempting clean-up by aborting upload", e); try { multipartAbortUpload(upload); } catch (S3ServiceException e2) { log.warn("Multipart upload failed and could not clean-up by aborting upload", e2); } // Throw original failure exception if (e instanceof ServiceException) { throw (ServiceException) e; } else { throw new ServiceException("Multipart upload failed", e); } } } } /** * Start a multipart upload process for a given object; must be done before * individual parts can be uploaded. * * @param bucketName * the name of the bucket in which the object will be stored. * @param objectKey * the key name of the object. * @param metadata * metadata to apply to the completed object, may be null. * @return * object representing this multipart upload. * @throws S3ServiceException */ public MultipartUpload multipartStartUpload(String bucketName, String objectKey, Map metadata) throws S3ServiceException { return multipartStartUpload(bucketName, objectKey, metadata, null, null); } /** * Start a multipart upload process for a given object; must be done before * individual parts can be uploaded. * * @param bucketName * the name of the bucket in which the object will be stored. * @param objectKey * the key name of the object. * @param metadata * metadata to apply to the completed object, may be null. * @param acl * ACL to apply to the completed upload, may be null. * @param storageClass * storage class to apply to the completed upload, may be null. * @return * object representing this multipart upload. * @throws S3ServiceException */ public MultipartUpload multipartStartUpload(String bucketName, String objectKey, Map metadata, AccessControlList acl, String storageClass) throws S3ServiceException { return multipartStartUploadImpl(bucketName, objectKey, metadata, acl, storageClass); } /** * Start a multipart upload process for a given object; must be done before * individual parts can be uploaded. * * @param bucketName * the name of the bucket in which the object will be stored. * @param object * object containing details to apply to the completed object, including: * key name, metadata, ACL, storage class * @return * object representing this multipart upload. * @throws S3ServiceException */ public MultipartUpload multipartStartUpload(String bucketName, S3Object object) throws S3ServiceException { return multipartStartUploadImpl(bucketName, object.getKey(), object.getMetadataMap(), object.getAcl(), object.getStorageClass()); } /** * Abort the given multipart upload process. Also deletes any parts that may * have already been uploaded. * * @param upload * the multipart upload to abort. * @throws S3ServiceException */ public void multipartAbortUpload(MultipartUpload upload) throws S3ServiceException { multipartAbortUploadImpl(upload.getUploadId(), upload.getBucketName(), upload.getObjectKey()); } /** * List the multipart uploads that have been started within a bucket and * have not yet been completed or aborted. * * @param bucketName * the bucket whose multipart uploads will be listed. * @return * a list of incomplete multipart uploads. * @throws S3ServiceException */ public List multipartListUploads(String bucketName) throws S3ServiceException { return multipartListUploads(bucketName, null, null, null); } /** * List a subset of the multipart uploads that have been started within * a bucket and have not yet been completed or aborted. * * @param bucketName * the bucket whose multipart uploads will be listed. * @param nextKeyMarker * marker indicating where this list subset should start by key name. * @param nextUploadIdMarker * marker indicating where this list subset should start by upload ID. * @param maxUploads * maximum number of uploads to list in a subset. * @return * a list of incomplete multipart uploads. * @throws S3ServiceException */ public List multipartListUploads(String bucketName, String nextKeyMarker, String nextUploadIdMarker, Integer maxUploads) throws S3ServiceException { return multipartListUploadsImpl( bucketName, nextKeyMarker, nextUploadIdMarker, maxUploads); } /** * List the parts that have been uploaded for a given multipart upload. * * @param upload * the multipart upload whose parts will be listed. * @return * a list of multipart parts that have been successfully uploaded. * @throws S3ServiceException */ public List multipartListParts(MultipartUpload upload) throws S3ServiceException { return multipartListPartsImpl(upload.getUploadId(), upload.getBucketName(), upload.getObjectKey()); } /** * Complete a multipart upload by combining all the given parts into * the final object. * * @param upload * the multipart upload whose parts will be completed. * @param parts * the parts comprising the final object. * @return * information about the completion operation. * @throws S3ServiceException */ public MultipartCompleted multipartCompleteUpload(MultipartUpload upload, List parts) throws S3ServiceException { return multipartCompleteUploadImpl(upload.getUploadId(), upload.getBucketName(), upload.getObjectKey(), parts); } /** * Convenience method to complete a multipart upload by automatically finding * its parts. This method does more work than the lower-level * {@link #multipartCompleteUpload(MultipartUpload, List)} API operation, but * relieves the caller of having to keep track of all the parts uploaded * for a multipart upload. * * @param upload * the multipart upload whose parts will be completed. * @return * information about the completion operation. * @throws S3ServiceException */ public MultipartCompleted multipartCompleteUpload(MultipartUpload upload) throws S3ServiceException { List parts = multipartListParts(upload); return multipartCompleteUploadImpl(upload.getUploadId(), upload.getBucketName(), upload.getObjectKey(), parts); } /** * Upload an individual part that will comprise a piece of a multipart upload object. * * @param upload * the multipart upload to which this part will be added. * @param partNumber * the part's number; must be between 1 and 10,000 and must uniquely identify a given * part and represent its order compared to all other parts. Part numbers need not * be sequential. * @param object * an object containing a input stream with data that will be sent to the storage service. * @return * information about the uploaded part, retain this information to eventually complete * the object with {@link #multipartCompleteUpload(MultipartUpload, List)}. * @throws S3ServiceException */ public MultipartPart multipartUploadPart(MultipartUpload upload, Integer partNumber, S3Object object) throws S3ServiceException { try { MultipartPart part = multipartUploadPartImpl(upload.getUploadId(), upload.getBucketName(), partNumber, object); upload.addMultipartPartToUploadedList(part); return part; } catch (S3ServiceException e) { throw e; } } /** * Apply a website configuration to a bucket. * * @param bucketName * bucket to which the website configuration will be applied. * @param config * the website configuration details. * @throws S3ServiceException */ public void setWebsiteConfig(String bucketName, WebsiteConfig config) throws S3ServiceException { setWebsiteConfigImpl(bucketName, config); } /** * @param bucketName * a bucket with a website configuration. * @return * the website configuration details. * @throws S3ServiceException */ public WebsiteConfig getWebsiteConfig(String bucketName) throws S3ServiceException { return getWebsiteConfigImpl(bucketName); } /** * Delete a bucket's website configuration; removes the effect of any * previously-applied configuration. * * @param bucketName * a bucket with a website configuration. * @throws S3ServiceException */ public void deleteWebsiteConfig(String bucketName) throws S3ServiceException { deleteWebsiteConfigImpl(bucketName); } /** * Apply a notification configuration to a bucket. * * @param bucketName * the bucket to which the notification configuration will be applied. * @param config * the notification configuration to apply. * @throws S3ServiceException */ public void setNotificationConfig(String bucketName, NotificationConfig config) throws S3ServiceException { setNotificationConfigImpl(bucketName, config); } /** * @param bucketName * a bucket with a notification configuration. * @return * the notification configuration details. * @throws S3ServiceException */ public NotificationConfig getNotificationConfig(String bucketName) throws S3ServiceException { return getNotificationConfigImpl(bucketName); } /** * Unset (delete) a bucket's notification configuration; removes the effect of any * previously-applied configuration. * * @param bucketName * a bucket with a notification configuration. * @throws S3ServiceException */ public void unsetNotificationConfig(String bucketName) throws S3ServiceException { setNotificationConfigImpl(bucketName, new NotificationConfig()); } /////////////////////////////////////////////////////////// // Abstract methods that must be implemented by S3 services /////////////////////////////////////////////////////////// protected abstract String getBucketLocationImpl(String bucketName) throws S3ServiceException; protected abstract S3BucketLoggingStatus getBucketLoggingStatusImpl(String bucketName) throws S3ServiceException; protected abstract void setBucketLoggingStatusImpl(String bucketName, S3BucketLoggingStatus status) throws S3ServiceException; protected abstract void setBucketPolicyImpl(String bucketName, String policyDocument) throws S3ServiceException; protected abstract String getBucketPolicyImpl(String bucketName) throws S3ServiceException; protected abstract void deleteBucketPolicyImpl(String bucketName) throws S3ServiceException; protected abstract void setRequesterPaysBucketImpl(String bucketName, boolean requesterPays) throws S3ServiceException; protected abstract boolean isRequesterPaysBucketImpl(String bucketName) throws S3ServiceException; protected abstract BaseVersionOrDeleteMarker[] listVersionedObjectsImpl(String bucketName, String prefix, String delimiter, String keyMarker, String versionMarker, long maxListingLength) throws S3ServiceException; /** * Lists version or delete markers in a versioned bucket, up to the maximum listing * length specified. * *

* Implementation notes * The implementation of this method returns only as many items as requested in the chunk * size. It is the responsibility of the caller to build a complete object listing from * multiple chunks, should this be necessary. *

* * @param bucketName * @param prefix * @param delimiter * only list objects with key names up to this delimiter, may be null. * @param maxListingLength * @param priorLastKey * @param completeListing * @throws S3ServiceException */ protected abstract VersionOrDeleteMarkersChunk listVersionedObjectsChunkedImpl( String bucketName, String prefix, String delimiter, long maxListingLength, String priorLastKey, String priorLastVersion, boolean completeListing) throws S3ServiceException; protected abstract void updateBucketVersioningStatusImpl(String bucketName, boolean enabled, boolean multiFactorAuthDeleteEnabled, String multiFactorSerialNumber, String multiFactorAuthCode) throws S3ServiceException; protected abstract S3BucketVersioningStatus getBucketVersioningStatusImpl( String bucketName) throws S3ServiceException; protected abstract MultipartUpload multipartStartUploadImpl(String bucketName, String objectKey, Map metadata, AccessControlList acl, String storageClass) throws S3ServiceException; protected abstract void multipartAbortUploadImpl(String uploadId, String bucketName, String objectKey) throws S3ServiceException; protected abstract List multipartListUploadsImpl(String bucketName, String nextKeyMarker, String nextUploadIdMarker, Integer maxUploads) throws S3ServiceException; protected abstract List multipartListPartsImpl(String uploadId, String bucketName, String objectKey) throws S3ServiceException; protected abstract MultipartCompleted multipartCompleteUploadImpl(String uploadId, String bucketName, String objectKey, List parts) throws S3ServiceException; protected abstract MultipartPart multipartUploadPartImpl(String uploadId, String bucketName, Integer partNumber, S3Object object) throws S3ServiceException; protected abstract void setWebsiteConfigImpl(String bucketName, WebsiteConfig config) throws S3ServiceException; protected abstract WebsiteConfig getWebsiteConfigImpl(String bucketName) throws S3ServiceException; protected abstract void deleteWebsiteConfigImpl(String bucketName) throws S3ServiceException; protected abstract void setNotificationConfigImpl(String bucketName, NotificationConfig config) throws S3ServiceException; protected abstract NotificationConfig getNotificationConfigImpl(String bucketName) throws S3ServiceException; } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/security/0002755000000000000000000000000011550421156017603 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/security/AWSDevPayCredentials.java0000644000000000000000000000743011441613550024371 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty, 2008 Zmanda Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.security; /** * Class to contain the Amazon Web Services (AWS) credentials of a user, * with bits needed for DevPay. * * @author Nikolas Coukouma */ public class AWSDevPayCredentials extends AWSCredentials { private static final long serialVersionUID = -8971737296373324817L; private String awsUserToken = null; private String awsProductToken = null; protected AWSDevPayCredentials(String awsAccessKey, String awsSecretAccessKey) { super(awsAccessKey, awsSecretAccessKey); } protected AWSDevPayCredentials(String awsAccessKey, String awsSecretAccessKey, String friendlyName) { super(awsAccessKey, awsSecretAccessKey, friendlyName); } @Override protected String getTypeName() { return "devpay"; } @Override public String getVersionPrefix() { return "jets3t AWS Credentials, version: "; } /** * Construct credentials. * * @param awsAccessKey * AWS access key for an Amazon S3 account. * @param awsSecretAccessKey * AWS secret key for an Amazon S3 account. * @param awsUserToken * DevPay user token for an Amazon S3 account. * @param awsProductToken * DevPay product token for an Amazon S3 account. */ public AWSDevPayCredentials(String awsAccessKey, String awsSecretAccessKey, String awsUserToken, String awsProductToken) { super(awsAccessKey, awsSecretAccessKey); this.awsUserToken = awsUserToken; this.awsProductToken = awsProductToken; } /** * Construct credentials. * * @param awsAccessKey * AWS access key for an Amazon S3 account. * @param awsSecretAccessKey * AWS secret key for an Amazon S3 account. * @param awsUserToken * DevPay user token for an Amazon S3 account. * @param awsProductToken * DevPay product token for an Amazon S3 account. * @param friendlyName * a name identifying the owner of the credentials, such as 'James'. */ public AWSDevPayCredentials(String awsAccessKey, String awsSecretAccessKey, String awsUserToken, String awsProductToken, String friendlyName) { super(awsAccessKey, awsSecretAccessKey, friendlyName); this.awsUserToken = awsUserToken; this.awsProductToken = awsProductToken; } /** * @return * the AWS User Token */ public String getUserToken() { return awsUserToken; } /** * @return * the AWS Product Token */ public String getProductToken() { return awsProductToken; } /** * @return * a string summarizing these credentials */ @Override public String getLogString() { return super.getLogString() + " : " + getUserToken() + " : " + getProductToken(); } /** * @return * the string of data that needs to be encrypted (for serialization) */ @Override protected String getDataToEncrypt() { return getAccessKey() + V3_KEYS_DELIMITER + getSecretKey() + V3_KEYS_DELIMITER + getUserToken() + V3_KEYS_DELIMITER + getProductToken(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/security/AWSCredentials.java0000644000000000000000000001157611441613550023266 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.security; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; /** * Class to contain the Amazon Web Services (AWS) credentials of a user. This class also includes * utility methods to store credentials to password-encrypted files, and retrieve credentials from * these files. * * @author James Murty * @author Nikolas Coukouma */ public class AWSCredentials extends ProviderCredentials { /** * Construct credentials. * * @param awsAccessKey * AWS access key for an Amazon S3 account. * @param awsSecretAccessKey * AWS secret key for an Amazon S3 account. */ public AWSCredentials(String awsAccessKey, String awsSecretAccessKey) { super(awsAccessKey, awsSecretAccessKey); } /** * Construct credentials, and associate them with a human-friendly name. * * @param awsAccessKey * AWS access key for an Amazon S3 account. * @param awsSecretAccessKey * AWS secret key for an Amazon S3 account. * @param friendlyName * a name identifying the owner of the credentials, such as 'James'. */ public AWSCredentials(String awsAccessKey, String awsSecretAccessKey, String friendlyName) { super(awsAccessKey, awsSecretAccessKey, friendlyName); } @Override protected String getTypeName() { return "regular"; } @Override public String getVersionPrefix() { return "jets3t AWS Credentials, version: "; } /** * Console utility to store AWS credentials information in an encrypted file in the toolkit's * default preferences directory. *

* This class can be run from the command line as: *

     * java org.jets3t.service.security.AWSCredentials <friendlyName> <credentialsFilename> <algorithm>
     * 
* When run it will prompt for the user's AWS access key,secret key and encryption password. * It will then encode into the specified credentials file. * * @param args */ public static void main(String[] args) throws Exception { if (args.length < 2 || args.length > 3) { printHelp(); System.exit(1); } String userName = args[0]; File encryptedFile = new File(args[1]); String algorithm = EncryptionUtil.DEFAULT_ALGORITHM; if (args.length == 3) { algorithm = args[2]; } // Check arguments provided. try { FileOutputStream testFOS = new FileOutputStream(encryptedFile); testFOS.close(); } catch (IOException e) { System.err.println("Unable to write to file: " + encryptedFile); } BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); // Obtain credentials and password from user. System.out.println("Please enter your AWS Credentials"); System.out.print("Access Key: "); String awsAccessKey = reader.readLine(); System.out.print("Secret Key: "); String awsSecretKey = reader.readLine(); System.out.println("Please enter a password to protect your credentials file (may be empty)"); System.out.print("Password: "); String password = reader.readLine(); // Create AWSCredentials object and save the details to an encrypted file. AWSCredentials awsCredentials = new AWSCredentials(awsAccessKey, awsSecretKey, userName); awsCredentials.save(password, encryptedFile, algorithm); System.out.println("Successfully saved AWS Credentials to " + encryptedFile); } /** * Prints help for the use of this class from the console (via the main method). */ private static void printHelp() { System.out.println("AWSCredentials [algorithm]"); System.out.println(); System.out.println("User Name: A human-friendly name for the owner of the credentials, e.g. Horace."); System.out.println("File Path: Path and name for the encrypted file. Will be replaced if it already exists."); System.out.println("Algorithm: PBE encryption algorithm. Defaults to PBEWithMD5AndDES"); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/security/EncryptionUtil.java0000644000000000000000000005120311550442020023426 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.security; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.Provider; import java.security.SecureRandom; import java.security.Security; import java.security.Signature; import java.security.SignatureException; import java.security.interfaces.RSAPrivateKey; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; import java.security.spec.PKCS8EncodedKeySpec; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.CipherInputStream; import javax.crypto.CipherOutputStream; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESedeKeySpec; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.PBEParameterSpec; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.Constants; import org.jets3t.service.utils.ServiceUtils; /** * Utility class to handle encryption and decryption in the JetS3t suite. *

* This class uses properties obtained through {@link org.jets3t.service.Jets3tProperties}. * For more information on these properties please refer to * JetS3t Configuration *

* * @author James Murty */ public class EncryptionUtil { private static final Log log = LogFactory.getLog(EncryptionUtil.class); public static final String DEFAULT_VERSION = "2"; public static final String DEFAULT_ALGORITHM = "PBEWithMD5AndDES"; private String algorithm = null; private String version = null; private SecretKey key = null; private AlgorithmParameterSpec algParamSpec = null; int ITERATION_COUNT = 5000; byte[] salt = { (byte)0xA4, (byte)0x0B, (byte)0xC8, (byte)0x34, (byte)0xD6, (byte)0x95, (byte)0xF3, (byte)0x13 }; static { try { Class bouncyCastleProviderClass = Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider"); if (bouncyCastleProviderClass != null) { Provider bouncyCastleProvider = (Provider) bouncyCastleProviderClass .getConstructor(new Class[] {}).newInstance(new Object[] {}); Security.addProvider(bouncyCastleProvider); } if (log.isDebugEnabled()) { log.debug("Loaded security provider BouncyCastleProvider"); } } catch (RuntimeException e) { throw e; } catch (Exception e) { if (log.isDebugEnabled()) { log.debug("Unable to load security provider BouncyCastleProvider"); } } } /** * Constructs class configured with the provided password, and set up to use the encryption * method specified. * * @param encryptionKey * the password to use for encryption/decryption. * @param algorithm * the Java name of an encryption algorithm to use, eg PBEWithMD5AndDES * @param version * the version of encyption to use, for historic and future compatibility. * Unless using an historic version, this should always be * {@link #DEFAULT_VERSION} * * @throws InvalidKeyException * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException * @throws InvalidKeySpecException */ public EncryptionUtil(String encryptionKey, String algorithm, String version) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException { this.algorithm = algorithm; this.version = version; if (log.isDebugEnabled()) { log.debug("Cryptographic properties: algorithm=" + this.algorithm + ", version=" + this.version); } if (!DEFAULT_VERSION.equals(version)) { throw new RuntimeException("Unrecognised crypto version setting: " + version); } PBEKeySpec keyspec = new PBEKeySpec(encryptionKey.toCharArray(), salt, ITERATION_COUNT, 32); SecretKeyFactory skf = SecretKeyFactory.getInstance(algorithm); key = skf.generateSecret(keyspec); algParamSpec = new PBEParameterSpec(salt, ITERATION_COUNT); } /** * Constructs class configured with the provided password, and set up to use the default encryption * algorithm PBEWithMD5AndDES. * * @param encryptionKey * the password to use for encryption/decryption. * * @throws InvalidKeyException * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException * @throws InvalidKeySpecException */ public EncryptionUtil(String encryptionKey) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException { this(encryptionKey, "PBEWithMD5AndDES", DEFAULT_VERSION); } protected Cipher initEncryptModeCipher() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException { Cipher cipher = Cipher.getInstance(algorithm); cipher.init(Cipher.ENCRYPT_MODE, key, algParamSpec); return cipher; } protected Cipher initDecryptModeCipher() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException { Cipher cipher = Cipher.getInstance(algorithm); cipher.init(Cipher.DECRYPT_MODE, key, algParamSpec); return cipher; } /** * Encrypts a UTF-8 string to byte data. * * @param data * data to encrypt. * @return * encrypted data. * * @throws IllegalStateException * @throws IllegalBlockSizeException * @throws BadPaddingException * @throws UnsupportedEncodingException * @throws InvalidKeySpecException * @throws InvalidKeyException * @throws InvalidAlgorithmParameterException * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException */ public byte[] encrypt(String data) throws IllegalStateException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException, InvalidKeySpecException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException { Cipher cipher = initEncryptModeCipher(); return cipher.doFinal(data.getBytes(Constants.DEFAULT_ENCODING)); } /** * Decrypts byte data to a UTF-8 string. * * @param data * data to decrypt. * @return * UTF-8 string of decrypted data. * * @throws InvalidKeyException * @throws InvalidAlgorithmParameterException * @throws UnsupportedEncodingException * @throws IllegalStateException * @throws IllegalBlockSizeException * @throws BadPaddingException * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException */ public String decryptString(byte[] data) throws InvalidKeyException, InvalidAlgorithmParameterException, UnsupportedEncodingException, IllegalStateException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException { Cipher cipher = initEncryptModeCipher(); return new String(cipher.doFinal(data), Constants.DEFAULT_ENCODING); } /** * Decrypts a UTF-8 string. * * @param data * data to decrypt. * @param startIndex * start index of data to decrypt. * @param endIndex * end index of data to decrypt. * @return * UTF-8 string of decrypted data. * * @throws InvalidKeyException * @throws InvalidAlgorithmParameterException * @throws UnsupportedEncodingException * @throws IllegalStateException * @throws IllegalBlockSizeException * @throws BadPaddingException * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException */ public String decryptString(byte[] data, int startIndex, int endIndex) throws InvalidKeyException, InvalidAlgorithmParameterException, UnsupportedEncodingException, IllegalStateException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException { Cipher cipher = initDecryptModeCipher(); return new String(cipher.doFinal(data, startIndex, endIndex), Constants.DEFAULT_ENCODING); } /** * Encrypts byte data to bytes. * * @param data * data to encrypt. * @return * encrypted data. * * @throws IllegalStateException * @throws IllegalBlockSizeException * @throws BadPaddingException * @throws InvalidKeyException * @throws InvalidAlgorithmParameterException * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException */ public byte[] encrypt(byte[] data) throws IllegalStateException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException { Cipher cipher = initEncryptModeCipher(); return cipher.doFinal(data); } /** * Decrypts byte data to bytes. * * @param data * data to decrypt * @return * decrypted data. * * @throws InvalidKeyException * @throws InvalidAlgorithmParameterException * @throws IllegalStateException * @throws IllegalBlockSizeException * @throws BadPaddingException * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException */ public byte[] decrypt(byte[] data) throws InvalidKeyException, InvalidAlgorithmParameterException, IllegalStateException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException { Cipher cipher = initDecryptModeCipher(); return cipher.doFinal(data); } /** * Decrypts a byte data range to bytes. * * @param data * @param startIndex * @param endIndex * @return * decrypted data. * @throws InvalidKeyException * @throws InvalidAlgorithmParameterException * @throws IllegalStateException * @throws IllegalBlockSizeException * @throws BadPaddingException * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException */ public byte[] decrypt(byte[] data, int startIndex, int endIndex) throws InvalidKeyException, InvalidAlgorithmParameterException, IllegalStateException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException { Cipher cipher = initDecryptModeCipher(); return cipher.doFinal(data, startIndex, endIndex); } /** * Wraps an input stream in an encrypting cipher stream. * * @param is * @return * encrypting cipher input stream. * @throws InvalidKeyException * @throws InvalidAlgorithmParameterException * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException */ public CipherInputStream encrypt(InputStream is) throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException { Cipher cipher = initEncryptModeCipher(); return new CipherInputStream(is, cipher); } /** * Wraps an input stream in an decrypting cipher stream. * * @param is * @return * decrypting cipher input stream. * @throws InvalidKeyException * @throws InvalidAlgorithmParameterException * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException */ public CipherInputStream decrypt(InputStream is) throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException { Cipher cipher = initDecryptModeCipher(); return new CipherInputStream(is, cipher); } /** * Wraps an output stream in an encrypting cipher stream. * * @param os * @return * encrypting cipher output stream. * @throws InvalidKeyException * @throws InvalidAlgorithmParameterException * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException */ public CipherOutputStream encrypt(OutputStream os) throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException { Cipher cipher = initEncryptModeCipher(); return new CipherOutputStream(os, cipher); } /** * Wraps an output stream in a decrypting cipher stream. * * @param os * @return * decrypting cipher output stream. * @throws InvalidKeyException * @throws InvalidAlgorithmParameterException * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException */ public CipherOutputStream decrypt(OutputStream os) throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException { Cipher cipher = initDecryptModeCipher(); return new CipherOutputStream(os, cipher); } /** * Returns an estimate of the number of bytes that will result when data * of the given length is encrypted. The accuracy of this estimate may * depend on the cipher you are using, so be wary of trusting this estimate * without supporting evidence. * * @param inputSize * The number of bytes you intend to encrypt. * * @return * an estimate of the number of bytes that will be generated by the * encryption cipher for the given number of bytes of input. * * @throws InvalidKeyException * @throws InvalidAlgorithmParameterException * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException */ public long getEncryptedOutputSize(long inputSize) throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException { Cipher cipher = initEncryptModeCipher(); long outputSize = 0; // Break input size into integer-sized chunks so we can estimate values // for large inputs. int maxChunk = Integer.MAX_VALUE - 8192; while (inputSize >= maxChunk) { outputSize += cipher.getOutputSize(maxChunk); inputSize -= maxChunk; } outputSize += cipher.getOutputSize((int)inputSize); return outputSize; } /** * @return * the Java name of the cipher algorithm being used by this class. */ public String getAlgorithm() { return algorithm; } /** * Returns true if the given cipher is available and can be used by this encryption * utility. To determine whether the cipher can actually be used a test string is * encrypted using the cipher. * * @param cipher * @return * true if the cipher is available and can be used, false otherwise. */ public static boolean isCipherAvailableForUse(String cipher) { try { EncryptionUtil encryptionUtil = new EncryptionUtil("Sample Key", cipher, EncryptionUtil.DEFAULT_VERSION); encryptionUtil.encrypt("Testing encryption..."); } catch (RuntimeException e) { throw e; } catch (Exception e) { if (log.isDebugEnabled()) { log.debug("Availability test failed for encryption cipher " + cipher); } return false; } return true; } /** * Lists the PBE ciphers available on the system, optionally eliminating those * ciphers that are apparently available but cannot actually be used (perhaps due to * the lack of export-grade JCE settings). * * @param testAvailability * if true each apparently available cipher is tested and only those that pass * {@link #isCipherAvailableForUse(String)} are returned. * * @return * a list of all the available PBE cipher names on the system. */ public static String[] listAvailablePbeCiphers(boolean testAvailability) { Set ciphers = Security.getAlgorithms("Cipher"); Set pbeCiphers = new HashSet(); for (Iterator iter = ciphers.iterator(); iter.hasNext(); ) { String cipher = (String) iter.next(); if (cipher.toLowerCase().startsWith("pbe")) { if (!testAvailability || isCipherAvailableForUse(cipher)) { pbeCiphers.add(cipher); } } } return (String[]) pbeCiphers.toArray(new String[pbeCiphers.size()]); } public static Provider[] listAvailableProviders() { return Security.getProviders(); } /** * Generate an RSA SHA1 signature of the given data using the given private * key DER certificate. * * Based on example code from: * http://www.java2s.com/Tutorial/Java/0490__Security/RSASignatureGeneration.htm * http://forums.sun.com/thread.jspa?threadID=5175986 * * @throws NoSuchAlgorithmException * @throws InvalidKeyException * @throws SignatureException * @throws InvalidKeySpecException * @throws NoSuchProviderException */ public static byte[] signWithRsaSha1(byte[] derPrivateKeyBytes, byte[] dataToSign) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, InvalidKeySpecException, NoSuchProviderException { // Build an RSA private key from private key data PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(derPrivateKeyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); RSAPrivateKey privateKey = (RSAPrivateKey) keyFactory.generatePrivate(privSpec); // Sign data Signature signature = Signature.getInstance("SHA1withRSA", "BC"); signature.initSign(privateKey, new SecureRandom()); signature.update(dataToSign); byte[] signatureBytes = signature.sign(); return signatureBytes; } /** * Convert a PEM encoded RSA certificate file into a DER format byte array. * * @param is * Input stream for PEM encoded RSA certificate data. * * @return * The RSA certificate data in DER format. * * @throws IOException */ public static byte[] convertRsaPemToDer(InputStream is) throws IOException { String pemData = ServiceUtils.readInputStreamToString(is, "UTF-8"); // Strip PEM header and footer int headerEndOffset = pemData.indexOf('\n'); int footerStartOffset = pemData.indexOf("-----END"); String strippedPemData = pemData.substring(headerEndOffset + 1, footerStartOffset - 1); // Decode Base64 PEM data to DER bytes byte[] derBytes = ServiceUtils.fromBase64(strippedPemData); return derBytes; } public static void main(String[] args) throws Exception { Provider[] providers = EncryptionUtil.listAvailableProviders(); System.out.println("Providers:"); for (int i = 0; i < providers.length; i++) { System.out.println(" - " + providers[i]); } String[] ciphers = EncryptionUtil.listAvailablePbeCiphers(false); System.out.println("PBE Ciphers available (untested):"); for (int i = 0; i < ciphers.length; i++) { System.out.println(" - " + ciphers[i]); } ciphers = EncryptionUtil.listAvailablePbeCiphers(true); System.out.println("PBE Ciphers available (tested):"); for (int i = 0; i < ciphers.length; i++) { System.out.println(" - " + ciphers[i]); } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/security/ProviderCredentials.java0000644000000000000000000003547711550421156024434 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.security; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; import javax.crypto.BadPaddingException; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.Constants; import org.jets3t.service.ServiceException; import org.jets3t.service.utils.ServiceUtils; /** * Abstract class to contain the credentials of a user. * * @author James Murty * @author Nikolas Coukouma * @author Google developers */ public abstract class ProviderCredentials { protected static final Log log = LogFactory.getLog(ProviderCredentials.class); protected static final int CREDENTIALS_STORAGE_VERSION = 3; protected static final String V2_KEYS_DELIMITER = "AWSKEYS"; protected static final String V3_KEYS_DELIMITER = "\n"; protected String accessKey = null; protected String secretKey = null; protected String friendlyName = null; /** * Construct credentials. * * @param accessKey * Access key for a storage account. * @param secretKey * Secret key for a storage account. */ public ProviderCredentials(String accessKey, String secretKey) { this.accessKey = accessKey; this.secretKey = secretKey; } /** * Construct credentials, and associate them with a human-friendly name. * * @param accessKey * Access key for a storage account. * @param secretKey * Secret key for a storage account. * @param friendlyName * a name identifying the owner of the credentials, such as 'James'. */ public ProviderCredentials(String accessKey, String secretKey, String friendlyName) { this(accessKey, secretKey); this.friendlyName = friendlyName; } /** * @return * the Access Key. */ public String getAccessKey() { return accessKey; } /** * @return * the Secret Key. */ public String getSecretKey() { return secretKey; } /** * @return * the friendly name associated with a storage account, if available. */ public String getFriendlyName() { return friendlyName; } /** * @return * true if there is a non-null and non-empty friendly name associated * with this account. */ public boolean hasFriendlyName() { return (friendlyName != null && friendlyName.trim().length() > 0); } /** * @return * a string summarizing these credentials */ public String getLogString() { return getAccessKey() + " : " + getSecretKey(); } /** * @return * the string of data that needs to be encrypted (for serialization) */ protected String getDataToEncrypt() { return getAccessKey() + V3_KEYS_DELIMITER + getSecretKey(); } /** * @return * string representing this credential type's name (for serialization) */ protected abstract String getTypeName(); protected abstract String getVersionPrefix(); /** * Encrypts ProviderCredentials with the given password and saves the encrypted data to a file. * * @param password * the password used to encrypt the credentials. * @param file * the file to write the encrypted credentials data to. * @param algorithm * the algorithm used to encrypt the output stream. * * @throws InvalidKeyException * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException * @throws InvalidKeySpecException * @throws IllegalStateException * @throws IllegalBlockSizeException * @throws BadPaddingException * @throws InvalidAlgorithmParameterException * @throws IOException */ public void save(String password, File file, String algorithm) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, IllegalStateException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, IOException { FileOutputStream fos = null; try { fos = new FileOutputStream(file); save(password, fos, algorithm); } finally { if (fos != null) { fos.close(); } } } /** * Encrypts ProviderCredentials with the given password and saves the encrypted data to a file * using the default algorithm {@link EncryptionUtil#DEFAULT_ALGORITHM}. * * @param password * the password used to encrypt the credentials. * @param file * the file to write the encrypted credentials data to. * * @throws InvalidKeyException * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException * @throws InvalidKeySpecException * @throws IllegalStateException * @throws IllegalBlockSizeException * @throws BadPaddingException * @throws InvalidAlgorithmParameterException * @throws IOException */ public void save(String password, File file) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, IllegalStateException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, IOException { save(password, file, EncryptionUtil.DEFAULT_ALGORITHM); } /** * Encrypts ProviderCredentials with the given password and writes the encrypted data to an * output stream. * * @param password * the password used to encrypt the credentials. * @param outputStream * the output stream to write the encrypted credentials data to, this stream must be closed by * the caller. * @param algorithm * the algorithm used to encrypt the output stream. * * @throws InvalidKeyException * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException * @throws InvalidKeySpecException * @throws IllegalStateException * @throws IllegalBlockSizeException * @throws BadPaddingException * @throws InvalidAlgorithmParameterException * @throws IOException */ public void save(String password, OutputStream outputStream, String algorithm) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, IllegalStateException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, IOException { BufferedOutputStream bufferedOS = null; EncryptionUtil encryptionUtil = new EncryptionUtil(password, algorithm, EncryptionUtil.DEFAULT_VERSION); bufferedOS = new BufferedOutputStream(outputStream); // Encrypt credentials byte[] encryptedData = encryptionUtil.encrypt(getDataToEncrypt()); // Write plain-text header information to file. bufferedOS.write((getVersionPrefix() + CREDENTIALS_STORAGE_VERSION + "\n").getBytes(Constants.DEFAULT_ENCODING)); bufferedOS.write((encryptionUtil.getAlgorithm() + "\n").getBytes(Constants.DEFAULT_ENCODING)); bufferedOS.write(((friendlyName == null? "" : friendlyName) + "\n").getBytes(Constants.DEFAULT_ENCODING)); bufferedOS.write((getTypeName() + "\n").getBytes(Constants.DEFAULT_ENCODING)); bufferedOS.write(encryptedData); bufferedOS.flush(); } /** * Encrypts ProviderCredentials with the given password and writes the encrypted data to an * output stream using the default algorithm {@link EncryptionUtil#DEFAULT_ALGORITHM}. * * @param password * the password used to encrypt the credentials. * @param outputStream * the output stream to write the encrypted credentials data to, this stream must be closed by * the caller. * * @throws InvalidKeyException * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException * @throws InvalidKeySpecException * @throws IllegalStateException * @throws IllegalBlockSizeException * @throws BadPaddingException * @throws InvalidAlgorithmParameterException * @throws IOException */ public void save(String password, OutputStream outputStream) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, IllegalStateException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, IOException { save(password, outputStream, EncryptionUtil.DEFAULT_ALGORITHM); } /** * Loads encrypted credentials from a file. * * @param password * the password used to decrypt the credentials. If null, the credentials are not decrypted * and only the version and friendly-name information is loaded. * @param file * a file containing an encrypted data encoding of an ProviderCredentials object. * @return * the decrypted credentials in an object. * * @throws ServiceException */ public static ProviderCredentials load(String password, File file) throws ServiceException { if (log.isDebugEnabled()) { log.debug("Loading credentials from file: " + file.getAbsolutePath()); } BufferedInputStream fileIS = null; try { fileIS = new BufferedInputStream(new FileInputStream(file)); return load(password, fileIS); } catch (Throwable t) { throw new ServiceException("Failed to load credentials", t); } finally { if (fileIS != null) { try { fileIS.close(); } catch (IOException e) { } } } } /** * Loads encrypted credentials from a data input stream. * * @param password * the password used to decrypt the credentials. If null, the credentials are not decrypted * and only the version and friendly-name information is loaded. * @param inputStream * an input stream containing an encrypted data encoding of an ProviderCredentials object. * @return * the decrypted credentials in an object. * * @throws ServiceException */ public static ProviderCredentials load(String password, BufferedInputStream inputStream) throws ServiceException { boolean partialReadOnly = (password == null); if (partialReadOnly) { if (log.isDebugEnabled()) { log.debug("Loading partial information about credentials from input stream"); } } else { if (log.isDebugEnabled()) { log.debug("Loading credentials from input stream"); } } try { EncryptionUtil encryptionUtil = null; byte[] encryptedKeys = new byte[2048]; int encryptedDataIndex = 0; String version = null; int versionNum = 0; String algorithm = ""; String friendlyName = ""; boolean usingDevPay = false; // Read version information from credentials file. version = ServiceUtils.readInputStreamLineToString(inputStream, Constants.DEFAULT_ENCODING); // Extract the version number int firstColonOffset = version.indexOf(":"); String versionString = version.substring(firstColonOffset + 1).trim(); versionNum = Integer.parseInt(versionString); // Read algorithm and friendly name from file. algorithm = ServiceUtils.readInputStreamLineToString(inputStream, Constants.DEFAULT_ENCODING); friendlyName = ServiceUtils.readInputStreamLineToString(inputStream, Constants.DEFAULT_ENCODING); if (!partialReadOnly) { encryptionUtil = new EncryptionUtil(password, algorithm, EncryptionUtil.DEFAULT_VERSION); } if (3 <= versionNum) { String credentialsType = ServiceUtils.readInputStreamLineToString(inputStream, Constants.DEFAULT_ENCODING); usingDevPay = ("devpay".equals(credentialsType)); } // Use AWS credentials classes as default non-abstract implementation if (partialReadOnly) { if (usingDevPay) { return new AWSDevPayCredentials(null, null, friendlyName); } else { return new AWSCredentials(null, null, friendlyName); } } // Read encrypted data bytes from file. encryptedDataIndex = inputStream.read(encryptedKeys); // Decrypt data. String keys = encryptionUtil.decryptString(encryptedKeys, 0, encryptedDataIndex); String[] parts = keys.split((3 <= versionNum)? V3_KEYS_DELIMITER : V2_KEYS_DELIMITER); int expectedParts = (usingDevPay? 4 : 2); if (parts.length != expectedParts) { throw new Exception("Number of parts (" + parts.length + ") did not match the expected number of parts (" + expectedParts + ") for this version (" + versionNum + ")"); } // Use AWS credentials classes as default non-abstract implementation if (usingDevPay) { return new AWSDevPayCredentials(parts[0], parts[1], parts[2], parts[3], friendlyName); } else { return new AWSCredentials(parts[0], parts[1], friendlyName); } } catch (BadPaddingException bpe) { throw new ServiceException("Unable to decrypt credentials. Is your password correct?", bpe); } catch (Throwable t) { throw new ServiceException("Failed to load credentials", t); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { } } } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/security/GSCredentials.java0000644000000000000000000000537711537563564023166 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.security; import java.io.BufferedInputStream; import java.io.File; import org.jets3t.service.ServiceException; /** * Class to contain the Google Storage (GS) credentials of a user. * * @author Google developers */ public class GSCredentials extends ProviderCredentials { protected static final String GS_TYPE_NAME = "gs"; /** * Construct credentials. * * @param accessKey * Access key for a Google Storage account. * @param secretKey * Secret key for a Google Storage account. */ public GSCredentials(String accessKey, String secretKey) { super(accessKey, secretKey); } /** * Construct credentials, and associate them with a human-friendly name. * * @param accessKey * Access key for a Google Storage account. * @param secretKey * Secret key for a Google Storage account. * @param friendlyName * a name identifying the owner of the credentials, such as 'James'. */ public GSCredentials(String accessKey, String secretKey, String friendlyName) { super(accessKey, secretKey, friendlyName); } /** * @return * string representing this credential type's name (for serialization) */ @Override protected String getTypeName() { return GS_TYPE_NAME; } @Override public String getVersionPrefix() { return "jets3t GS Credentials, version: "; } public static ProviderCredentials load(String password, File file) throws ServiceException { ProviderCredentials credentials = ProviderCredentials.load(password, file); return new GSCredentials( credentials.accessKey, credentials.getSecretKey(), credentials.getFriendlyName()); } public static ProviderCredentials load(String password, BufferedInputStream inputStream) throws ServiceException { ProviderCredentials credentials = ProviderCredentials.load(password, inputStream); return new GSCredentials( credentials.accessKey, credentials.getSecretKey(), credentials.getFriendlyName()); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multithread/0002755000000000000000000000000011550421156020256 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multithread/S3ServiceMulti.java0000644000000000000000000036572411550442012023753 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multithread; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.S3ObjectsChunk; import org.jets3t.service.S3Service; import org.jets3t.service.S3ServiceException; import org.jets3t.service.ServiceException; import org.jets3t.service.StorageObjectsChunk; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.io.BytesProgressWatcher; import org.jets3t.service.io.InterruptableInputStream; import org.jets3t.service.io.ProgressMonitoredInputStream; import org.jets3t.service.io.TempFile; import org.jets3t.service.model.S3Bucket; import org.jets3t.service.model.S3Object; import org.jets3t.service.model.S3Version; import org.jets3t.service.security.ProviderCredentials; import org.jets3t.service.utils.ServiceUtils; import org.jets3t.service.utils.signedurl.SignedUrlAndObject; import org.jets3t.service.utils.signedurl.SignedUrlHandler; /** * S3 service wrapper that performs multiple S3 requests at a time using multi-threading and an * underlying thread-safe {@link S3Service} implementation. *

* This service is designed to be run in non-blocking threads that therefore communicates * information about its progress by firing {@link ServiceEvent} events. It is the responsibility * of applications using this service to correctly handle these events - see the JetS3t application * {@link org.jets3t.apps.synchronize.Synchronize} for examples of how an application can use these * events. *

*

* For cases where the full power, and complexity, of the event notification mechanism is not required * the simplified multi-threaded service {@link S3ServiceSimpleMulti} can be used. *

*

* This class uses properties obtained through {@link Jets3tProperties}. For more information on * these properties please refer to * JetS3t Configuration *

* * @deprecated 0.8.0 use {@link org.jets3t.service.multi.ThreadedStorageService} instead. * * @author James Murty */ @Deprecated public class S3ServiceMulti { private static final Log log = LogFactory.getLog(S3ServiceMulti.class); private S3Service s3Service = null; private final boolean[] isShutdown = new boolean[] { false }; private final ArrayList serviceEventListeners = new ArrayList(); private final long sleepTime; /** * Construct a multi-threaded service based on an S3Service and which sends event notifications * to an event listening class. EVENT_IN_PROGRESS events are sent at the default time interval * of 500ms. * * @param s3Service * an S3Service implementation that will be used to perform S3 requests. This implementation * must be thread-safe. * @param listener * the event listener which will handle event notifications. */ public S3ServiceMulti(S3Service s3Service, S3ServiceEventListener listener) { this(s3Service, listener, 500); } /** * Construct a multi-threaded service based on an S3Service and which sends event notifications * to an event listening class, and which will send EVENT_IN_PROGRESS events at the specified * time interval. * * @param s3Service * an S3Service implementation that will be used to perform S3 requests. This implementation * must be thread-safe. * @param listener * the event listener which will handle event notifications. * @param threadSleepTimeMS * how many milliseconds to wait before sending each EVENT_IN_PROGRESS notification event. */ public S3ServiceMulti( S3Service s3Service, S3ServiceEventListener listener, long threadSleepTimeMS) { this.s3Service = s3Service; addServiceEventListener(listener); this.sleepTime = threadSleepTimeMS; // Sanity-check the maximum thread and connection settings to ensure the maximum number // of connections is at least equal to the largest of the maximum thread counts, and warn // the use of potential problems. int adminMaxThreadCount = this.s3Service.getJetS3tProperties() .getIntProperty("s3service.admin-max-thread-count", 20); int maxThreadCount = this.s3Service.getJetS3tProperties() .getIntProperty("s3service.max-thread-count", 2); int maxConnectionCount = this.s3Service.getJetS3tProperties() .getIntProperty("httpclient.max-connections", 20); if (maxConnectionCount < maxThreadCount) { if (log.isWarnEnabled()) { log.warn("Insufficient connections available (httpclient.max-connections=" + maxConnectionCount + ") to run " + maxThreadCount + " simultaneous threads (s3service.max-thread-count) - please adjust JetS3t settings"); } } if (maxConnectionCount < adminMaxThreadCount) { if (log.isWarnEnabled()) { log.warn("Insufficient connections available (httpclient.max-connections=" + maxConnectionCount + ") to run " + adminMaxThreadCount + " simultaneous admin threads (s3service.admin-max-thread-count) - please adjust JetS3t settings"); } } } /** * Make a best-possible effort to shutdown and clean up any resources used by this * service such as HTTP connections, connection pools, threads etc. After calling * this method the service instance will no longer be usable -- a new instance must * be created to do more work. * * @throws S3ServiceException */ public void shutdown() throws S3ServiceException { this.isShutdown[0] = true; try { this.getS3Service().shutdown(); } catch (ServiceException se) { throw new S3ServiceException(se); } } /** * @return true if the {@link #shutdown()} method has been used to shut down and * clean up this service. If this function returns true this service instance * can no longer be used to do work. */ public boolean isShutdown() { return this.isShutdown[0]; } /** * @return * the underlying S3 service implementation. */ public S3Service getS3Service() { return s3Service; } /** * Adds a service event listener to the set of listeners that will be notified of events. * * @param listener * an event listener to add to the event notification chain. */ public void addServiceEventListener(S3ServiceEventListener listener) { if (listener != null) { serviceEventListeners.add(listener); } } /** * Removes a service event listener from the set of listeners that will be notified of events. * * @param listener * an event listener to remove from the event notification chain. */ public void removeServiceEventListener(S3ServiceEventListener listener) { if (listener != null) { serviceEventListeners.remove(listener); } } /** * Sends a service event to each of the listeners registered with this service. * @param event * the event to send to this service's registered event listeners. */ protected void fireServiceEvent(ServiceEvent event) { if (serviceEventListeners.size() == 0) { if (log.isWarnEnabled()) { log.warn("S3ServiceMulti invoked without any S3ServiceEventListener objects, this is dangerous!"); } } Iterator listenerIter = serviceEventListeners.iterator(); while (listenerIter.hasNext()) { S3ServiceEventListener listener = listenerIter.next(); if (event instanceof CreateObjectsEvent) { listener.s3ServiceEventPerformed((CreateObjectsEvent) event); } else if (event instanceof CopyObjectsEvent) { listener.s3ServiceEventPerformed((CopyObjectsEvent) event); } else if (event instanceof CreateBucketsEvent) { listener.s3ServiceEventPerformed((CreateBucketsEvent) event); } else if (event instanceof ListObjectsEvent) { listener.s3ServiceEventPerformed((ListObjectsEvent) event); } else if (event instanceof DeleteObjectsEvent) { listener.s3ServiceEventPerformed((DeleteObjectsEvent) event); } else if (event instanceof DeleteVersionedObjectsEvent) { listener.s3ServiceEventPerformed((DeleteVersionedObjectsEvent) event); } else if (event instanceof GetObjectsEvent) { listener.s3ServiceEventPerformed((GetObjectsEvent) event); } else if (event instanceof GetObjectHeadsEvent) { listener.s3ServiceEventPerformed((GetObjectHeadsEvent) event); } else if (event instanceof LookupACLEvent) { listener.s3ServiceEventPerformed((LookupACLEvent) event); } else if (event instanceof UpdateACLEvent) { listener.s3ServiceEventPerformed((UpdateACLEvent) event); } else if (event instanceof DownloadObjectsEvent) { listener.s3ServiceEventPerformed((DownloadObjectsEvent) event); } else { throw new IllegalArgumentException("Listener not invoked for event class: " + event.getClass()); } } } /** * @return * true if the underlying S3Service implementation is authenticated. */ public boolean isAuthenticatedConnection() { return s3Service.isAuthenticatedConnection(); } /** * @return * the AWS credentials in the underlying S3Service. */ public ProviderCredentials getAWSCredentials() { return s3Service.getAWSCredentials(); } /** * Lists the objects in a bucket based on an array of prefix strings, and * sends {@link ListObjectsEvent} notification events. * The objects that match each prefix are listed in a separate background * thread, potentially allowing you to list the contents of large buckets more * quickly than if you had to list all the objects in sequence. *

* Objects in the bucket that do not match one of the prefixes will not be * listed. * * @param bucketName * the name of the bucket in which the objects are stored. * @param prefixes * an array of prefix strings. A separate listing thread will be run for * each of these prefix strings, and the method will only complete once * the entire object listing for each prefix has been obtained (unless the * operation is cancelled, or an error occurs) * @param delimiter * an optional delimiter string to apply to each listing operation. This * parameter should be null if you do not wish to apply a delimiter. * @param maxListingLength * the maximum number of objects to list in each iteration. This should be a * value between 1 and 1000, where 1000 will be the best choice in almost all * circumstances. Regardless of this value, all the objects in the bucket that * match the criteria will be returned. * *

* The maximum number of threads is controlled by the JetS3t configuration property * s3service.admin-max-thread-count. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean listObjects(final String bucketName, final String[] prefixes, final String delimiter, final long maxListingLength) { final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. ListObjectsRunnable[] runnables = new ListObjectsRunnable[prefixes.length]; for (int i = 0; i < runnables.length; i++) { runnables[i] = new ListObjectsRunnable(bucketName, prefixes[i], delimiter, maxListingLength, null); } // Wait for threads to finish, or be cancelled. (new ThreadGroupManager(runnables, new ThreadWatcher(runnables.length), this.s3Service.getJetS3tProperties(), true) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(ListObjectsEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List chunkList) { fireServiceEvent(ListObjectsEvent.newInProgressEvent(threadWatcher, chunkList, uniqueOperationId)); } @Override public void fireCancelEvent() { success[0] = false; fireServiceEvent(ListObjectsEvent.newCancelledEvent(uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(ListObjectsEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(ListObjectsEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(ListObjectsEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Creates multiple buckets, and sends {@link CreateBucketsEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * s3service.admin-max-thread-count. * * @param buckets * the buckets to create. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean createBuckets(final S3Bucket[] buckets) { final List incompletedBucketList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. CreateBucketRunnable[] runnables = new CreateBucketRunnable[buckets.length]; for (int i = 0; i < runnables.length; i++) { incompletedBucketList.add(buckets[i]); runnables[i] = new CreateBucketRunnable(buckets[i]); } // Wait for threads to finish, or be cancelled. (new ThreadGroupManager(runnables, new ThreadWatcher(runnables.length), this.s3Service.getJetS3tProperties(), true) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(CreateBucketsEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { incompletedBucketList.removeAll(completedResults); S3Bucket[] completedBuckets = (S3Bucket[]) completedResults .toArray(new S3Bucket[completedResults.size()]); fireServiceEvent(CreateBucketsEvent.newInProgressEvent(threadWatcher, completedBuckets, uniqueOperationId)); } @Override public void fireCancelEvent() { S3Bucket[] incompletedBuckets = (S3Bucket[]) incompletedBucketList .toArray(new S3Bucket[incompletedBucketList.size()]); success[0] = false; fireServiceEvent(CreateBucketsEvent.newCancelledEvent(incompletedBuckets, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(CreateBucketsEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(CreateBucketsEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(CreateBucketsEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Copies multiple objects within or between buckets, while sending * {@link CopyObjectsEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * s3service.admin-max-thread-count. * * @param sourceBucketName * the name of the bucket containing the objects that will be copied. * @param destinationBucketName * the name of the bucket to which the objects will be copied. The destination * bucket may be the same as the source bucket. * @param sourceObjectKeys * the key names of the objects that will be copied. * @param destinationObjects * objects that will be created by the copy operation. The AccessControlList * setting of each object will determine the access permissions of the * resultant object, and if the replaceMetadata flag is true the metadata * items in each object will also be applied to the resultant object. * @param replaceMetadata * if true, the metadata items in the destination objects will be stored * in S3 by using the REPLACE metadata copying option. If false, the metadata * items will be copied unchanged from the original objects using the COPY * metadata copying option.s * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean copyObjects(final String sourceBucketName, final String destinationBucketName, final String[] sourceObjectKeys, final S3Object[] destinationObjects, boolean replaceMetadata) { final List incompletedObjectsList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. CopyObjectRunnable[] runnables = new CopyObjectRunnable[sourceObjectKeys.length]; for (int i = 0; i < runnables.length; i++) { incompletedObjectsList.add(destinationObjects[i]); runnables[i] = new CopyObjectRunnable(sourceBucketName, destinationBucketName, sourceObjectKeys[i], destinationObjects[i], replaceMetadata); } // Wait for threads to finish, or be cancelled. (new ThreadGroupManager(runnables, new ThreadWatcher(runnables.length), this.s3Service.getJetS3tProperties(), true) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(CopyObjectsEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { incompletedObjectsList.removeAll(completedResults); Map[] copyResults = (Map[]) completedResults .toArray(new Map[completedResults.size()]); fireServiceEvent(CopyObjectsEvent.newInProgressEvent(threadWatcher, copyResults, uniqueOperationId)); } @Override public void fireCancelEvent() { S3Object[] incompletedObjects = (S3Object[]) incompletedObjectsList .toArray(new S3Object[incompletedObjectsList.size()]); success[0] = false; fireServiceEvent(CopyObjectsEvent.newCancelledEvent(incompletedObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(CopyObjectsEvent.newCompletedEvent(uniqueOperationId, sourceObjectKeys, destinationObjects)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(CopyObjectsEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(CopyObjectsEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Creates multiple objects in a bucket, and sends {@link CreateObjectsEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * s3service.max-admin-thread-count. * * @param bucket * the bucket to create the objects in * @param objects * the objects to create/upload. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean putObjects(final S3Bucket bucket, final S3Object[] objects) { final List incompletedObjectsList = new ArrayList(); final List progressWatchers = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. CreateObjectRunnable[] runnables = new CreateObjectRunnable[objects.length]; for (int i = 0; i < runnables.length; i++) { incompletedObjectsList.add(objects[i]); BytesProgressWatcher progressMonitor = new BytesProgressWatcher(objects[i].getContentLength()); runnables[i] = new CreateObjectRunnable(bucket, objects[i], progressMonitor); progressWatchers.add(progressMonitor); } // Wait for threads to finish, or be cancelled. ThreadWatcher threadWatcher = new ThreadWatcher( (BytesProgressWatcher[]) progressWatchers.toArray(new BytesProgressWatcher[progressWatchers.size()])); (new ThreadGroupManager(runnables, threadWatcher, this.s3Service.getJetS3tProperties(), false) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(CreateObjectsEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { incompletedObjectsList.removeAll(completedResults); S3Object[] completedObjects = (S3Object[]) completedResults .toArray(new S3Object[completedResults.size()]); fireServiceEvent(CreateObjectsEvent.newInProgressEvent(threadWatcher, completedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { S3Object[] incompletedObjects = (S3Object[]) incompletedObjectsList .toArray(new S3Object[incompletedObjectsList.size()]); success[0] = false; fireServiceEvent(CreateObjectsEvent.newCancelledEvent(incompletedObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(CreateObjectsEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(CreateObjectsEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(CreateObjectsEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Deletes multiple objects from a bucket, and sends {@link DeleteObjectsEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * s3service.admin-max-thread-count. * * @param bucket * the bucket containing the objects to be deleted * @param objectKeys * key names of objects to delete * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean deleteObjects(final S3Bucket bucket, String[] objectKeys) { S3Object objects[] = new S3Object[objectKeys.length]; for (int i = 0; i < objects.length; i++) { objects[i] = new S3Object(objectKeys[i]); } return this.deleteObjects(bucket, objects); } /** * Deletes multiple objects from a bucket, and sends {@link DeleteObjectsEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * s3service.admin-max-thread-count. * * @param bucket * the bucket containing the objects to be deleted * @param objects * the objects to delete * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean deleteObjects(final S3Bucket bucket, final S3Object[] objects) { final List objectsToDeleteList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. DeleteObjectRunnable[] runnables = new DeleteObjectRunnable[objects.length]; for (int i = 0; i < runnables.length; i++) { objectsToDeleteList.add(objects[i]); runnables[i] = new DeleteObjectRunnable(bucket, objects[i]); } // Wait for threads to finish, or be cancelled. (new ThreadGroupManager(runnables, new ThreadWatcher(runnables.length), this.s3Service.getJetS3tProperties(), true) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(DeleteObjectsEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { objectsToDeleteList.removeAll(completedResults); S3Object[] deletedObjects = (S3Object[]) completedResults .toArray(new S3Object[completedResults.size()]); fireServiceEvent(DeleteObjectsEvent.newInProgressEvent(threadWatcher, deletedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { S3Object[] remainingObjects = (S3Object[]) objectsToDeleteList .toArray(new S3Object[objectsToDeleteList.size()]); success[0] = false; fireServiceEvent(DeleteObjectsEvent.newCancelledEvent(remainingObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(DeleteObjectsEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(DeleteObjectsEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(DeleteObjectsEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Delete multiple object versions from a bucket in S3, and sends * {@link DeleteVersionedObjectsEvent} notification events. This will delete only the specific * version identified and will not affect any other Version or DeleteMarkers related to * the object. *

* The maximum number of threads is controlled by the JetS3t configuration property * s3service.admin-max-thread-count. * * @param versionIds * the identifiers of the object versions that will be deleted. * @param multiFactorSerialNumber * the serial number for a multi-factor authentication device. * @param multiFactorAuthCode * a multi-factor authentication code generated by a device. * @param bucketName * the name of the versioned bucket containing the object to be deleted. * @param objectKey * the key representing the object in S3. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean deleteVersionsOfObjectWithMFA(final String[] versionIds, String multiFactorSerialNumber, String multiFactorAuthCode, String bucketName, String objectKey) { final List versionsToDeleteList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. DeleteVersionedObjectRunnable[] runnables = new DeleteVersionedObjectRunnable[versionIds.length]; for (int i = 0; i < runnables.length; i++) { versionsToDeleteList.add(new S3Version(objectKey, versionIds[i])); runnables[i] = new DeleteVersionedObjectRunnable( versionIds[i], multiFactorSerialNumber, multiFactorAuthCode, bucketName, objectKey); } // Wait for threads to finish, or be cancelled. (new ThreadGroupManager(runnables, new ThreadWatcher(runnables.length), this.s3Service.getJetS3tProperties(), true) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(DeleteVersionedObjectsEvent.newStartedEvent( threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { versionsToDeleteList.removeAll(completedResults); S3Version[] deletedVersions = (S3Version[]) completedResults .toArray(new S3Version[completedResults.size()]); fireServiceEvent(DeleteVersionedObjectsEvent.newInProgressEvent( threadWatcher, deletedVersions, uniqueOperationId)); } @Override public void fireCancelEvent() { S3Version[] remainingVersions = (S3Version[]) versionsToDeleteList .toArray(new S3Version[versionsToDeleteList.size()]); success[0] = false; fireServiceEvent(DeleteVersionedObjectsEvent.newCancelledEvent( remainingVersions, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(DeleteVersionedObjectsEvent.newCompletedEvent( uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(DeleteVersionedObjectsEvent.newErrorEvent( throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(DeleteVersionedObjectsEvent.newIgnoredErrorsEvent( threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Delete multiple object versions from a bucket in S3, and sends * {@link DeleteVersionedObjectsEvent} notification events. This will delete only the specific * version identified and will not affect any other Version or DeleteMarkers related to * the object. *

* The maximum number of threads is controlled by the JetS3t configuration property * s3service.admin-max-thread-count. * * @param versionIds * the identifiers of the object versions that will be deleted. * @param bucketName * the name of the versioned bucket containing the object to be deleted. * @param objectKey * the key representing the object in S3. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean deleteVersionsOfObject(final String[] versionIds, String bucketName, String objectKey) { return deleteVersionsOfObjectWithMFA(versionIds, null, null, bucketName, objectKey); } /** * Retrieves multiple objects (details and data) from a bucket, and sends * {@link GetObjectsEvent} notification events. * * @param bucket * the bucket containing the objects to retrieve. * @param objects * the objects to retrieve. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean getObjects(S3Bucket bucket, S3Object[] objects) { String[] objectKeys = new String[objects.length]; for (int i = 0; i < objects.length; i++) { objectKeys[i] = objects[i].getKey(); } return getObjects(bucket, objectKeys); } /** * Retrieves multiple objects (details and data) from a bucket, and sends * {@link GetObjectsEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * s3service.max-thread-count. * * @param bucket * the bucket containing the objects to retrieve. * @param objectKeys * the key names of the objects to retrieve. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean getObjects(final S3Bucket bucket, final String[] objectKeys) { final List pendingObjectKeysList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. GetObjectRunnable[] runnables = new GetObjectRunnable[objectKeys.length]; for (int i = 0; i < runnables.length; i++) { pendingObjectKeysList.add(objectKeys[i]); runnables[i] = new GetObjectRunnable(bucket, objectKeys[i], false); } // Wait for threads to finish, or be cancelled. (new ThreadGroupManager(runnables, new ThreadWatcher(runnables.length), this.s3Service.getJetS3tProperties(), false) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(GetObjectsEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { S3Object[] completedObjects = (S3Object[]) completedResults .toArray(new S3Object[completedResults.size()]); for (int i = 0; i < completedObjects.length; i++) { pendingObjectKeysList.remove(completedObjects[i].getKey()); } fireServiceEvent(GetObjectsEvent.newInProgressEvent(threadWatcher, completedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { List cancelledObjectsList = new ArrayList(); Iterator iter = pendingObjectKeysList.iterator(); while (iter.hasNext()) { String key = (String) iter.next(); cancelledObjectsList.add(new S3Object(key)); } S3Object[] cancelledObjects = (S3Object[]) cancelledObjectsList .toArray(new S3Object[cancelledObjectsList.size()]); success[0] = false; fireServiceEvent(GetObjectsEvent.newCancelledEvent(cancelledObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(GetObjectsEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(GetObjectsEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(GetObjectsEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Retrieves details (but no data) about multiple objects from a bucket, and sends * {@link GetObjectHeadsEvent} notification events. * * @param bucket * the bucket containing the objects whose details will be retrieved. * @param objects * the objects with details to retrieve. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean getObjectsHeads(S3Bucket bucket, S3Object[] objects) { String[] objectKeys = new String[objects.length]; for (int i = 0; i < objects.length; i++) { objectKeys[i] = objects[i].getKey(); } return getObjectsHeads(bucket, objectKeys); } /** * Retrieves details (but no data) about multiple objects from a bucket, and sends * {@link GetObjectHeadsEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * s3service.admin-max-thread-count. * * @param bucket * the bucket containing the objects whose details will be retrieved. * @param objectKeys * the key names of the objects with details to retrieve. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean getObjectsHeads(final S3Bucket bucket, final String[] objectKeys) { final List pendingObjectKeysList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. GetObjectRunnable[] runnables = new GetObjectRunnable[objectKeys.length]; for (int i = 0; i < runnables.length; i++) { pendingObjectKeysList.add(objectKeys[i]); runnables[i] = new GetObjectRunnable(bucket, objectKeys[i], true); } // Wait for threads to finish, or be cancelled. (new ThreadGroupManager(runnables, new ThreadWatcher(runnables.length), this.s3Service.getJetS3tProperties(), true) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(GetObjectHeadsEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { S3Object[] completedObjects = (S3Object[]) completedResults .toArray(new S3Object[completedResults.size()]); for (int i = 0; i < completedObjects.length; i++) { pendingObjectKeysList.remove(completedObjects[i].getKey()); } fireServiceEvent(GetObjectHeadsEvent.newInProgressEvent(threadWatcher, completedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { List cancelledObjectsList = new ArrayList(); Iterator iter = pendingObjectKeysList.iterator(); while (iter.hasNext()) { String key = (String) iter.next(); cancelledObjectsList.add(new S3Object(key)); } S3Object[] cancelledObjects = (S3Object[]) cancelledObjectsList .toArray(new S3Object[cancelledObjectsList.size()]); success[0] = false; fireServiceEvent(GetObjectHeadsEvent.newCancelledEvent(cancelledObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(GetObjectHeadsEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(GetObjectHeadsEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(GetObjectHeadsEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Retrieves Access Control List (ACL) information for multiple objects from a bucket, and sends * {@link LookupACLEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * s3service.admin-max-thread-count. * * @param bucket * the bucket containing the objects * @param objects * the objects to retrieve ACL details for. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean getObjectACLs(final S3Bucket bucket, final S3Object[] objects) { final List pendingObjectsList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. GetACLRunnable[] runnables = new GetACLRunnable[objects.length]; for (int i = 0; i < runnables.length; i++) { pendingObjectsList.add(objects[i]); runnables[i] = new GetACLRunnable(bucket, objects[i]); } // Wait for threads to finish, or be cancelled. (new ThreadGroupManager(runnables, new ThreadWatcher(runnables.length), this.s3Service.getJetS3tProperties(), true) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(LookupACLEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { pendingObjectsList.removeAll(completedResults); S3Object[] completedObjects = (S3Object[]) completedResults .toArray(new S3Object[completedResults.size()]); fireServiceEvent(LookupACLEvent.newInProgressEvent(threadWatcher, completedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { S3Object[] cancelledObjects = (S3Object[]) pendingObjectsList .toArray(new S3Object[pendingObjectsList.size()]); success[0] = false; fireServiceEvent(LookupACLEvent.newCancelledEvent(cancelledObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(LookupACLEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(LookupACLEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(LookupACLEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Updates/sets Access Control List (ACL) information for multiple objects in a bucket, and sends * {@link UpdateACLEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * s3service.admin-max-thread-count. * * @param bucket * the bucket containing the objects * @param objects * the objects to update/set ACL details for. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean putACLs(final S3Bucket bucket, final S3Object[] objects) { final List pendingObjectsList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. PutACLRunnable[] runnables = new PutACLRunnable[objects.length]; for (int i = 0; i < runnables.length; i++) { pendingObjectsList.add(objects[i]); runnables[i] = new PutACLRunnable(bucket, objects[i]); } // Wait for threads to finish, or be cancelled. (new ThreadGroupManager(runnables, new ThreadWatcher(runnables.length), this.s3Service.getJetS3tProperties(), true) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(UpdateACLEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { pendingObjectsList.removeAll(completedResults); S3Object[] completedObjects = (S3Object[]) completedResults .toArray(new S3Object[completedResults.size()]); fireServiceEvent(UpdateACLEvent.newInProgressEvent(threadWatcher, completedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { S3Object[] cancelledObjects = (S3Object[]) pendingObjectsList .toArray(new S3Object[pendingObjectsList.size()]); success[0] = false; fireServiceEvent(UpdateACLEvent.newCancelledEvent(cancelledObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(UpdateACLEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(UpdateACLEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(UpdateACLEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * A convenience method to download multiple objects from S3 to pre-existing * output streams, which is particularly useful for downloading objects to files. * The S3 objects can be represented as S3Objects or as signed URLs in a * {@link DownloadPackage} package. This method sends * {@link DownloadObjectsEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * s3service.max-thread-count. *

* If the JetS3t configuration property downloads.restoreLastModifiedDate is set * to true, any files created by this method will have their last modified date set according * to the value of the S3 object's {@link Constants#METADATA_JETS3T_LOCAL_FILE_DATE} metadata * item. * * @param bucket * the bucket containing the objects * @param downloadPackages * an array of download packages containing the object to be downloaded, and able to build * an output stream where the object's contents will be written to. * * @return * true if all the threaded tasks completed successfully, false otherwise. * @throws S3ServiceException */ public boolean downloadObjects(final S3Bucket bucket, final DownloadPackage[] downloadPackages) throws S3ServiceException { final List progressWatchers = new ArrayList(); final List incompleteObjectDownloadList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; boolean restoreLastModifiedDate = this.s3Service.getJetS3tProperties() .getBoolProperty("downloads.restoreLastModifiedDate", false); // Start all queries in the background. DownloadObjectRunnable[] runnables = new DownloadObjectRunnable[downloadPackages.length]; final S3Object[] objects = new S3Object[downloadPackages.length]; for (int i = 0; i < runnables.length; i++) { if (downloadPackages[i].getObject() == null) { // For signed URL downloads without corresponding object information, we create // a surrogate S3Object containing nothing but the object's key name. // This will allow the download to work, but total download size will not be known. try { URL url = new URL(downloadPackages[i].getSignedUrl()); objects[i] = ServiceUtils.buildObjectFromUrl( url.getHost(), url.getPath(), s3Service.getEndpoint()); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new S3ServiceException("Unable to determine S3 Object key name from signed URL: " + downloadPackages[i].getSignedUrl()); } } else { objects[i] = downloadPackages[i].getObject(); } BytesProgressWatcher progressMonitor = new BytesProgressWatcher(objects[i].getContentLength()); incompleteObjectDownloadList.add(objects[i]); progressWatchers.add(progressMonitor); if (downloadPackages[i].isSignedDownload()) { runnables[i] = new DownloadObjectRunnable( downloadPackages[i], progressMonitor, restoreLastModifiedDate); } else { runnables[i] = new DownloadObjectRunnable(bucket, objects[i].getKey(), downloadPackages[i], progressMonitor, restoreLastModifiedDate); } } // Wait for threads to finish, or be cancelled. ThreadWatcher threadWatcher = new ThreadWatcher( (BytesProgressWatcher[]) progressWatchers.toArray(new BytesProgressWatcher[progressWatchers.size()])); (new ThreadGroupManager(runnables, threadWatcher, this.s3Service.getJetS3tProperties(), false) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(DownloadObjectsEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { incompleteObjectDownloadList.removeAll(completedResults); S3Object[] completedObjects = (S3Object[]) completedResults .toArray(new S3Object[completedResults.size()]); fireServiceEvent(DownloadObjectsEvent.newInProgressEvent(threadWatcher, completedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { S3Object[] incompleteObjects = (S3Object[]) incompleteObjectDownloadList .toArray(new S3Object[incompleteObjectDownloadList.size()]); success[0] = false; fireServiceEvent(DownloadObjectsEvent.newCancelledEvent(incompleteObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(DownloadObjectsEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(DownloadObjectsEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(DownloadObjectsEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * A convenience method to download multiple objects from S3 to pre-existing * output streams, which is particularly useful for downloading objects to files. * This method sends {@link DownloadObjectsEvent} notification events. *

* This method can only download S3 objects represented by {@link DownloadPackage} * packages based on signed URL. To download objects when you don't have * signed URLs, you must use the method * {@link #downloadObjects(S3Bucket, DownloadPackage[])} *

* The maximum number of threads is controlled by the JetS3t configuration property * s3service.max-thread-count. *

* If the JetS3t configuration property downloads.restoreLastModifiedDate is set * to true, any files created by this method will have their last modified date set according * to the value of the S3 object's {@link Constants#METADATA_JETS3T_LOCAL_FILE_DATE} metadata * item. * * @param downloadPackages * an array of download packages containing the object to be downloaded, represented * with signed URL strings. * * @return * true if all the threaded tasks completed successfully, false otherwise. * @throws S3ServiceException */ public boolean downloadObjects(final DownloadPackage[] downloadPackages) throws S3ServiceException { // Sanity check to ensure all packages are based on signed URLs for (int i = 0; i < downloadPackages.length; i++) { if (!downloadPackages[i].isSignedDownload()) { throw new S3ServiceException( "The downloadObjects(DownloadPackage[]) method may only be used with " + "download packages based on signed URLs. Download package " + (i + 1) + " of " + downloadPackages.length + " is not based on a signed URL"); } } return downloadObjects(null, downloadPackages); } /** * Retrieves multiple objects (details and data) from a bucket using signed GET URLs corresponding * to those objects. *

* Object retrieval using signed GET URLs can be performed without the underlying S3Service knowing * the AWSCredentials for the target S3 account, however the underlying service must implement * the {@link SignedUrlHandler} interface. *

* This method sends {@link GetObjectHeadsEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * s3service.max-thread-count. * * @param signedGetURLs * signed GET URL strings corresponding to the objects to be deleted. * * @throws IllegalStateException * if the underlying S3Service does not implement {@link SignedUrlHandler} * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean getObjects(final String[] signedGetURLs) throws MalformedURLException, UnsupportedEncodingException { if (!(s3Service instanceof SignedUrlHandler)) { throw new IllegalStateException("S3ServiceMutli's underlying S3Service must implement the" + "SignedUrlHandler interface to make the method getObjects(String[] signedGetURLs) available"); } final List pendingObjectKeysList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. GetObjectRunnable[] runnables = new GetObjectRunnable[signedGetURLs.length]; for (int i = 0; i < runnables.length; i++) { URL url = new URL(signedGetURLs[i]); S3Object object = ServiceUtils.buildObjectFromUrl( url.getHost(), url.getPath(), s3Service.getEndpoint()); pendingObjectKeysList.add(object); runnables[i] = new GetObjectRunnable(signedGetURLs[i], false); } // Wait for threads to finish, or be cancelled. (new ThreadGroupManager(runnables, new ThreadWatcher(runnables.length), this.s3Service.getJetS3tProperties(), false) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(GetObjectsEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { S3Object[] completedObjects = (S3Object[]) completedResults .toArray(new S3Object[completedResults.size()]); for (int i = 0; i < completedObjects.length; i++) { pendingObjectKeysList.remove(completedObjects[i].getKey()); } fireServiceEvent(GetObjectsEvent.newInProgressEvent(threadWatcher, completedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { List cancelledObjectsList = new ArrayList(); Iterator iter = pendingObjectKeysList.iterator(); while (iter.hasNext()) { String key = (String) iter.next(); cancelledObjectsList.add(new S3Object(key)); } S3Object[] cancelledObjects = (S3Object[]) cancelledObjectsList .toArray(new S3Object[cancelledObjectsList.size()]); success[0] = false; fireServiceEvent(GetObjectsEvent.newCancelledEvent(cancelledObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(GetObjectsEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(GetObjectsEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(GetObjectsEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Retrieves details (but no data) about multiple objects using signed HEAD URLs corresponding * to those objects. *

* Detail retrieval using signed HEAD URLs can be performed without the underlying S3Service knowing * the AWSCredentials for the target S3 account, however the underlying service must implement * the {@link SignedUrlHandler} interface. *

* This method sends {@link GetObjectHeadsEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * s3service.admin-max-thread-count. * * @param signedHeadURLs * signed HEAD URL strings corresponding to the objects to be deleted. * * @throws IllegalStateException * if the underlying S3Service does not implement {@link SignedUrlHandler} * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean getObjectsHeads(final String[] signedHeadURLs) throws MalformedURLException, UnsupportedEncodingException { if (!(s3Service instanceof SignedUrlHandler)) { throw new IllegalStateException("S3ServiceMutli's underlying S3Service must implement the" + "SignedUrlHandler interface to make the method getObjectsHeads(String[] signedHeadURLs) available"); } final List pendingObjectKeysList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. GetObjectRunnable[] runnables = new GetObjectRunnable[signedHeadURLs.length]; for (int i = 0; i < runnables.length; i++) { URL url = new URL(signedHeadURLs[i]); S3Object object = ServiceUtils.buildObjectFromUrl( url.getHost(), url.getPath(), s3Service.getEndpoint()); pendingObjectKeysList.add(object); runnables[i] = new GetObjectRunnable(signedHeadURLs[i], true); } // Wait for threads to finish, or be cancelled. (new ThreadGroupManager(runnables, new ThreadWatcher(runnables.length), this.s3Service.getJetS3tProperties(), true) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(GetObjectHeadsEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { S3Object[] completedObjects = (S3Object[]) completedResults .toArray(new S3Object[completedResults.size()]); for (int i = 0; i < completedObjects.length; i++) { pendingObjectKeysList.remove(completedObjects[i].getKey()); } fireServiceEvent(GetObjectHeadsEvent.newInProgressEvent(threadWatcher, completedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { List cancelledObjectsList = new ArrayList(); Iterator iter = pendingObjectKeysList.iterator(); while (iter.hasNext()) { String key = (String) iter.next(); cancelledObjectsList.add(new S3Object(key)); } S3Object[] cancelledObjects = (S3Object[]) cancelledObjectsList .toArray(new S3Object[cancelledObjectsList.size()]); success[0] = false; fireServiceEvent(GetObjectHeadsEvent.newCancelledEvent(cancelledObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(GetObjectHeadsEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(GetObjectHeadsEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(GetObjectHeadsEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Updates/sets Access Control List (ACL) information for multiple objects in * a bucket, and sends {@link UpdateACLEvent} notification events. * The S3 objects are represented as signed URLs. *

* The maximum number of threads is controlled by the JetS3t configuration property * s3service.admin-max-thread-count. * * @param signedURLs * URL strings that are authenticated and signed to allow a PUT request to * be performed for the referenced object. * @param acl * the access control list settings to apply to the objects. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean putObjectsACLs(final String[] signedURLs, final AccessControlList acl) throws MalformedURLException, UnsupportedEncodingException { final List pendingObjectsList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. PutACLRunnable[] runnables = new PutACLRunnable[signedURLs.length]; for (int i = 0; i < runnables.length; i++) { URL url = new URL(signedURLs[i]); S3Object object = ServiceUtils.buildObjectFromUrl( url.getHost(), url.getPath(), s3Service.getEndpoint()); pendingObjectsList.add(object); runnables[i] = new PutACLRunnable(signedURLs[i], acl); } // Wait for threads to finish, or be cancelled. (new ThreadGroupManager(runnables, new ThreadWatcher(runnables.length), this.s3Service.getJetS3tProperties(), true) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(UpdateACLEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { pendingObjectsList.removeAll(completedResults); S3Object[] completedObjects = (S3Object[]) completedResults .toArray(new S3Object[completedResults.size()]); fireServiceEvent(UpdateACLEvent.newInProgressEvent(threadWatcher, completedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { S3Object[] cancelledObjects = (S3Object[]) pendingObjectsList .toArray(new S3Object[pendingObjectsList.size()]); success[0] = false; fireServiceEvent(UpdateACLEvent.newCancelledEvent(cancelledObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(UpdateACLEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(UpdateACLEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(UpdateACLEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Deletes multiple objects from a bucket using signed DELETE URLs corresponding to those objects. *

* Deletes using signed DELETE URLs can be performed without the underlying S3Service knowing * the AWSCredentials for the target S3 account, however the underlying service must implement * the {@link SignedUrlHandler} interface. *

* This method sends {@link DeleteObjectsEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * s3service.admin-max-thread-count. * * @param signedDeleteUrls * signed DELETE URL strings corresponding to the objects to be deleted. * * @throws IllegalStateException * if the underlying S3Service does not implement {@link SignedUrlHandler} * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean deleteObjects(final String[] signedDeleteUrls) throws MalformedURLException, UnsupportedEncodingException { if (!(s3Service instanceof SignedUrlHandler)) { throw new IllegalStateException("S3ServiceMutli's underlying S3Service must implement the" + "SignedUrlHandler interface to make the method deleteObjects(String[] signedDeleteURLs) available"); } final List objectsToDeleteList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. DeleteObjectRunnable[] runnables = new DeleteObjectRunnable[signedDeleteUrls.length]; for (int i = 0; i < runnables.length; i++) { URL url = new URL(signedDeleteUrls[i]); S3Object object = ServiceUtils.buildObjectFromUrl( url.getHost(), url.getPath(), s3Service.getEndpoint()); objectsToDeleteList.add(object); runnables[i] = new DeleteObjectRunnable(signedDeleteUrls[i]); } // Wait for threads to finish, or be cancelled. (new ThreadGroupManager(runnables, new ThreadWatcher(runnables.length), this.s3Service.getJetS3tProperties(), true) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(DeleteObjectsEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { objectsToDeleteList.removeAll(completedResults); S3Object[] deletedObjects = (S3Object[]) completedResults .toArray(new S3Object[completedResults.size()]); fireServiceEvent(DeleteObjectsEvent.newInProgressEvent(threadWatcher, deletedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { S3Object[] remainingObjects = (S3Object[]) objectsToDeleteList .toArray(new S3Object[objectsToDeleteList.size()]); success[0] = false; fireServiceEvent(DeleteObjectsEvent.newCancelledEvent(remainingObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(DeleteObjectsEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(DeleteObjectsEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(DeleteObjectsEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Creates multiple objects in a bucket using a pre-signed PUT URL for each object. *

* Uploads using signed PUT URLs can be performed without the underlying S3Service knowing * the AWSCredentials for the target S3 account, however the underlying service must implement * the {@link SignedUrlHandler} interface. *

* This method sends {@link CreateObjectsEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * s3service.max-thread-count. * * @param signedPutUrlAndObjects * packages containing the S3Object to upload and the corresponding signed PUT URL. * * @throws IllegalStateException * if the underlying S3Service does not implement {@link SignedUrlHandler} * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean putObjects(final SignedUrlAndObject[] signedPutUrlAndObjects) { if (!(s3Service instanceof SignedUrlHandler)) { throw new IllegalStateException("S3ServiceMutli's underlying S3Service must implement the" + "SignedUrlHandler interface to make the method putObjects(SignedUrlAndObject[] signedPutUrlAndObjects) available"); } final List progressWatchers = new ArrayList(); final List incompletedObjectsList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Calculate total byte count being transferred. S3Object objects[] = new S3Object[signedPutUrlAndObjects.length]; for (int i = 0; i < signedPutUrlAndObjects.length; i++) { objects[i] = signedPutUrlAndObjects[i].getObject(); } // Start all queries in the background. SignedPutRunnable[] runnables = new SignedPutRunnable[signedPutUrlAndObjects.length]; for (int i = 0; i < runnables.length; i++) { BytesProgressWatcher progressMonitor = new BytesProgressWatcher(objects[i].getContentLength()); progressWatchers.add(progressMonitor); incompletedObjectsList.add(signedPutUrlAndObjects[i].getObject()); runnables[i] = new SignedPutRunnable(signedPutUrlAndObjects[i], progressMonitor); } // Wait for threads to finish, or be cancelled. ThreadWatcher threadWatcher = new ThreadWatcher( (BytesProgressWatcher[]) progressWatchers.toArray(new BytesProgressWatcher[progressWatchers.size()])); (new ThreadGroupManager(runnables, threadWatcher, this.s3Service.getJetS3tProperties(), false) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(CreateObjectsEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { incompletedObjectsList.removeAll(completedResults); S3Object[] completedObjects = (S3Object[]) completedResults .toArray(new S3Object[completedResults.size()]); fireServiceEvent(CreateObjectsEvent.newInProgressEvent(threadWatcher, completedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { S3Object[] incompletedObjects = (S3Object[]) incompletedObjectsList .toArray(new S3Object[incompletedObjectsList.size()]); success[0] = false; fireServiceEvent(CreateObjectsEvent.newCancelledEvent(incompletedObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(CreateObjectsEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(CreateObjectsEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(CreateObjectsEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Retrieves ACL information about multiple objects from a bucket using signed GET ACL URLs * corresponding to those objects. * The S3 objects are represented as signed URLs. *

* Object retrieval using signed GET URLs can be performed without the underlying S3Service knowing * the AWSCredentials for the target S3 account, however the underlying service must implement * the {@link SignedUrlHandler} interface. *

* This method sends {@link LookupACLEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * s3service.max-thread-count. * * @param signedAclURLs * signed GET URL strings corresponding to the objects to be queried. * * @throws IllegalStateException * if the underlying S3Service does not implement {@link SignedUrlHandler} * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean getObjectsACLs(final String[] signedAclURLs) throws MalformedURLException, UnsupportedEncodingException { if (!(s3Service instanceof SignedUrlHandler)) { throw new IllegalStateException("S3ServiceMutli's underlying S3Service must implement the" + "SignedUrlHandler interface to make the method getObjects(String[] signedGetURLs) available"); } final List pendingObjectKeysList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. GetACLRunnable[] runnables = new GetACLRunnable[signedAclURLs.length]; for (int i = 0; i < runnables.length; i++) { URL url = new URL(signedAclURLs[i]); S3Object object = ServiceUtils.buildObjectFromUrl( url.getHost(), url.getPath(),s3Service.getEndpoint()); pendingObjectKeysList.add(object); runnables[i] = new GetACLRunnable(signedAclURLs[i]); } // Wait for threads to finish, or be cancelled. (new ThreadGroupManager(runnables, new ThreadWatcher(runnables.length), this.s3Service.getJetS3tProperties(), false) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(LookupACLEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { S3Object[] completedObjects = (S3Object[]) completedResults .toArray(new S3Object[completedResults.size()]); for (int i = 0; i < completedObjects.length; i++) { pendingObjectKeysList.remove(completedObjects[i].getKey()); } fireServiceEvent(LookupACLEvent.newInProgressEvent(threadWatcher, completedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { List cancelledObjectsList = new ArrayList(); Iterator iter = pendingObjectKeysList.iterator(); while (iter.hasNext()) { cancelledObjectsList.add(iter.next()); } S3Object[] cancelledObjects = (S3Object[]) cancelledObjectsList .toArray(new S3Object[cancelledObjectsList.size()]); success[0] = false; fireServiceEvent(LookupACLEvent.newCancelledEvent(cancelledObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(LookupACLEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(LookupACLEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(LookupACLEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /////////////////////////////////////////////// // Private classes used by the methods above // /////////////////////////////////////////////// /** * All the operation threads used by this service extend this class, which provides common * methods used to retrieve the result object from a completed thread (via {@link #getResult()} * or force a thread to be interrupted (via {@link #forceInterrupt}. */ private abstract class AbstractRunnable implements Runnable { public abstract Object getResult(); public abstract void forceInterruptCalled(); protected void forceInterrupt() { forceInterruptCalled(); } } /** * Thread for performing the update/set of Access Control List information for an object. */ private class PutACLRunnable extends AbstractRunnable { private S3Bucket bucket = null; private S3Object s3Object = null; private String signedUrl = null; private AccessControlList signedUrlAcl = null; private Object result = null; public PutACLRunnable(S3Bucket bucket, S3Object s3Object) { this.bucket = bucket; this.s3Object = s3Object; } public PutACLRunnable(String signedAclUrl, AccessControlList signedUrlAcl) { this.signedUrl = signedAclUrl; this.signedUrlAcl = signedUrlAcl; this.bucket = null; this.s3Object = null; } public void run() { try { if (signedUrl == null) { if (s3Object == null) { s3Service.putBucketAcl(bucket); } else { s3Service.putObjectAcl(bucket, s3Object); } result = s3Object; } else { SignedUrlHandler handler = s3Service; handler.putObjectAclWithSignedUrl(signedUrl, signedUrlAcl); URL url = new URL(signedUrl); S3Object object = ServiceUtils.buildObjectFromUrl( url.getHost(), url.getPath(), s3Service.getEndpoint()); object.setAcl(signedUrlAcl); result = object; } } catch (RuntimeException e) { result = e; throw e; } catch (Exception e) { result = e; } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { // This is an atomic operation, cannot interrupt. Ignore. } } /** * Thread for retrieving Access Control List information for an object. */ private class GetACLRunnable extends AbstractRunnable { private S3Bucket bucket = null; private S3Object object = null; private String signedAclUrl = null; private Object result = null; public GetACLRunnable(S3Bucket bucket, S3Object object) { this.bucket = bucket; this.object = object; } public GetACLRunnable(String signedAclUrl) { this.signedAclUrl = signedAclUrl; this.bucket = null; this.object = null; } public void run() { try { if (signedAclUrl == null) { AccessControlList acl = s3Service.getObjectAcl(bucket, object.getKey()); object.setAcl(acl); result = object; } else { SignedUrlHandler handler = s3Service; AccessControlList acl = handler.getObjectAclWithSignedUrl(signedAclUrl); URL url = new URL(signedAclUrl); object = ServiceUtils.buildObjectFromUrl( url.getHost(), url.getPath(), s3Service.getEndpoint()); object.setAcl(acl); result = object; } } catch (RuntimeException e) { result = e; throw e; } catch (Exception e) { result = e; } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { // This is an atomic operation, cannot interrupt. Ignore. } } /** * Thread for deleting an object. */ private class DeleteObjectRunnable extends AbstractRunnable { private S3Bucket bucket = null; private S3Object object = null; private String signedDeleteUrl = null; private Object result = null; public DeleteObjectRunnable(S3Bucket bucket, S3Object object) { this.signedDeleteUrl = null; this.bucket = bucket; this.object = object; } public DeleteObjectRunnable(String signedDeleteUrl) { this.signedDeleteUrl = signedDeleteUrl; this.bucket = null; this.object = null; } public void run() { try { if (signedDeleteUrl == null) { s3Service.deleteObject(bucket, object.getKey()); result = object; } else { SignedUrlHandler handler = s3Service; handler.deleteObjectWithSignedUrl(signedDeleteUrl); URL url = new URL(signedDeleteUrl); result = ServiceUtils.buildObjectFromUrl( url.getHost(), url.getPath(), s3Service.getEndpoint()); } } catch (RuntimeException e) { result = e; throw e; } catch (Exception e) { result = e; } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { // This is an atomic operation, cannot interrupt. Ignore. } } /** * Thread for deleting a versioned object. */ private class DeleteVersionedObjectRunnable extends AbstractRunnable { private String versionId = null; private String multiFactorSerialNumber = null; private String multiFactorAuthCode = null; private String bucketName = null; private String objectKey = null; private Object result = null; public DeleteVersionedObjectRunnable(String versionId, String multiFactorSerialNumber, String multiFactorAuthCode, String bucketName, String objectKey) { this.versionId = versionId; this.multiFactorSerialNumber = multiFactorSerialNumber; this.multiFactorAuthCode = multiFactorAuthCode; this.bucketName = bucketName; this.objectKey = objectKey; } public void run() { try { s3Service.deleteVersionedObjectWithMFA(versionId, multiFactorSerialNumber, multiFactorAuthCode, bucketName, objectKey); result = new S3Version(objectKey, versionId); } catch (RuntimeException e) { result = e; throw e; } catch (Exception e) { result = e; } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { // This is an atomic operation, cannot interrupt. Ignore. } } /** * Thread for creating a bucket. */ private class CreateBucketRunnable extends AbstractRunnable { private S3Bucket bucket = null; private Object result = null; public CreateBucketRunnable(S3Bucket bucket) { this.bucket = bucket; } public void run() { try { result = s3Service.createBucket(bucket); } catch (S3ServiceException e) { result = e; } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { // This is an atomic operation, cannot interrupt. Ignore. } } /** * Thread for listing the objects in a bucket. */ private class ListObjectsRunnable extends AbstractRunnable { private Object result = null; private String bucketName = null; private String prefix = null; private String delimiter = null; private long maxListingLength = 1000; private String priorLastKey = null; private boolean halted = false; public ListObjectsRunnable(String bucketName, String prefix, String delimiter, long maxListingLength, String priorLastKey) { this.bucketName = bucketName; this.prefix = prefix; this.delimiter = delimiter; this.maxListingLength = maxListingLength; this.priorLastKey = priorLastKey; } public void run() { try { List allObjects = new ArrayList(); List allCommonPrefixes = new ArrayList(); do { StorageObjectsChunk chunk = s3Service.listObjectsChunked( bucketName, prefix, delimiter, maxListingLength, priorLastKey); priorLastKey = chunk.getPriorLastKey(); allObjects.addAll(Arrays.asList(chunk.getObjects())); allCommonPrefixes.addAll(Arrays.asList(chunk.getCommonPrefixes())); } while (!halted && priorLastKey != null); result = new S3ObjectsChunk( prefix, delimiter, (S3Object[]) allObjects.toArray(new S3Object[allObjects.size()]), (String[]) allCommonPrefixes.toArray(new String[allCommonPrefixes.size()]), null); } catch (ServiceException se) { result = new S3ServiceException(se); } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { halted = true; } } /** * Thread for creating/uploading an object. The upload of any object data is monitored with a * {@link ProgressMonitoredInputStream} and can be can cancelled as the input stream is wrapped in * an {@link InterruptableInputStream}. */ private class CreateObjectRunnable extends AbstractRunnable { private S3Bucket bucket = null; private S3Object s3Object = null; private InterruptableInputStream interruptableInputStream = null; private BytesProgressWatcher progressMonitor = null; private Object result = null; public CreateObjectRunnable(S3Bucket bucket, S3Object s3Object, BytesProgressWatcher progressMonitor) { this.bucket = bucket; this.s3Object = s3Object; this.progressMonitor = progressMonitor; } public void run() { try { File underlyingFile = s3Object.getDataInputFile(); if (s3Object.getDataInputStream() != null) { interruptableInputStream = new InterruptableInputStream(s3Object.getDataInputStream()); ProgressMonitoredInputStream pmInputStream = new ProgressMonitoredInputStream( interruptableInputStream, progressMonitor); s3Object.setDataInputStream(pmInputStream); } result = s3Service.putObject(bucket, s3Object); if (underlyingFile instanceof TempFile) { underlyingFile.delete(); } } catch (ServiceException se) { result = new S3ServiceException(se); } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { if (interruptableInputStream != null) { interruptableInputStream.interrupt(); } } } /** * Thread for copying an object. */ private class CopyObjectRunnable extends AbstractRunnable { private String sourceBucketName = null; private String destinationBucketName = null; private String sourceObjectKey = null; private S3Object destinationObject = null; private boolean replaceMetadata = false; private Object result = null; public CopyObjectRunnable(String sourceBucketName, String destinationBucketName, String sourceObjectKey, S3Object destinationObject, boolean replaceMetadata) { this.sourceBucketName = sourceBucketName; this.destinationBucketName = destinationBucketName; this.sourceObjectKey = sourceObjectKey; this.destinationObject = destinationObject; this.replaceMetadata = replaceMetadata; } public void run() { try { result = s3Service.copyObject(sourceBucketName, sourceObjectKey, destinationBucketName, destinationObject, replaceMetadata); } catch (ServiceException se) { result = new S3ServiceException(se); } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { // This is an atomic operation, cannot interrupt. Ignore. } } /** * Thread for retrieving an object. */ private class GetObjectRunnable extends AbstractRunnable { private S3Bucket bucket = null; private String objectKey = null; private String signedGetOrHeadUrl = null; private boolean headOnly = false; private Object result = null; public GetObjectRunnable(S3Bucket bucket, String objectKey, boolean headOnly) { this.signedGetOrHeadUrl = null; this.bucket = bucket; this.objectKey = objectKey; this.headOnly = headOnly; } public GetObjectRunnable(String signedGetOrHeadUrl, boolean headOnly) { this.signedGetOrHeadUrl = signedGetOrHeadUrl; this.bucket = null; this.objectKey = null; this.headOnly = headOnly; } public void run() { try { if (headOnly) { if (signedGetOrHeadUrl == null) { result = s3Service.getObjectDetails(bucket, objectKey); } else { SignedUrlHandler handler = s3Service; result = handler.getObjectDetailsWithSignedUrl(signedGetOrHeadUrl); } } else { if (signedGetOrHeadUrl == null) { result = s3Service.getObject(bucket, objectKey); } else { SignedUrlHandler handler = s3Service; result = handler.getObjectWithSignedUrl(signedGetOrHeadUrl); } } } catch (ServiceException se) { result = new S3ServiceException(se); } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { // This is an atomic operation, cannot interrupt. Ignore. } } /** * Thread for downloading an object. The download of any object data is monitored with a * {@link ProgressMonitoredInputStream} and can be can cancelled as the input stream is wrapped in * an {@link InterruptableInputStream}. */ private class DownloadObjectRunnable extends AbstractRunnable { private String objectKey = null; private S3Bucket bucket = null; private DownloadPackage downloadPackage = null; private InterruptableInputStream interruptableInputStream = null; private BytesProgressWatcher progressMonitor = null; private boolean restoreLastModifiedDate = true; private Object result = null; public DownloadObjectRunnable(S3Bucket bucket, String objectKey, DownloadPackage downloadPackage, BytesProgressWatcher progressMonitor, boolean restoreLastModifiedDate) { this.bucket = bucket; this.objectKey = objectKey; this.downloadPackage = downloadPackage; this.progressMonitor = progressMonitor; this.restoreLastModifiedDate = restoreLastModifiedDate; } public DownloadObjectRunnable(DownloadPackage downloadPackage, BytesProgressWatcher progressMonitor, boolean restoreLastModifiedDate) { this.downloadPackage = downloadPackage; this.progressMonitor = progressMonitor; this.restoreLastModifiedDate = restoreLastModifiedDate; } public void run() { BufferedInputStream bufferedInputStream = null; BufferedOutputStream bufferedOutputStream = null; S3Object object = null; try { if (!downloadPackage.isSignedDownload()) { object = s3Service.getObject(bucket, objectKey); } else { SignedUrlHandler handler = s3Service; object = handler.getObjectWithSignedUrl(downloadPackage.getSignedUrl()); } // Replace the S3 object in the download package with the downloaded version to make metadata available. downloadPackage.setObject(object); // Setup monitoring of stream bytes transferred. interruptableInputStream = new InterruptableInputStream(object.getDataInputStream()); bufferedInputStream = new BufferedInputStream( new ProgressMonitoredInputStream(interruptableInputStream, progressMonitor)); bufferedOutputStream = new BufferedOutputStream( downloadPackage.getOutputStream()); MessageDigest messageDigest = null; try { messageDigest = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { if (log.isWarnEnabled()) { log.warn("Unable to calculate MD5 hash of data received as algorithm is not available", e); } } try { byte[] buffer = new byte[1024]; int byteCount = -1; while ((byteCount = bufferedInputStream.read(buffer)) != -1) { bufferedOutputStream.write(buffer, 0, byteCount); if (messageDigest != null) { messageDigest.update(buffer, 0, byteCount); } } // Check that actual bytes received match expected hash value if (messageDigest != null) { byte[] dataMD5Hash = messageDigest.digest(); String hexMD5OfDownloadedData = ServiceUtils.toHex(dataMD5Hash); // Don't check MD5 hash against ETag if ETag doesn't look like an MD5 value if (!ServiceUtils.isEtagAlsoAnMD5Hash(object.getETag())) { // Use JetS3t's own MD5 hash metadata value for comparison, if it's available if (!hexMD5OfDownloadedData.equals(object.getMd5HashAsHex())) { if (log.isWarnEnabled()) { log.warn("Unable to verify MD5 hash of downloaded data against" + " ETag returned by service because ETag value \"" + object.getETag() + "\" is not an MD5 hash value" + ", for object key: " + object.getKey()); } } } else { if (!hexMD5OfDownloadedData.equals(object.getETag())) { throw new S3ServiceException("Mismatch between MD5 hash of downloaded data (" + hexMD5OfDownloadedData + ") and ETag returned by S3 (" + object.getETag() + ") for object key: " + object.getKey()); } else { if (log.isDebugEnabled()) { log.debug("Object download was automatically verified, the calculated MD5 hash "+ "value matched the ETag provided by S3: " + object.getKey()); } } } } } finally { if (bufferedOutputStream != null) { bufferedOutputStream.close(); } if (bufferedInputStream != null) { bufferedInputStream.close(); } } object.setDataInputStream(null); object.setDataInputFile(downloadPackage.getDataFile()); // If data was downloaded to a file, set the file's Last Modified date // to the original last modified date metadata stored with the object. if (restoreLastModifiedDate && downloadPackage.getDataFile() != null) { String metadataLocalFileDate = (String) object.getMetadata( Constants.METADATA_JETS3T_LOCAL_FILE_DATE); if (metadataLocalFileDate != null) { if (log.isDebugEnabled()) { log.debug("Restoring original Last Modified date for object '" + object.getKey() + "' to file '" + downloadPackage.getDataFile() + "': " + metadataLocalFileDate); } downloadPackage.getDataFile().setLastModified( ServiceUtils.parseIso8601Date(metadataLocalFileDate).getTime()); } } result = object; } catch (Throwable t) { result = t; } finally { if (bufferedInputStream != null) { try { bufferedInputStream.close(); } catch (Exception e) { if (log.isErrorEnabled()) { log.error("Unable to close Object input stream", e); } } } if (bufferedOutputStream != null) { try { bufferedOutputStream.close(); } catch (Exception e) { if (log.isErrorEnabled()) { log.error("Unable to close download output stream", e); } } } } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { if (interruptableInputStream != null) { interruptableInputStream.interrupt(); } } } /** * Thread for creating/uploading an object using a pre-signed PUT URL. The upload of any object * data is monitored with a {@link ProgressMonitoredInputStream} and can be can cancelled as * the input stream is wrapped in an {@link InterruptableInputStream}. */ private class SignedPutRunnable extends AbstractRunnable { private SignedUrlAndObject signedUrlAndObject = null; private InterruptableInputStream interruptableInputStream = null; private BytesProgressWatcher progressMonitor = null; private Object result = null; public SignedPutRunnable(SignedUrlAndObject signedUrlAndObject, BytesProgressWatcher progressMonitor) { this.signedUrlAndObject = signedUrlAndObject; this.progressMonitor = progressMonitor; } public void run() { try { File underlyingFile = signedUrlAndObject.getObject().getDataInputFile(); if (signedUrlAndObject.getObject().getDataInputStream() != null) { interruptableInputStream = new InterruptableInputStream( signedUrlAndObject.getObject().getDataInputStream()); ProgressMonitoredInputStream pmInputStream = new ProgressMonitoredInputStream( interruptableInputStream, progressMonitor); signedUrlAndObject.getObject().setDataInputStream(pmInputStream); } SignedUrlHandler signedPutUploader = s3Service; result = signedPutUploader.putObjectWithSignedUrl( signedUrlAndObject.getSignedUrl(), signedUrlAndObject.getObject()); if (underlyingFile instanceof TempFile) { underlyingFile.delete(); } } catch (ServiceException se) { result = new S3ServiceException(se); } finally { try { signedUrlAndObject.getObject().closeDataInputStream(); } catch (IOException e) { if (log.isErrorEnabled()) { log.error("Unable to close Object's input stream", e); } } } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { if (interruptableInputStream != null) { interruptableInputStream.interrupt(); } } } /** * The thread group manager is responsible for starting, running and stopping the set of threads * required to perform an S3 operation. *

* The manager starts all the threads, monitors their progress and stops threads when they are * cancelled or an error occurs - all the while firing the appropriate {@link ServiceEvent} event * notifications. */ private abstract class ThreadGroupManager { private final Log log = LogFactory.getLog(ThreadGroupManager.class); private int maxThreadCount = 1; /** * the set of runnable objects to execute. */ private AbstractRunnable[] runnables = null; /** * Thread objects that are currently running, where the index corresponds to the * runnables index. Any AbstractThread runnable that is not started, or has completed, * will have a null value in this array. */ private Thread[] threads = null; private boolean ignoreExceptions = false; /** * set of flags indicating which runnable items have been started */ private boolean started[] = null; /** * set of flags indicating which threads have already had In Progress events fired on * their behalf. These threads have finished running. */ private boolean alreadyFired[] = null; private ThreadWatcher threadWatcher = null; private long lastProgressEventFiredTime = 0; public ThreadGroupManager(AbstractRunnable[] runnables, ThreadWatcher threadWatcher, Jets3tProperties jets3tProperties, boolean isAdminTask) { this.runnables = runnables; this.threadWatcher = threadWatcher; if (isAdminTask) { this.maxThreadCount = jets3tProperties .getIntProperty("s3service.admin-max-thread-count", 20); } else { this.maxThreadCount = jets3tProperties .getIntProperty("s3service.max-thread-count", 2); } this.ignoreExceptions = jets3tProperties .getBoolProperty("s3service.ignore-exceptions-in-multi", false); this.threads = new Thread[runnables.length]; started = new boolean[runnables.length]; // All values initialized to false. alreadyFired = new boolean[runnables.length]; // All values initialized to false. } /** * Determine which threads, if any, have finished since the last time an In Progress event * was fired. * * @return * a list of the threads that finished since the last In Progress event was fired. This list may * be empty. * * @throws Throwable */ private ResultsTuple getNewlyCompletedResults() throws Throwable { ArrayList completedResults = new ArrayList(); ArrayList errorResults = new ArrayList(); for (int i = 0; i < threads.length; i++) { if (!alreadyFired[i] && started[i] && !threads[i].isAlive()) { alreadyFired[i] = true; if (log.isDebugEnabled()) { log.debug("Thread " + (i+1) + " of " + threads.length + " has recently completed, releasing resources"); } if (runnables[i].getResult() instanceof Throwable) { Throwable throwable = (Throwable) runnables[i].getResult(); runnables[i] = null; threads[i] = null; if (ignoreExceptions) { // Ignore exceptions if (log.isWarnEnabled()) { log.warn("Ignoring exception (property " + "s3service.ignore-exceptions-in-multi is set to true)", throwable); } errorResults.add(throwable); } else { throw throwable; } } else { completedResults.add(runnables[i].getResult()); runnables[i] = null; threads[i] = null; } } } Throwable[] ignoredErrors = new Throwable[] {}; if (errorResults.size() > 0) { ignoredErrors = (Throwable[]) errorResults.toArray(new Throwable[errorResults.size()]); } return new ResultsTuple(completedResults, ignoredErrors); } /** * Starts pending threads such that the total of running threads never exceeds the * maximum count set in the jets3t property s3service.max-thread-count. * * @throws Throwable */ private void startPendingThreads() throws Throwable { // Count active threads that are running (i.e. have been started but final event not fired) int runningThreadCount = 0; for (int i = 0; i < runnables.length; i++) { if (started[i] && !alreadyFired[i]) { runningThreadCount++; } } // Start threads until we are running the maximum number allowed. for (int i = 0; runningThreadCount < maxThreadCount && i < started.length; i++) { if (!started[i]) { threads[i] = new Thread(runnables[i]); threads[i].start(); started[i] = true; runningThreadCount++; if (log.isDebugEnabled()) { log.debug("Thread " + (i+1) + " of " + runnables.length + " has started"); } } } } /** * @return * the number of threads that have not finished running (sum of those currently running, and those awaiting start) */ private int getPendingThreadCount() { int pendingThreadCount = 0; for (int i = 0; i < runnables.length; i++) { if (!alreadyFired[i]) { pendingThreadCount++; } } return pendingThreadCount; } /** * Invokes the {@link AbstractRunnable#forceInterrupt} on all threads being managed. * */ private void forceInterruptAllRunnables() { if (log.isDebugEnabled()) { log.debug("Setting force interrupt flag on all runnables"); } for (int i = 0; i < runnables.length; i++) { if (runnables[i] != null) { runnables[i].forceInterrupt(); runnables[i] = null; } } } /** * Runs and manages all the threads involved in an S3 multi-operation. * */ public void run() { if (log.isDebugEnabled()) { log.debug("Started ThreadManager"); } final boolean[] interrupted = new boolean[] { false }; /* * Create a cancel event trigger, so all the managed threads can be cancelled if required. */ final CancelEventTrigger cancelEventTrigger = new CancelEventTrigger() { private static final long serialVersionUID = 6328417466929608235L; public void cancelTask(Object eventSource) { if (log.isDebugEnabled()) { log.debug("Cancel task invoked on ThreadManager"); } // Flag that this ThreadManager class should shutdown. interrupted[0] = true; // Set force interrupt flag for all runnables. forceInterruptAllRunnables(); } }; // Actual thread management happens in the code block below. try { // Start some threads startPendingThreads(); threadWatcher.updateThreadsCompletedCount(0, cancelEventTrigger); fireStartEvent(threadWatcher); // Loop while threads haven't been interrupted/cancelled, and at least one thread is // still active (ie hasn't finished its work) while (!interrupted[0] && getPendingThreadCount() > 0) { try { // Shut down threads if this service has been shutdown. if (isShutdown[0]) { throw new InterruptedException("S3ServiceMulti#shutdown method invoked"); } Thread.sleep(100); if (interrupted[0]) { // Do nothing, we've been interrupted during sleep. } else { if (System.currentTimeMillis() - lastProgressEventFiredTime > sleepTime) { // Fire progress event. int completedThreads = runnables.length - getPendingThreadCount(); threadWatcher.updateThreadsCompletedCount(completedThreads, cancelEventTrigger); ResultsTuple results = getNewlyCompletedResults(); lastProgressEventFiredTime = System.currentTimeMillis(); fireProgressEvent(threadWatcher, results.completedResults); if (results.errorResults.length > 0) { fireIgnoredErrorsEvent(threadWatcher, results.errorResults); } } // Start more threads. startPendingThreads(); } } catch (InterruptedException e) { interrupted[0] = true; forceInterruptAllRunnables(); } } if (interrupted[0]) { fireCancelEvent(); } else { int completedThreads = runnables.length - getPendingThreadCount(); threadWatcher.updateThreadsCompletedCount(completedThreads, cancelEventTrigger); ResultsTuple results = getNewlyCompletedResults(); fireProgressEvent(threadWatcher, results.completedResults); if (results.completedResults.size() > 0) { if (log.isDebugEnabled()) { log.debug(results.completedResults.size() + " threads have recently completed"); } } if (results.errorResults.length > 0) { fireIgnoredErrorsEvent(threadWatcher, results.errorResults); } fireCompletedEvent(); } } catch (Throwable t) { if (log.isErrorEnabled()) { log.error("A thread failed with an exception. Firing ERROR event and cancelling all threads", t); } // Set force interrupt flag for all runnables. forceInterruptAllRunnables(); fireErrorEvent(t); } } public abstract void fireStartEvent(ThreadWatcher threadWatcher); public abstract void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults); public abstract void fireCompletedEvent(); public abstract void fireCancelEvent(); public abstract void fireErrorEvent(Throwable t); public abstract void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors); private class ResultsTuple { public List completedResults = null; public Throwable[] errorResults = null; public ResultsTuple(List completedResults, Throwable[] errorResults) { this.completedResults = completedResults; this.errorResults = errorResults; } } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multithread/GetObjectsEvent.java0000644000000000000000000001027711441110076024154 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multithread; import org.jets3t.service.model.S3Object; /** * Multi-threaded service event fired by {@link S3ServiceMulti#getObjects}. *

* EVENT_IN_PROGRESS events include an array of the {@link S3Object}s that have been retrieved * since the last progress event was fired. These objects are available via * {@link #getCompletedObjects()}. *

* EVENT_CANCELLED events include an array of the {@link S3Object}s that had not been retrieved * before the operation was cancelled. These objects are available via * {@link #getCancelledObjects()}. * * @author James Murty */ public class GetObjectsEvent extends ServiceEvent { private S3Object[] objects = null; private GetObjectsEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static GetObjectsEvent newErrorEvent(Throwable t, Object uniqueOperationId) { GetObjectsEvent event = new GetObjectsEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static GetObjectsEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { GetObjectsEvent event = new GetObjectsEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static GetObjectsEvent newInProgressEvent(ThreadWatcher threadWatcher, S3Object[] completedObjects, Object uniqueOperationId) { GetObjectsEvent event = new GetObjectsEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setObjects(completedObjects); return event; } public static GetObjectsEvent newCompletedEvent(Object uniqueOperationId) { GetObjectsEvent event = new GetObjectsEvent(EVENT_COMPLETED, uniqueOperationId); return event; } public static GetObjectsEvent newCancelledEvent(S3Object[] incompletedObjects, Object uniqueOperationId) { GetObjectsEvent event = new GetObjectsEvent(EVENT_CANCELLED, uniqueOperationId); event.setObjects(incompletedObjects); return event; } public static GetObjectsEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { GetObjectsEvent event = new GetObjectsEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setObjects(S3Object[] objects) { this.objects = objects; } /** * @return * the S3Objects that have been retrieved since the last progress event was fired. * @throws IllegalStateException * completed objects are only available from EVENT_IN_PROGRESS events. */ public S3Object[] getCompletedObjects() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Completed Objects are only available from EVENT_IN_PROGRESS events"); } return objects; } /** * @return * the S3Objects that were not retrieved before the operation was cancelled. * @throws IllegalStateException * cancelled objects are only available from EVENT_CANCELLED events. */ public S3Object[] getCancelledObjects() throws IllegalStateException { if (getEventCode() != EVENT_CANCELLED) { throw new IllegalStateException("Cancelled Objects are only available from EVENT_CANCELLED events"); } return objects; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multithread/DownloadObjectsEvent.java0000644000000000000000000001055711441110076025205 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multithread; import org.jets3t.service.model.S3Object; /** * Multi-threaded service event fired by * {@link S3ServiceMulti#downloadObjects(org.jets3t.service.model.S3Bucket, DownloadPackage[])}. *

* EVENT_IN_PROGRESS events include an array of the {@link S3Object}s that have finished downloading * since the last progress event was fired. These objects are available via * {@link #getDownloadedObjects()}. *

* EVENT_CANCELLED events include an array of the {@link S3Object}s that were not downloaded * before the operation was cancelled. These objects are available via * {@link #getCancelledObjects()}. * * @author James Murty */ public class DownloadObjectsEvent extends ServiceEvent { private S3Object[] objects = null; private DownloadObjectsEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static DownloadObjectsEvent newErrorEvent(Throwable t, Object uniqueOperationId) { DownloadObjectsEvent event = new DownloadObjectsEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static DownloadObjectsEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { DownloadObjectsEvent event = new DownloadObjectsEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static DownloadObjectsEvent newInProgressEvent(ThreadWatcher threadWatcher, S3Object[] completedObjects, Object uniqueOperationId) { DownloadObjectsEvent event = new DownloadObjectsEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setObjects(completedObjects); return event; } public static DownloadObjectsEvent newCompletedEvent(Object uniqueOperationId) { DownloadObjectsEvent event = new DownloadObjectsEvent(EVENT_COMPLETED, uniqueOperationId); return event; } public static DownloadObjectsEvent newCancelledEvent(S3Object[] incompletedObjects, Object uniqueOperationId) { DownloadObjectsEvent event = new DownloadObjectsEvent(EVENT_CANCELLED, uniqueOperationId); event.setObjects(incompletedObjects); return event; } public static DownloadObjectsEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { DownloadObjectsEvent event = new DownloadObjectsEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setObjects(S3Object[] objects) { this.objects = objects; } /** * @return * the S3Objects that have finished downloading since the last progress event was fired. * @throws IllegalStateException * downloaded objects are only available from EVENT_IN_PROGRESS events. */ public S3Object[] getDownloadedObjects() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Downloaded Objects are only available from EVENT_IN_PROGRESS events"); } return objects; } /** * @return * the S3Objects that were not downloaded before the operation was cancelled. * @throws IllegalStateException * cancelled objects are only available from EVENT_CANCELLED events. */ public S3Object[] getCancelledObjects() throws IllegalStateException { if (getEventCode() != EVENT_CANCELLED) { throw new IllegalStateException("Cancelled Objects are only available from EVENT_CANCELLED events"); } return objects; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multithread/ThreadWatcher.java0000644000000000000000000000615011441613550023646 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multithread; import org.jets3t.service.io.BytesProgressWatcher; /** * A thread watcher is associated with a multi-threaded S3 operation and contains information about * the progress of the operation. *

* As a minimum, this object will contain a count of the total number of threads involved in the operation * (via {@link #getThreadCount}) and the count of threads that have already finished * (via {@link #getCompletedThreads}). *

* For operations involving data transfer, such as uploads or downloads, this object may * also include a count of the total bytes being transferred (via {@link #getBytesTotal}) and a count * of how many bytes have already been transferred (via {@link #getBytesTransferred}). The * availability of this information is indicated by the result of {@link #isBytesTransferredInfoAvailable()}. *

* Further data tranfer information may be also available, such as the current transfer rate (via * {@link #getBytesPerSecond()}) and an estimate of the time remaining until the transfer is * completed (via {@link #getTimeRemaining()}). The availability of this information is indicated * by the result of {@link #isTimeRemainingAvailable()}. *

* It is possible to cancel some S3 operations. If an operation may be cancelled, this object will * include a {@link CancelEventTrigger} (available from {@link #getCancelEventListener()}) which can * be used to trigger a cancellation. Whether the operation can be cancelled is indicated by * {@link #isCancelTaskSupported()}. * * @author James Murty * * @deprecated 0.8.0 use {@link org.jets3t.service.multi.ThreadWatcher} instead. */ @Deprecated public class ThreadWatcher extends org.jets3t.service.multi.ThreadWatcher { protected ThreadWatcher(BytesProgressWatcher[] progressWatchers) { super(progressWatchers); } protected ThreadWatcher(long threadCount) { super(threadCount); } public void updateThreadsCompletedCount(long completedThreads, org.jets3t.service.multithread.CancelEventTrigger cancelEventListener) { // TODO Auto-generated method stub super.updateThreadsCompletedCount(completedThreads, cancelEventListener); } @Override public org.jets3t.service.multithread.CancelEventTrigger getCancelEventListener() { // TODO Auto-generated method stub return (org.jets3t.service.multithread.CancelEventTrigger) super.getCancelEventListener(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multithread/CreateObjectsEvent.java0000644000000000000000000001045311441613550024641 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multithread; import org.jets3t.service.model.S3Bucket; import org.jets3t.service.model.S3Object; /** * Multi-threaded service event fired by {@link S3ServiceMulti#putObjects(S3Bucket, S3Object[])}. *

* EVENT_IN_PROGRESS events include an array of the {@link S3Object}s that have been created * since the last progress event was fired. These objects are available via * {@link #getCreatedObjects()}. *

* EVENT_CANCELLED events include an array of the {@link S3Object}s that had not been created * before the operation was cancelled. These objects are available via * {@link #getCancelledObjects()}. * * @author James Murty */ public class CreateObjectsEvent extends ServiceEvent { private S3Object[] objects = null; private CreateObjectsEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static CreateObjectsEvent newErrorEvent(Throwable t, Object uniqueOperationId) { CreateObjectsEvent event = new CreateObjectsEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static CreateObjectsEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { CreateObjectsEvent event = new CreateObjectsEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static CreateObjectsEvent newInProgressEvent(ThreadWatcher threadWatcher, S3Object[] completedObjects, Object uniqueOperationId) { CreateObjectsEvent event = new CreateObjectsEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setObjects(completedObjects); return event; } public static CreateObjectsEvent newCompletedEvent(Object uniqueOperationId) { CreateObjectsEvent event = new CreateObjectsEvent(EVENT_COMPLETED, uniqueOperationId); return event; } public static CreateObjectsEvent newCancelledEvent(S3Object[] incompletedObjects, Object uniqueOperationId) { CreateObjectsEvent event = new CreateObjectsEvent(EVENT_CANCELLED, uniqueOperationId); event.setObjects(incompletedObjects); return event; } public static CreateObjectsEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { CreateObjectsEvent event = new CreateObjectsEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setObjects(S3Object[] objects) { this.objects = objects; } /** * @return * the S3Objects that have been created since the last progress event was fired. * @throws IllegalStateException * created objects are only available from EVENT_IN_PROGRESS events. */ public S3Object[] getCreatedObjects() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Created Objects are only available from EVENT_IN_PROGRESS events"); } return objects; } /** * @return * the S3Objects that were not created before the operation was cancelled. * @throws IllegalStateException * cancelled objects are only available from EVENT_CANCELLED events. */ public S3Object[] getCancelledObjects() throws IllegalStateException { if (getEventCode() != EVENT_CANCELLED) { throw new IllegalStateException("Cancelled Objects are only available from EVENT_CANCELLED events"); } return objects; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multithread/UpdateACLEvent.java0000644000000000000000000001032011441110076023652 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multithread; import org.jets3t.service.model.S3Object; /** * Multi-threaded service event fired by {@link S3ServiceMulti#putACLs}. *

* EVENT_IN_PROGRESS events include an array of the {@link S3Object}s that have had their ACLs updated * since the last progress event was fired. These objects are available via * {@link #getObjectsWithUpdatedACL()}. *

* EVENT_CANCELLED events include an array of the {@link S3Object}s that did not have their ACLs updated * before the operation was cancelled. These objects are available via * {@link #getCancelledObjects()}. * * @author James Murty */ public class UpdateACLEvent extends ServiceEvent { private S3Object[] objects = null; private UpdateACLEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static UpdateACLEvent newErrorEvent(Throwable t, Object uniqueOperationId) { UpdateACLEvent event = new UpdateACLEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static UpdateACLEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { UpdateACLEvent event = new UpdateACLEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static UpdateACLEvent newInProgressEvent(ThreadWatcher threadWatcher, S3Object[] completedObjects, Object uniqueOperationId) { UpdateACLEvent event = new UpdateACLEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setObjects(completedObjects); return event; } public static UpdateACLEvent newCompletedEvent(Object uniqueOperationId) { UpdateACLEvent event = new UpdateACLEvent(EVENT_COMPLETED, uniqueOperationId); return event; } public static UpdateACLEvent newCancelledEvent(S3Object[] incompletedObjects, Object uniqueOperationId) { UpdateACLEvent event = new UpdateACLEvent(EVENT_CANCELLED, uniqueOperationId); event.setObjects(incompletedObjects); return event; } public static UpdateACLEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { UpdateACLEvent event = new UpdateACLEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setObjects(S3Object[] objects) { this.objects = objects; } /** * @return * the S3Objects that have had their ACLs updated since the last progress event was fired. * @throws IllegalStateException * updated objects are only available from EVENT_IN_PROGRESS events. */ public S3Object[] getObjectsWithUpdatedACL() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Completed Objects are only available from EVENT_IN_PROGRESS events"); } return objects; } /** * @return * the S3Objects that did not have ACLs updated before the operation was cancelled. * @throws IllegalStateException * cancelled objects are only available from EVENT_CANCELLED events. */ public S3Object[] getCancelledObjects() throws IllegalStateException { if (getEventCode() != EVENT_CANCELLED) { throw new IllegalStateException("Cancelled Objects are only available from EVENT_CANCELLED events"); } return objects; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multithread/S3ServiceEventListener.java0000644000000000000000000000327011427702124025437 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multithread; /** * Listener for events produced by {@link S3ServiceMulti}, where each event type is represented * by an object passed to the s3ServiceEventPerformed method. * * @author James Murty */ public interface S3ServiceEventListener { public void s3ServiceEventPerformed(ListObjectsEvent event); public void s3ServiceEventPerformed(CreateObjectsEvent event); public void s3ServiceEventPerformed(CopyObjectsEvent event); public void s3ServiceEventPerformed(CreateBucketsEvent event); public void s3ServiceEventPerformed(DeleteObjectsEvent event); public void s3ServiceEventPerformed(DeleteVersionedObjectsEvent event); public void s3ServiceEventPerformed(GetObjectsEvent event); public void s3ServiceEventPerformed(GetObjectHeadsEvent event); public void s3ServiceEventPerformed(LookupACLEvent event); public void s3ServiceEventPerformed(UpdateACLEvent event); public void s3ServiceEventPerformed(DownloadObjectsEvent event); } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multithread/DownloadPackage.java0000644000000000000000000000575111441613550024152 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multithread; import java.io.File; import java.io.OutputStream; import org.jets3t.service.model.S3Object; import org.jets3t.service.security.EncryptionUtil; /** * A simple container object to associate one of an {@link S3Object} or a signed URL string * with an output file or output stream to which the S3 object's data will be written. *

* This class is used by * {@link S3ServiceMulti#downloadObjects(org.jets3t.service.model.S3Bucket, DownloadPackage[])} * to download objects. * * @author James Murty * @deprecated 0.8.0 use {@link org.jets3t.service.multi.DownloadPackage} instead. */ @Deprecated public class DownloadPackage extends org.jets3t.service.multi.DownloadPackage { private String signedUrl = null; public DownloadPackage(String signedUrl, File outputFile, boolean isUnzipping, EncryptionUtil encryptionUtil) { super(null, outputFile, isUnzipping, encryptionUtil); this.signedUrl = signedUrl; } public DownloadPackage(String signedUrl, OutputStream outputStream, boolean isUnzipping, EncryptionUtil encryptionUtil) { super(null, outputStream, isUnzipping, encryptionUtil); this.signedUrl = signedUrl; } public DownloadPackage(S3Object object, File outputFile) { this(object, outputFile, false, null); } public DownloadPackage(S3Object object, File outputFile, boolean isUnzipping, EncryptionUtil encryptionUtil) { super(object, outputFile, isUnzipping, encryptionUtil); } public DownloadPackage(S3Object object, OutputStream outputStream) { this(object, outputStream, false, null); } public DownloadPackage(S3Object object, OutputStream outputStream, boolean isUnzipping, EncryptionUtil encryptionUtil) { super(object, outputStream, isUnzipping, encryptionUtil); } public String getSignedUrl() { return signedUrl; } public void setSignedUrl(String url) { signedUrl = url; } public boolean isSignedDownload() { return signedUrl != null; } @Override public S3Object getObject() { // TODO Auto-generated method stub return (S3Object) super.getObject(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multithread/LookupACLEvent.java0000644000000000000000000001041511441613550023713 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multithread; import org.jets3t.service.model.S3Bucket; import org.jets3t.service.model.S3Object; /** * Multi-threaded service event fired by {@link S3ServiceMulti#getObjectACLs(S3Bucket, S3Object[])}. *

* EVENT_IN_PROGRESS events include an array of the {@link S3Object}s whose ACLs have been retrieved * since the last progress event was fired. These objects are available via * {@link #getObjectsWithACL()}. *

* EVENT_CANCELLED events include an array of the {@link S3Object}s whose ACLs had not been retrieved * before the operation was cancelled. These objects are available via * {@link #getCancelledObjects()}. * * @author James Murty */ public class LookupACLEvent extends ServiceEvent { private S3Object[] objects = null; private LookupACLEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static LookupACLEvent newErrorEvent(Throwable t, Object uniqueOperationId) { LookupACLEvent event = new LookupACLEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static LookupACLEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { LookupACLEvent event = new LookupACLEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static LookupACLEvent newInProgressEvent(ThreadWatcher threadWatcher, S3Object[] completedObjects, Object uniqueOperationId) { LookupACLEvent event = new LookupACLEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setObjects(completedObjects); return event; } public static LookupACLEvent newCompletedEvent(Object uniqueOperationId) { LookupACLEvent event = new LookupACLEvent(EVENT_COMPLETED, uniqueOperationId); return event; } public static LookupACLEvent newCancelledEvent(S3Object[] incompletedObjects, Object uniqueOperationId) { LookupACLEvent event = new LookupACLEvent(EVENT_CANCELLED, uniqueOperationId); event.setObjects(incompletedObjects); return event; } public static LookupACLEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { LookupACLEvent event = new LookupACLEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setObjects(S3Object[] objects) { this.objects = objects; } /** * @return * the S3Objects whose ACLs have been retrieved since the last progress event was fired. * @throws IllegalStateException * objects with ACL are only available from EVENT_IN_PROGRESS events. */ public S3Object[] getObjectsWithACL() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Completed Objects are only available from EVENT_IN_PROGRESS events"); } return objects; } /** * @return * the S3Objects whose ACLs were not retrieved before the operation was cancelled. * @throws IllegalStateException * cancelled objects are only available from EVENT_CANCELLED events. */ public S3Object[] getCancelledObjects() throws IllegalStateException { if (getEventCode() != EVENT_CANCELLED) { throw new IllegalStateException("Cancelled Objects are only available from EVENT_CANCELLED events"); } return objects; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multithread/ListObjectsEvent.java0000644000000000000000000000722311441110076024345 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multithread; import java.util.List; import org.jets3t.service.S3ObjectsChunk; /** * Multi-threaded service event fired by * {@link S3ServiceMulti#listObjects(String, String[], String, long)}. *

* EVENT_IN_PROGRESS events include a List of {@link S3ObjectsChunk} objects * that contain information about the objects and common-prefixes for the * bucket listing operation. Each chunk object will contain a prefix identifying * the prefix value used by the listing operation that produced the chunk. * These objects are available via {@link #getChunkList()}. * * @author James Murty */ public class ListObjectsEvent extends ServiceEvent { private List chunkList = null; private ListObjectsEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static ListObjectsEvent newErrorEvent(Throwable t, Object uniqueOperationId) { ListObjectsEvent event = new ListObjectsEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static ListObjectsEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { ListObjectsEvent event = new ListObjectsEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static ListObjectsEvent newInProgressEvent(ThreadWatcher threadWatcher, List chunkList, Object uniqueOperationId) { ListObjectsEvent event = new ListObjectsEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setChunkList(chunkList); return event; } public static ListObjectsEvent newCompletedEvent(Object uniqueOperationId) { ListObjectsEvent event = new ListObjectsEvent(EVENT_COMPLETED, uniqueOperationId); return event; } public static ListObjectsEvent newCancelledEvent(Object uniqueOperationId) { ListObjectsEvent event = new ListObjectsEvent(EVENT_CANCELLED, uniqueOperationId); return event; } public static ListObjectsEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { ListObjectsEvent event = new ListObjectsEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setChunkList(List chunkList) { this.chunkList = chunkList; } /** * @return * a list of the {@link S3ObjectsChunk}s that have been generated since the * last progress event was fired. * @throws IllegalStateException * listed objects are only available from EVENT_IN_PROGRESS events. */ public List getChunkList() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Chunk list is only available from EVENT_IN_PROGRESS events"); } return this.chunkList; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multithread/ServiceEvent.java0000644000000000000000000000620511441613550023524 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multithread; import org.jets3t.service.multi.ThreadWatcher; /** * Base class of all events produced by {@link S3ServiceMulti}. *

* Every event has an event code that indicates the state of a process when the event was * generated. The event code will also give a guide as to what information the event will contain. *

* The event codes, and their meanings, are: *

    *
  • EVENT_STARTED: An S3 operation has commenced, but no work has yet been done.
  • *
  • EVENT_IN_PROGRESS: An S3 operation is in progress. Progress events are fired at regular time * intervals, and will include information about any work that have been completed * as part of the overall operation.
  • *
  • EVENT_COMPLETED: An S3 operation has completed, and all the work has been done.
  • *
  • EVENT_CANCELLED: An S3 operation was started but has been cancelled before it could complete. * If an operation is cancelled, this event will be fired instead of the EVENT_COMPLETED.
  • *
  • EVENT_ERROR: An S3 operation has failed and an exception has been thrown. The error * will be availble from {@link #getErrorCause()}
  • *
  • EVENT_IGNORED_ERRORS: One or more operations have failed but ,because the * "s3service.ignore-exceptions-in-multi" JetS3t property value is set to true, * the overall operation has continued. The errors will be available from * {@link #getIgnoredErrors()}
  • *
*

* EVENT_STARTED and EVENT_IN_PROGRESS events may include a {@link ThreadWatcher} object containing * detailed information about the progress of an S3 operation, such as how many threads have * completed and, of uploads and downloads, how many bytes have been transferred at what speed and * how long until the transfer is complete. *

* See the event object specific to the operation you are performing for more details about the * information available in service events. * * @author James Murty * @deprecated 0.8.0 use {@link org.jets3t.service.multi.event.ServiceEvent} instead. */ @Deprecated public abstract class ServiceEvent extends org.jets3t.service.multi.event.ServiceEvent { protected ServiceEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } @Override public org.jets3t.service.multithread.ThreadWatcher getThreadWatcher() throws IllegalStateException { return (org.jets3t.service.multithread.ThreadWatcher) super.getThreadWatcher(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multithread/CreateBucketsEvent.java0000644000000000000000000001037711441110076024650 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multithread; import org.jets3t.service.model.S3Bucket; /** * Multi-threaded service event fired by {@link S3ServiceMulti#createBuckets(S3Bucket[])}. *

* EVENT_IN_PROGRESS events include an array of the {@link S3Bucket}s that have been created * since the last progress event was fired. These objects are available via * {@link #getCreatedBuckets()}. *

* EVENT_CANCELLED events include an array of the {@link S3Bucket}s that had not been created * before the operation was cancelled. These objects are available via * {@link #getCancelledBuckets()}. * * @author James Murty */ public class CreateBucketsEvent extends ServiceEvent { private S3Bucket[] buckets = null; private CreateBucketsEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static CreateBucketsEvent newErrorEvent(Throwable t, Object uniqueOperationId) { CreateBucketsEvent event = new CreateBucketsEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static CreateBucketsEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { CreateBucketsEvent event = new CreateBucketsEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static CreateBucketsEvent newInProgressEvent(ThreadWatcher threadWatcher, S3Bucket[] completedBuckets, Object uniqueOperationId) { CreateBucketsEvent event = new CreateBucketsEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setBuckets(completedBuckets); return event; } public static CreateBucketsEvent newCompletedEvent(Object uniqueOperationId) { CreateBucketsEvent event = new CreateBucketsEvent(EVENT_COMPLETED, uniqueOperationId); return event; } public static CreateBucketsEvent newCancelledEvent(S3Bucket[] incompletedBuckets, Object uniqueOperationId) { CreateBucketsEvent event = new CreateBucketsEvent(EVENT_CANCELLED, uniqueOperationId); event.setBuckets(incompletedBuckets); return event; } public static CreateBucketsEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { CreateBucketsEvent event = new CreateBucketsEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setBuckets(S3Bucket[] buckets) { this.buckets = buckets; } /** * @return * the S3Buckets that have been created since the last progress event was fired. * @throws IllegalStateException * created buckets are only available from EVENT_IN_PROGRESS events. */ public S3Bucket[] getCreatedBuckets() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Created Buckets are only available from EVENT_IN_PROGRESS events"); } return buckets; } /** * @return * the S3Buckets that had not been created before the operation was cancelled. * @throws IllegalStateException * cancelled buckets are only available from EVENT_CANCELLED events. */ public S3Bucket[] getCancelledBuckets() throws IllegalStateException { if (getEventCode() != EVENT_CANCELLED) { throw new IllegalStateException("Cancelled Buckets are only available from EVENT_CANCELLED events"); } return buckets; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multithread/S3ServiceEventAdaptor.java0000644000000000000000000000613211441114302025233 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multithread; /** * Simple implementation of {@link S3ServiceEventListener} to listen for events produced by * {@link S3ServiceMulti}. *

* By default this adaptor does nothing but store the first Error event it comes across, if any, * and make it available through {@link #getErrorThrown}. *

*

* The behaviour of this class can be specialised by over-riding the appropriate * s3ServiceEventPerformed methods, though always be sure to call the super * version of these methods if you are relying on the default error-trapping functions of this * class. *

* * @author James Murty */ public class S3ServiceEventAdaptor implements S3ServiceEventListener { private Throwable t[] = new Throwable[1]; public void s3ServiceEventPerformed(ListObjectsEvent event) { storeThrowable(event); } public void s3ServiceEventPerformed(CreateObjectsEvent event) { storeThrowable(event); } public void s3ServiceEventPerformed(CopyObjectsEvent event) { storeThrowable(event); } public void s3ServiceEventPerformed(CreateBucketsEvent event) { storeThrowable(event); } public void s3ServiceEventPerformed(DeleteObjectsEvent event) { storeThrowable(event); } public void s3ServiceEventPerformed(DeleteVersionedObjectsEvent event) { storeThrowable(event); } public void s3ServiceEventPerformed(GetObjectsEvent event) { storeThrowable(event); } public void s3ServiceEventPerformed(GetObjectHeadsEvent event) { storeThrowable(event); } public void s3ServiceEventPerformed(LookupACLEvent event) { storeThrowable(event); } public void s3ServiceEventPerformed(UpdateACLEvent event) { storeThrowable(event); } public void s3ServiceEventPerformed(DownloadObjectsEvent event) { storeThrowable(event); } protected void storeThrowable(ServiceEvent event) { if (t[0] == null && event.getEventCode() == ServiceEvent.EVENT_ERROR) { t[0] = event.getErrorCause(); } } /** * @return * true if an event has resulted in an exception. */ public boolean wasErrorThrown() { return t[0] != null; } /** * @return * the first error thrown by an event, or null if no error has been thrown. */ public Throwable getErrorThrown() { return t[0]; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multithread/DeleteObjectsEvent.java0000644000000000000000000001044511441613550024641 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multithread; import org.jets3t.service.model.S3Bucket; import org.jets3t.service.model.S3Object; /** * Multi-threaded service event fired by {@link S3ServiceMulti#deleteObjects(S3Bucket, S3Object[])}. *

* EVENT_IN_PROGRESS events include an array of the {@link S3Object}s that have been deleted * since the last progress event was fired. These objects are available via * {@link #getDeletedObjects()}. *

* EVENT_CANCELLED events include an array of the {@link S3Object}s that had not been deleted * before the operation was cancelled. These objects are available via * {@link #getCancelledObjects()}. * * @author James Murty */ public class DeleteObjectsEvent extends ServiceEvent { private S3Object[] objects = null; private DeleteObjectsEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static DeleteObjectsEvent newErrorEvent(Throwable t, Object uniqueOperationId) { DeleteObjectsEvent event = new DeleteObjectsEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static DeleteObjectsEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { DeleteObjectsEvent event = new DeleteObjectsEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static DeleteObjectsEvent newInProgressEvent(ThreadWatcher threadWatcher, S3Object[] deletedObjects, Object uniqueOperationId) { DeleteObjectsEvent event = new DeleteObjectsEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setObjects(deletedObjects); return event; } public static DeleteObjectsEvent newCompletedEvent(Object uniqueOperationId) { DeleteObjectsEvent event = new DeleteObjectsEvent(EVENT_COMPLETED, uniqueOperationId); return event; } public static DeleteObjectsEvent newCancelledEvent(S3Object[] remainingObjects, Object uniqueOperationId) { DeleteObjectsEvent event = new DeleteObjectsEvent(EVENT_CANCELLED, uniqueOperationId); event.setObjects(remainingObjects); return event; } public static DeleteObjectsEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { DeleteObjectsEvent event = new DeleteObjectsEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setObjects(S3Object[] objects) { this.objects = objects; } /** * @return * the S3Objects that have been deleted since the last progress event was fired. * @throws IllegalStateException * deleted objects are only available from EVENT_IN_PROGRESS events. */ public S3Object[] getDeletedObjects() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Deleted Objects are only available from EVENT_IN_PROGRESS events"); } return objects; } /** * @return * the S3Objects that were not deleted before the operation was cancelled. * @throws IllegalStateException * cancelled objects are only available from EVENT_CANCELLED events. */ public S3Object[] getCancelledObjects() throws IllegalStateException { if (getEventCode() != EVENT_CANCELLED) { throw new IllegalStateException("Cancelled Objects are only available from EVENT_CANCELLED events"); } return objects; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multithread/CopyObjectsEvent.java0000644000000000000000000001402211450546146024352 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multithread; import java.util.Map; import org.jets3t.service.S3Service; import org.jets3t.service.model.S3Object; /** * Multi-threaded service event fired by * {@link S3ServiceMulti#copyObjects(String, String, String[], S3Object[], boolean)}. *

* EVENT_IN_PROGRESS events include an array of the Map results returned by the * copy operation, see * {@link S3Service#copyObject(String, String, String, org.jets3t.service.model.StorageObject, boolean)}. * These objects are available via {@link #getCopyResults()}. *

* EVENT_CANCELLED events include an array of the {@link S3Object}s that had not been * copied before the operation was cancelled. These objects are available via * {@link #getCancelledObjects()}. * * @author James Murty */ public class CopyObjectsEvent extends ServiceEvent { private Map[] results = null; private S3Object[] copyCancelledObjects = null; private S3Object[] destinationObjects = null; private String[] sourceObjectKeys = null; private CopyObjectsEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static CopyObjectsEvent newErrorEvent(Throwable t, Object uniqueOperationId) { CopyObjectsEvent event = new CopyObjectsEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static CopyObjectsEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { CopyObjectsEvent event = new CopyObjectsEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static CopyObjectsEvent newInProgressEvent(ThreadWatcher threadWatcher, Map[] completedResults, Object uniqueOperationId) { CopyObjectsEvent event = new CopyObjectsEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setResults(completedResults); return event; } public static CopyObjectsEvent newCompletedEvent(Object uniqueOperationId, String[] sourceObjectKeys, S3Object[] destinationObjects) { CopyObjectsEvent event = new CopyObjectsEvent(EVENT_COMPLETED, uniqueOperationId); event.setDestinationObjects(destinationObjects); event.setSourceObjectKeys(sourceObjectKeys); return event; } public static CopyObjectsEvent newCancelledEvent(S3Object[] incompletedObjects, Object uniqueOperationId) { CopyObjectsEvent event = new CopyObjectsEvent(EVENT_CANCELLED, uniqueOperationId); event.setCopyCancelledObjects(incompletedObjects); return event; } public static CopyObjectsEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { CopyObjectsEvent event = new CopyObjectsEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setResults(Map[] results) { this.results = results; } private void setSourceObjectKeys(String[] sourceObjectKeys) { this.sourceObjectKeys = sourceObjectKeys; } private void setCopyCancelledObjects(S3Object[] objects) { this.copyCancelledObjects = objects; } private void setDestinationObjects(S3Object[] objects) { this.destinationObjects = objects; } /** * @return * the Map results for the objects that have been copied since the last progress event was fired. * @throws IllegalStateException * results are only available from EVENT_IN_PROGRESS events. */ public Map[] getCopyResults() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Copy results are only available from EVENT_IN_PROGRESS events"); } return results; } /** * @return * the S3Objects that were not copied before the operation was cancelled. * @throws IllegalStateException * cancelled objects are only available from EVENT_CANCELLED events. */ public S3Object[] getCancelledObjects() throws IllegalStateException { if (getEventCode() != EVENT_CANCELLED) { throw new IllegalStateException("Cancelled Objects are only available from EVENT_CANCELLED events"); } return copyCancelledObjects; } /** * @return * the S3Objects that were created by a a successful copy operation. * @throws IllegalStateException * copied objects are only available from EVENT_COMPLETED events. */ public S3Object[] getCopiedObjects() throws IllegalStateException { if (getEventCode() != EVENT_COMPLETED) { throw new IllegalStateException("Cancelled Objects are only available from EVENT_COMPLETED events"); } return destinationObjects; } /** * @return * the key names of source objects that were copied in a successful operation. * @throws IllegalStateException * source object key names are only available from EVENT_COMPLETED events. */ public String[] getSourceObjectKeys() throws IllegalStateException { if (getEventCode() != EVENT_COMPLETED) { throw new IllegalStateException("Source Objects are only available from EVENT_COMPLETED events"); } return sourceObjectKeys; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multithread/CancelEventTrigger.java0000644000000000000000000000203711441613550024634 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multithread; /** * Interface implemented by multi-threaded S3 operations that can be cancelled prior to finishing. * * @author James Murty * * @deprecated 0.8.0 use {@link org.jets3t.service.multi.CancelEventTrigger} instead. */ @Deprecated public interface CancelEventTrigger extends org.jets3t.service.multi.CancelEventTrigger { } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multithread/DeleteVersionedObjectsEvent.java0000644000000000000000000001107511441110076026513 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multithread; import org.jets3t.service.model.S3Version; /** * Multi-threaded service event fired by * {@link S3ServiceMulti#deleteVersionsOfObject(String[], String, String)} or * {@link S3ServiceMulti#deleteVersionsOfObjectWithMFA(String[], String, String, String, String)}. *

* EVENT_IN_PROGRESS events include an array of the {@link S3Version}s that have been deleted * since the last progress event was fired. These versions are available via * {@link #getDeletedVersions()}. *

* EVENT_CANCELLED events include an array of the {@link S3Version}s that had not been deleted * before the operation was cancelled. These versions are available via * {@link #getCancelledVersions()}. * * @author James Murty */ public class DeleteVersionedObjectsEvent extends ServiceEvent { private S3Version[] versions = null; private DeleteVersionedObjectsEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static DeleteVersionedObjectsEvent newErrorEvent(Throwable t, Object uniqueOperationId) { DeleteVersionedObjectsEvent event = new DeleteVersionedObjectsEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static DeleteVersionedObjectsEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { DeleteVersionedObjectsEvent event = new DeleteVersionedObjectsEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static DeleteVersionedObjectsEvent newInProgressEvent(ThreadWatcher threadWatcher, S3Version[] deletedVersions, Object uniqueOperationId) { DeleteVersionedObjectsEvent event = new DeleteVersionedObjectsEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setObjects(deletedVersions); return event; } public static DeleteVersionedObjectsEvent newCompletedEvent(Object uniqueOperationId) { DeleteVersionedObjectsEvent event = new DeleteVersionedObjectsEvent(EVENT_COMPLETED, uniqueOperationId); return event; } public static DeleteVersionedObjectsEvent newCancelledEvent(S3Version[] remainingVersions, Object uniqueOperationId) { DeleteVersionedObjectsEvent event = new DeleteVersionedObjectsEvent(EVENT_CANCELLED, uniqueOperationId); event.setObjects(remainingVersions); return event; } public static DeleteVersionedObjectsEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { DeleteVersionedObjectsEvent event = new DeleteVersionedObjectsEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setObjects(S3Version[] versions) { this.versions = versions; } /** * @return * the S3Versions that have been deleted since the last progress event was fired. * @throws IllegalStateException * deleted versions are only available from EVENT_IN_PROGRESS events. */ public S3Version[] getDeletedVersions() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Deleted versions are only available from EVENT_IN_PROGRESS events"); } return versions; } /** * @return * the S3Versions that were not deleted before the operation was cancelled. * @throws IllegalStateException * cancelled objects are only available from EVENT_CANCELLED events. */ public S3Version[] getCancelledVersions() throws IllegalStateException { if (getEventCode() != EVENT_CANCELLED) { throw new IllegalStateException("Cancelled versions are only available from EVENT_CANCELLED events"); } return versions; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multithread/S3ServiceSimpleMulti.java0000644000000000000000000004057611450023056025122 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multithread; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import org.jets3t.service.S3Service; import org.jets3t.service.S3ServiceException; import org.jets3t.service.model.S3Bucket; import org.jets3t.service.model.S3Object; /** * S3 service wrapper that performs multiple S3 requests at a time using multi-threading and an * underlying thread-safe {@link S3Service} implementation. *

* This class provides a simplified interface to the {@link S3ServiceMulti} service. It will block while * doing its work, return the results of an operation when it is finished, and throw an exception if * anything goes wrong. *

* For a non-blocking multi-threading service that is more powerful, but also more complicated, * see {@link S3ServiceMulti}. * * @deprecated 0.8.0 use {@link org.jets3t.service.multi.SimpleThreadedStorageService} instead. * * @author James Murty */ @Deprecated public class S3ServiceSimpleMulti { private S3Service s3Service = null; /** * Construct a multi-threaded service based on an S3Service. * * @param s3Service * an S3Service implementation that will be used to perform S3 requests. This implementation * must be thread-safe. */ public S3ServiceSimpleMulti(S3Service s3Service) { this.s3Service = s3Service; } /** * Utility method to check an {@link S3ServiceEventAdaptor} for the occurrence of an error, and if * one is present to throw it. * * @param adaptor * @throws S3ServiceException */ protected void throwError(S3ServiceEventAdaptor adaptor) throws S3ServiceException { if (adaptor.wasErrorThrown()) { Throwable thrown = adaptor.getErrorThrown(); if (thrown instanceof S3ServiceException) { throw (S3ServiceException) thrown; } else { throw new S3ServiceException(thrown); } } } /** * Creates multiple buckets. * * @param buckets * the buckets to create. * @return * the created buckets. * @throws S3ServiceException */ public S3Bucket[] createBuckets(final S3Bucket[] buckets) throws S3ServiceException { final List bucketList = new ArrayList(); S3ServiceEventAdaptor adaptor = new S3ServiceEventAdaptor() { @Override public void s3ServiceEventPerformed(CreateBucketsEvent event) { super.s3ServiceEventPerformed(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { bucketList.addAll(Arrays.asList(event.getCreatedBuckets())); } }; }; (new S3ServiceMulti(s3Service, adaptor)).createBuckets(buckets); throwError(adaptor); return (S3Bucket[]) bucketList.toArray(new S3Bucket[bucketList.size()]); } /** * Creates/uploads multiple objects. * * @param bucket * the bucket to create the objects in. * @param objects * the objects to create/upload. * @return * the created/uploaded objects. * @throws S3ServiceException */ public S3Object[] putObjects(final S3Bucket bucket, final S3Object[] objects) throws S3ServiceException { final List objectList = new ArrayList(); S3ServiceEventAdaptor adaptor = new S3ServiceEventAdaptor() { @Override public void s3ServiceEventPerformed(CreateObjectsEvent event) { super.s3ServiceEventPerformed(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { objectList.addAll(Arrays.asList(event.getCreatedObjects())); } }; }; (new S3ServiceMulti(s3Service, adaptor)).putObjects(bucket, objects); throwError(adaptor); return (S3Object[]) objectList.toArray(new S3Object[objectList.size()]); } /** * Copies multiple objects within or between buckets. * * @param sourceBucketName * the name of the bucket containing the objects that will be copied. * @param destinationBucketName * the name of the bucket to which the objects will be copied. The destination * bucket may be the same as the source bucket. * @param sourceObjectKeys * the key names of the objects that will be copied. * @param destinationObjects * objects that will be created by the copy operation. The AccessControlList * setting of each object will determine the access permissions of the * resultant object, and if the replaceMetadata flag is true the metadata * items in each object will also be applied to the resultant object. * @param replaceMetadata * if true, the metadata items in the destination objects will be stored * in S3 by using the REPLACE metadata copying option. If false, the metadata * items will be copied unchanged from the original objects using the COPY * metadata copying option.s */ public Map[] copyObjects(final String sourceBucketName, final String destinationBucketName, final String[] sourceObjectKeys, final S3Object[] destinationObjects, boolean replaceMetadata) throws S3ServiceException { final List resultsList = new ArrayList(); S3ServiceEventAdaptor adaptor = new S3ServiceEventAdaptor() { @Override public void s3ServiceEventPerformed(CopyObjectsEvent event) { super.s3ServiceEventPerformed(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { resultsList.addAll(Arrays.asList(event.getCopyResults())); } }; }; (new S3ServiceMulti(s3Service, adaptor)).copyObjects(sourceBucketName, destinationBucketName, sourceObjectKeys, destinationObjects, replaceMetadata); throwError(adaptor); return (Map[]) resultsList.toArray(new Map[resultsList.size()]); } /** * Deletes multiple objects * * @param bucket * the bucket containing the objects to delete. * @param objects * the objects to delete. * @throws S3ServiceException */ public void deleteObjects(final S3Bucket bucket, final S3Object[] objects) throws S3ServiceException { final List objectList = new ArrayList(); S3ServiceEventAdaptor adaptor = new S3ServiceEventAdaptor() { @Override public void s3ServiceEventPerformed(DeleteObjectsEvent event) { super.s3ServiceEventPerformed(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { objectList.addAll(Arrays.asList(event.getDeletedObjects())); } }; }; (new S3ServiceMulti(s3Service, adaptor)).deleteObjects(bucket, objects); throwError(adaptor); } /** * Deletes multiple versions. * * @param versionIds * the identifiers of the object versions that will be deleted. * @param multiFactorSerialNumber * the serial number for a multi-factor authentication device. * @param multiFactorAuthCode * a multi-factor authentication code generated by a device. * @param bucketName * the name of the versioned bucket containing the object to be deleted. * @param objectKey * the key representing the object in S3. * * @throws S3ServiceException */ public void deleteVersionsOfObjectWithMFA(final String[] versionIds, String multiFactorSerialNumber, String multiFactorAuthCode, String bucketName, String objectKey) throws S3ServiceException { S3ServiceEventAdaptor adaptor = new S3ServiceEventAdaptor(); (new S3ServiceMulti(s3Service, adaptor)).deleteVersionsOfObjectWithMFA( versionIds, multiFactorSerialNumber, multiFactorAuthCode, bucketName, objectKey); throwError(adaptor); } /** * Deletes multiple versions. * * @param versionIds * the identifiers of the object versions that will be deleted. * @param bucketName * the name of the versioned bucket containing the object to be deleted. * @param objectKey * the key representing the object in S3. * * @throws S3ServiceException */ public void deleteVersionsOfObject(final String[] versionIds, String bucketName, String objectKey) throws S3ServiceException { deleteVersionsOfObjectWithMFA(versionIds, null, null, bucketName, objectKey); } /** * Retrieves multiple objects (including details and data). * The objects' data will be stored in temporary files, and can be retrieved using * {@link S3Object#getDataInputStream()}. * * @param bucket * the bucket containing the objects. * @param objects * the objects to retrieve. * @return * the retrieved objects. * @throws S3ServiceException */ public S3Object[] getObjects(S3Bucket bucket, S3Object[] objects) throws S3ServiceException { DownloadPackage[] downloadPackages = new DownloadPackage[objects.length]; try { for (int i = 0; i < downloadPackages.length; i++) { // Create a temporary file for data, file will auto-delete on JVM exit. File tempFile = File.createTempFile("jets3t-", ".tmp"); tempFile.deleteOnExit(); downloadPackages[i] = new DownloadPackage(objects[i], tempFile); } } catch (IOException e) { throw new S3ServiceException("Unable to create temporary file to store object data", e); } final List objectList = new ArrayList(); S3ServiceEventAdaptor adaptor = new S3ServiceEventAdaptor() { @Override public void s3ServiceEventPerformed(DownloadObjectsEvent event) { super.s3ServiceEventPerformed(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { objectList.addAll(Arrays.asList(event.getDownloadedObjects())); } }; }; (new S3ServiceMulti(s3Service, adaptor)).downloadObjects(bucket, downloadPackages); throwError(adaptor); return (S3Object[]) objectList.toArray(new S3Object[objectList.size()]); } /** * Retrieves multiple objects (including details and data). * The objects' data will be stored in temporary files, and can be retrieved using * {@link S3Object#getDataInputStream()}. * * @param bucket * the bucket containing the objects. * @param objectKeys * the key names of the objects to retrieve. * @return * the retrieved objects. * * @throws S3ServiceException */ public S3Object[] getObjects(final S3Bucket bucket, final String[] objectKeys) throws S3ServiceException { S3Object[] objects = new S3Object[objectKeys.length]; for (int i = 0; i < objectKeys.length; i++) { objects[i] = new S3Object(objectKeys[i]); } return getObjects(bucket, objects); } /** * Retrieves details of multiple objects (details only, no data) * * @param bucket * the bucket containing the objects. * @param objects * the objects to retrieve. * @return * objects populated with the details retrieved. * @throws S3ServiceException */ public S3Object[] getObjectsHeads(S3Bucket bucket, S3Object[] objects) throws S3ServiceException { String[] objectKeys = new String[objects.length]; for (int i = 0; i < objects.length; i++) { objectKeys[i] = objects[i].getKey(); } return getObjectsHeads(bucket, objectKeys); } /** * Retrieves details of multiple objects (details only, no data) * * @param bucket * the bucket containing the objects. * @param objectKeys * the key names of the objects to retrieve. * @return * objects populated with the details retrieved. * @throws S3ServiceException */ public S3Object[] getObjectsHeads(final S3Bucket bucket, final String[] objectKeys) throws S3ServiceException { final List objectList = new ArrayList(); S3ServiceEventAdaptor adaptor = new S3ServiceEventAdaptor() { @Override public void s3ServiceEventPerformed(GetObjectHeadsEvent event) { super.s3ServiceEventPerformed(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { objectList.addAll(Arrays.asList(event.getCompletedObjects())); } }; }; (new S3ServiceMulti(s3Service, adaptor)).getObjectsHeads(bucket, objectKeys); throwError(adaptor); return (S3Object[]) objectList.toArray(new S3Object[objectList.size()]); } /** * Retrieves Access Control List (ACL) settings for multiple objects. * * @param bucket * the bucket containing the objects. * @param objects * the objects whose ACLs will be retrieved. * @return * objects including the ACL information retrieved. * @throws S3ServiceException */ public S3Object[] getObjectACLs(final S3Bucket bucket, final S3Object[] objects) throws S3ServiceException { final List objectList = new ArrayList(); S3ServiceEventAdaptor adaptor = new S3ServiceEventAdaptor() { @Override public void s3ServiceEventPerformed(LookupACLEvent event) { super.s3ServiceEventPerformed(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { objectList.addAll(Arrays.asList(event.getObjectsWithACL())); } }; }; (new S3ServiceMulti(s3Service, adaptor)).getObjectACLs(bucket, objects); throwError(adaptor); return (S3Object[]) objectList.toArray(new S3Object[objectList.size()]); } /** * Updates/sets Access Control List (ACL) settings for multiple objects. * * @param bucket * the bucket containing the objects. * @param objects * objects containing ACL settings that will be updated/set. * @return * objects whose ACL settings were updated/set. * @throws S3ServiceException */ public S3Object[] putACLs(final S3Bucket bucket, final S3Object[] objects) throws S3ServiceException { final List objectList = new ArrayList(); S3ServiceEventAdaptor adaptor = new S3ServiceEventAdaptor() { @Override public void s3ServiceEventPerformed(UpdateACLEvent event) { super.s3ServiceEventPerformed(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { objectList.addAll(Arrays.asList(event.getObjectsWithUpdatedACL())); } }; }; (new S3ServiceMulti(s3Service, adaptor)).putACLs(bucket, objects); throwError(adaptor); return (S3Object[]) objectList.toArray(new S3Object[objectList.size()]); } /** * A convenience method to download multiple objects from S3 to pre-existing output streams, which * is particularly useful for downloading objects to files. * * @param bucket * the bucket containing the objects * @param downloadPackages * an array of download package objects that manage the output of data for an S3Object. * * @throws S3ServiceException */ public void downloadObjects(final S3Bucket bucket, final DownloadPackage[] downloadPackages) throws S3ServiceException { S3ServiceEventAdaptor adaptor = new S3ServiceEventAdaptor(); (new S3ServiceMulti(s3Service, adaptor)).downloadObjects(bucket, downloadPackages); throwError(adaptor); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multithread/GetObjectHeadsEvent.java0000644000000000000000000001042411441110076024730 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multithread; import org.jets3t.service.model.S3Object; /** * Multi-threaded service event fired by {@link S3ServiceMulti#getObjectsHeads}. *

* EVENT_IN_PROGRESS events include an array of the {@link S3Object}s that have been retrieved * since the last progress event was fired. These objects are available via * {@link #getCompletedObjects()}. *

* EVENT_CANCELLED events include an array of the {@link S3Object}s that had not been retrieved * before the operation was cancelled. These objects are available via * {@link #getCancelledObjects()}. * * @author James Murty */ public class GetObjectHeadsEvent extends ServiceEvent { private S3Object[] objects = null; private GetObjectHeadsEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static GetObjectHeadsEvent newErrorEvent(Throwable t, Object uniqueOperationId) { GetObjectHeadsEvent event = new GetObjectHeadsEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static GetObjectHeadsEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { GetObjectHeadsEvent event = new GetObjectHeadsEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static GetObjectHeadsEvent newInProgressEvent(ThreadWatcher threadWatcher, S3Object[] completedObjects, Object uniqueOperationId) { GetObjectHeadsEvent event = new GetObjectHeadsEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setObjects(completedObjects); return event; } public static GetObjectHeadsEvent newCompletedEvent(Object uniqueOperationId) { GetObjectHeadsEvent event = new GetObjectHeadsEvent(EVENT_COMPLETED, uniqueOperationId); return event; } public static GetObjectHeadsEvent newCancelledEvent(S3Object[] incompletedObjects, Object uniqueOperationId) { GetObjectHeadsEvent event = new GetObjectHeadsEvent(EVENT_CANCELLED, uniqueOperationId); event.setObjects(incompletedObjects); return event; } public static GetObjectHeadsEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { GetObjectHeadsEvent event = new GetObjectHeadsEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setObjects(S3Object[] objects) { this.objects = objects; } /** * @return * the S3Objects that have been retrieved since the last progress event was fired. * @throws IllegalStateException * completed objects are only available from EVENT_IN_PROGRESS events. */ public S3Object[] getCompletedObjects() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Completed Objects are only available from EVENT_IN_PROGRESS events"); } return objects; } /** * @return * the S3Objects that were not retrieved before the operation was cancelled. * @throws IllegalStateException * cancelled objects are only available from EVENT_CANCELLED events. */ public S3Object[] getCancelledObjects() throws IllegalStateException { if (getEventCode() != EVENT_CANCELLED) { throw new IllegalStateException("Cancelled Objects are only available from EVENT_CANCELLED events"); } return objects; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/0002755000000000000000000000000011537563564017105 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/ThreadedStorageService.java0000644000000000000000000024346011550442004024321 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.ServiceException; import org.jets3t.service.StorageObjectsChunk; import org.jets3t.service.StorageService; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.io.BytesProgressWatcher; import org.jets3t.service.io.InterruptableInputStream; import org.jets3t.service.io.ProgressMonitoredInputStream; import org.jets3t.service.io.TempFile; import org.jets3t.service.model.StorageBucket; import org.jets3t.service.model.StorageObject; import org.jets3t.service.multi.event.CopyObjectsEvent; import org.jets3t.service.multi.event.CreateBucketsEvent; import org.jets3t.service.multi.event.CreateObjectsEvent; import org.jets3t.service.multi.event.DeleteObjectsEvent; import org.jets3t.service.multi.event.DownloadObjectsEvent; import org.jets3t.service.multi.event.GetObjectHeadsEvent; import org.jets3t.service.multi.event.GetObjectsEvent; import org.jets3t.service.multi.event.ListObjectsEvent; import org.jets3t.service.multi.event.LookupACLEvent; import org.jets3t.service.multi.event.ServiceEvent; import org.jets3t.service.multi.event.UpdateACLEvent; import org.jets3t.service.security.ProviderCredentials; import org.jets3t.service.utils.ServiceUtils; /** * Storage service wrapper that performs multiple service requests at a time using * multi-threading and an underlying thread-safe {@link StorageService} implementation. *

* This service is designed to be run in non-blocking threads that therefore communicates * information about its progress by firing {@link ServiceEvent} events. It is the responsibility * of applications using this service to correctly handle these events - see the JetS3t application * {@link org.jets3t.apps.synchronize.Synchronize} for examples of how an application can use these * events. *

*

* For cases where the full power, and complexity, of the event notification mechanism is not required * the simplified multi-threaded service {@link SimpleThreadedStorageService} can be used. *

*

* This class uses properties obtained through {@link Jets3tProperties}. For more information on * these properties please refer to * JetS3t Configuration *

* * @author James Murty */ public class ThreadedStorageService { private static final Log log = LogFactory.getLog(ThreadedStorageService.class); protected StorageService storageService = null; protected final boolean[] isShutdown = new boolean[] { false }; protected final List serviceEventListeners = new ArrayList(); protected final long sleepTime; /** * Construct a multi-threaded service based on a StorageService and which sends event notifications * to an event listening class. EVENT_IN_PROGRESS events are sent at the default time interval * of 500ms. * * @param service * an storage service implementation that will be used to perform requests. * @param listener * the event listener which will handle event notifications. * @throws ServiceException */ public ThreadedStorageService(StorageService service, StorageServiceEventListener listener) throws ServiceException { this(service, listener, 500); } /** * Construct a multi-threaded service based on an storage service and which sends event notifications * to an event listening class, and which will send EVENT_IN_PROGRESS events at the specified * time interval. * * @param service * a storage service implementation that will be used to perform requests. * @param listener * the event listener which will handle event notifications. * @param threadSleepTimeMS * how many milliseconds to wait before sending each EVENT_IN_PROGRESS notification event. * @throws ServiceException */ public ThreadedStorageService(StorageService service, StorageServiceEventListener listener, long threadSleepTimeMS) throws ServiceException { this.storageService = service; addServiceEventListener(listener); this.sleepTime = threadSleepTimeMS; // Sanity-check the maximum thread and connection settings to ensure the maximum number // of connections is at least equal to the largest of the maximum thread counts, and warn // the use of potential problems. int adminMaxThreadCount = this.storageService.getJetS3tProperties() .getIntProperty("threaded-service.admin-max-thread-count", 20); int maxThreadCount = this.storageService.getJetS3tProperties() .getIntProperty("threaded-service.max-thread-count", 2); int maxConnectionCount = this.storageService.getJetS3tProperties() .getIntProperty("httpclient.max-connections", 20); if (maxConnectionCount < maxThreadCount) { throw new ServiceException( "Insufficient connections available (httpclient.max-connections=" + maxConnectionCount + ") to run (threaded-service.max-thread-count=" + maxThreadCount + ") simultaneous threads - please adjust JetS3t properties"); } if (maxConnectionCount < adminMaxThreadCount) { throw new ServiceException( "Insufficient connections available (httpclient.max-connections=" + maxConnectionCount + ") to run (threaded-service.admin-max-thread-count=" + adminMaxThreadCount + ") simultaneous admin threads - please adjust JetS3t properties"); } } /** * Make a best-possible effort to shutdown and clean up any resources used by this * service such as HTTP connections, connection pools, threads etc. After calling * this method the service instance will no longer be usable -- a new instance must * be created to do more work. */ public void shutdown() throws ServiceException { this.isShutdown[0] = true; this.getStorageService().shutdown(); } /** * @return true if the {@link #shutdown()} method has been used to shut down and * clean up this service. If this function returns true this service instance * can no longer be used to do work. */ public boolean isShutdown() { return this.isShutdown[0]; } /** * @return * the underlying service implementation. */ public StorageService getStorageService() { return storageService; } /** * Adds a service event listener to the set of listeners that will be notified of events. * * @param listener * an event listener to add to the event notification chain. */ public void addServiceEventListener(StorageServiceEventListener listener) { if (listener != null) { serviceEventListeners.add(listener); } } /** * Removes a service event listener from the set of listeners that will be notified of events. * * @param listener * an event listener to remove from the event notification chain. */ public void removeServiceEventListener(StorageServiceEventListener listener) { if (listener != null) { serviceEventListeners.remove(listener); } } /** * Sends a service event to each of the listeners registered with this service. * @param event * the event to send to this service's registered event listeners. */ protected void fireServiceEvent(ServiceEvent event) { if (serviceEventListeners.size() == 0) { if (log.isWarnEnabled()) { log.warn("ThreadedStorageService invoked without any StorageServiceEventListener objects, this is dangerous!"); } } for (StorageServiceEventListener listener: this.serviceEventListeners) { if (event instanceof CreateObjectsEvent) { listener.event((CreateObjectsEvent) event); } else if (event instanceof CopyObjectsEvent) { listener.event((CopyObjectsEvent) event); } else if (event instanceof CreateBucketsEvent) { listener.event((CreateBucketsEvent) event); } else if (event instanceof ListObjectsEvent) { listener.event((ListObjectsEvent) event); } else if (event instanceof DeleteObjectsEvent) { listener.event((DeleteObjectsEvent) event); } else if (event instanceof GetObjectsEvent) { listener.event((GetObjectsEvent) event); } else if (event instanceof GetObjectHeadsEvent) { listener.event((GetObjectHeadsEvent) event); } else if (event instanceof LookupACLEvent) { listener.event((LookupACLEvent) event); } else if (event instanceof UpdateACLEvent) { listener.event((UpdateACLEvent) event); } else if (event instanceof DownloadObjectsEvent) { listener.event((DownloadObjectsEvent) event); } else { throw new IllegalArgumentException("Listener not invoked for event class: " + event.getClass()); } } } /** * @return * true if the underlying service implementation is authenticated. */ public boolean isAuthenticatedConnection() { return storageService.isAuthenticatedConnection(); } /** * @return the credentials in the underlying storage service. */ public ProviderCredentials getProviderCredentials() { return storageService.getProviderCredentials(); } /** * Lists the objects in a bucket based on an array of prefix strings, and * sends {@link ListObjectsEvent} notification events. * The objects that match each prefix are listed in a separate background * thread, potentially allowing you to list the contents of large buckets more * quickly than if you had to list all the objects in sequence. *

* Objects in the bucket that do not match one of the prefixes will not be * listed. * * @param bucketName * the name of the bucket in which the objects are stored. * @param prefixes * an array of prefix strings. A separate listing thread will be run for * each of these prefix strings, and the method will only complete once * the entire object listing for each prefix has been obtained (unless the * operation is cancelled, or an error occurs) * @param delimiter * an optional delimiter string to apply to each listing operation. This * parameter should be null if you do not wish to apply a delimiter. * @param maxListingLength * the maximum number of objects to list in each iteration. This should be a * value between 1 and 1000, where 1000 will be the best choice in almost all * circumstances. Regardless of this value, all the objects in the bucket that * match the criteria will be returned. * *

* The maximum number of threads is controlled by the JetS3t configuration property * threaded-service.admin-max-thread-count. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean listObjects(final String bucketName, final String[] prefixes, final String delimiter, final long maxListingLength) { final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. ListObjectsRunnable[] runnables = new ListObjectsRunnable[prefixes.length]; for (int i = 0; i < runnables.length; i++) { runnables[i] = new ListObjectsRunnable(bucketName, prefixes[i], delimiter, maxListingLength, null); } // Wait for threads to finish, or be cancelled. (new ThreadGroupManager(runnables, new ThreadWatcher(runnables.length), this.storageService.getJetS3tProperties(), true) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(ListObjectsEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List chunkList) { fireServiceEvent(ListObjectsEvent.newInProgressEvent( threadWatcher, chunkList, uniqueOperationId)); } @Override public void fireCancelEvent() { success[0] = false; fireServiceEvent(ListObjectsEvent.newCancelledEvent(uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(ListObjectsEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(ListObjectsEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(ListObjectsEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Creates multiple buckets, and sends {@link CreateBucketsEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * threaded-service.admin-max-thread-count. * * @param bucketNames * names of buckets to create. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean createBuckets(final String[] bucketNames) { final List incompletedBucketList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. CreateBucketRunnable[] runnables = new CreateBucketRunnable[bucketNames.length]; for (int i = 0; i < runnables.length; i++) { incompletedBucketList.add(bucketNames[i]); runnables[i] = new CreateBucketRunnable(bucketNames[i]); } // Wait for threads to finish, or be cancelled. (new ThreadGroupManager(runnables, new ThreadWatcher(runnables.length), this.storageService.getJetS3tProperties(), true) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(CreateBucketsEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { incompletedBucketList.removeAll(completedResults); StorageBucket[] completedBuckets = (StorageBucket[]) completedResults .toArray(new StorageBucket[completedResults.size()]); fireServiceEvent(CreateBucketsEvent.newInProgressEvent(threadWatcher, completedBuckets, uniqueOperationId)); } @Override public void fireCancelEvent() { StorageBucket[] incompletedBuckets = (StorageBucket[]) incompletedBucketList .toArray(new StorageBucket[incompletedBucketList.size()]); success[0] = false; fireServiceEvent(CreateBucketsEvent.newCancelledEvent(incompletedBuckets, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(CreateBucketsEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(CreateBucketsEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(CreateBucketsEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Copies multiple objects within or between buckets, while sending * {@link CopyObjectsEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * threaded-service.admin-max-thread-count. * * @param sourceBucketName * the name of the bucket containing the objects that will be copied. * @param destinationBucketName * the name of the bucket to which the objects will be copied. The destination * bucket may be the same as the source bucket. * @param sourceObjectKeys * the key names of the objects that will be copied. * @param destinationObjects * objects that will be created by the copy operation. The AccessControlList * setting of each object will determine the access permissions of the * resultant object, and if the replaceMetadata flag is true the metadata * items in each object will also be applied to the resultant object. * @param replaceMetadata * if true, the metadata items in the destination objects will be stored * in using the REPLACE metadata copying option. If false, the metadata * items will be copied unchanged from the original objects using the COPY * metadata copying option. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean copyObjects(final String sourceBucketName, final String destinationBucketName, final String[] sourceObjectKeys, final StorageObject[] destinationObjects, boolean replaceMetadata) { final List incompletedObjectsList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. CopyObjectRunnable[] runnables = new CopyObjectRunnable[sourceObjectKeys.length]; for (int i = 0; i < runnables.length; i++) { incompletedObjectsList.add(destinationObjects[i]); runnables[i] = new CopyObjectRunnable(sourceBucketName, destinationBucketName, sourceObjectKeys[i], destinationObjects[i], replaceMetadata); } // Wait for threads to finish, or be cancelled. (new ThreadGroupManager(runnables, new ThreadWatcher(runnables.length), this.storageService.getJetS3tProperties(), true) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(CopyObjectsEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { incompletedObjectsList.removeAll(completedResults); Map[] copyResults = (Map[]) completedResults .toArray(new Map[completedResults.size()]); fireServiceEvent(CopyObjectsEvent.newInProgressEvent(threadWatcher, copyResults, uniqueOperationId)); } @Override public void fireCancelEvent() { StorageObject[] incompletedObjects = (StorageObject[]) incompletedObjectsList .toArray(new StorageObject[incompletedObjectsList.size()]); success[0] = false; fireServiceEvent(CopyObjectsEvent.newCancelledEvent(incompletedObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(CopyObjectsEvent.newCompletedEvent(uniqueOperationId, sourceObjectKeys, destinationObjects)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(CopyObjectsEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(CopyObjectsEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Creates multiple objects in a bucket, and sends {@link CreateObjectsEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * threaded-service.max-admin-thread-count. * * @param bucketName * name of the bucket where objects will be stored * @param objects * the objects to create/upload. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean putObjects(final String bucketName, final StorageObject[] objects) { final List incompletedObjectsList = new ArrayList(); final List progressWatchers = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. CreateObjectRunnable[] runnables = new CreateObjectRunnable[objects.length]; for (int i = 0; i < runnables.length; i++) { incompletedObjectsList.add(objects[i]); BytesProgressWatcher progressMonitor = new BytesProgressWatcher(objects[i].getContentLength()); runnables[i] = new CreateObjectRunnable(bucketName, objects[i], progressMonitor); progressWatchers.add(progressMonitor); } // Wait for threads to finish, or be cancelled. ThreadWatcher threadWatcher = new ThreadWatcher( (BytesProgressWatcher[]) progressWatchers.toArray(new BytesProgressWatcher[progressWatchers.size()])); (new ThreadGroupManager(runnables, threadWatcher, this.storageService.getJetS3tProperties(), false) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(CreateObjectsEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { incompletedObjectsList.removeAll(completedResults); StorageObject[] completedObjects = (StorageObject[]) completedResults .toArray(new StorageObject[completedResults.size()]); fireServiceEvent(CreateObjectsEvent.newInProgressEvent(threadWatcher, completedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { StorageObject[] incompletedObjects = (StorageObject[]) incompletedObjectsList .toArray(new StorageObject[incompletedObjectsList.size()]); success[0] = false; fireServiceEvent(CreateObjectsEvent.newCancelledEvent(incompletedObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(CreateObjectsEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(CreateObjectsEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(CreateObjectsEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Deletes multiple objects from a bucket, and sends {@link DeleteObjectsEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * threaded-service.admin-max-thread-count. * * @param bucketName * name of the bucket containing objects to delete * @param objectKeys * key names of objects to delete * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean deleteObjects(final String bucketName, String[] objectKeys) { StorageObject objects[] = new StorageObject[objectKeys.length]; for (int i = 0; i < objects.length; i++) { objects[i] = new StorageObject(objectKeys[i]); } return this.deleteObjects(bucketName, objects); } /** * Deletes multiple objects from a bucket, and sends {@link DeleteObjectsEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * threaded-service.admin-max-thread-count. * * @param bucketName * name of the bucket containing the objects to be deleted * @param objects * the objects to delete * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean deleteObjects(final String bucketName, final StorageObject[] objects) { final List objectsToDeleteList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. DeleteObjectRunnable[] runnables = new DeleteObjectRunnable[objects.length]; for (int i = 0; i < runnables.length; i++) { objectsToDeleteList.add(objects[i]); runnables[i] = new DeleteObjectRunnable(bucketName, objects[i]); } // Wait for threads to finish, or be cancelled. (new ThreadGroupManager(runnables, new ThreadWatcher(runnables.length), this.storageService.getJetS3tProperties(), true) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(DeleteObjectsEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { objectsToDeleteList.removeAll(completedResults); StorageObject[] deletedObjects = (StorageObject[]) completedResults .toArray(new StorageObject[completedResults.size()]); fireServiceEvent(DeleteObjectsEvent.newInProgressEvent(threadWatcher, deletedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { StorageObject[] remainingObjects = (StorageObject[]) objectsToDeleteList .toArray(new StorageObject[objectsToDeleteList.size()]); success[0] = false; fireServiceEvent(DeleteObjectsEvent.newCancelledEvent(remainingObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(DeleteObjectsEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(DeleteObjectsEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(DeleteObjectsEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Retrieves multiple objects (details and data) from a bucket, and sends * {@link GetObjectsEvent} notification events. * * @param bucketName * name of the bucket containing the objects. * @param objects * the objects to retrieve. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean getObjects(String bucketName, StorageObject[] objects) { String[] objectKeys = new String[objects.length]; for (int i = 0; i < objects.length; i++) { objectKeys[i] = objects[i].getKey(); } return getObjects(bucketName, objectKeys); } /** * Retrieves multiple objects (details and data) from a bucket, and sends * {@link GetObjectsEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * threaded-service.max-thread-count. * * @param bucketName * the bucket containing the objects. * @param objectKeys * the key names of the objects to retrieve. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean getObjects(final String bucketName, final String[] objectKeys) { final List pendingObjectKeysList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. GetObjectRunnable[] runnables = new GetObjectRunnable[objectKeys.length]; for (int i = 0; i < runnables.length; i++) { pendingObjectKeysList.add(objectKeys[i]); runnables[i] = new GetObjectRunnable(bucketName, objectKeys[i], false); } // Wait for threads to finish, or be cancelled. (new ThreadGroupManager(runnables, new ThreadWatcher(runnables.length), this.storageService.getJetS3tProperties(), false) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(GetObjectsEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { StorageObject[] completedObjects = (StorageObject[]) completedResults .toArray(new StorageObject[completedResults.size()]); for (int i = 0; i < completedObjects.length; i++) { pendingObjectKeysList.remove(completedObjects[i].getKey()); } fireServiceEvent(GetObjectsEvent.newInProgressEvent(threadWatcher, completedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { List cancelledObjectsList = new ArrayList(); Iterator iter = pendingObjectKeysList.iterator(); while (iter.hasNext()) { String key = (String) iter.next(); cancelledObjectsList.add(new StorageObject(key)); } StorageObject[] cancelledObjects = (StorageObject[]) cancelledObjectsList .toArray(new StorageObject[cancelledObjectsList.size()]); success[0] = false; fireServiceEvent(GetObjectsEvent.newCancelledEvent(cancelledObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(GetObjectsEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(GetObjectsEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(GetObjectsEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Retrieves details (but no data) about multiple objects from a bucket, and sends * {@link GetObjectHeadsEvent} notification events. * * @param bucketName * name of the bucket containing the objects whose details will be retrieved. * @param objects * the objects with details to retrieve. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean getObjectsHeads(String bucketName, StorageObject[] objects) { String[] objectKeys = new String[objects.length]; for (int i = 0; i < objects.length; i++) { objectKeys[i] = objects[i].getKey(); } return getObjectsHeads(bucketName, objectKeys); } /** * Retrieves details (but no data) about multiple objects from a bucket, and sends * {@link GetObjectHeadsEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * threaded-service.admin-max-thread-count. * * @param bucketName * name of the bucket containing the objects. * @param objectKeys * the key names of the objects with details to retrieve. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean getObjectsHeads(final String bucketName, final String[] objectKeys) { final List pendingObjectKeysList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. GetObjectRunnable[] runnables = new GetObjectRunnable[objectKeys.length]; for (int i = 0; i < runnables.length; i++) { pendingObjectKeysList.add(objectKeys[i]); runnables[i] = new GetObjectRunnable(bucketName, objectKeys[i], true); } // Wait for threads to finish, or be cancelled. (new ThreadGroupManager(runnables, new ThreadWatcher(runnables.length), this.storageService.getJetS3tProperties(), true) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(GetObjectHeadsEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { StorageObject[] completedObjects = (StorageObject[]) completedResults .toArray(new StorageObject[completedResults.size()]); for (int i = 0; i < completedObjects.length; i++) { pendingObjectKeysList.remove(completedObjects[i].getKey()); } fireServiceEvent(GetObjectHeadsEvent.newInProgressEvent(threadWatcher, completedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { List cancelledObjectsList = new ArrayList(); Iterator iter = pendingObjectKeysList.iterator(); while (iter.hasNext()) { String key = (String) iter.next(); cancelledObjectsList.add(new StorageObject(key)); } StorageObject[] cancelledObjects = (StorageObject[]) cancelledObjectsList .toArray(new StorageObject[cancelledObjectsList.size()]); success[0] = false; fireServiceEvent(GetObjectHeadsEvent.newCancelledEvent(cancelledObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(GetObjectHeadsEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(GetObjectHeadsEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(GetObjectHeadsEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Retrieves Access Control List (ACL) information for multiple objects from a bucket, and sends * {@link LookupACLEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * threaded-service.admin-max-thread-count. * * @param bucketName * name of the bucket containing the objects * @param objects * the objects to retrieve ACL details for. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean getObjectACLs(final String bucketName, final StorageObject[] objects) { final List pendingObjectsList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. GetACLRunnable[] runnables = new GetACLRunnable[objects.length]; for (int i = 0; i < runnables.length; i++) { pendingObjectsList.add(objects[i]); runnables[i] = new GetACLRunnable(bucketName, objects[i]); } // Wait for threads to finish, or be cancelled. (new ThreadGroupManager(runnables, new ThreadWatcher(runnables.length), this.storageService.getJetS3tProperties(), true) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(LookupACLEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { pendingObjectsList.removeAll(completedResults); StorageObject[] completedObjects = (StorageObject[]) completedResults .toArray(new StorageObject[completedResults.size()]); fireServiceEvent(LookupACLEvent.newInProgressEvent(threadWatcher, completedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { StorageObject[] cancelledObjects = (StorageObject[]) pendingObjectsList .toArray(new StorageObject[pendingObjectsList.size()]); success[0] = false; fireServiceEvent(LookupACLEvent.newCancelledEvent(cancelledObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(LookupACLEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(LookupACLEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(LookupACLEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Updates/sets Access Control List (ACL) information for multiple objects in a bucket, and sends * {@link UpdateACLEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * threaded-service.admin-max-thread-count. * * @param bucketName * name of the bucket containing the objects. * @param objects * the objects to update/set ACL details for. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean putACLs(final String bucketName, final StorageObject[] objects) { final List pendingObjectsList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. PutACLRunnable[] runnables = new PutACLRunnable[objects.length]; for (int i = 0; i < runnables.length; i++) { pendingObjectsList.add(objects[i]); runnables[i] = new PutACLRunnable(bucketName, objects[i]); } // Wait for threads to finish, or be cancelled. (new ThreadGroupManager(runnables, new ThreadWatcher(runnables.length), this.storageService.getJetS3tProperties(), true) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(UpdateACLEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { pendingObjectsList.removeAll(completedResults); StorageObject[] completedObjects = (StorageObject[]) completedResults .toArray(new StorageObject[completedResults.size()]); fireServiceEvent(UpdateACLEvent.newInProgressEvent(threadWatcher, completedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { StorageObject[] cancelledObjects = (StorageObject[]) pendingObjectsList .toArray(new StorageObject[pendingObjectsList.size()]); success[0] = false; fireServiceEvent(UpdateACLEvent.newCancelledEvent(cancelledObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(UpdateACLEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(UpdateACLEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(UpdateACLEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * A convenience method to download multiple objects to pre-existing * output streams, which is particularly useful for downloading objects to files. *

* The maximum number of threads is controlled by the JetS3t configuration property * threaded-service.max-thread-count. *

* If the JetS3t configuration property downloads.restoreLastModifiedDate is set * to true, any files created by this method will have their last modified date set according * to the value of the object's {@link Constants#METADATA_JETS3T_LOCAL_FILE_DATE} metadata * item. * * @param bucketName * name of the bucket containing the objects * @param downloadPackages * an array of download packages containing the object to be downloaded, and able to build * an output stream where the object's contents will be written to. * * @return * true if all the threaded tasks completed successfully, false otherwise. * @throws ServiceException */ public boolean downloadObjects(final String bucketName, final DownloadPackage[] downloadPackages) throws ServiceException { final List progressWatchers = new ArrayList(); final List incompleteObjectDownloadList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; boolean restoreLastModifiedDate = this.storageService.getJetS3tProperties() .getBoolProperty("downloads.restoreLastModifiedDate", false); // Start all queries in the background. DownloadObjectRunnable[] runnables = new DownloadObjectRunnable[downloadPackages.length]; final StorageObject[] objects = new StorageObject[downloadPackages.length]; for (int i = 0; i < runnables.length; i++) { objects[i] = downloadPackages[i].getObject(); BytesProgressWatcher progressMonitor = new BytesProgressWatcher(objects[i].getContentLength()); incompleteObjectDownloadList.add(objects[i]); progressWatchers.add(progressMonitor); runnables[i] = new DownloadObjectRunnable(bucketName, objects[i].getKey(), downloadPackages[i], progressMonitor, restoreLastModifiedDate); } // Wait for threads to finish, or be cancelled. ThreadWatcher threadWatcher = new ThreadWatcher( (BytesProgressWatcher[]) progressWatchers.toArray(new BytesProgressWatcher[progressWatchers.size()])); (new ThreadGroupManager(runnables, threadWatcher, this.storageService.getJetS3tProperties(), false) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(DownloadObjectsEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { incompleteObjectDownloadList.removeAll(completedResults); StorageObject[] completedObjects = (StorageObject[]) completedResults .toArray(new StorageObject[completedResults.size()]); fireServiceEvent(DownloadObjectsEvent.newInProgressEvent(threadWatcher, completedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { StorageObject[] incompleteObjects = (StorageObject[]) incompleteObjectDownloadList .toArray(new StorageObject[incompleteObjectDownloadList.size()]); success[0] = false; fireServiceEvent(DownloadObjectsEvent.newCancelledEvent(incompleteObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(DownloadObjectsEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(DownloadObjectsEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(DownloadObjectsEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /////////////////////////////////////////////// // Private classes used by the methods above // /////////////////////////////////////////////// /** * All the operation threads used by this service extend this class, which provides common * methods used to retrieve the result object from a completed thread (via {@link #getResult()} * or force a thread to be interrupted (via {@link #forceInterrupt}. */ protected abstract class AbstractRunnable implements Runnable { public abstract Object getResult(); public abstract void forceInterruptCalled(); protected void forceInterrupt() { forceInterruptCalled(); } } /** * Thread for performing the update/set of Access Control List information for an object. */ private class PutACLRunnable extends AbstractRunnable { private StorageBucket bucket = null; private String bucketName = null; private StorageObject object = null; private Object result = null; public PutACLRunnable(StorageBucket bucket) { this.bucket = bucket; } public PutACLRunnable(String bucketName, StorageObject object) { this.bucketName = bucketName; this.object = object; } public void run() { try { if (object == null) { storageService.putBucketAcl(bucket); result = bucket; } else { storageService.putObjectAcl(bucketName, object); result = object; } } catch (RuntimeException e) { result = e; throw e; } catch (Exception e) { result = e; } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { // This is an atomic operation, cannot interrupt. Ignore. } } /** * Thread for retrieving Access Control List information for an object. */ private class GetACLRunnable extends AbstractRunnable { private String bucketName = null; private StorageObject object = null; private Object result = null; public GetACLRunnable(String bucketName, StorageObject object) { this.bucketName = bucketName; this.object = object; } public void run() { try { AccessControlList acl = storageService.getObjectAcl( bucketName, object.getKey()); object.setAcl(acl); result = object; } catch (RuntimeException e) { result = e; throw e; } catch (Exception e) { result = e; } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { // This is an atomic operation, cannot interrupt. Ignore. } } /** * Thread for deleting an object. */ private class DeleteObjectRunnable extends AbstractRunnable { private String bucketName = null; private StorageObject object = null; private Object result = null; public DeleteObjectRunnable(String bucketName, StorageObject object) { this.bucketName = bucketName; this.object = object; } public void run() { try { storageService.deleteObject(bucketName, object.getKey()); result = object; } catch (RuntimeException e) { result = e; throw e; } catch (Exception e) { result = e; } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { // This is an atomic operation, cannot interrupt. Ignore. } } /** * Thread for creating a bucket. */ private class CreateBucketRunnable extends AbstractRunnable { private String bucketName = null; private Object result = null; public CreateBucketRunnable(String bucketName) { this.bucketName = bucketName; } public void run() { try { result = storageService.createBucket(bucketName); } catch (ServiceException e) { result = e; } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { // This is an atomic operation, cannot interrupt. Ignore. } } /** * Thread for listing the objects in a bucket. */ private class ListObjectsRunnable extends AbstractRunnable { private Object result = null; private String bucketName = null; private String prefix = null; private String delimiter = null; private long maxListingLength = 1000; private String priorLastKey = null; private boolean halted = false; public ListObjectsRunnable(String bucketName, String prefix, String delimiter, long maxListingLength, String priorLastKey) { this.bucketName = bucketName; this.prefix = prefix; this.delimiter = delimiter; this.maxListingLength = maxListingLength; this.priorLastKey = priorLastKey; } public void run() { try { List allObjects = new ArrayList(); List allCommonPrefixes = new ArrayList(); do { StorageObjectsChunk chunk = storageService.listObjectsChunked( bucketName, prefix, delimiter, maxListingLength, priorLastKey); priorLastKey = chunk.getPriorLastKey(); allObjects.addAll(Arrays.asList(chunk.getObjects())); allCommonPrefixes.addAll(Arrays.asList(chunk.getCommonPrefixes())); } while (!halted && priorLastKey != null); result = new StorageObjectsChunk( prefix, delimiter, (StorageObject[]) allObjects.toArray(new StorageObject[allObjects.size()]), (String[]) allCommonPrefixes.toArray(new String[allCommonPrefixes.size()]), null); } catch (ServiceException e) { result = e; } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { halted = true; } } /** * Thread for creating/uploading an object. The upload of any object data is monitored with a * {@link ProgressMonitoredInputStream} and can be can cancelled as the input stream is wrapped in * an {@link InterruptableInputStream}. */ private class CreateObjectRunnable extends AbstractRunnable { private String bucketName = null; private StorageObject object = null; private InterruptableInputStream interruptableInputStream = null; private BytesProgressWatcher progressMonitor = null; private Object result = null; public CreateObjectRunnable(String bucketName, StorageObject object, BytesProgressWatcher progressMonitor) { this.bucketName = bucketName; this.object = object; this.progressMonitor = progressMonitor; } public void run() { try { File underlyingFile = object.getDataInputFile(); if (object.getDataInputStream() != null) { interruptableInputStream = new InterruptableInputStream(object.getDataInputStream()); ProgressMonitoredInputStream pmInputStream = new ProgressMonitoredInputStream( interruptableInputStream, progressMonitor); object.setDataInputStream(pmInputStream); } result = storageService.putObject(bucketName, object); if (underlyingFile instanceof TempFile) { underlyingFile.delete(); } } catch (ServiceException e) { result = e; } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { if (interruptableInputStream != null) { interruptableInputStream.interrupt(); } } } /** * Thread for copying an object. */ private class CopyObjectRunnable extends AbstractRunnable { private String sourceBucketName = null; private String destinationBucketName = null; private String sourceObjectKey = null; private StorageObject destinationObject = null; private boolean replaceMetadata = false; private Object result = null; public CopyObjectRunnable(String sourceBucketName, String destinationBucketName, String sourceObjectKey, StorageObject destinationObject, boolean replaceMetadata) { this.sourceBucketName = sourceBucketName; this.destinationBucketName = destinationBucketName; this.sourceObjectKey = sourceObjectKey; this.destinationObject = destinationObject; this.replaceMetadata = replaceMetadata; } public void run() { try { result = storageService.copyObject(sourceBucketName, sourceObjectKey, destinationBucketName, destinationObject, replaceMetadata); } catch (ServiceException e) { result = e; } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { // This is an atomic operation, cannot interrupt. Ignore. } } /** * Thread for retrieving an object. */ private class GetObjectRunnable extends AbstractRunnable { private String bucketName = null; private String objectKey = null; private boolean headOnly = false; private Object result = null; public GetObjectRunnable(String bucketName, String objectKey, boolean headOnly) { this.bucketName = bucketName; this.objectKey = objectKey; this.headOnly = headOnly; } public void run() { try { if (headOnly) { result = storageService.getObjectDetails( bucketName, objectKey); } else { result = storageService.getObject( bucketName, objectKey); } } catch (ServiceException e) { result = e; } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { // This is an atomic operation, cannot interrupt. Ignore. } } /** * Thread for downloading an object. The download of any object data is monitored with a * {@link ProgressMonitoredInputStream} and can be can cancelled as the input stream is wrapped in * an {@link InterruptableInputStream}. */ private class DownloadObjectRunnable extends AbstractRunnable { private String objectKey = null; private String bucketName = null; private DownloadPackage downloadPackage = null; private InterruptableInputStream interruptableInputStream = null; private BytesProgressWatcher progressMonitor = null; private boolean restoreLastModifiedDate = true; private Object result = null; public DownloadObjectRunnable(String bucketName, String objectKey, DownloadPackage downloadPackage, BytesProgressWatcher progressMonitor, boolean restoreLastModifiedDate) { this.bucketName = bucketName; this.objectKey = objectKey; this.downloadPackage = downloadPackage; this.progressMonitor = progressMonitor; this.restoreLastModifiedDate = restoreLastModifiedDate; } public DownloadObjectRunnable(DownloadPackage downloadPackage, BytesProgressWatcher progressMonitor, boolean restoreLastModifiedDate) { this.downloadPackage = downloadPackage; this.progressMonitor = progressMonitor; this.restoreLastModifiedDate = restoreLastModifiedDate; } public void run() { BufferedInputStream bufferedInputStream = null; BufferedOutputStream bufferedOutputStream = null; StorageObject object = null; try { object = storageService.getObject( bucketName, objectKey); // Replace the object in the download package with the downloaded version to make metadata available. downloadPackage.setObject(object); // Setup monitoring of stream bytes transferred. interruptableInputStream = new InterruptableInputStream(object.getDataInputStream()); bufferedInputStream = new BufferedInputStream( new ProgressMonitoredInputStream(interruptableInputStream, progressMonitor)); bufferedOutputStream = new BufferedOutputStream( downloadPackage.getOutputStream()); MessageDigest messageDigest = null; try { messageDigest = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { if (log.isWarnEnabled()) { log.warn("Unable to calculate MD5 hash of data received as algorithm is not available", e); } } try { byte[] buffer = new byte[1024]; int byteCount = -1; while ((byteCount = bufferedInputStream.read(buffer)) != -1) { bufferedOutputStream.write(buffer, 0, byteCount); if (messageDigest != null) { messageDigest.update(buffer, 0, byteCount); } } // Check that actual bytes received match expected hash value if (messageDigest != null) { byte[] dataMD5Hash = messageDigest.digest(); String hexMD5OfDownloadedData = ServiceUtils.toHex(dataMD5Hash); // Don't check MD5 hash against ETag if ETag doesn't look like an MD5 value if (!ServiceUtils.isEtagAlsoAnMD5Hash(object.getETag())) { // Use JetS3t's own MD5 hash metadata value for comparison, if it's available if (!hexMD5OfDownloadedData.equals(object.getMd5HashAsHex())) { if (log.isWarnEnabled()) { log.warn("Unable to verify MD5 hash of downloaded data against" + " ETag returned by service because ETag value \"" + object.getETag() + "\" is not an MD5 hash value" + ", for object key: " + object.getKey()); } } } else { if (!hexMD5OfDownloadedData.equals(object.getETag())) { throw new ServiceException("Mismatch between MD5 hash of downloaded data (" + hexMD5OfDownloadedData + ") and ETag returned by service (" + object.getETag() + ") for object key: " + object.getKey()); } else { if (log.isDebugEnabled()) { log.debug("Object download was automatically verified, the calculated MD5 hash "+ "value matched the ETag provided by service: " + object.getKey()); } } } } } finally { if (bufferedOutputStream != null) { bufferedOutputStream.close(); } if (bufferedInputStream != null) { bufferedInputStream.close(); } } object.setDataInputStream(null); object.setDataInputFile(downloadPackage.getDataFile()); // If data was downloaded to a file, set the file's Last Modified date // to the original last modified date metadata stored with the object. if (restoreLastModifiedDate && downloadPackage.getDataFile() != null) { String metadataLocalFileDate = (String) object.getMetadata( Constants.METADATA_JETS3T_LOCAL_FILE_DATE); if (metadataLocalFileDate != null) { if (log.isDebugEnabled()) { log.debug("Restoring original Last Modified date for object '" + object.getKey() + "' to file '" + downloadPackage.getDataFile() + "': " + metadataLocalFileDate); } downloadPackage.getDataFile().setLastModified( ServiceUtils.parseIso8601Date(metadataLocalFileDate).getTime()); } } result = object; } catch (Throwable t) { result = t; } finally { if (bufferedInputStream != null) { try { bufferedInputStream.close(); } catch (Exception e) { if (log.isErrorEnabled()) { log.error("Unable to close Object input stream", e); } } } if (bufferedOutputStream != null) { try { bufferedOutputStream.close(); } catch (Exception e) { if (log.isErrorEnabled()) { log.error("Unable to close download output stream", e); } } } } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { if (interruptableInputStream != null) { interruptableInputStream.interrupt(); } } } /** * The thread group manager is responsible for starting, running and stopping the set of threads * required to perform an operation. *

* The manager starts all the threads, monitors their progress and stops threads when they are * cancelled or an error occurs - all the while firing the appropriate {@link ServiceEvent} event * notifications. */ protected abstract class ThreadGroupManager { private final Log log = LogFactory.getLog(ThreadGroupManager.class); private int maxThreadCount = 1; /** * the set of runnable objects to execute. */ private AbstractRunnable[] runnables = null; /** * Thread objects that are currently running, where the index corresponds to the * runnables index. Any AbstractThread runnable that is not started, or has completed, * will have a null value in this array. */ private Thread[] threads = null; private boolean ignoreExceptions = false; /** * set of flags indicating which runnable items have been started */ private boolean started[] = null; /** * set of flags indicating which threads have already had In Progress events fired on * their behalf. These threads have finished running. */ private boolean alreadyFired[] = null; private ThreadWatcher threadWatcher = null; private long lastProgressEventFiredTime = 0; public ThreadGroupManager(AbstractRunnable[] runnables, ThreadWatcher threadWatcher, Jets3tProperties jets3tProperties, boolean isAdminTask) { this.runnables = runnables; this.threadWatcher = threadWatcher; if (isAdminTask) { this.maxThreadCount = jets3tProperties .getIntProperty("threaded-service.admin-max-thread-count", 20); } else { this.maxThreadCount = jets3tProperties .getIntProperty("threaded-service.max-thread-count", 2); } this.ignoreExceptions = jets3tProperties .getBoolProperty("threaded-service.ignore-exceptions-in-multi", false); this.threads = new Thread[runnables.length]; started = new boolean[runnables.length]; // All values initialized to false. alreadyFired = new boolean[runnables.length]; // All values initialized to false. } /** * Determine which threads, if any, have finished since the last time an In Progress event * was fired. * * @return * a list of the threads that finished since the last In Progress event was fired. This list may * be empty. * * @throws Throwable */ private ResultsTuple getNewlyCompletedResults() throws Throwable { ArrayList completedResults = new ArrayList(); ArrayList errorResults = new ArrayList(); for (int i = 0; i < threads.length; i++) { if (!alreadyFired[i] && started[i] && !threads[i].isAlive()) { alreadyFired[i] = true; if (log.isDebugEnabled()) { log.debug("Thread " + (i+1) + " of " + threads.length + " has recently completed, releasing resources"); } if (runnables[i].getResult() instanceof Throwable) { Throwable throwable = (Throwable) runnables[i].getResult(); runnables[i] = null; threads[i] = null; if (ignoreExceptions) { // Ignore exceptions if (log.isWarnEnabled()) { log.warn("Ignoring exception (property " + "threaded-service.ignore-exceptions-in-multi is set to true)", throwable); } errorResults.add(throwable); } else { throw throwable; } } else { completedResults.add(runnables[i].getResult()); runnables[i] = null; threads[i] = null; } } } Throwable[] ignoredErrors = new Throwable[] {}; if (errorResults.size() > 0) { ignoredErrors = (Throwable[]) errorResults.toArray(new Throwable[errorResults.size()]); } return new ResultsTuple(completedResults, ignoredErrors); } /** * Starts pending threads such that the total of running threads never exceeds the * maximum count set in the JetS3t property threaded-service.max-thread-count. * * @throws Throwable */ private void startPendingThreads() throws Throwable { // Count active threads that are running (i.e. have been started but final event not fired) int runningThreadCount = 0; for (int i = 0; i < runnables.length; i++) { if (started[i] && !alreadyFired[i]) { runningThreadCount++; } } // Start threads until we are running the maximum number allowed. for (int i = 0; runningThreadCount < maxThreadCount && i < started.length; i++) { if (!started[i]) { threads[i] = new Thread(runnables[i]); threads[i].start(); started[i] = true; runningThreadCount++; if (log.isDebugEnabled()) { log.debug("Thread " + (i+1) + " of " + runnables.length + " has started"); } } } } /** * @return * the number of threads that have not finished running (sum of those currently running, and those awaiting start) */ private int getPendingThreadCount() { int pendingThreadCount = 0; for (int i = 0; i < runnables.length; i++) { if (!alreadyFired[i]) { pendingThreadCount++; } } return pendingThreadCount; } /** * Invokes the {@link AbstractRunnable#forceInterrupt} on all threads being managed. * */ private void forceInterruptAllRunnables() { if (log.isDebugEnabled()) { log.debug("Setting force interrupt flag on all runnables"); } for (int i = 0; i < runnables.length; i++) { if (runnables[i] != null) { runnables[i].forceInterrupt(); runnables[i] = null; } } } /** * Runs and manages all the threads involved in a multi-operation. * */ public void run() { if (log.isDebugEnabled()) { log.debug("Started ThreadManager"); } final boolean[] interrupted = new boolean[] { false }; /* * Create a cancel event trigger, so all the managed threads can be cancelled if required. */ final CancelEventTrigger cancelEventTrigger = new CancelEventTrigger() { private static final long serialVersionUID = 6328417466929608235L; public void cancelTask(Object eventSource) { if (log.isDebugEnabled()) { log.debug("Cancel task invoked on ThreadManager"); } // Flag that this ThreadManager class should shutdown. interrupted[0] = true; // Set force interrupt flag for all runnables. forceInterruptAllRunnables(); } }; // Actual thread management happens in the code block below. try { // Start some threads startPendingThreads(); threadWatcher.updateThreadsCompletedCount(0, cancelEventTrigger); fireStartEvent(threadWatcher); // Loop while threads haven't been interrupted/cancelled, and at least one thread is // still active (ie hasn't finished its work) while (!interrupted[0] && getPendingThreadCount() > 0) { try { // Shut down threads if this service has been shutdown. if (isShutdown[0]) { throw new InterruptedException("StorageServiceMulti#shutdown method invoked"); } Thread.sleep(100); if (interrupted[0]) { // Do nothing, we've been interrupted during sleep. } else { if (System.currentTimeMillis() - lastProgressEventFiredTime > sleepTime) { // Fire progress event. int completedThreads = runnables.length - getPendingThreadCount(); threadWatcher.updateThreadsCompletedCount(completedThreads, cancelEventTrigger); ResultsTuple results = getNewlyCompletedResults(); lastProgressEventFiredTime = System.currentTimeMillis(); fireProgressEvent(threadWatcher, results.completedResults); if (results.errorResults.length > 0) { fireIgnoredErrorsEvent(threadWatcher, results.errorResults); } } // Start more threads. startPendingThreads(); } } catch (InterruptedException e) { interrupted[0] = true; forceInterruptAllRunnables(); } } if (interrupted[0]) { fireCancelEvent(); } else { int completedThreads = runnables.length - getPendingThreadCount(); threadWatcher.updateThreadsCompletedCount(completedThreads, cancelEventTrigger); ResultsTuple results = getNewlyCompletedResults(); fireProgressEvent(threadWatcher, results.completedResults); if (results.completedResults.size() > 0) { if (log.isDebugEnabled()) { log.debug(results.completedResults.size() + " threads have recently completed"); } } if (results.errorResults.length > 0) { fireIgnoredErrorsEvent(threadWatcher, results.errorResults); } fireCompletedEvent(); } } catch (Throwable t) { if (log.isErrorEnabled()) { log.error("A thread failed with an exception. Firing ERROR event and cancelling all threads", t); } // Set force interrupt flag for all runnables. forceInterruptAllRunnables(); fireErrorEvent(t); } } public abstract void fireStartEvent(ThreadWatcher threadWatcher); public abstract void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults); public abstract void fireCompletedEvent(); public abstract void fireCancelEvent(); public abstract void fireErrorEvent(Throwable t); public abstract void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors); private class ResultsTuple { public List completedResults = null; public Throwable[] errorResults = null; public ResultsTuple(List completedResults, Throwable[] errorResults) { this.completedResults = completedResults; this.errorResults = errorResults; } } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/event/0002755000000000000000000000000011512775766020230 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/event/GetObjectsEvent.java0000644000000000000000000001060711450544246024114 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi.event; import org.jets3t.service.model.StorageObject; import org.jets3t.service.multi.ThreadedStorageService; import org.jets3t.service.multi.ThreadWatcher; /** * Multi-threaded service event fired by {@link ThreadedStorageService#getObjects(String, String[])}. *

* EVENT_IN_PROGRESS events include an array of the {@link StorageObject}s that have been retrieved * since the last progress event was fired. These objects are available via * {@link #getCompletedObjects()}. *

* EVENT_CANCELLED events include an array of the {@link StorageObject}s that had not been retrieved * before the operation was cancelled. These objects are available via * {@link #getCancelledObjects()}. * * @author James Murty */ public class GetObjectsEvent extends ServiceEvent { private StorageObject[] objects = null; private GetObjectsEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static GetObjectsEvent newErrorEvent(Throwable t, Object uniqueOperationId) { GetObjectsEvent event = new GetObjectsEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static GetObjectsEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { GetObjectsEvent event = new GetObjectsEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static GetObjectsEvent newInProgressEvent(ThreadWatcher threadWatcher, StorageObject[] completedObjects, Object uniqueOperationId) { GetObjectsEvent event = new GetObjectsEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setObjects(completedObjects); return event; } public static GetObjectsEvent newCompletedEvent(Object uniqueOperationId) { GetObjectsEvent event = new GetObjectsEvent(EVENT_COMPLETED, uniqueOperationId); return event; } public static GetObjectsEvent newCancelledEvent(StorageObject[] incompletedObjects, Object uniqueOperationId) { GetObjectsEvent event = new GetObjectsEvent(EVENT_CANCELLED, uniqueOperationId); event.setObjects(incompletedObjects); return event; } public static GetObjectsEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { GetObjectsEvent event = new GetObjectsEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setObjects(StorageObject[] objects) { this.objects = objects; } /** * @return * the {@link StorageObject}s that have been retrieved since the last progress event was fired. * @throws IllegalStateException * completed objects are only available from EVENT_IN_PROGRESS events. */ public StorageObject[] getCompletedObjects() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Completed Objects are only available from EVENT_IN_PROGRESS events"); } return objects; } /** * @return * the {@link StorageObject}s that were not retrieved before the operation was cancelled. * @throws IllegalStateException * cancelled objects are only available from EVENT_CANCELLED events. */ public StorageObject[] getCancelledObjects() throws IllegalStateException { if (getEventCode() != EVENT_CANCELLED) { throw new IllegalStateException("Cancelled Objects are only available from EVENT_CANCELLED events"); } return objects; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/event/DownloadObjectsEvent.java0000644000000000000000000001104311450544316025135 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi.event; import org.jets3t.service.model.StorageObject; import org.jets3t.service.multi.ThreadedStorageService; import org.jets3t.service.multi.ThreadWatcher; /** * Multi-threaded service event fired by * {@link ThreadedStorageService#downloadObjects(String, org.jets3t.service.multi.DownloadPackage[])}. *

* EVENT_IN_PROGRESS events include an array of the {@link StorageObject}s that have finished downloading * since the last progress event was fired. These objects are available via * {@link #getDownloadedObjects()}. *

* EVENT_CANCELLED events include an array of the {@link StorageObject}s that were not downloaded * before the operation was cancelled. These objects are available via * {@link #getCancelledObjects()}. * * @author James Murty */ public class DownloadObjectsEvent extends ServiceEvent { private StorageObject[] objects = null; private DownloadObjectsEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static DownloadObjectsEvent newErrorEvent(Throwable t, Object uniqueOperationId) { DownloadObjectsEvent event = new DownloadObjectsEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static DownloadObjectsEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { DownloadObjectsEvent event = new DownloadObjectsEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static DownloadObjectsEvent newInProgressEvent(ThreadWatcher threadWatcher, StorageObject[] completedObjects, Object uniqueOperationId) { DownloadObjectsEvent event = new DownloadObjectsEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setObjects(completedObjects); return event; } public static DownloadObjectsEvent newCompletedEvent(Object uniqueOperationId) { DownloadObjectsEvent event = new DownloadObjectsEvent(EVENT_COMPLETED, uniqueOperationId); return event; } public static DownloadObjectsEvent newCancelledEvent(StorageObject[] incompletedObjects, Object uniqueOperationId) { DownloadObjectsEvent event = new DownloadObjectsEvent(EVENT_CANCELLED, uniqueOperationId); event.setObjects(incompletedObjects); return event; } public static DownloadObjectsEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { DownloadObjectsEvent event = new DownloadObjectsEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setObjects(StorageObject[] objects) { this.objects = objects; } /** * @return * the {@link StorageObject}s that have finished downloading since the last progress event was fired. * @throws IllegalStateException * downloaded objects are only available from EVENT_IN_PROGRESS events. */ public StorageObject[] getDownloadedObjects() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Downloaded Objects are only available from EVENT_IN_PROGRESS events"); } return objects; } /** * @return * the {@link StorageObject}s that were not downloaded before the operation was cancelled. * @throws IllegalStateException * cancelled objects are only available from EVENT_CANCELLED events. */ public StorageObject[] getCancelledObjects() throws IllegalStateException { if (getEventCode() != EVENT_CANCELLED) { throw new IllegalStateException("Cancelled Objects are only available from EVENT_CANCELLED events"); } return objects; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/event/CreateObjectsEvent.java0000644000000000000000000001067511450544360024602 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi.event; import org.jets3t.service.model.StorageObject; import org.jets3t.service.multi.ThreadWatcher; import org.jets3t.service.multi.ThreadedStorageService; /** * Multi-threaded service event fired by * {@link ThreadedStorageService#putObjects(String, StorageObject[])}. *

* EVENT_IN_PROGRESS events include an array of the {@link StorageObject}s that have been created * since the last progress event was fired. These objects are available via * {@link #getCreatedObjects()}. *

* EVENT_CANCELLED events include an array of the {@link StorageObject}s that had not been created * before the operation was cancelled. These objects are available via * {@link #getCancelledObjects()}. * * @author James Murty */ public class CreateObjectsEvent extends ServiceEvent { private StorageObject[] objects = null; private CreateObjectsEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static CreateObjectsEvent newErrorEvent(Throwable t, Object uniqueOperationId) { CreateObjectsEvent event = new CreateObjectsEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static CreateObjectsEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { CreateObjectsEvent event = new CreateObjectsEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static CreateObjectsEvent newInProgressEvent(ThreadWatcher threadWatcher, StorageObject[] completedObjects, Object uniqueOperationId) { CreateObjectsEvent event = new CreateObjectsEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setObjects(completedObjects); return event; } public static CreateObjectsEvent newCompletedEvent(Object uniqueOperationId) { CreateObjectsEvent event = new CreateObjectsEvent(EVENT_COMPLETED, uniqueOperationId); return event; } public static CreateObjectsEvent newCancelledEvent(StorageObject[] incompletedObjects, Object uniqueOperationId) { CreateObjectsEvent event = new CreateObjectsEvent(EVENT_CANCELLED, uniqueOperationId); event.setObjects(incompletedObjects); return event; } public static CreateObjectsEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { CreateObjectsEvent event = new CreateObjectsEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setObjects(StorageObject[] objects) { this.objects = objects; } /** * @return * the {@link StorageObject}s that have been created since the last progress event was fired. * @throws IllegalStateException * created objects are only available from EVENT_IN_PROGRESS events. */ public StorageObject[] getCreatedObjects() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Created Objects are only available from EVENT_IN_PROGRESS events"); } return objects; } /** * @return * the {@link StorageObject}s that were not created before the operation was cancelled. * @throws IllegalStateException * cancelled objects are only available from EVENT_CANCELLED events. */ public StorageObject[] getCancelledObjects() throws IllegalStateException { if (getEventCode() != EVENT_CANCELLED) { throw new IllegalStateException("Cancelled Objects are only available from EVENT_CANCELLED events"); } return objects; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/event/UpdateACLEvent.java0000644000000000000000000001064311450544200023613 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi.event; import org.jets3t.service.model.StorageObject; import org.jets3t.service.multi.ThreadedStorageService; import org.jets3t.service.multi.ThreadWatcher; /** * Multi-threaded service event fired by * {@link ThreadedStorageService#putACLs(String, StorageObject[])}. *

* EVENT_IN_PROGRESS events include an array of the {@link StorageObject}s that have had their ACLs updated * since the last progress event was fired. These objects are available via * {@link #getObjectsWithUpdatedACL()}. *

* EVENT_CANCELLED events include an array of the {@link StorageObject}s that did not have their ACLs updated * before the operation was cancelled. These objects are available via * {@link #getCancelledObjects()}. * * @author James Murty */ public class UpdateACLEvent extends ServiceEvent { private StorageObject[] objects = null; private UpdateACLEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static UpdateACLEvent newErrorEvent(Throwable t, Object uniqueOperationId) { UpdateACLEvent event = new UpdateACLEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static UpdateACLEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { UpdateACLEvent event = new UpdateACLEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static UpdateACLEvent newInProgressEvent(ThreadWatcher threadWatcher, StorageObject[] completedObjects, Object uniqueOperationId) { UpdateACLEvent event = new UpdateACLEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setObjects(completedObjects); return event; } public static UpdateACLEvent newCompletedEvent(Object uniqueOperationId) { UpdateACLEvent event = new UpdateACLEvent(EVENT_COMPLETED, uniqueOperationId); return event; } public static UpdateACLEvent newCancelledEvent(StorageObject[] incompletedObjects, Object uniqueOperationId) { UpdateACLEvent event = new UpdateACLEvent(EVENT_CANCELLED, uniqueOperationId); event.setObjects(incompletedObjects); return event; } public static UpdateACLEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { UpdateACLEvent event = new UpdateACLEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setObjects(StorageObject[] objects) { this.objects = objects; } /** * @return * the {@link StorageObject}s that have had their ACLs updated since the last progress event was fired. * @throws IllegalStateException * updated objects are only available from EVENT_IN_PROGRESS events. */ public StorageObject[] getObjectsWithUpdatedACL() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Completed Objects are only available from EVENT_IN_PROGRESS events"); } return objects; } /** * @return * the {@link StorageObject}s that did not have ACLs updated before the operation was cancelled. * @throws IllegalStateException * cancelled objects are only available from EVENT_CANCELLED events. */ public StorageObject[] getCancelledObjects() throws IllegalStateException { if (getEventCode() != EVENT_CANCELLED) { throw new IllegalStateException("Cancelled Objects are only available from EVENT_CANCELLED events"); } return objects; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/event/LookupACLEvent.java0000644000000000000000000001063711450544220023647 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi.event; import org.jets3t.service.model.StorageObject; import org.jets3t.service.multi.ThreadWatcher; import org.jets3t.service.multi.ThreadedStorageService; /** * Multi-threaded service event fired by * {@link ThreadedStorageService#getObjectACLs(String, StorageObject[])}. *

* EVENT_IN_PROGRESS events include an array of the {@link StorageObject}s whose ACLs have been retrieved * since the last progress event was fired. These objects are available via * {@link #getObjectsWithACL()}. *

* EVENT_CANCELLED events include an array of the {@link StorageObject}s whose ACLs had not been retrieved * before the operation was cancelled. These objects are available via * {@link #getCancelledObjects()}. * * @author James Murty */ public class LookupACLEvent extends ServiceEvent { private StorageObject[] objects = null; private LookupACLEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static LookupACLEvent newErrorEvent(Throwable t, Object uniqueOperationId) { LookupACLEvent event = new LookupACLEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static LookupACLEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { LookupACLEvent event = new LookupACLEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static LookupACLEvent newInProgressEvent(ThreadWatcher threadWatcher, StorageObject[] completedObjects, Object uniqueOperationId) { LookupACLEvent event = new LookupACLEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setObjects(completedObjects); return event; } public static LookupACLEvent newCompletedEvent(Object uniqueOperationId) { LookupACLEvent event = new LookupACLEvent(EVENT_COMPLETED, uniqueOperationId); return event; } public static LookupACLEvent newCancelledEvent(StorageObject[] incompletedObjects, Object uniqueOperationId) { LookupACLEvent event = new LookupACLEvent(EVENT_CANCELLED, uniqueOperationId); event.setObjects(incompletedObjects); return event; } public static LookupACLEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { LookupACLEvent event = new LookupACLEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setObjects(StorageObject[] objects) { this.objects = objects; } /** * @return * the {@link StorageObject}s whose ACLs have been retrieved since the last progress event was fired. * @throws IllegalStateException * objects with ACL are only available from EVENT_IN_PROGRESS events. */ public StorageObject[] getObjectsWithACL() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Completed Objects are only available from EVENT_IN_PROGRESS events"); } return objects; } /** * @return * the {@link StorageObject}s whose ACLs were not retrieved before the operation was cancelled. * @throws IllegalStateException * cancelled objects are only available from EVENT_CANCELLED events. */ public StorageObject[] getCancelledObjects() throws IllegalStateException { if (getEventCode() != EVENT_CANCELLED) { throw new IllegalStateException("Cancelled Objects are only available from EVENT_CANCELLED events"); } return objects; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/event/ListObjectsEvent.java0000644000000000000000000000754511450000672024305 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi.event; import java.util.List; import org.jets3t.service.StorageObjectsChunk; import org.jets3t.service.multi.ThreadedStorageService; import org.jets3t.service.multi.ThreadWatcher; /** * Multi-threaded service event fired by * {@link ThreadedStorageService#listObjects(String, String[], String, long)}. *

* EVENT_IN_PROGRESS events include a List of {@link StorageObjectsChunk} objects * that contain information about the objects and common-prefixes for the * bucket listing operation. Each chunk object will contain a prefix identifying * the prefix value used by the listing operation that produced the chunk. * These objects are available via {@link #getChunkList()}. * * @author James Murty */ public class ListObjectsEvent extends ServiceEvent { private List chunkList = null; private ListObjectsEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static ListObjectsEvent newErrorEvent(Throwable t, Object uniqueOperationId) { ListObjectsEvent event = new ListObjectsEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static ListObjectsEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { ListObjectsEvent event = new ListObjectsEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static ListObjectsEvent newInProgressEvent(ThreadWatcher threadWatcher, List chunkList, Object uniqueOperationId) { ListObjectsEvent event = new ListObjectsEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setChunkList(chunkList); return event; } public static ListObjectsEvent newCompletedEvent(Object uniqueOperationId) { ListObjectsEvent event = new ListObjectsEvent(EVENT_COMPLETED, uniqueOperationId); return event; } public static ListObjectsEvent newCancelledEvent(Object uniqueOperationId) { ListObjectsEvent event = new ListObjectsEvent(EVENT_CANCELLED, uniqueOperationId); return event; } public static ListObjectsEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { ListObjectsEvent event = new ListObjectsEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setChunkList(List chunkList) { this.chunkList = chunkList; } /** * @return * a list of the {@link StorageObjectsChunk}s that have been generated since the * last progress event was fired. * @throws IllegalStateException * listed objects are only available from EVENT_IN_PROGRESS events. */ public List getChunkList() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Chunk list is only available from EVENT_IN_PROGRESS events"); } return this.chunkList; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/event/ServiceEvent.java0000644000000000000000000001436011450005634023454 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi.event; import org.jets3t.service.multi.ThreadedStorageService; import org.jets3t.service.multi.ThreadWatcher; /** * Base class of all events produced by {@link ThreadedStorageService}. *

* Every event has an event code that indicates the state of a process when the event was * generated. The event code will also give a guide as to what information the event will contain. *

* The event codes, and their meanings, are: *

    *
  • EVENT_STARTED: An operation has commenced, but no work has yet been done.
  • *
  • EVENT_IN_PROGRESS: An operation is in progress. Progress events are fired at regular time * intervals, and will include information about any work that have been completed * as part of the overall operation.
  • *
  • EVENT_COMPLETED: An operation has completed, and all the work has been done.
  • *
  • EVENT_CANCELLED: An operation was started but has been cancelled before it could complete. * If an operation is cancelled, this event will be fired instead of the EVENT_COMPLETED.
  • *
  • EVENT_ERROR: An operation has failed and an exception has been thrown. The error * will be availble from {@link #getErrorCause()}
  • *
  • EVENT_IGNORED_ERRORS: One or more operations have failed but ,because the * "threaded-service.ignore-exceptions-in-multi" JetS3t property value is set to true, * the overall operation has continued. The errors will be available from * {@link #getIgnoredErrors()}
  • *
*

* EVENT_STARTED and EVENT_IN_PROGRESS events may include a {@link ThreadWatcher} object containing * detailed information about the progress of an operation, such as how many threads have * completed and, of uploads and downloads, how many bytes have been transferred at what speed and * how long until the transfer is complete. *

* See the event object specific to the operation you are performing for more details about the * information available in service events. * * @author James Murty */ public abstract class ServiceEvent { public static final int EVENT_ERROR = 0; public static final int EVENT_STARTED = 1; public static final int EVENT_COMPLETED = 2; public static final int EVENT_IN_PROGRESS = 3; public static final int EVENT_CANCELLED = 4; public static final int EVENT_IGNORED_ERRORS = 5; private int eventCode = 0; private Object uniqueOperationId = null; private Throwable t = null; private ThreadWatcher threadWatcher = null; private Throwable[] ignoredErrors = null; protected ServiceEvent(int eventCode, Object uniqueOperationId) { this.eventCode = eventCode; this.uniqueOperationId = uniqueOperationId; } protected void setThreadWatcher(ThreadWatcher threadWatcher) { this.threadWatcher = threadWatcher; } protected void setErrorCause(Throwable t) { this.t = t; } protected void setIgnoredErrors(Throwable[] ignoredErrors) { this.ignoredErrors = ignoredErrors; } public Object getUniqueOperationId() { return uniqueOperationId; } /** * @return * the event code, which will match one of this class's public static EVENT_XXX variables. */ public int getEventCode() { return eventCode; } /** * @return * the error that caused an operation to fail. * @throws IllegalStateException * an error cause can only be retrieved from an EVENT_ERROR event. */ public Throwable getErrorCause() throws IllegalStateException { if (eventCode != EVENT_ERROR) { throw new IllegalStateException("Error Cause is only available from EVENT_ERROR events"); } return t; } /** * @return * a list of one or more errors that occurred during an operation, but which were * ignored at the time (so the overall operation continued). * @throws IllegalStateException * ignored errors can only be retrieved from an EVENT_IGNORED_ERRORS event. */ public Throwable[] getIgnoredErrors() throws IllegalStateException { if (eventCode != EVENT_IGNORED_ERRORS) { throw new IllegalStateException("Ignored errors are only available from EVENT_IGNORED_ERRORS events"); } return ignoredErrors; } /** * @return * a thread watcher object containing information about the progress of an operation. * @throws IllegalStateException * a thread watcher can only be retrieved from an EVENET_STARTED or EVENT_IN_PROGRESS event. */ public ThreadWatcher getThreadWatcher() throws IllegalStateException { if (eventCode != EVENT_STARTED && eventCode != EVENT_IN_PROGRESS) { throw new IllegalStateException("Thread Watcher is only available from EVENT_STARTED " + "or EVENT_IN_PROGRESS events"); } return threadWatcher; } @Override public String toString() { String eventText = eventCode == EVENT_ERROR ? "EVENT_ERROR" : eventCode == EVENT_STARTED ? "EVENT_STARTED" : eventCode == EVENT_COMPLETED ? "EVENT_COMPLETED" : eventCode == EVENT_IN_PROGRESS ? "EVENT_IN_PROGRESS" : eventCode == EVENT_CANCELLED ? "EVENT_CANCELLED" : eventCode == EVENT_IGNORED_ERRORS ? "EVENT_IGNORED_ERRORS" : "Unrecognised event status code: " + eventCode; if (eventCode == EVENT_ERROR && getErrorCause() != null) { return eventText + " " + getErrorCause(); } else { return eventText; } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/event/CreateBucketsEvent.java0000644000000000000000000001066311450544402024603 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi.event; import org.jets3t.service.model.StorageBucket; import org.jets3t.service.multi.ThreadedStorageService; import org.jets3t.service.multi.ThreadWatcher; /** * Multi-threaded service event fired by {@link ThreadedStorageService#createBuckets(String[])}. *

* EVENT_IN_PROGRESS events include an array of the {@link StorageBucket}s that have been created * since the last progress event was fired. These objects are available via * {@link #getCreatedBuckets()}. *

* EVENT_CANCELLED events include an array of the {@link StorageBucket}s that had not been created * before the operation was cancelled. These objects are available via * {@link #getCancelledBuckets()}. * * @author James Murty */ public class CreateBucketsEvent extends ServiceEvent { private StorageBucket[] buckets = null; private CreateBucketsEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static CreateBucketsEvent newErrorEvent(Throwable t, Object uniqueOperationId) { CreateBucketsEvent event = new CreateBucketsEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static CreateBucketsEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { CreateBucketsEvent event = new CreateBucketsEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static CreateBucketsEvent newInProgressEvent(ThreadWatcher threadWatcher, StorageBucket[] completedBuckets, Object uniqueOperationId) { CreateBucketsEvent event = new CreateBucketsEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setBuckets(completedBuckets); return event; } public static CreateBucketsEvent newCompletedEvent(Object uniqueOperationId) { CreateBucketsEvent event = new CreateBucketsEvent(EVENT_COMPLETED, uniqueOperationId); return event; } public static CreateBucketsEvent newCancelledEvent(StorageBucket[] incompletedBuckets, Object uniqueOperationId) { CreateBucketsEvent event = new CreateBucketsEvent(EVENT_CANCELLED, uniqueOperationId); event.setBuckets(incompletedBuckets); return event; } public static CreateBucketsEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { CreateBucketsEvent event = new CreateBucketsEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setBuckets(StorageBucket[] buckets) { this.buckets = buckets; } /** * @return * the {@link StorageBucket}s that have been created since the last progress event was fired. * @throws IllegalStateException * created buckets are only available from EVENT_IN_PROGRESS events. */ public StorageBucket[] getCreatedBuckets() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Created Buckets are only available from EVENT_IN_PROGRESS events"); } return buckets; } /** * @return * the {@link StorageBucket}s that had not been created before the operation was cancelled. * @throws IllegalStateException * cancelled buckets are only available from EVENT_CANCELLED events. */ public StorageBucket[] getCancelledBuckets() throws IllegalStateException { if (getEventCode() != EVENT_CANCELLED) { throw new IllegalStateException("Cancelled Buckets are only available from EVENT_CANCELLED events"); } return buckets; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/event/DeleteObjectsEvent.java0000644000000000000000000001066011450544342024573 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi.event; import org.jets3t.service.model.StorageObject; import org.jets3t.service.multi.ThreadWatcher; import org.jets3t.service.multi.ThreadedStorageService; /** * Multi-threaded service event fired by * {@link ThreadedStorageService#deleteObjects(String, String[])}. *

* EVENT_IN_PROGRESS events include an array of the {@link StorageObject}s that have been deleted * since the last progress event was fired. These objects are available via * {@link #getDeletedObjects()}. *

* EVENT_CANCELLED events include an array of the {@link StorageObject}s that had not been deleted * before the operation was cancelled. These objects are available via * {@link #getCancelledObjects()}. * * @author James Murty */ public class DeleteObjectsEvent extends ServiceEvent { private StorageObject[] objects = null; private DeleteObjectsEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static DeleteObjectsEvent newErrorEvent(Throwable t, Object uniqueOperationId) { DeleteObjectsEvent event = new DeleteObjectsEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static DeleteObjectsEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { DeleteObjectsEvent event = new DeleteObjectsEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static DeleteObjectsEvent newInProgressEvent(ThreadWatcher threadWatcher, StorageObject[] deletedObjects, Object uniqueOperationId) { DeleteObjectsEvent event = new DeleteObjectsEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setObjects(deletedObjects); return event; } public static DeleteObjectsEvent newCompletedEvent(Object uniqueOperationId) { DeleteObjectsEvent event = new DeleteObjectsEvent(EVENT_COMPLETED, uniqueOperationId); return event; } public static DeleteObjectsEvent newCancelledEvent(StorageObject[] remainingObjects, Object uniqueOperationId) { DeleteObjectsEvent event = new DeleteObjectsEvent(EVENT_CANCELLED, uniqueOperationId); event.setObjects(remainingObjects); return event; } public static DeleteObjectsEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { DeleteObjectsEvent event = new DeleteObjectsEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setObjects(StorageObject[] objects) { this.objects = objects; } /** * @return * the {@link StorageObject}s that have been deleted since the last progress event was fired. * @throws IllegalStateException * deleted objects are only available from EVENT_IN_PROGRESS events. */ public StorageObject[] getDeletedObjects() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Deleted Objects are only available from EVENT_IN_PROGRESS events"); } return objects; } /** * @return * the {@link StorageObject}s that were not deleted before the operation was cancelled. * @throws IllegalStateException * cancelled objects are only available from EVENT_CANCELLED events. */ public StorageObject[] getCancelledObjects() throws IllegalStateException { if (getEventCode() != EVENT_CANCELLED) { throw new IllegalStateException("Cancelled Objects are only available from EVENT_CANCELLED events"); } return objects; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/event/CopyObjectsEvent.java0000644000000000000000000001432411450546054024306 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi.event; import java.util.Map; import org.jets3t.service.StorageService; import org.jets3t.service.model.StorageObject; import org.jets3t.service.multi.ThreadWatcher; import org.jets3t.service.multi.ThreadedStorageService; /** * Multi-threaded service event fired by * {@link ThreadedStorageService#copyObjects(String, String, String[], StorageObject[], boolean)}. *

* EVENT_IN_PROGRESS events include an array of the Map results returned by the * copy operation, see * {@link StorageService#copyObject(String, String, String, StorageObject, boolean)}. * These objects are available via {@link #getCopyResults()}. *

* EVENT_CANCELLED events include an array of the {@link StorageObject}s that had not been * copied before the operation was cancelled. These objects are available via * {@link #getCancelledObjects()}. * * @author James Murty */ public class CopyObjectsEvent extends ServiceEvent { private Map[] results = null; private StorageObject[] copyCancelledObjects = null; private StorageObject[] destinationObjects = null; private String[] sourceObjectKeys = null; private CopyObjectsEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static CopyObjectsEvent newErrorEvent(Throwable t, Object uniqueOperationId) { CopyObjectsEvent event = new CopyObjectsEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static CopyObjectsEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { CopyObjectsEvent event = new CopyObjectsEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static CopyObjectsEvent newInProgressEvent(ThreadWatcher threadWatcher, Map[] completedResults, Object uniqueOperationId) { CopyObjectsEvent event = new CopyObjectsEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setResults(completedResults); return event; } public static CopyObjectsEvent newCompletedEvent(Object uniqueOperationId, String[] sourceObjectKeys, StorageObject[] destinationObjects) { CopyObjectsEvent event = new CopyObjectsEvent(EVENT_COMPLETED, uniqueOperationId); event.setDestinationObjects(destinationObjects); event.setSourceObjectKeys(sourceObjectKeys); return event; } public static CopyObjectsEvent newCancelledEvent(StorageObject[] incompletedObjects, Object uniqueOperationId) { CopyObjectsEvent event = new CopyObjectsEvent(EVENT_CANCELLED, uniqueOperationId); event.setCopyCancelledObjects(incompletedObjects); return event; } public static CopyObjectsEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { CopyObjectsEvent event = new CopyObjectsEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setResults(Map[] results) { this.results = results; } private void setSourceObjectKeys(String[] sourceObjectKeys) { this.sourceObjectKeys = sourceObjectKeys; } private void setCopyCancelledObjects(StorageObject[] objects) { this.copyCancelledObjects = objects; } private void setDestinationObjects(StorageObject[] objects) { this.destinationObjects = objects; } /** * @return * the Map results for the objects that have been copied since the last progress event was fired. * @throws IllegalStateException * results are only available from EVENT_IN_PROGRESS events. */ public Map[] getCopyResults() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException( "Copy results are only available from EVENT_IN_PROGRESS events"); } return results; } /** * @return * the {@link StorageObject}s that were not copied before the operation was cancelled. * @throws IllegalStateException * cancelled objects are only available from EVENT_CANCELLED events. */ public StorageObject[] getCancelledObjects() throws IllegalStateException { if (getEventCode() != EVENT_CANCELLED) { throw new IllegalStateException("Cancelled Objects are only available from EVENT_CANCELLED events"); } return copyCancelledObjects; } /** * @return * the {@link StorageObject}s that were created by a a successful copy operation. * @throws IllegalStateException * copied objects are only available from EVENT_COMPLETED events. */ public StorageObject[] getCopiedObjects() throws IllegalStateException { if (getEventCode() != EVENT_COMPLETED) { throw new IllegalStateException("Cancelled Objects are only available from EVENT_COMPLETED events"); } return destinationObjects; } /** * @return * the key names of source objects that were copied in a successful operation. * @throws IllegalStateException * source object key names are only available from EVENT_COMPLETED events. */ public String[] getSourceObjectKeys() throws IllegalStateException { if (getEventCode() != EVENT_COMPLETED) { throw new IllegalStateException("Source Objects are only available from EVENT_COMPLETED events"); } return sourceObjectKeys; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/event/GetObjectHeadsEvent.java0000644000000000000000000001073711450544276024705 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi.event; import org.jets3t.service.model.StorageObject; import org.jets3t.service.multi.ThreadedStorageService; import org.jets3t.service.multi.ThreadWatcher; /** * Multi-threaded service event fired by * {@link ThreadedStorageService#getObjectsHeads(String, String[])}. *

* EVENT_IN_PROGRESS events include an array of the {@link StorageObject}s that have been retrieved * since the last progress event was fired. These objects are available via * {@link #getCompletedObjects()}. *

* EVENT_CANCELLED events include an array of the {@link StorageObject}s that had not been retrieved * before the operation was cancelled. These objects are available via * {@link #getCancelledObjects()}. * * @author James Murty */ public class GetObjectHeadsEvent extends ServiceEvent { private StorageObject[] objects = null; private GetObjectHeadsEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static GetObjectHeadsEvent newErrorEvent(Throwable t, Object uniqueOperationId) { GetObjectHeadsEvent event = new GetObjectHeadsEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static GetObjectHeadsEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { GetObjectHeadsEvent event = new GetObjectHeadsEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static GetObjectHeadsEvent newInProgressEvent(ThreadWatcher threadWatcher, StorageObject[] completedObjects, Object uniqueOperationId) { GetObjectHeadsEvent event = new GetObjectHeadsEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setObjects(completedObjects); return event; } public static GetObjectHeadsEvent newCompletedEvent(Object uniqueOperationId) { GetObjectHeadsEvent event = new GetObjectHeadsEvent(EVENT_COMPLETED, uniqueOperationId); return event; } public static GetObjectHeadsEvent newCancelledEvent(StorageObject[] incompletedObjects, Object uniqueOperationId) { GetObjectHeadsEvent event = new GetObjectHeadsEvent(EVENT_CANCELLED, uniqueOperationId); event.setObjects(incompletedObjects); return event; } public static GetObjectHeadsEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { GetObjectHeadsEvent event = new GetObjectHeadsEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setObjects(StorageObject[] objects) { this.objects = objects; } /** * @return * the {@link StorageObject}s that have been retrieved since the last progress event was fired. * @throws IllegalStateException * completed objects are only available from EVENT_IN_PROGRESS events. */ public StorageObject[] getCompletedObjects() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Completed Objects are only available from EVENT_IN_PROGRESS events"); } return objects; } /** * @return * the {@link StorageObject}s that were not retrieved before the operation was cancelled. * @throws IllegalStateException * cancelled objects are only available from EVENT_CANCELLED events. */ public StorageObject[] getCancelledObjects() throws IllegalStateException { if (getEventCode() != EVENT_CANCELLED) { throw new IllegalStateException("Cancelled Objects are only available from EVENT_CANCELLED events"); } return objects; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/ThreadWatcher.java0000644000000000000000000001711211537563564022475 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi; import org.jets3t.service.io.BytesProgressWatcher; /** * A thread watcher is associated with a multi-threaded operation and contains information about * the progress of the operation. *

* As a minimum, this object will contain a count of the total number of threads involved in the operation * (via {@link #getThreadCount}) and the count of threads that have already finished * (via {@link #getCompletedThreads}). *

* For operations involving data transfer, such as uploads or downloads, this object may * also include a count of the total bytes being transferred (via {@link #getBytesTotal}) and a count * of how many bytes have already been transferred (via {@link #getBytesTransferred}). The * availability of this information is indicated by the result of {@link #isBytesTransferredInfoAvailable()}. *

* Further data tranfer information may be also available, such as the current transfer rate (via * {@link #getBytesPerSecond()}) and an estimate of the time remaining until the transfer is * completed (via {@link #getTimeRemaining()}). The availability of this information is indicated * by the result of {@link #isTimeRemainingAvailable()}. *

* It is possible to cancel some operations. If an operation may be cancelled, this object will * include a {@link CancelEventTrigger} (available from {@link #getCancelEventListener()}) which can * be used to trigger a cancellation. Whether the operation can be cancelled is indicated by * {@link #isCancelTaskSupported()}. * * @author James Murty */ public class ThreadWatcher { private long completedThreads = 0; private long threadCount = 0; private CancelEventTrigger cancelEventListener = null; private BytesProgressWatcher[] progressWatchers = null; public ThreadWatcher(BytesProgressWatcher[] progressWatchers) { this.progressWatchers = progressWatchers; this.threadCount = this.progressWatchers.length; } public ThreadWatcher(long threadCount) { this.threadCount = threadCount; } /** * Sets information about the number of threads completed and the total number of threads. * * @param completedThreads * the number of threads that have completed. */ public void updateThreadsCompletedCount(long completedThreads) { updateThreadsCompletedCount(completedThreads, null); } /** * Sets information about the number of threads completed and the total number of threads, * as well as setting the cancellation listener that will be notified if the event is cancelled. * * @param completedThreads * the number of threads that have completed. * @param cancelEventListener * the listener to notify of cancellation events. */ public void updateThreadsCompletedCount(long completedThreads, CancelEventTrigger cancelEventListener) { this.completedThreads = completedThreads; this.cancelEventListener = cancelEventListener; } /** * @return * the number of threads that have completed. */ public long getCompletedThreads() { return completedThreads; } /** * @return * the total number of threads involved in an operation. */ public long getThreadCount() { return threadCount; } /** * If this method returns true, the methods {@link #getBytesTotal()} and {@link #getBytesTransferred()} * will contain information about the amount of data being transferred by the watched threads. * * @return * true if this watcher contains information about the bytes transferred by * the threads it is watching. */ public boolean isBytesTransferredInfoAvailable() { return (progressWatchers != null); } /** * @return * the expected total of bytes that will be transferred by the watched threads. * @throws IllegalStateException * if the bytes transferred information is not available - check this availability * with the {@link #isBytesTransferredInfoAvailable()} method. */ public long getBytesTotal() throws IllegalStateException { if (!isBytesTransferredInfoAvailable()) { throw new IllegalStateException("Bytes Transferred Info is not available in this object"); } return BytesProgressWatcher.sumBytesToTransfer(progressWatchers); } /** * @return * the count of bytes that have been transferred by the watched threads. * @throws IllegalStateException * if the bytes transferred information is not available - check this availability * with the {@link #isBytesTransferredInfoAvailable()} method. */ public long getBytesTransferred() { if (!isBytesTransferredInfoAvailable()) { throw new IllegalStateException("Bytes Transferred Info is not available in this object"); } return BytesProgressWatcher.sumBytesTransferred(progressWatchers); } /** * @return * an estimate of the recent rate of bytes/second transfer speed. */ public long getBytesPerSecond() { return BytesProgressWatcher.calculateRecentByteRatePerSecond(progressWatchers); } /** * If this method returns true, the method {@link #getTimeRemaining()} will contain * an estimate of the completion time for the data transfer. * * @return * true if this watcher contains an estimate of the completion time for the data transfer. */ public boolean isTimeRemainingAvailable() { return (progressWatchers != null); } /** * @return * an estimate of the how many seconds until the data transfer completes, based on the * overall byte rate of the transmission. * @throws IllegalStateException * if the time remaining estimave is not available - check this availability * with the {@link #isTimeRemainingAvailable()} method. */ public long getTimeRemaining() { if (!isTimeRemainingAvailable()) { throw new IllegalStateException("Time remaining estimate is not available in this object"); } return BytesProgressWatcher.calculateRemainingTime(progressWatchers); } /** * @return * true if the operation this object is associated with can be cancelled, and a * {@link CancelEventTrigger} is available. */ public boolean isCancelTaskSupported() { return cancelEventListener != null; } /** * Convenience method to trigger an event cancellation via {@link CancelEventTrigger#cancelTask} * if this thread watcher is associated with an operation that can be cancelled. */ public void cancelTask() { if (isCancelTaskSupported()) { cancelEventListener.cancelTask(this); } } /** * @return * the cancel event trigger associated with an operation, if any. */ public CancelEventTrigger getCancelEventListener() { return cancelEventListener; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/DownloadPackage.java0000644000000000000000000001145511441613550022760 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.io.GZipInflatingOutputStream; import org.jets3t.service.model.StorageObject; import org.jets3t.service.security.EncryptionUtil; /** * A simple container object to associate a {@link StorageObject} with an * output file or output stream to which the object's data will be written. * * @author James Murty */ public class DownloadPackage { private static final Log log = LogFactory.getLog(DownloadPackage.class); protected StorageObject object = null; protected File outputFile = null; protected OutputStream outputStream = null; protected boolean isUnzipping = false; protected EncryptionUtil encryptionUtil = null; private boolean appendToFile = false; public DownloadPackage(StorageObject object, File outputFile) { this(object, outputFile, false, null); } public DownloadPackage(StorageObject object, File outputFile, boolean isUnzipping, EncryptionUtil encryptionUtil) { this.object = object; this.outputFile = outputFile; this.isUnzipping = isUnzipping; this.encryptionUtil = encryptionUtil; } public DownloadPackage(StorageObject object, OutputStream outputStream) { this(object, outputStream, false, null); } public DownloadPackage(StorageObject object, OutputStream outputStream, boolean isUnzipping, EncryptionUtil encryptionUtil) { this.object = object; this.outputStream = outputStream; this.isUnzipping = isUnzipping; this.encryptionUtil = encryptionUtil; } public StorageObject getObject() { return object; } public void setObject(StorageObject object) { this.object = object; } /** * @return the target output file for data, or null if this package * has an output stream as its target. */ public File getDataFile() { return outputFile; } public boolean isAppendToFile() { return appendToFile; } /** * Data will be appended to the target file instead of overwriting it. * This option is relevant only for packages with a target file, not * those with a target output stream. * * @param appendToFile */ public void setAppendToFile(boolean appendToFile) { this.appendToFile = appendToFile; } /** * Creates an output stream to receive the object's data. The output stream is either * the output stream provided to this package in its constructor, or an * automatically-created FileOutputStream if a File object was provided as the target * output object. The output stream will also be wrapped in a GZipInflatingOutputStream if * isUnzipping is true and/or a decrypting output stream if this package has an associated * non-null EncryptionUtil. * * @return * an output stream that writes data to the output target managed by this class. * * @throws Exception */ public OutputStream getOutputStream() throws Exception { OutputStream outputStream = null; if (outputFile != null) { // Create parent directories for file, if necessary. if (outputFile.getParentFile() != null) { outputFile.getParentFile().mkdirs(); } outputStream = new FileOutputStream(outputFile, appendToFile); } else { outputStream = this.outputStream; } if (isUnzipping) { log.debug("Inflating gzipped data for object: " + object.getKey()); outputStream = new GZipInflatingOutputStream(outputStream); } if (encryptionUtil != null) { log.debug("Decrypting encrypted data for object: " + object.getKey()); outputStream = encryptionUtil.decrypt(outputStream); } return outputStream; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/StorageServiceEventListener.java0000644000000000000000000000361311537563564025406 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi; import org.jets3t.service.multi.event.CopyObjectsEvent; import org.jets3t.service.multi.event.CreateBucketsEvent; import org.jets3t.service.multi.event.CreateObjectsEvent; import org.jets3t.service.multi.event.DeleteObjectsEvent; import org.jets3t.service.multi.event.DownloadObjectsEvent; import org.jets3t.service.multi.event.GetObjectHeadsEvent; import org.jets3t.service.multi.event.GetObjectsEvent; import org.jets3t.service.multi.event.ListObjectsEvent; import org.jets3t.service.multi.event.LookupACLEvent; import org.jets3t.service.multi.event.UpdateACLEvent; /** * Listener for events produced by {@link ThreadedStorageService}. * * @author James Murty */ public interface StorageServiceEventListener { public void event(ListObjectsEvent event); public void event(CreateObjectsEvent event); public void event(CopyObjectsEvent event); public void event(CreateBucketsEvent event); public void event(DeleteObjectsEvent event); public void event(GetObjectsEvent event); public void event(GetObjectHeadsEvent event); public void event(LookupACLEvent event); public void event(UpdateACLEvent event); public void event(DownloadObjectsEvent event); } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/s3/0002755000000000000000000000000011537563564017432 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/s3/ThreadedS3Service.java0000644000000000000000000004333111547526520023536 0ustar package org.jets3t.service.multi.s3; import java.util.ArrayList; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.S3Service; import org.jets3t.service.ServiceException; import org.jets3t.service.io.BytesProgressWatcher; import org.jets3t.service.io.InterruptableInputStream; import org.jets3t.service.io.ProgressMonitoredInputStream; import org.jets3t.service.model.MultipartCompleted; import org.jets3t.service.model.MultipartUpload; import org.jets3t.service.model.S3Object; import org.jets3t.service.model.StorageObject; import org.jets3t.service.multi.StorageServiceEventListener; import org.jets3t.service.multi.ThreadWatcher; import org.jets3t.service.multi.ThreadedStorageService; import org.jets3t.service.multi.event.ServiceEvent; public class ThreadedS3Service extends ThreadedStorageService { private static final Log log = LogFactory.getLog(ThreadedS3Service.class); public ThreadedS3Service(S3Service service, StorageServiceEventListener listener) throws ServiceException { super(service, listener); } @Override protected void fireServiceEvent(ServiceEvent event) { if (serviceEventListeners.size() == 0) { if (log.isWarnEnabled()) { log.warn("ThreadedS3Service invoked without any StorageServiceEventListener objects, this is dangerous!"); } } for (StorageServiceEventListener listener: this.serviceEventListeners) { if (listener instanceof S3ServiceEventListener) { if (event instanceof MultipartUploadsEvent) { ((S3ServiceEventListener)listener).event((MultipartUploadsEvent) event); } else if (event instanceof MultipartStartsEvent) { ((S3ServiceEventListener)listener).event((MultipartStartsEvent) event); } else if (event instanceof MultipartCompletesEvent) { ((S3ServiceEventListener)listener).event((MultipartCompletesEvent) event); } else { super.fireServiceEvent(event); } } else { super.fireServiceEvent(event); } } } private void assertIsS3Service() { if (!(storageService instanceof S3Service)) { throw new IllegalStateException( "Multipart uploads are only available in Amazon S3, " + "you must use the S3Service implementation of StorageService"); } } /** * Starts multiple multipart uploads and sends {@link MultipartStartsEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * threaded-service.max-admin-thread-count. * * @param bucketName * the target bucket. * @param objects * a list of objects representing the overall multipart object. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean multipartStartUploads(final String bucketName, final List objects) { assertIsS3Service(); final List incompletedObjectsList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. List runnableList = new ArrayList(); for (StorageObject object: objects) { incompletedObjectsList.add(object); runnableList.add(new MultipartStartRunnable(bucketName, object)); } // Wait for threads to finish, or be canceled. ThreadWatcher threadWatcher = new ThreadWatcher(runnableList.size()); (new ThreadGroupManager(runnableList.toArray(new MultipartStartRunnable[] {}), threadWatcher, this.storageService.getJetS3tProperties(), true) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(MultipartStartsEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { MultipartUpload[] completedObjects = (MultipartUpload[]) completedResults .toArray(new MultipartUpload[completedResults.size()]); // Hack way to remove completed objects from incomplete list List completedStorageObjects = new ArrayList(); for (MultipartUpload upload: completedObjects) { for (StorageObject object: incompletedObjectsList) { if (object.getKey().equals(upload.getObjectKey())) { completedStorageObjects.add(object); } } } incompletedObjectsList.removeAll(completedStorageObjects); fireServiceEvent(MultipartStartsEvent.newInProgressEvent(threadWatcher, completedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { StorageObject[] incompletedObjects = incompletedObjectsList .toArray(new StorageObject[incompletedObjectsList.size()]); success[0] = false; fireServiceEvent(MultipartStartsEvent.newCancelledEvent(incompletedObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(MultipartStartsEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(MultipartStartsEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(MultipartStartsEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Completes multiple multipart uploads and sends {@link MultipartCompletesEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * threaded-service.max-admin-thread-count. * * @param multipartUploads * a list of objects representing the multipart-uploads that will be completed. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean multipartCompleteUploads(final List multipartUploads) { assertIsS3Service(); final List incompletedObjectsList = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. List runnableList = new ArrayList(); for (MultipartUpload multipartUpload: multipartUploads) { incompletedObjectsList.add(multipartUpload); runnableList.add(new MultipartCompleteRunnable(multipartUpload)); } // Wait for threads to finish, or be canceled. ThreadWatcher threadWatcher = new ThreadWatcher(runnableList.size()); (new ThreadGroupManager(runnableList.toArray(new MultipartCompleteRunnable[] {}), threadWatcher, this.storageService.getJetS3tProperties(), true) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(MultipartCompletesEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { incompletedObjectsList.removeAll(completedResults); MultipartCompleted[] completedObjects = (MultipartCompleted[]) completedResults .toArray(new MultipartCompleted[completedResults.size()]); fireServiceEvent(MultipartCompletesEvent.newInProgressEvent(threadWatcher, completedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { MultipartUpload[] incompletedObjects = incompletedObjectsList .toArray(new MultipartUpload[incompletedObjectsList.size()]); success[0] = false; fireServiceEvent(MultipartCompletesEvent.newCancelledEvent(incompletedObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(MultipartCompletesEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(MultipartCompletesEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(MultipartCompletesEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Uploads multiple objects that will constitute a single final object, * and sends {@link MultipartUploadsEvent} notification events. *

* The maximum number of threads is controlled by the JetS3t configuration property * threaded-service.max-admin-thread-count. * * @param uploadAndPartsList * list of wrapper objects containing a previously-started MultipartUpload and a * list of objects representing the parts that will make up the final object. * * @return * true if all the threaded tasks completed successfully, false otherwise. */ public boolean multipartUploadParts(List uploadAndPartsList) { assertIsS3Service(); final List incompletedObjectsList = new ArrayList(); final List progressWatchers = new ArrayList(); final Object uniqueOperationId = new Object(); // Special object used to identify this operation. final boolean[] success = new boolean[] {true}; // Start all queries in the background. List runnableList = new ArrayList(); for (MultipartUploadAndParts multipartUploadAndParts: uploadAndPartsList) { int partNumber = multipartUploadAndParts.getPartNumberOffset(); for (S3Object partObject: multipartUploadAndParts.getPartObjects()) { incompletedObjectsList.add(partObject); BytesProgressWatcher progressMonitor = new BytesProgressWatcher(partObject.getContentLength()); runnableList.add(new MultipartUploadObjectRunnable( multipartUploadAndParts.getMultipartUpload(), partNumber, partObject, progressMonitor)); progressWatchers.add(progressMonitor); partNumber++; } } // Wait for threads to finish, or be canceled. ThreadWatcher threadWatcher = new ThreadWatcher( progressWatchers.toArray(new BytesProgressWatcher[progressWatchers.size()])); (new ThreadGroupManager(runnableList.toArray(new MultipartUploadObjectRunnable[] {}), threadWatcher, this.storageService.getJetS3tProperties(), false) { @Override public void fireStartEvent(ThreadWatcher threadWatcher) { fireServiceEvent(MultipartUploadsEvent.newStartedEvent(threadWatcher, uniqueOperationId)); } @Override public void fireProgressEvent(ThreadWatcher threadWatcher, List completedResults) { incompletedObjectsList.removeAll(completedResults); StorageObject[] completedObjects = (StorageObject[]) completedResults .toArray(new StorageObject[completedResults.size()]); fireServiceEvent(MultipartUploadsEvent.newInProgressEvent(threadWatcher, completedObjects, uniqueOperationId)); } @Override public void fireCancelEvent() { StorageObject[] incompletedObjects = incompletedObjectsList .toArray(new StorageObject[incompletedObjectsList.size()]); success[0] = false; fireServiceEvent(MultipartUploadsEvent.newCancelledEvent(incompletedObjects, uniqueOperationId)); } @Override public void fireCompletedEvent() { fireServiceEvent(MultipartUploadsEvent.newCompletedEvent(uniqueOperationId)); } @Override public void fireErrorEvent(Throwable throwable) { success[0] = false; fireServiceEvent(MultipartUploadsEvent.newErrorEvent(throwable, uniqueOperationId)); } @Override public void fireIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors) { success[0] = false; fireServiceEvent(MultipartUploadsEvent.newIgnoredErrorsEvent(threadWatcher, ignoredErrors, uniqueOperationId)); } }).run(); return success[0]; } /** * Thread for starting a single multipart object upload. */ private class MultipartStartRunnable extends AbstractRunnable { private String bucketName = null; private StorageObject object = null; private Object result = null; public MultipartStartRunnable(String bucketName, StorageObject object) { this.bucketName = bucketName; this.object = object; } public void run() { try { result = ((S3Service)storageService).multipartStartUpload(bucketName, object.getKey(), object.getMetadataMap(), object.getAcl(), object.getStorageClass()); } catch (ServiceException e) { result = e; } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { super.forceInterrupt(); } } /** * Thread for completing a single multipart object upload. */ private class MultipartCompleteRunnable extends AbstractRunnable { private MultipartUpload multipartUpload = null; private Object result = null; public MultipartCompleteRunnable(MultipartUpload multipartUpload) { this.multipartUpload = multipartUpload; } public void run() { try { result = ((S3Service)storageService).multipartCompleteUpload(multipartUpload); } catch (ServiceException e) { result = e; } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { super.forceInterrupt(); } } /** * Thread for creating/uploading an object that is part of a single multipart object. * The upload of any object data is monitored with a * {@link ProgressMonitoredInputStream} and can be can cancelled as the input stream is wrapped in * an {@link InterruptableInputStream}. */ private class MultipartUploadObjectRunnable extends AbstractRunnable { private MultipartUpload multipartUpload = null; private Integer partNumber = null; private S3Object object = null; private InterruptableInputStream interruptableInputStream = null; private BytesProgressWatcher progressMonitor = null; private Object result = null; public MultipartUploadObjectRunnable(MultipartUpload multipartUpload, Integer partNumber, S3Object object, BytesProgressWatcher progressMonitor) { this.multipartUpload = multipartUpload; this.partNumber = partNumber; this.object = object; this.progressMonitor = progressMonitor; } public void run() { try { if (object.getDataInputStream() != null) { interruptableInputStream = new InterruptableInputStream(object.getDataInputStream()); ProgressMonitoredInputStream pmInputStream = new ProgressMonitoredInputStream( interruptableInputStream, progressMonitor); object.setDataInputStream(pmInputStream); } ((S3Service)storageService).multipartUploadPart( multipartUpload, partNumber, object); result = object; } catch (ServiceException e) { result = e; } } @Override public Object getResult() { return result; } @Override public void forceInterruptCalled() { if (interruptableInputStream != null) { interruptableInputStream.interrupt(); } } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/s3/S3ServiceEventListener.java0000644000000000000000000000214511537563564024613 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi.s3; import org.jets3t.service.multi.StorageServiceEventListener; /** * Listener for events produced by {@link ThreadedS3Service}. * * @author James Murty */ public interface S3ServiceEventListener extends StorageServiceEventListener { public void event(MultipartUploadsEvent event); public void event(MultipartStartsEvent event); public void event(MultipartCompletesEvent event); } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/s3/S3ServiceEventAdaptor.java0000644000000000000000000000355111537563564024422 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi.s3; import org.jets3t.service.multi.StorageServiceEventAdaptor; import org.jets3t.service.multi.ThreadedStorageService; /** * Simple implementation of {@link S3ServiceEventListener} to listen for events produced by * {@link ThreadedS3Service} and {@link ThreadedStorageService}. *

* By default this adaptor does nothing but store the first Error event it comes across, if any, * and make it available through {@link #getErrorThrown()}. *

*

* The behaviour of this class can be specialised by over-riding the appropriate * event methods, though always be sure to call the super * version of these methods if you are relying on the default error-trapping functions of this * class. *

* * @author James Murty */ public class S3ServiceEventAdaptor extends StorageServiceEventAdaptor implements S3ServiceEventListener { public void event(MultipartUploadsEvent event) { storeThrowable(event); } public void event(MultipartStartsEvent event) { storeThrowable(event); } public void event(MultipartCompletesEvent event) { storeThrowable(event); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/s3/MultipartStartsEvent.java0000644000000000000000000001153111547526224024451 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi.s3; import org.jets3t.service.model.MultipartUpload; import org.jets3t.service.model.S3Object; import org.jets3t.service.model.StorageObject; import org.jets3t.service.multi.ThreadWatcher; import org.jets3t.service.multi.event.ServiceEvent; /** * Multi-threaded service event fired by * {@link ThreadedS3Service#multipartStartUploads(String, java.util.List)}. *

* EVENT_IN_PROGRESS events include an array of the {@link S3Object}s that have been created * since the last progress event was fired. These objects are available via * {@link #getStartedUploads()}. *

* EVENT_CANCELLED events include an array of the {@link S3Object}s that had not been created * before the operation was cancelled. These objects are available via * {@link #getCancelledObjects()}. * * @author James Murty */ public class MultipartStartsEvent extends ServiceEvent { private MultipartUpload[] completedMultipartUploads = null; private StorageObject[] incompletedObjects = null; private MultipartStartsEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static MultipartStartsEvent newErrorEvent(Throwable t, Object uniqueOperationId) { MultipartStartsEvent event = new MultipartStartsEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static MultipartStartsEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { MultipartStartsEvent event = new MultipartStartsEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static MultipartStartsEvent newInProgressEvent(ThreadWatcher threadWatcher, MultipartUpload[] completedMultipartUploads, Object uniqueOperationId) { MultipartStartsEvent event = new MultipartStartsEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setCompletedUploads(completedMultipartUploads); return event; } public static MultipartStartsEvent newCompletedEvent(Object uniqueOperationId) { MultipartStartsEvent event = new MultipartStartsEvent(EVENT_COMPLETED, uniqueOperationId); return event; } public static MultipartStartsEvent newCancelledEvent(StorageObject[] incompletedObjects, Object uniqueOperationId) { MultipartStartsEvent event = new MultipartStartsEvent(EVENT_CANCELLED, uniqueOperationId); event.setIncompletedObjects(incompletedObjects); return event; } public static MultipartStartsEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { MultipartStartsEvent event = new MultipartStartsEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setIncompletedObjects(StorageObject[] objects) { this.incompletedObjects = objects; } private void setCompletedUploads(MultipartUpload[] uploads) { this.completedMultipartUploads = uploads; } /** * @return * the {@link MultipartUpload}s that have been started since the last progress event was fired. * @throws IllegalStateException * created objects are only available from EVENT_IN_PROGRESS events. */ public MultipartUpload[] getStartedUploads() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Started Objects are only available from EVENT_IN_PROGRESS events"); } return completedMultipartUploads; } /** * @return * the {@link StorageObject}s that were not created before the operation was cancelled. * @throws IllegalStateException * cancelled objects are only available from EVENT_CANCELLED events. */ public StorageObject[] getCancelledObjects() throws IllegalStateException { if (getEventCode() != EVENT_CANCELLED) { throw new IllegalStateException("Cancelled Objects are only available from EVENT_CANCELLED events"); } return incompletedObjects; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/s3/MultipartCompletesEvent.java0000644000000000000000000001161711547526174025135 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi.s3; import org.jets3t.service.model.MultipartCompleted; import org.jets3t.service.model.MultipartUpload; import org.jets3t.service.model.S3Object; import org.jets3t.service.multi.ThreadWatcher; import org.jets3t.service.multi.event.ServiceEvent; /** * Multi-threaded service event fired by * {@link ThreadedS3Service#multipartCompleteUploads(java.util.List)}. *

* EVENT_IN_PROGRESS events include an array of the {@link S3Object}s that have been created * since the last progress event was fired. These objects are available via * {@link #getCompletedUploads()}. *

* EVENT_CANCELLED events include an array of the {@link S3Object}s that had not been created * before the operation was cancelled. These objects are available via * {@link #getCancelledUploads()}. * * @author James Murty */ public class MultipartCompletesEvent extends ServiceEvent { private MultipartUpload[] incompleteUploads = null; private MultipartCompleted[] completedUploads = null; private MultipartCompletesEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static MultipartCompletesEvent newErrorEvent(Throwable t, Object uniqueOperationId) { MultipartCompletesEvent event = new MultipartCompletesEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static MultipartCompletesEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { MultipartCompletesEvent event = new MultipartCompletesEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static MultipartCompletesEvent newInProgressEvent(ThreadWatcher threadWatcher, MultipartCompleted[] completedUploads, Object uniqueOperationId) { MultipartCompletesEvent event = new MultipartCompletesEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setCompleteUploads(completedUploads); return event; } public static MultipartCompletesEvent newCompletedEvent(Object uniqueOperationId) { MultipartCompletesEvent event = new MultipartCompletesEvent(EVENT_COMPLETED, uniqueOperationId); return event; } public static MultipartCompletesEvent newCancelledEvent(MultipartUpload[] incompletedUploads, Object uniqueOperationId) { MultipartCompletesEvent event = new MultipartCompletesEvent(EVENT_CANCELLED, uniqueOperationId); event.setIncompleteUploads(incompletedUploads); return event; } public static MultipartCompletesEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { MultipartCompletesEvent event = new MultipartCompletesEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setIncompleteUploads(MultipartUpload[] uploads) { this.incompleteUploads = uploads; } private void setCompleteUploads(MultipartCompleted[] completed) { this.completedUploads = completed; } /** * @return * the {@link MultipartUpload}s that have been completed since the last progress event was fired. * @throws IllegalStateException * created objects are only available from EVENT_IN_PROGRESS events. */ public MultipartCompleted[] getCompletedUploads() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Started Objects are only available from EVENT_IN_PROGRESS events"); } return completedUploads; } /** * @return * the {@link MultipartUpload}s that were not completed before the operation was cancelled. * @throws IllegalStateException * cancelled objects are only available from EVENT_CANCELLED events. */ public MultipartUpload[] getCancelledUploads() throws IllegalStateException { if (getEventCode() != EVENT_CANCELLED) { throw new IllegalStateException("Cancelled Objects are only available from EVENT_CANCELLED events"); } return incompleteUploads; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/s3/MultipartUploadsEvent.java0000644000000000000000000001104711547526426024606 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi.s3; import org.jets3t.service.model.StorageObject; import org.jets3t.service.multi.ThreadWatcher; import org.jets3t.service.multi.s3.ThreadedS3Service; import org.jets3t.service.multi.event.ServiceEvent; /** * Multi-threaded service event fired by * {@link ThreadedS3Service#multipartUploadParts(java.util.List)}. *

* EVENT_IN_PROGRESS events include an array of the {@link StorageObject}s that have been created * since the last progress event was fired. These objects are available via * {@link #getUploadedObjects()}. *

* EVENT_CANCELLED events include an array of the {@link StorageObject}s that had not been created * before the operation was cancelled. These objects are available via * {@link #getCancelledObjects()}. * * @author James Murty */ public class MultipartUploadsEvent extends ServiceEvent { private StorageObject[] objects = null; private MultipartUploadsEvent(int eventCode, Object uniqueOperationId) { super(eventCode, uniqueOperationId); } public static MultipartUploadsEvent newErrorEvent(Throwable t, Object uniqueOperationId) { MultipartUploadsEvent event = new MultipartUploadsEvent(EVENT_ERROR, uniqueOperationId); event.setErrorCause(t); return event; } public static MultipartUploadsEvent newStartedEvent(ThreadWatcher threadWatcher, Object uniqueOperationId) { MultipartUploadsEvent event = new MultipartUploadsEvent(EVENT_STARTED, uniqueOperationId); event.setThreadWatcher(threadWatcher); return event; } public static MultipartUploadsEvent newInProgressEvent(ThreadWatcher threadWatcher, StorageObject[] completedObjects, Object uniqueOperationId) { MultipartUploadsEvent event = new MultipartUploadsEvent(EVENT_IN_PROGRESS, uniqueOperationId); event.setThreadWatcher(threadWatcher); event.setObjects(completedObjects); return event; } public static MultipartUploadsEvent newCompletedEvent(Object uniqueOperationId) { MultipartUploadsEvent event = new MultipartUploadsEvent(EVENT_COMPLETED, uniqueOperationId); return event; } public static MultipartUploadsEvent newCancelledEvent(StorageObject[] incompletedObjects, Object uniqueOperationId) { MultipartUploadsEvent event = new MultipartUploadsEvent(EVENT_CANCELLED, uniqueOperationId); event.setObjects(incompletedObjects); return event; } public static MultipartUploadsEvent newIgnoredErrorsEvent(ThreadWatcher threadWatcher, Throwable[] ignoredErrors, Object uniqueOperationId) { MultipartUploadsEvent event = new MultipartUploadsEvent(EVENT_IGNORED_ERRORS, uniqueOperationId); event.setIgnoredErrors(ignoredErrors); return event; } private void setObjects(StorageObject[] objects) { this.objects = objects; } /** * @return * the {@link StorageObject}s that have been uploaded since the last progress event was fired. * @throws IllegalStateException * created objects are only available from EVENT_IN_PROGRESS events. */ public StorageObject[] getUploadedObjects() throws IllegalStateException { if (getEventCode() != EVENT_IN_PROGRESS) { throw new IllegalStateException("Created Objects are only available from EVENT_IN_PROGRESS events"); } return objects; } /** * @return * the {@link StorageObject}s that were not created before the operation was cancelled. * @throws IllegalStateException * cancelled objects are only available from EVENT_CANCELLED events. */ public StorageObject[] getCancelledObjects() throws IllegalStateException { if (getEventCode() != EVENT_CANCELLED) { throw new IllegalStateException("Cancelled Objects are only available from EVENT_CANCELLED events"); } return objects; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/s3/MultipartUploadAndParts.java0000644000000000000000000000404411537563564025060 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi.s3; import java.util.ArrayList; import java.util.List; import org.jets3t.service.model.MultipartUpload; import org.jets3t.service.model.S3Object; /** * Packages together a MultipartUpload and a set of its component * S3Object parts. * * @author James Murty */ public class MultipartUploadAndParts { private MultipartUpload multipartUpload; private List partObjects; private Integer partNumberOffset; public MultipartUploadAndParts(MultipartUpload multipartUpload, List partObjects, Integer partNumberOffset) { this.multipartUpload = multipartUpload; this.partObjects = partObjects; this.partNumberOffset = partNumberOffset; } public MultipartUploadAndParts(MultipartUpload multipartUpload, List partObjects) { this(multipartUpload, partObjects, 1); } public MultipartUploadAndParts(MultipartUpload multipartUpload) { this(multipartUpload, new ArrayList(), 1); } public void addPartObject(S3Object partObject) { this.partObjects.add(partObject); } public MultipartUpload getMultipartUpload() { return multipartUpload; } public List getPartObjects() { return partObjects; } public Integer getPartNumberOffset() { return partNumberOffset; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/StorageServiceEventAdaptor.java0000644000000000000000000000756311537563564025223 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi; import org.jets3t.service.multi.event.CopyObjectsEvent; import org.jets3t.service.multi.event.CreateBucketsEvent; import org.jets3t.service.multi.event.CreateObjectsEvent; import org.jets3t.service.multi.event.DeleteObjectsEvent; import org.jets3t.service.multi.event.DownloadObjectsEvent; import org.jets3t.service.multi.event.GetObjectHeadsEvent; import org.jets3t.service.multi.event.GetObjectsEvent; import org.jets3t.service.multi.event.ListObjectsEvent; import org.jets3t.service.multi.event.LookupACLEvent; import org.jets3t.service.multi.event.ServiceEvent; import org.jets3t.service.multi.event.UpdateACLEvent; /** * Simple implementation of {@link StorageServiceEventListener} to listen for events produced by * {@link ThreadedStorageService}. *

* By default this adaptor does nothing but store the first Error event it comes across, if any, * and make it available through {@link #getErrorThrown()}. *

*

* The behaviour of this class can be specialised by over-riding the appropriate * event methods, though always be sure to call the super * version of these methods if you are relying on the default error-trapping functions of this * class. *

* * @author James Murty */ public class StorageServiceEventAdaptor implements StorageServiceEventListener { private final Throwable t[] = new Throwable[1]; public void event(ListObjectsEvent event) { storeThrowable(event); } public void event(CreateObjectsEvent event) { storeThrowable(event); } public void event(CopyObjectsEvent event) { storeThrowable(event); } public void event(CreateBucketsEvent event) { storeThrowable(event); } public void event(DeleteObjectsEvent event) { storeThrowable(event); } public void event(GetObjectsEvent event) { storeThrowable(event); } public void event(GetObjectHeadsEvent event) { storeThrowable(event); } public void event(LookupACLEvent event) { storeThrowable(event); } public void event(UpdateACLEvent event) { storeThrowable(event); } public void event(DownloadObjectsEvent event) { storeThrowable(event); } protected void storeThrowable(ServiceEvent event) { if (t[0] == null && event.getEventCode() == ServiceEvent.EVENT_ERROR) { t[0] = event.getErrorCause(); } } /** * @return * true if an event has resulted in an exception. */ public boolean wasErrorThrown() { return t[0] != null; } /** * @return * the first error thrown by an event, or null if no error has been thrown. */ public Throwable getErrorThrown() { return t[0]; } /** * @throws Exception * throws first error thrown by an event, or does nothing if no error occurred. */ public void throwErrorIfPresent() throws Exception { if (this.wasErrorThrown()) { Throwable thrown = this.getErrorThrown(); if (thrown instanceof Exception) { throw (Exception) thrown; } else { throw new Exception(thrown); } } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/SimpleThreadedStorageService.java0000644000000000000000000003646711450545314025511 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import org.jets3t.service.StorageService; import org.jets3t.service.ServiceException; import org.jets3t.service.model.StorageBucket; import org.jets3t.service.model.StorageObject; import org.jets3t.service.multi.event.CopyObjectsEvent; import org.jets3t.service.multi.event.CreateBucketsEvent; import org.jets3t.service.multi.event.CreateObjectsEvent; import org.jets3t.service.multi.event.DeleteObjectsEvent; import org.jets3t.service.multi.event.DownloadObjectsEvent; import org.jets3t.service.multi.event.GetObjectHeadsEvent; import org.jets3t.service.multi.event.LookupACLEvent; import org.jets3t.service.multi.event.ServiceEvent; import org.jets3t.service.multi.event.UpdateACLEvent; /** * S3 service wrapper that performs multiple S3 requests at a time using multi-threading and an * underlying thread-safe {@link StorageService} implementation. *

* This class provides a simplified interface to the {@link ThreadedStorageService} service. * It will block while doing its work, return the results of an operation when it is finished, * and throw an exception if anything goes wrong. *

* For a non-blocking multi-threading service that is more powerful, but also more complicated, * see {@link ThreadedStorageService}. * * @author James Murty */ public class SimpleThreadedStorageService { private StorageService service = null; /** * Construct a multi-threaded service based on a StorageService. * * @param service * a StorageService implementation that will be used to perform S3 requests. */ public SimpleThreadedStorageService(StorageService service) { this.service = service; } /** * Utility method to check an {@link StorageServiceEventAdaptor} for the occurrence of an error, * and if one is present to throw it. * * @param adaptor * @throws ServiceException */ protected void throwError(StorageServiceEventAdaptor adaptor) throws ServiceException { if (adaptor.wasErrorThrown()) { Throwable thrown = adaptor.getErrorThrown(); if (thrown instanceof ServiceException) { throw (ServiceException) thrown; } else { throw new ServiceException(thrown); } } } /** * Creates multiple buckets. * * @param bucketNames * name of the buckets to create. * @return * the created buckets. * @throws ServiceException */ public StorageBucket[] createBuckets(final String[] bucketNames) throws ServiceException { final List bucketList = new ArrayList(); StorageServiceEventAdaptor adaptor = new StorageServiceEventAdaptor() { @Override public void event(CreateBucketsEvent event) { super.event(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { bucketList.addAll(Arrays.asList(event.getCreatedBuckets())); } }; }; (new ThreadedStorageService(service, adaptor)).createBuckets(bucketNames); throwError(adaptor); return bucketList.toArray(new StorageBucket[bucketList.size()]); } /** * Creates/uploads multiple objects. * * @param bucketName * the bucket where objects will be stored. * @param objects * the objects to create/upload. * @return * the created/uploaded objects. * @throws ServiceException */ public StorageObject[] putObjects(String bucketName, final StorageObject[] objects) throws ServiceException { final List objectList = new ArrayList(); StorageServiceEventAdaptor adaptor = new StorageServiceEventAdaptor() { @Override public void event(CreateObjectsEvent event) { super.event(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { objectList.addAll(Arrays.asList(event.getCreatedObjects())); } }; }; (new ThreadedStorageService(service, adaptor)).putObjects(bucketName, objects); throwError(adaptor); return objectList.toArray(new StorageObject[objectList.size()]); } /** * Copies multiple objects within or between buckets. * * @param sourceBucketName * the name of the bucket containing the objects that will be copied. * @param destinationBucketName * the name of the bucket to which the objects will be copied. The destination * bucket may be the same as the source bucket. * @param sourceObjectKeys * the key names of the objects that will be copied. * @param destinationObjects * objects that will be created by the copy operation. The AccessControlList * setting of each object will determine the access permissions of the * resultant object, and if the replaceMetadata flag is true the metadata * items in each object will also be applied to the resultant object. * @param replaceMetadata * if true, the metadata items in the destination objects will be stored * in S3 by using the REPLACE metadata copying option. If false, the metadata * items will be copied unchanged from the original objects using the COPY * metadata copying option.s */ public Map[] copyObjects(final String sourceBucketName, final String destinationBucketName, final String[] sourceObjectKeys, final StorageObject[] destinationObjects, boolean replaceMetadata) throws ServiceException { final List resultsList = new ArrayList(); StorageServiceEventAdaptor adaptor = new StorageServiceEventAdaptor() { @Override public void event(CopyObjectsEvent event) { super.event(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { resultsList.addAll(Arrays.asList(event.getCopyResults())); } }; }; (new ThreadedStorageService(service, adaptor)).copyObjects(sourceBucketName, destinationBucketName, sourceObjectKeys, destinationObjects, replaceMetadata); throwError(adaptor); return (Map[]) resultsList.toArray(new Map[resultsList.size()]); } /** * Deletes multiple objects * * @param bucketName * name of the bucket containing the objects to delete. * @param objects * the objects to delete. * @throws ServiceException */ public void deleteObjects(String bucketName, final StorageObject[] objects) throws ServiceException { final List objectList = new ArrayList(); StorageServiceEventAdaptor adaptor = new StorageServiceEventAdaptor() { @Override public void event(DeleteObjectsEvent event) { super.event(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { objectList.addAll(Arrays.asList(event.getDeletedObjects())); } }; }; (new ThreadedStorageService(service, adaptor)).deleteObjects(bucketName, objects); throwError(adaptor); } /** * Retrieves multiple objects (including details and data). * The objects' data will be stored in temporary files, and can be retrieved using * {@link StorageObject#getDataInputStream()}. * * @param bucketName * name of the bucket containing the objects. * @param objects * the objects to retrieve. * @return * the retrieved objects. * @throws ServiceException */ public StorageObject[] getObjects(String bucketName, StorageObject[] objects) throws ServiceException { DownloadPackage[] downloadPackages = new DownloadPackage[objects.length]; try { for (int i = 0; i < downloadPackages.length; i++) { // Create a temporary file for data, file will auto-delete on JVM exit. File tempFile = File.createTempFile("jets3t-", ".tmp"); tempFile.deleteOnExit(); downloadPackages[i] = new DownloadPackage(objects[i], tempFile); } } catch (IOException e) { throw new ServiceException("Unable to create temporary file to store object data", e); } final List objectList = new ArrayList(); StorageServiceEventAdaptor adaptor = new StorageServiceEventAdaptor() { @Override public void event(DownloadObjectsEvent event) { super.event(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { objectList.addAll(Arrays.asList(event.getDownloadedObjects())); } }; }; (new ThreadedStorageService(service, adaptor)).downloadObjects(bucketName, downloadPackages); throwError(adaptor); return objectList.toArray(new StorageObject[objectList.size()]); } /** * Retrieves multiple objects (including details and data). * The objects' data will be stored in temporary files, and can be retrieved using * {@link StorageObject#getDataInputStream()}. * * @param bucketName * name of the bucket containing the objects. * @param objectKeys * the key names of the objects to retrieve. * @return * the retrieved objects. * * @throws ServiceException */ public StorageObject[] getObjects(String bucketName, final String[] objectKeys) throws ServiceException { StorageObject[] objects = new StorageObject[objectKeys.length]; for (int i = 0; i < objectKeys.length; i++) { objects[i] = new StorageObject(objectKeys[i]); } return getObjects(bucketName, objects); } /** * Retrieves details of multiple objects (details only, no data) * * @param bucketName * name of the bucket containing the objects. * @param objects * the objects to retrieve. * @return * objects populated with the details retrieved. * @throws ServiceException */ public StorageObject[] getObjectsHeads(String bucketName, StorageObject[] objects) throws ServiceException { String[] objectKeys = new String[objects.length]; for (int i = 0; i < objects.length; i++) { objectKeys[i] = objects[i].getKey(); } return getObjectsHeads(bucketName, objectKeys); } /** * Retrieves details of multiple objects (details only, no data) * * @param bucketName * name of the bucket containing the objects. * @param objectKeys * the key names of the objects to retrieve. * @return * objects populated with the details retrieved. * @throws ServiceException */ public StorageObject[] getObjectsHeads(String bucketName, final String[] objectKeys) throws ServiceException { final List objectList = new ArrayList(); StorageServiceEventAdaptor adaptor = new StorageServiceEventAdaptor() { @Override public void event(GetObjectHeadsEvent event) { super.event(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { objectList.addAll(Arrays.asList(event.getCompletedObjects())); } }; }; (new ThreadedStorageService(service, adaptor)).getObjectsHeads(bucketName, objectKeys); throwError(adaptor); return objectList.toArray(new StorageObject[objectList.size()]); } /** * Retrieves Access Control List (ACL) settings for multiple objects. * * @param bucketName * name of the bucket containing the objects. * @param objects * the objects whose ACLs will be retrieved. * @return * objects including the ACL information retrieved. * @throws ServiceException */ public StorageObject[] getObjectACLs(String bucketName, final StorageObject[] objects) throws ServiceException { final List objectList = new ArrayList(); StorageServiceEventAdaptor adaptor = new StorageServiceEventAdaptor() { @Override public void event(LookupACLEvent event) { super.event(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { objectList.addAll(Arrays.asList(event.getObjectsWithACL())); } }; }; (new ThreadedStorageService(service, adaptor)).getObjectACLs(bucketName, objects); throwError(adaptor); return objectList.toArray(new StorageObject[objectList.size()]); } /** * Updates/sets Access Control List (ACL) settings for multiple objects. * * @param bucketName * name of the bucket containing the objects. * @param objects * objects containing ACL settings that will be updated/set. * @return * objects whose ACL settings were updated/set. * @throws ServiceException */ public StorageObject[] putACLs(String bucketName, final StorageObject[] objects) throws ServiceException { final List objectList = new ArrayList(); StorageServiceEventAdaptor adaptor = new StorageServiceEventAdaptor() { @Override public void event(UpdateACLEvent event) { super.event(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { objectList.addAll(Arrays.asList(event.getObjectsWithUpdatedACL())); } }; }; (new ThreadedStorageService(service, adaptor)).putACLs(bucketName, objects); throwError(adaptor); return objectList.toArray(new StorageObject[objectList.size()]); } /** * A convenience method to download multiple objects from S3 to pre-existing output streams, which * is particularly useful for downloading objects to files. * * @param bucketName * name of the bucket containing the objects * @param downloadPackages * an array of download package objects that manage the output of data for an object. * * @throws ServiceException */ public void downloadObjects(String bucketName, final DownloadPackage[] downloadPackages) throws ServiceException { StorageServiceEventAdaptor adaptor = new StorageServiceEventAdaptor(); (new ThreadedStorageService(service, adaptor)).downloadObjects(bucketName, downloadPackages); throwError(adaptor); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/multi/CancelEventTrigger.java0000644000000000000000000000226011441613550023442 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.multi; import java.util.EventListener; /** * Interface implemented by multi-threaded operations that can be cancelled prior to finishing. * * @author James Murty */ public interface CancelEventTrigger extends EventListener { /** * Triggers a cancellation of some operation. * * @param eventSource * the object source that triggered the cancellation, useful for logging purposes. * */ public abstract void cancelTask(Object eventSource); } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/VersionOrDeleteMarkersChunk.java0000644000000000000000000000520311441613550024164 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service; import org.jets3t.service.model.BaseVersionOrDeleteMarker; public class VersionOrDeleteMarkersChunk { private String prefix = null; private String delimiter = null; private BaseVersionOrDeleteMarker[] items = null; private String[] commonPrefixes = null; private String nextKeyMarker = null; private String nextVersionIdMarker = null; public VersionOrDeleteMarkersChunk(String prefix, String delimiter, BaseVersionOrDeleteMarker[] items, String[] commonPrefixes, String nextKeyMarker, String nextVersionIdMarker) { this.prefix = prefix; this.delimiter = delimiter; this.items = items; this.commonPrefixes = commonPrefixes; this.nextKeyMarker = nextKeyMarker; this.nextVersionIdMarker = nextVersionIdMarker; } public BaseVersionOrDeleteMarker[] getItems() { return items; } public int getItemCount() { return items.length; } /** * @return * the common prefixes in this chunk. */ public String[] getCommonPrefixes() { return commonPrefixes; } /** * @return * the last key returned by the previous chunk if that chunk was incomplete, null otherwise. */ public String getNextKeyMarker() { return nextKeyMarker; } public String getNextVersionIdMarker() { return nextVersionIdMarker; } /** * @return * the prefix applied when this object chunk was generated. If no prefix was * applied, this method will return null. */ public String getPrefix() { return prefix; } /** * @return * the delimiter applied when this object chunk was generated. If no * delimiter was applied, this method will return null. */ public String getDelimiter() { return delimiter; } public boolean isListingComplete() { return (nextKeyMarker != null && nextVersionIdMarker != null); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/StorageService.java0000644000000000000000000020272211550442110021520 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008-2010 James Murty, 2008 Zmanda Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.impl.rest.XmlResponsesSaxParser; import org.jets3t.service.impl.rest.httpclient.GoogleStorageService; import org.jets3t.service.model.GSBucket; import org.jets3t.service.model.GSObject; import org.jets3t.service.model.S3Bucket; import org.jets3t.service.model.S3Object; import org.jets3t.service.model.StorageBucket; import org.jets3t.service.model.StorageOwner; import org.jets3t.service.model.StorageObject; import org.jets3t.service.mx.MxDelegate; import org.jets3t.service.security.ProviderCredentials; import org.jets3t.service.utils.RestUtils; /** * A service that handles communication with a storage service, offering all the operations that * can be performed on generic storage services. *

* This class must be extended by implementation classes that perform the communication with * a specific service using a specific interface, such as REST or SOAP. *

*

* Implementations of StorageService must be thread-safe as they will probably be used by * the multi-threaded service class {@link org.jets3t.service.multi.ThreadedStorageService}. *

*

* This class uses properties obtained through {@link Jets3tProperties}. For more information on * these properties please refer to * JetS3t Configuration *

* * @author James Murty * @author Nikolas Coukouma */ public abstract class StorageService { private static final Log log = LogFactory.getLog(StorageService.class); /** * Status code returned by {@link #checkBucketStatus(String)} for a bucket * that exists and is owned by the service user. */ public static final int BUCKET_STATUS__MY_BUCKET = 0; /** * Status code returned by {@link #checkBucketStatus(String)} for a bucket * that does not exist. */ public static final int BUCKET_STATUS__DOES_NOT_EXIST = 1; /** * Status code returned by {@link #checkBucketStatus(String)} for a bucket * that exists but is not owned by the service user (i.e. another user has * already created this bucket in the service's namespace). */ public static final int BUCKET_STATUS__ALREADY_CLAIMED = 2; protected Jets3tProperties jets3tProperties = null; protected ProviderCredentials credentials = null; private String invokingApplicationDescription = null; private boolean isHttpsOnly = true; private int internalErrorRetryMax = 5; private boolean isShutdown = false; /** * The approximate difference in the current time between your computer and * a target service, measured in milliseconds. * * This value is 0 by default. Use the {@link #getCurrentTimeWithOffset()} * to obtain the current time with this offset factor included, and the * {@link RestUtils#getAWSTimeAdjustment()} method to calculate an offset value for your * computer based on a response from an AWS server. */ protected long timeOffset = 0; /** * Construct a StorageService identified by the given user credentials. * * @param credentials * the user credentials, may be null in which case the communication is done as an anonymous user. * @param invokingApplicationDescription * a short description of the application using the service, suitable for inclusion in a * user agent string for REST/HTTP requests. Ideally this would include the application's * version number, for example: Cockpit/0.7.3 or My App Name/1.0 * @param jets3tProperties * JetS3t properties that will be applied within this service. */ protected StorageService(ProviderCredentials credentials, String invokingApplicationDescription, Jets3tProperties jets3tProperties) { this.credentials = credentials; this.invokingApplicationDescription = invokingApplicationDescription; this.jets3tProperties = jets3tProperties; this.isHttpsOnly = this.getHttpsOnly(); this.internalErrorRetryMax = jets3tProperties.getIntProperty( "storage-service.internal-error-retry-max", 5); // Configure the InetAddress DNS caching times to work well with remote services. The cached // DNS will timeout after 5 minutes, while failed DNS lookups will be retried after 1 second. System.setProperty("networkaddress.cache.ttl", "300"); System.setProperty("networkaddress.cache.negative.ttl", "1"); // (Re)initialize the JetS3t JMX delegate, in case system properties have changed. MxDelegate.getInstance().init(); MxDelegate.getInstance().registerS3ServiceMBean(); MxDelegate.getInstance().registerS3ServiceExceptionMBean(); } /** * Construct a StorageService identified by the given user credentials. * * @param credentials * the user credentials, may be null in which case the communication is done as an anonymous user. * @param invokingApplicationDescription * a short description of the application using the service, suitable for inclusion in a * user agent string for REST/HTTP requests. Ideally this would include the application's * version number, for example: Cockpit/0.7.3 or My App Name/1.0 */ protected StorageService(ProviderCredentials credentials, String invokingApplicationDescription) { this(credentials, invokingApplicationDescription, Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME)); } /** * Construct a StorageService identified by the given user credentials. * * @param credentials * the user credentials, may be null in which case the communication is done as an anonymous user. */ protected StorageService(ProviderCredentials credentials) { this(credentials, null); } /** * Make a best-possible effort to shutdown and clean up any resources used by this * service such as HTTP connections, connection pools, threads etc, although there is * no guarantee that all such resources will indeed be fully cleaned up. * * After calling this method the service instance will no longer be usable -- a new * instance must be created to do more work. * @throws ServiceException */ public void shutdown() throws ServiceException { this.isShutdown = true; this.shutdownImpl(); } /** * @return true if the {@link #shutdown()} method has been used to shut down and * clean up this service. If this function returns true this service instance * can no longer be used to do work. */ public boolean isShutdown() { return this.isShutdown; } /** * @return * true if this service has {@link ProviderCredentials} identifying a user, false * if the service is acting as an anonymous user. */ public boolean isAuthenticatedConnection() { return credentials != null; } /** * Whether to use secure HTTPS or insecure HTTP for communicating with a service, * as configured in the {@link Jets3tProperties}. * * @return * true if this service should use only secure HTTPS communication channels. * If false, the non-secure HTTP protocol will be used. */ public boolean isHttpsOnly() { return isHttpsOnly; } /** * @return * The maximum number of times to retry when Internal Error (500) errors are encountered, * as configured by the {@link Jets3tProperties}. */ public int getInternalErrorRetryMax() { return internalErrorRetryMax; } /** * @return * the JetS3t properties that will be used by this service. */ public Jets3tProperties getJetS3tProperties() { return jets3tProperties; } protected XmlResponsesSaxParser getXmlResponseSaxParser() throws ServiceException { return new XmlResponsesSaxParser(this.jets3tProperties, (this instanceof GoogleStorageService)); } protected StorageBucket newBucket() { if (this instanceof GoogleStorageService) { return new GSBucket(); } else { return new S3Bucket(); } } protected StorageObject newObject() { if (this instanceof GoogleStorageService) { return new GSObject(); } else { return new S3Object(); } } /** * Sleeps for a period of time based on the number of Internal Server errors a request has * encountered, provided the number of errors does not exceed the value set with the * property storage-service.internal-error-retry-max. If the maximum error count is * exceeded, this method will throw an {@link ServiceException}. * * The millisecond delay grows rapidly according to the formula * 50 * (internalErrorCount ^ 2). * * * * * * * * *
Error countDelay in milliseconds
150
2200
3450
4800
51250
* * @param internalErrorCount * the number of Internal Server errors encountered by a request. * * @throws ServiceException * thrown if the number of internal errors exceeds the value of internalErrorCount. * @throws InterruptedException * thrown if the thread sleep is interrupted. */ protected void sleepOnInternalError(int internalErrorCount) throws ServiceException, InterruptedException { if (internalErrorCount <= internalErrorRetryMax) { long delayMs = 50L * (int) Math.pow(internalErrorCount, 2); if (log.isWarnEnabled()) { log.warn("Encountered " + internalErrorCount + " Internal Server error(s), will retry in " + delayMs + "ms"); } Thread.sleep(delayMs); } else { throw new ServiceException("Encountered too many Internal Server errors (" + internalErrorCount + "), aborting request."); } } /** * @return the credentials identifying the service user, or null for anonymous. */ public ProviderCredentials getProviderCredentials() { return credentials; } /** * @return a description of the application using this service, suitable for inclusion in the * user agent string of REST/HTTP requests. */ public String getInvokingApplicationDescription() { return invokingApplicationDescription; } ///////////////////////////////////////////////////////////////////////////// // Assertion methods used to sanity-check parameters provided to this service ///////////////////////////////////////////////////////////////////////////// /** * Throws an exception if this service is anonymous (that is, it was created without * an {@link ProviderCredentials} object representing a user account. * @param action * the action being attempted which this assertion is applied, for debugging purposes. * @throws ServiceException */ protected void assertAuthenticatedConnection(String action) throws ServiceException { if (!isAuthenticatedConnection()) { throw new ServiceException( "The requested action cannot be performed with a non-authenticated service: " + action); } } /** * Throws an exception if a bucket is null or contains a null/empty name. * @param bucket * @param action * the action being attempted which this assertion is applied, for debugging purposes. * @throws ServiceException */ protected void assertValidBucket(StorageBucket bucket, String action) throws ServiceException { if (bucket == null || bucket.getName() == null || bucket.getName().length() == 0) { throw new ServiceException("The action " + action + " cannot be performed with an invalid bucket: " + bucket); } } /** * Throws an exception if an object is null or contains a null/empty key. * @param object * @param action * the action being attempted which this assertion is applied, for debugging purposes. * @throws ServiceException */ protected void assertValidObject(StorageObject object, String action) throws ServiceException { if (object == null || object.getKey() == null || object.getKey().length() == 0) { throw new ServiceException("The action " + action + " cannot be performed with an invalid object: " + object); } } /** * Throws an exception if an object's key name is null or empty. * @param key * An object's key name. * @param action * the action being attempted which this assertion is applied, for debugging purposes. * @throws ServiceException */ protected void assertValidObject(String key, String action) throws ServiceException { if (key == null || key.length() == 0) { throw new ServiceException("The action " + action + " cannot be performed with an invalid object key name: " + key); } } //////////////////////////////////////////////////////////////// // Methods below this point perform actions in a storage service //////////////////////////////////////////////////////////////// /** * Lists the objects in a bucket. *

* The objects returned by this method contain only minimal information * such as the object's size, ETag, and LastModified timestamp. To retrieve * the objects' metadata you must perform follow-up getObject * or getObjectDetails operations. *

* This method can be performed by anonymous services. Anonymous services * can only list the objects in a publicly-readable bucket. * * @param bucketName * the name of the bucket whose contents will be listed. * @return * the set of objects contained in a bucket. * @throws ServiceException */ public StorageObject[] listObjects(String bucketName) throws ServiceException { return listObjects(bucketName, null, null, Constants.DEFAULT_OBJECT_LIST_CHUNK_SIZE); } /** * Lists the objects in a bucket matching a prefix and delimiter. *

* The objects returned by this method contain only minimal information * such as the object's size, ETag, and LastModified timestamp. To retrieve * the objects' metadata you must perform follow-up getObject * or getObjectDetails operations. *

* This method can be performed by anonymous services. Anonymous services * can only list the objects in a publicly-readable bucket. *

* NOTE: If you supply a delimiter value that could cause virtual path * "subdirectories" to be included in the results from the service, use the * {@link #listObjectsChunked(String, String, String, long, String, boolean)} * method instead of this one to obtain both object and path values. * * @param bucketName * the name of the bucket whose contents will be listed. * @param prefix * only objects with a key that starts with this prefix will be listed * @param delimiter * only list objects with key names up to this delimiter, may be null. * See note above. * Note: If a non-null delimiter is specified, the prefix must include enough text to * reach the first occurrence of the delimiter in the bucket's keys, or no results will be returned. * @return * the set of objects contained in a bucket whose keys start with the given prefix. * @throws ServiceException */ public StorageObject[] listObjects(String bucketName, String prefix, String delimiter) throws ServiceException { return listObjects(bucketName, prefix, delimiter, Constants.DEFAULT_OBJECT_LIST_CHUNK_SIZE); } /** * Creates a bucket. * * Caution: Performing this operation unnecessarily when a bucket already * exists may cause OperationAborted errors with the message "A conflicting conditional * operation is currently in progress against this resource.". To avoid this error, use the * {@link #getOrCreateBucket(String)} in situations where the bucket may already exist. * * This method cannot be performed by anonymous services. * * @param bucketName * the name of the bucket to create. * @return * the created bucket object. Note: the object returned has minimal information about * the bucket that was created, including only the bucket's name. * @throws ServiceException */ public StorageBucket createBucket(String bucketName) throws ServiceException { return createBucketImpl(bucketName, null, null); } /** * Create a bucket with the Access Control List settings of the bucket object (if any). *

* Caution: Performing this operation unnecessarily when a bucket already * exists may cause OperationAborted errors with the message "A conflicting conditional * operation is currently in progress against this resource.". To avoid this error, use the * {@link #getOrCreateBucket(String)} in situations where the bucket may already exist. *

* This method cannot be performed by anonymous services. * * @param bucket * the bucket to create, including optional ACL settings. * @return * the created bucket object. Note: the object returned has minimal information about * the bucket that was created, including only the bucket's name. * @throws ServiceException */ public StorageBucket createBucket(StorageBucket bucket) throws ServiceException { return createBucketImpl(bucket.getName(), null, bucket.getAcl()); } /** * Convenience method to check whether an object exists in a bucket. * * @param bucketName * the name of the bucket containing the object. * @param objectKey * the key identifying the object. * @return * false if the object is not found in the bucket, true if the object * exists (although it may be inaccessible to you). * @throws ServiceException */ public boolean isObjectInBucket(String bucketName, String objectKey) throws ServiceException { try { getObjectDetails(bucketName, objectKey); } catch (ServiceException e) { if (404 == e.getResponseCode() || "NoSuchKey".equals(e.getErrorCode()) || "NoSuchBucket".equals(e.getErrorCode())) { return false; } if ("AccessDenied".equals(e.getErrorCode())) { // Object is inaccessible to current user, but does exist. return true; } // Something else has gone wrong throw e; } return true; } /** * Returns an object representing the details and data of an item in a service, * without applying any preconditions. *

* This method can be performed by anonymous services. Anonymous services * can get a publicly-readable object. *

* Important: It is the caller's responsibility to close the object's data input stream. * The data stream should be consumed and closed as soon as is practical as network connections * may be held open until the streams are closed. Excessive unclosed streams can lead to * connection starvation. * * @param bucketName * the name of the bucket containing the object. * @param objectKey * the key identifying the object. * @return * the object with the given key, including the object's data input stream. * @throws ServiceException */ public StorageObject getObject(String bucketName, String objectKey) throws ServiceException { return getObject(bucketName, objectKey, null, null, null, null, null, null); } /** * Returns an object representing the details of an item in without the object's data, and * without applying any preconditions. *

* This method can be performed by anonymous services. Anonymous services * can get a publicly-readable object's details. * * @param bucketName * the name of the bucket containing the object. * @param objectKey * the key identifying the object. * @return * the object with the given key, including only general details and metadata * (not the data input stream) * @throws ServiceException */ public StorageObject getObjectDetails(String bucketName, String objectKey) throws ServiceException { return getObjectDetails(bucketName, objectKey, null, null, null, null); } /** * Lists the buckets belonging to the service user. *

* This method cannot be performed by anonymous services, and will fail with an exception * if the service is not authenticated. * * @return * the list of buckets owned by the service user. * @throws ServiceException */ public StorageBucket[] listAllBuckets() throws ServiceException { assertAuthenticatedConnection("List all buckets"); StorageBucket[] buckets = listAllBucketsImpl(); MxDelegate.getInstance().registerStorageBucketMBeans(buckets); return buckets; } /** * Returns the owner of an account, using information available in the * bucket listing response. *

* This method cannot be performed by anonymous services, and will fail with an exception * if the service is not authenticated. * * @return * the owner of the account. * @throws ServiceException */ public StorageOwner getAccountOwner() throws ServiceException { assertAuthenticatedConnection("List all buckets to find account owner"); return getAccountOwnerImpl(); } /** * Lists the objects in a bucket matching a prefix, while instructing the service * to send response messages containing no more than a given number of object * results. *

* The objects returned by this method contain only minimal information * such as the object's size, ETag, and LastModified timestamp. To retrieve * the objects' metadata you must perform follow-up getObject * or getObjectDetails operations. *

* This method can be performed by anonymous services. Anonymous services * can list the contents of a publicly-readable bucket. *

* NOTE: If you supply a delimiter value that could cause virtual path * "subdirectories" to be included in the results from the service, use the * {@link #listObjectsChunked(String, String, String, long, String, boolean)} * method instead of this one to obtain both object and path values. * * @param bucketName * the name of the the bucket whose contents will be listed. * @param prefix * only objects with a key that starts with this prefix will be listed * @param delimiter * only list objects with key names up to this delimiter, may be null. * See note above. * @param maxListingLength * the maximum number of objects to include in each result message. This value * has no effect on the number of objects * that will be returned by this method, because it will always return all * the objects in the bucket. * @return * the set of objects contained in a bucket whose keys start with the given prefix. * @throws ServiceException */ public StorageObject[] listObjects(String bucketName, String prefix, String delimiter, long maxListingLength) throws ServiceException { MxDelegate.getInstance().registerStorageBucketListEvent(bucketName); StorageObject[] objects = listObjectsImpl(bucketName, prefix, delimiter, maxListingLength); MxDelegate.getInstance().registerStorageObjectMBean(bucketName, objects); return objects; } /** * Lists the objects in a bucket matching a prefix, chunking the results into batches of * a given size, and returning each chunk separately. It is the responsibility of the caller * to building a complete bucket object listing by performing follow-up requests if necessary. *

* The objects returned by this method contain only minimal information * such as the object's size, ETag, and LastModified timestamp. To retrieve * the objects' metadata you must perform follow-up getObject * or getObjectDetails operations. *

* This method can be performed by anonymous services. Anonymous services * can list the contents of a publicly-readable bucket. * * @param bucketName * the name of the the bucket whose contents will be listed. * @param prefix * only objects with a key that starts with this prefix will be listed, may be null. * @param delimiter * only list objects with key names up to this delimiter, may be null. * @param maxListingLength * the maximum number of objects to include in each result chunk * @param priorLastKey * the last object key received in a prior call to this method. The next chunk of objects * listed will start with the next object in the bucket after this key name. * This parameter may be null, in which case the listing will start at the beginning of the * bucket's object contents. * @return * the set of objects contained in a bucket whose keys start with the given prefix. * @throws ServiceException */ public StorageObjectsChunk listObjectsChunked(String bucketName, String prefix, String delimiter, long maxListingLength, String priorLastKey) throws ServiceException { MxDelegate.getInstance().registerStorageBucketListEvent(bucketName); StorageObjectsChunk chunk = listObjectsChunkedImpl( bucketName, prefix, delimiter, maxListingLength, priorLastKey, false); MxDelegate.getInstance().registerStorageObjectMBean(bucketName, chunk.getObjects()); return chunk; } /** * Lists the objects in a bucket matching a prefix and also returns the * common prefixes. Depending on the value of the completeListing * variable, this method can be set to automatically perform follow-up requests * to build a complete object listing, or to return only a partial listing. *

* The objects returned by this method contain only minimal information * such as the object's size, ETag, and LastModified timestamp. To retrieve * the objects' metadata you must perform follow-up getObject * or getObjectDetails operations. *

* This method can be performed by anonymous services. Anonymous services * can list the contents of a publicly-readable bucket. * * @param bucketName * the name of the the bucket whose contents will be listed. * @param prefix * only objects with a key that starts with this prefix will be listed, may be null. * @param delimiter * only objects with a key that starts with this prefix will be listed, may be null. * @param maxListingLength * the maximum number of objects to include in each result chunk * @param priorLastKey * the last object key received in a prior call to this method. The next chunk of objects * listed will start with the next object in the bucket after this key name. * This parameter may be null, in which case the listing will start at the beginning of the * bucket's object contents. * @param completeListing * if true, the service class will automatically perform follow-up requests to * build a complete bucket object listing. * @return * the set of objects contained in a bucket whose keys start with the given prefix. * @throws ServiceException */ public StorageObjectsChunk listObjectsChunked(String bucketName, String prefix, String delimiter, long maxListingLength, String priorLastKey, boolean completeListing) throws ServiceException { MxDelegate.getInstance().registerStorageBucketListEvent(bucketName); StorageObjectsChunk chunk = listObjectsChunkedImpl( bucketName, prefix, delimiter, maxListingLength, priorLastKey, completeListing); MxDelegate.getInstance().registerStorageObjectMBean(bucketName, chunk.getObjects()); return chunk; } /** * Returns a bucket in your account by listing all your buckets * (using {@link #listAllBuckets()}), and looking for the named bucket in * this list. *

* This method cannot be performed by anonymous services. * * @param bucketName * @return * the bucket in your account, or null if you do not own the named bucket. * * @throws ServiceException */ public StorageBucket getBucket(String bucketName) throws ServiceException { assertAuthenticatedConnection("Get Bucket"); // List existing buckets and return the named bucket if it exists. StorageBucket[] existingBuckets = listAllBuckets(); for (int i = 0; i < existingBuckets.length; i++) { if (existingBuckets[i].getName().equals(bucketName)) { return existingBuckets[i]; } } return null; } /** * Returns a bucket in your account, and creates the bucket if * it does not yet exist. * * @param bucketName * the name of the bucket to retrieve or create. * @return * the bucket in your account. * * @throws ServiceException */ public StorageBucket getOrCreateBucket(String bucketName) throws ServiceException { StorageBucket bucket = getBucket(bucketName); if (bucket == null) { // Bucket does not exist in this user's account, create it. bucket = createBucket(bucketName); } return bucket; } /** * Deletes a bucket. Only the owner of a bucket may delete it. *

* This method cannot be performed by anonymous services. * * @param bucket * the bucket to delete. * @throws ServiceException */ public void deleteBucket(StorageBucket bucket) throws ServiceException { assertValidBucket(bucket, "Delete bucket"); deleteBucketImpl(bucket.getName()); } /** * Deletes a bucket. Only the owner of a bucket may delete it. *

* This method cannot be performed by anonymous services. * * @param bucketName * the name of the bucket to delete. * @throws ServiceException */ public void deleteBucket(String bucketName) throws ServiceException { deleteBucketImpl(bucketName); } /** * Puts an object inside an existing bucket, creating a new object or overwriting * an existing one with the same key. The Access Control List settings of the object * (if any) will also be applied. *

* This method can be performed by anonymous services. Anonymous services * can put objects into a publicly-writable bucket. * * @param bucketName * the name of the bucket inside which the object will be put. * @param object * the object containing all information that will be written to the service. * At very least this object must be valid. Beyond that it may contain: an input stream * with the object's data content, metadata, and access control settings. *

* Note: It is very important to set the object's Content-Length to match the size of the * data input stream when possible, as this can remove the need to read data into memory to * determine its size. * * @return * the object populated with any metadata. * @throws ServiceException */ public StorageObject putObject(String bucketName, StorageObject object) throws ServiceException { assertValidObject(object, "Create Object in bucket " + bucketName); MxDelegate.getInstance().registerStorageObjectPutEvent(bucketName, object.getKey()); return putObjectImpl(bucketName, object); } /** * Copy an object. You can copy an object within a single bucket or between buckets, * and can optionally update the object's metadata at the same time. *

* This method cannot be performed by anonymous services. You must have read * access to the source object and write access to the destination bucket. *

* An object can be copied over itself, in which case you can update its * metadata without making any other changes. * * @param sourceBucketName * the name of the bucket that contains the original object. * @param sourceObjectKey * the key name of the original object. * @param destinationBucketName * the name of the destination bucket to which the object will be copied. * @param destinationObject * the object that will be created by the copy operation. If this item * includes an AccessControlList setting the copied object will be assigned * that ACL, otherwise the copied object will be assigned the default private * ACL setting. * @param replaceMetadata * If this parameter is true, the copied object will be assigned the metadata * values present in the destinationObject. Otherwise, the copied object will * have the same metadata as the original object. * @param ifModifiedSince * a precondition specifying a date after which the object must have been * modified, ignored if null. * @param ifUnmodifiedSince * a precondition specifying a date after which the object must not have * been modified, ignored if null. * @param ifMatchTags * a precondition specifying an MD5 hash the object must match, ignored if * null. * @param ifNoneMatchTags * a precondition specifying an MD5 hash the object must not match, ignored * if null. * * @return * a map of the header and result information resulting from the object * copy. The map includes the object's MD5 hash value (ETag), its size * (Content-Length), and update timestamp (Last-Modified). * * @throws ServiceException */ public Map copyObject(String sourceBucketName, String sourceObjectKey, String destinationBucketName, StorageObject destinationObject, boolean replaceMetadata, Calendar ifModifiedSince, Calendar ifUnmodifiedSince, String[] ifMatchTags, String[] ifNoneMatchTags) throws ServiceException { assertAuthenticatedConnection("copyObject"); Map destinationMetadata = replaceMetadata ? destinationObject.getModifiableMetadata() : null; MxDelegate.getInstance().registerStorageObjectCopyEvent(sourceBucketName, sourceObjectKey); return copyObjectImpl(sourceBucketName, sourceObjectKey, destinationBucketName, destinationObject.getKey(), destinationObject.getAcl(), destinationMetadata, ifModifiedSince, ifUnmodifiedSince, ifMatchTags, ifNoneMatchTags, null, destinationObject.getStorageClass()); } /** * Copy an object. You can copy an object within a * single bucket or between buckets, and can optionally update the object's * metadata at the same time. *

* This method cannot be performed by anonymous services. You must have read * access to the source object and write access to the destination bucket. *

* An object can be copied over itself, in which case you can update its * metadata without making any other changes. * * @param sourceBucketName * the name of the bucket that contains the original object. * @param sourceObjectKey * the key name of the original object. * @param destinationBucketName * the name of the destination bucket to which the object will be copied. * @param destinationObject * the object that will be created by the copy operation. If this item * includes an AccessControlList setting the copied object will be assigned * that ACL, otherwise the copied object will be assigned the default private * ACL setting. * @param replaceMetadata * If this parameter is true, the copied object will be assigned the metadata * values present in the destinationObject. Otherwise, the copied object will * have the same metadata as the original object. * * @return * a map of the header and result information after the object * copy. The map includes the object's MD5 hash value (ETag), its size * (Content-Length), and update timestamp (Last-Modified). * * @throws ServiceException */ public Map copyObject(String sourceBucketName, String sourceObjectKey, String destinationBucketName, StorageObject destinationObject, boolean replaceMetadata) throws ServiceException { return copyObject(sourceBucketName, sourceObjectKey, destinationBucketName, destinationObject, replaceMetadata, null, null, null, null); } /** * Move an object. This method works by invoking the * {@link #copyObject(String, String, String, StorageObject, boolean)} method to * copy the original object, then deletes the original object once the * copy has succeeded. *

* This method cannot be performed by anonymous services. You must have read * access to the source object, write access to the destination bucket, and * write access to the source bucket. *

* If the copy operation succeeds but the delete operation fails, this * method will not throw an exception but the result map object will contain * an item named "DeleteException" with the exception thrown by the delete * operation. * * @param sourceBucketName * the name of the bucket that contains the original object. * @param sourceObjectKey * the key name of the original object. * @param destinationBucketName * the name of the destination bucket to which the object will be copied. * @param destinationObject * the object that will be created by the move operation. If this item * includes an AccessControlList setting the copied object will be assigned * that ACL, otherwise the copied object will be assigned the default private * ACL setting. * @param replaceMetadata * If this parameter is true, the copied object will be assigned the metadata * values present in the destinationObject. Otherwise, the copied object will * have the same metadata as the original object. * * @return * a map of the header and result information after the object * copy. The map includes the object's MD5 hash value (ETag), its size * (Content-Length), and update timestamp (Last-Modified). If the object was * successfully copied but the original could not be deleted, the map will * also include an item named "DeleteException" with the exception thrown by * the delete operation. * * @throws ServiceException */ public Map moveObject(String sourceBucketName, String sourceObjectKey, String destinationBucketName, StorageObject destinationObject, boolean replaceMetadata) throws ServiceException { Map copyResult = copyObject(sourceBucketName, sourceObjectKey, destinationBucketName, destinationObject, replaceMetadata); try { deleteObject(sourceBucketName, sourceObjectKey); } catch (Exception e) { copyResult.put("DeleteException", e); } return copyResult; } /** * Rename an object. This method works by invoking the * {@link #moveObject(String, String, String, StorageObject, boolean)} method to * move the original object to a new key name. *

* The original object's metadata is retained, but to apply an access * control setting other than private you must specify an ACL in the * destination object. *

* This method cannot be performed by anonymous services. You must have * write access to the source object and write access to the bucket. * * @param bucketName * the name of the bucket containing the original object that will be copied. * @param sourceObjectKey * the key name of the original object. * @param destinationObject * the object that will be created by the rename operation. If this item * includes an AccessControlList setting the copied object will be assigned * that ACL, otherwise the copied object will be assigned the default private * ACL setting. * * @return * a map of the header and result information after the object * copy. The map includes the object's MD5 hash value (ETag), its size * (Content-Length), and update timestamp (Last-Modified). If the object was * successfully copied but the original could not be deleted, the map will * also include an item named "DeleteException" with the exception thrown by * the delete operation. * * @throws ServiceException */ public Map renameObject(String bucketName, String sourceObjectKey, StorageObject destinationObject) throws ServiceException { return moveObject(bucketName, sourceObjectKey, bucketName, destinationObject, false); } /** * Update an object's metadata. This method works by invoking the * {@link #copyObject(String, String, String, StorageObject, boolean)} method to * copy the original object over itself, applying the new metadata in the * process. * * @param bucketName * the name of the bucket containing the object that will be updated. * @param object * the object that will be updated. If this item includes an * AccessControlList setting the copied object will be assigned * that ACL, otherwise the copied object will be assigned the default private * ACL setting. * * @return * a map of the header and result information after the object * copy. The map includes the object's MD5 hash value (ETag), its size * (Content-Length), and update timestamp (Last-Modified). * * @throws ServiceException */ public Map updateObjectMetadata(String bucketName, StorageObject object) throws ServiceException { return copyObject(bucketName, object.getKey(), bucketName, object, true); } /** * Deletes an object from a bucket. *

* This method can be performed by anonymous services. Anonymous services * can delete objects from publicly-writable buckets. * * @param bucketName * the name of the bucket containing the object to be deleted. * @param objectKey * the key representing the object * @throws ServiceException */ public void deleteObject(String bucketName, String objectKey) throws ServiceException { assertValidObject(objectKey, "deleteObject"); MxDelegate.getInstance().registerStorageObjectDeleteEvent(bucketName, objectKey); deleteObjectImpl(bucketName, objectKey, null, null, null); } /** * Returns an object representing the details of an item that meets any given preconditions. * The object is returned without the object's data. *

* An exception is thrown if any of the preconditions fail. * Preconditions are only applied if they are non-null. *

* This method can be performed by anonymous services. Anonymous services * can get details of publicly-readable objects. * * @param bucketName * the name of the bucket containing the object. * @param objectKey * the key identifying the object. * @param ifModifiedSince * a precondition specifying a date after which the object must have been modified, ignored if null. * @param ifUnmodifiedSince * a precondition specifying a date after which the object must not have been modified, ignored if null. * @param ifMatchTags * a precondition specifying an MD5 hash the object must match, ignored if null. * @param ifNoneMatchTags * a precondition specifying an MD5 hash the object must not match, ignored if null. * @return * the object with the given key, including only general details and metadata (not the data * input stream) * @throws ServiceException */ public StorageObject getObjectDetails(String bucketName, String objectKey, Calendar ifModifiedSince, Calendar ifUnmodifiedSince, String[] ifMatchTags, String[] ifNoneMatchTags) throws ServiceException { MxDelegate.getInstance().registerStorageObjectHeadEvent(bucketName, objectKey); return getObjectDetailsImpl(bucketName, objectKey, ifModifiedSince, ifUnmodifiedSince, ifMatchTags, ifNoneMatchTags, null); } /** * Returns an object representing the details and data of an item that meets any given preconditions. *

* Important: It is the caller's responsibility to close the object's data input stream. * The data stream should be consumed and closed as soon as is practical as network connections * may be held open until the streams are closed. Excessive unclosed streams can lead to * connection starvation. *

* An exception is thrown if any of the preconditions fail. * Preconditions are only applied if they are non-null. *

* This method can be performed by anonymous services. Anonymous services * can get a publicly-readable object. *

* Implementation notes

* Implementations should use {@link #assertValidBucket} assertion. * * @param bucketName * the name of the bucket containing the object. * @param objectKey * the key identifying the object. * @param ifModifiedSince * a precondition specifying a date after which the object must have been modified, ignored if null. * @param ifUnmodifiedSince * a precondition specifying a date after which the object must not have been modified, ignored if null. * @param ifMatchTags * a precondition specifying an MD5 hash the object must match, ignored if null. * @param ifNoneMatchTags * a precondition specifying an MD5 hash the object must not match, ignored if null. * @param byteRangeStart * include only a portion of the object's data - starting at this point, ignored if null. * @param byteRangeEnd * include only a portion of the object's data - ending at this point, ignored if null. * @return * the object with the given key, including only general details and metadata (not the data * input stream) * @throws ServiceException */ public StorageObject getObject(String bucketName, String objectKey, Calendar ifModifiedSince, Calendar ifUnmodifiedSince, String[] ifMatchTags, String[] ifNoneMatchTags, Long byteRangeStart, Long byteRangeEnd) throws ServiceException { MxDelegate.getInstance().registerStorageObjectGetEvent(bucketName, objectKey); return getObjectImpl(bucketName, objectKey, ifModifiedSince, ifUnmodifiedSince, ifMatchTags, ifNoneMatchTags, byteRangeStart, byteRangeEnd, null); } /** * Applies access control settings to an object. The ACL settings must be included * with the object. * * This method can be performed by anonymous services, but can only succeed if the * object's existing ACL already allows write access by the anonymous user. * In general, you can only access the ACL of an object if the ACL already in place * for that object allows you to do so. * * @param bucketName * the name of the bucket containing the object to modify. * @param object * the object with ACL settings that will be applied. * @throws ServiceException */ public void putObjectAcl(String bucketName, StorageObject object) throws ServiceException { assertValidObject(object, "Put Object Access Control List"); putObjectAcl(bucketName, object.getKey(), object.getAcl()); } /** * Applies access control settings to an object. The ACL settings must be included * with the object. * * This method can be performed by anonymous services, but can only succeed if the * object's existing ACL already allows write access by the anonymous user. * In general, you can only access the ACL of an object if the ACL already in place * for that object allows you to do so. * * @param bucketName * the name of the bucket containing the object to modify. * @param objectKey * the key name of the object with ACL settings that will be applied. * @param acl * the ACL to apply. * @throws ServiceException */ public void putObjectAcl(String bucketName, String objectKey, AccessControlList acl) throws ServiceException { if (acl == null) { throw new ServiceException("The object '" + objectKey + "' does not include ACL information"); } putObjectAclImpl(bucketName, objectKey, acl, null); } /** * Retrieves the access control settings of an object. * * This method can be performed by anonymous services, but can only succeed if the * object's existing ACL already allows write access by the anonymous user. * In general, you can only access the ACL of an object if the ACL already in place * for that object allows you to do so. * * @param bucketName * the name of the bucket whose ACL settings will be retrieved (if objectKey is null) or the * name of the bucket containing the object whose ACL settings will be retrieved (if objectKey is non-null). * @param objectKey * if non-null, the key of the object whose ACL settings will be retrieved. Ignored if null. * @return * the ACL settings of the bucket or object. * @throws ServiceException */ public AccessControlList getObjectAcl(String bucketName, String objectKey) throws ServiceException { return getObjectAclImpl(bucketName, objectKey, null); } /** * Applies access control settings to a bucket. The ACL settings must be included * inside the bucket. * * This method can be performed by anonymous services, but can only succeed if the * bucket's existing ACL already allows write access by the anonymous user. * In general, you can only access the ACL of a bucket if the ACL already in place * for that bucket allows you to do so. * * @param bucketName * a name of the bucket with ACL settings to apply. * @param acl * the ACL to apply. * @throws ServiceException */ public void putBucketAcl(String bucketName, AccessControlList acl) throws ServiceException { if (acl == null) { throw new ServiceException("The bucket '" + bucketName + "' does not include ACL information"); } putBucketAclImpl(bucketName, acl); } /** * Applies access control settings to a bucket. The ACL settings must be included * inside the bucket. * * This method can be performed by anonymous services, but can only succeed if the * bucket's existing ACL already allows write access by the anonymous user. * In general, you can only access the ACL of a bucket if the ACL already in place * for that bucket allows you to do so. * * @param bucket * a bucket with ACL settings to apply. * @throws ServiceException */ public void putBucketAcl(StorageBucket bucket) throws ServiceException { assertValidBucket(bucket, "Put Bucket Access Control List"); putBucketAcl(bucket.getName(), bucket.getAcl()); } /** * Retrieves the access control settings of a bucket. * * This method can be performed by anonymous services, but can only succeed if the * bucket's existing ACL already allows write access by the anonymous user. * In general, you can only access the ACL of a bucket if the ACL already in place * for that bucket allows you to do so. * * @param bucketName * the name of the bucket whose access control settings will be returned. * @return * the ACL settings of the bucket. * @throws ServiceException */ public AccessControlList getBucketAcl(String bucketName) throws ServiceException { return getBucketAclImpl(bucketName); } /** * Returns the current date and time, adjusted according to the time * offset between your computer and an AWS server (as set by the * {@link RestUtils#getAWSTimeAdjustment()} method). * * @return * the current time, or the current time adjusted to match the AWS time * if the {@link RestUtils#getAWSTimeAdjustment()} method has been invoked. */ public Date getCurrentTimeWithOffset() { return new Date(System.currentTimeMillis() + timeOffset); } /** * Renames metadata property names to be suitable for use as HTTP Headers. This is done * by renaming any non-HTTP headers to have the a service-specific prefix and leaving the * HTTP header names unchanged. The HTTP header names left unchanged are those found in * {@link RestUtils#HTTP_HEADER_METADATA_NAMES} * * @param metadata * @return * a map of metadata property name/value pairs renamed to be suitable for use as HTTP headers. */ public Map renameMetadataKeys(Map metadata) { Map convertedMetadata = new HashMap(); // Add all meta-data headers. if (metadata != null) { for (Map.Entry entry: metadata.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); if (!RestUtils.HTTP_HEADER_METADATA_NAMES.contains(key.toLowerCase(Locale.getDefault())) && !key.startsWith(this.getRestHeaderPrefix())) { key = this.getRestMetadataPrefix() + key; } convertedMetadata.put(key, value); } } return convertedMetadata; } // /////////////////////////////////////////////////////////////////////////////// // Abstract methods that must be implemented by interface-specific service classes // /////////////////////////////////////////////////////////////////////////////// /** * Indicates whether a bucket exists and is accessible to a service user. *

* Caution: This check started to cause issues in situations where you need to * immediately create a bucket when it does not exist. To conditionally create a bucket, * use the {@link #getOrCreateBucket(String)} method instead. *

* This method can be performed by anonymous services. *

* Implementation notes

* This method can be implemented by attempting to list the objects in a bucket. If the listing * is successful return true, if the listing failed for any reason return false. * * @param bucketName * the bucket to check. * @return * true if the bucket exists and is accessible to the service user, false otherwise. * @throws ServiceException */ public abstract boolean isBucketAccessible(String bucketName) throws ServiceException; /** * Find out the status of a bucket with the given name. *

* Caveats: *

    *
  • If someone else owns the bucket but has made it public, this method will * mistakenly return {@link #BUCKET_STATUS__MY_BUCKET}.
  • *
  • *

    * S3 can act strangely when you use this method in some circumstances. * If you check the status of a bucket and find that it does not exist, then create the * bucket, the service will continue to tell you the bucket does not exists for up to 30 * seconds. This problem has something to do with connection caching (I think).

    *

    * This S3 quirk makes it a bad idea to use this method to check for a bucket's * existence before creating that bucket. Use the {@link #getOrCreateBucket(String)} * method for this purpose instead.

    *
  • *
*

* * @param bucketName * @return * {@link #BUCKET_STATUS__MY_BUCKET} if you already own the bucket, * {@link #BUCKET_STATUS__DOES_NOT_EXIST} if the bucket does not yet exist, or * {@link #BUCKET_STATUS__ALREADY_CLAIMED} if someone else has * already created a bucket with the given name. * * @throws ServiceException */ public abstract int checkBucketStatus(String bucketName) throws ServiceException; /** * @return * the buckets in your account. * * @throws ServiceException */ protected abstract StorageBucket[] listAllBucketsImpl() throws ServiceException; /** * @return * the owner of an account. * @throws ServiceException */ protected abstract StorageOwner getAccountOwnerImpl() throws ServiceException; /** * Lists objects in a bucket. * * Implementation notes

* The implementation of this method is expected to return all the objects * in a bucket, not a subset. This may require repeating the list operation if the * first one doesn't include all the available objects, such as when the number of objects * is greater than maxListingLength. *

* * @param bucketName * @param prefix * only objects with a key that starts with this prefix will be listed, may be null. * @param delimiter * only list objects with key names up to this delimiter, may be null. * @param maxListingLength * @return * the objects in a bucket. * * @throws ServiceException */ protected abstract StorageObject[] listObjectsImpl(String bucketName, String prefix, String delimiter, long maxListingLength) throws ServiceException; /** * Lists objects in a bucket up to the maximum listing length specified. * *

* Implementation notes * The implementation of this method returns only as many objects as requested in the chunk * size. It is the responsibility of the caller to build a complete object listing from * multiple chunks, should this be necessary. *

* * @param bucketName * @param prefix * only objects with a key that starts with this prefix will be listed, may be null. * @param delimiter * only list objects with key names up to this delimiter, may be null. * @param maxListingLength * @param priorLastKey * @param completeListing * @throws ServiceException */ protected abstract StorageObjectsChunk listObjectsChunkedImpl(String bucketName, String prefix, String delimiter, long maxListingLength, String priorLastKey, boolean completeListing) throws ServiceException; /** * Creates a bucket. * * Implementation notes

* The implementing method must populate the bucket object's metadata with the results of the * operation before returning the object. It must also apply any AccessControlList * settings included with the bucket. * * @param bucketName * the name of the bucket to create. * @param location * the geographical location where the bucket will be stored (if applicable for the target * service). A null string value will cause the bucket to be stored in the default location. * @param acl * an access control object representing the initial acl values for the bucket. * May be null, in which case the default permissions are applied. * @return * the created bucket object, populated with all metadata made available by the creation operation. * @throws ServiceException */ protected abstract StorageBucket createBucketImpl(String bucketName, String location, AccessControlList acl) throws ServiceException; protected abstract void deleteBucketImpl(String bucketName) throws ServiceException; protected abstract StorageObject putObjectImpl(String bucketName, StorageObject object) throws ServiceException; /** * Copy an object within your account. Copies within a single bucket or between * buckets, and optionally updates the object's metadata at the same time. An * object can be copied over itself, allowing you to update the metadata without * making any other changes. * * @param sourceBucketName * the name of the bucket that contains the original object. * @param sourceObjectKey * the key name of the original object. * @param destinationBucketName * the name of the destination bucket to which the object will be copied. * @param destinationObjectKey * the key name for the copied object. * @param acl * the access control settings that will be applied to the copied object. * If this parameter is null, the default (private) ACL setting will be * applied to the copied object. * @param destinationMetadata * metadata items to apply to the copied object. If this parameter is null, * the metadata will be copied unchanged from the original object. If this * parameter is not null, the copied object will have only the supplied * metadata. * * @return * a map of the header and result information returned after the object * copy. The map includes the object's MD5 hash value (ETag), its size * (Content-Length), and update timestamp (Last-Modified). * * @throws ServiceException */ protected abstract Map copyObjectImpl(String sourceBucketName, String sourceObjectKey, String destinationBucketName, String destinationObjectKey, AccessControlList acl, Map destinationMetadata, Calendar ifModifiedSince, Calendar ifUnmodifiedSince, String[] ifMatchTags, String[] ifNoneMatchTags, String versionId, String destinationObjectStorageClass) throws ServiceException; protected abstract void deleteObjectImpl(String bucketName, String objectKey, String versionId, String multiFactorSerialNumber, String multiFactorAuthCode) throws ServiceException; protected abstract StorageObject getObjectDetailsImpl(String bucketName, String objectKey, Calendar ifModifiedSince, Calendar ifUnmodifiedSince, String[] ifMatchTags, String[] ifNoneMatchTags, String versionId) throws ServiceException; protected abstract StorageObject getObjectImpl(String bucketName, String objectKey, Calendar ifModifiedSince, Calendar ifUnmodifiedSince, String[] ifMatchTags, String[] ifNoneMatchTags, Long byteRangeStart, Long byteRangeEnd, String versionId) throws ServiceException; protected abstract void putBucketAclImpl(String bucketName, AccessControlList acl) throws ServiceException; protected abstract void putObjectAclImpl(String bucketName, String objectKey, AccessControlList acl, String versionId) throws ServiceException; protected abstract AccessControlList getObjectAclImpl(String bucketName, String objectKey, String versionId) throws ServiceException; protected abstract AccessControlList getBucketAclImpl(String bucketName) throws ServiceException; protected abstract void shutdownImpl() throws ServiceException; /** * @return * the URL end-point of the target service. */ public abstract String getEndpoint(); protected abstract String getVirtualPath(); protected abstract String getSignatureIdentifier(); /** * @return * the REST header prefix used by the target service. */ public abstract String getRestHeaderPrefix(); /** * @return * GET parameter names that represent specific resources in the target * service, as opposed to representing REST operation "plumbing". For * example the "acl" parameter might be used to represent a resource's * access control list settings. */ public abstract List getResourceParameterNames(); /** * @return * the REST header prefix used by the target service to identify * metadata information. */ public abstract String getRestMetadataPrefix(); protected abstract int getHttpPort(); protected abstract int getHttpsPort(); protected abstract boolean getHttpsOnly(); protected abstract boolean getDisableDnsBuckets(); protected abstract boolean getEnableStorageClasses(); } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/io/0002755000000000000000000000000011550421156016343 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/io/InterruptableInputStream.java0000644000000000000000000000643011537563564024242 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.io; import java.io.IOException; import java.io.InputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Input stream wrapper that allows the underlying wrapped input stream to be interrupted. * Every time a blocking stream operation is invoked on this class, the interrupt flag is * checked first. If this flag is set, the underlying stream is closed and an IOException * "Input Stream Interrupted" is thrown. *

* Note: This hacky class does not really solve the problem of interrupting blocking * Java input streams, as it cannot unblock a blocked read operation. It really just serves * as a convenient way to interrupt streams before any potentially blocking operations. * * @author James Murty */ public class InterruptableInputStream extends InputStream implements InputStreamWrapper { private static final Log log = LogFactory.getLog(InterruptableInputStream.class); private InputStream inputStream = null; private boolean interrupted = false; public InterruptableInputStream(InputStream inputStream) { this.inputStream = inputStream; } private void maybeInterruptInputStream() throws IOException { if (interrupted) { if (log.isDebugEnabled()) { log.debug("Input stream interrupted, closing underlying input stream " + this.inputStream.getClass()); } try { close(); } catch (IOException ioe) { if (log.isWarnEnabled()) { log.warn("Unable to close underlying InputStream on interrupt"); } } // Throw an unrecoverable exception to indicate that this exception was deliberate, and // should not be recovered from. throw new UnrecoverableIOException("Reading from input stream deliberately interrupted"); } } @Override public int read() throws IOException { maybeInterruptInputStream(); return inputStream.read(); } @Override public int read(byte[] b, int off, int len) throws IOException { maybeInterruptInputStream(); return inputStream.read(b, off, len); } @Override public int available() throws IOException { maybeInterruptInputStream(); return inputStream.available(); } @Override public void close() throws IOException { inputStream.close(); } public InputStream getWrappedInputStream() { return inputStream; } public void interrupt() { interrupted = true; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/io/OutputStreamWrapper.java0000644000000000000000000000210411427702124023216 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.io; import java.io.OutputStream; /** * Interface used by output streams that wrap other output streams, so that the underlying output * stream can be retrieved. * * @author James Murty */ public interface OutputStreamWrapper { /** * @return * the underlying input stream wrapped by this class. */ public OutputStream getWrappedOutputStream(); } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/io/RepeatableInputStream.java0000644000000000000000000001571311550441756023463 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.io; import java.io.IOException; import java.io.InputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.Jets3tProperties; /** * A repeatable input stream wrapper for any input stream. This input stream relies on buffered * data to repeat, and can therefore only be repeated when less data has been read than this * buffer can hold. *

* Note: Always use a {@link RepeatableFileInputStream} instead of this class if you are * sourcing data from a file, as the file-based repeatable input stream can be repeated without * any limitations. * *

* This class uses properties obtained through {@link Jets3tProperties}. For more information on * these properties please refer to * JetS3t Configuration *

* * @author James Murty */ public class RepeatableInputStream extends InputStream implements InputStreamWrapper { private static final Log log = LogFactory.getLog(RepeatableInputStream.class); private InputStream is = null; private int bufferSize = 0; private int bufferOffset = 0; private long bytesReadPastMark = 0; private byte[] buffer = null; /** * Creates a repeatable input stream based on another input stream. * * @param inputStream * an input stream to wrap. The data read from the wrapped input stream is buffered as it is * read, up to the buffer limit specified. * @param bufferSize * the number of bytes buffered by this class. */ public RepeatableInputStream(InputStream inputStream, int bufferSize) { if (inputStream == null) { throw new IllegalArgumentException("InputStream cannot be null"); } this.is = inputStream; this.bufferSize = bufferSize; this.buffer = new byte[this.bufferSize]; if (log.isDebugEnabled()) { log.debug("Underlying input stream will be repeatable up to " + this.buffer.length + " bytes"); } } /** * Resets the input stream to the beginning by pointing the buffer offset to the beginning of the * available data buffer. * * @throws UnrecoverableIOException * when the available buffer size has been exceeded, in which case the input stream data cannot * be repeated. */ @Override public void reset() throws IOException { if (bytesReadPastMark <= bufferSize) { if (log.isDebugEnabled()) { log.debug("Reset after reading " + bytesReadPastMark + " bytes."); } bufferOffset = 0; } else { throw new UnrecoverableIOException( "Input stream cannot be reset as " + this.bytesReadPastMark + " bytes have been written, exceeding the available buffer size of " + this.bufferSize); } } @Override public boolean markSupported() { return true; } /** * This method can only be used while less data has been read from the input * stream than fits into the buffer. The readLimit parameter is ignored entirely. */ @Override public synchronized void mark(int readlimit) { if (log.isDebugEnabled()) { log.debug("Input stream marked at " + bytesReadPastMark + " bytes"); } if (bytesReadPastMark <= bufferSize && buffer != null) { // Clear buffer of already-read data to make more space. // it is safe to cast bytesReadPastMark to an int because it is known to be less than bufferSize, which is an int byte[] newBuffer = new byte[this.bufferSize]; System.arraycopy(buffer, bufferOffset, newBuffer, 0, (int)(bytesReadPastMark - bufferOffset)); this.buffer = newBuffer; this.bytesReadPastMark -= bufferOffset; this.bufferOffset = 0; } else { // If mark is called after the buffer was already exceeded, create a new buffer. this.bufferOffset = 0; this.bytesReadPastMark = 0; this.buffer = new byte[this.bufferSize]; } } @Override public int available() throws IOException { return is.available(); } @Override public void close() throws IOException { is.close(); } @Override public int read(byte[] out, int outOffset, int outLength) throws IOException { byte[] tmp = new byte[outLength]; // Check whether we already have buffered data. if (bufferOffset < bytesReadPastMark && buffer != null) { // Data is being repeated, so read from buffer instead of wrapped input stream. int bytesFromBuffer = tmp.length; if (bufferOffset + bytesFromBuffer > bytesReadPastMark) { bytesFromBuffer = (int) bytesReadPastMark - bufferOffset; } // Write to output. System.arraycopy(buffer, bufferOffset, out, outOffset, bytesFromBuffer); bufferOffset += bytesFromBuffer; return bytesFromBuffer; } // Read data from input stream. int count = is.read(tmp); if (count <= 0) { return count; } // Fill the buffer with data, as long as we won't exceed its capacity. if (bytesReadPastMark + count <= bufferSize) { System.arraycopy(tmp, 0, buffer, (int) bytesReadPastMark, count); bufferOffset += count; } else if (buffer != null) { // We have exceeded the buffer capacity, after which point it is of no use. Free the memory. if (log.isDebugEnabled()) { log.debug("Buffer size " + bufferSize + " has been exceeded and the input stream " + "will not be repeatable until the next mark. Freeing buffer memory"); } buffer = null; } // Write to output byte array. System.arraycopy(tmp, 0, out, outOffset, count); bytesReadPastMark += count; return count; } @Override public int read() throws IOException { byte[] tmp = new byte[1]; int count = read(tmp); if (count != -1) { return tmp[0]; } else { return count; } } public InputStream getWrappedInputStream() { return is; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/io/GZipInflatingOutputStream.java0000644000000000000000000002326411427702124024315 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.io; import java.io.IOException; import java.io.OutputStream; import java.util.zip.CRC32; import java.util.zip.DataFormatException; import java.util.zip.Deflater; import java.util.zip.Inflater; /** * Output stream that wraps another stream and inflates (de-compresses) the underlying stream's * data on-the-fly. This class provides only a basic implementation of GZip functionality. * * @author James Murty */ public class GZipInflatingOutputStream extends OutputStream implements OutputStreamWrapper { /* * GZIP header magic number. */ public final static int GZIP_MAGIC = 0x8b1f; /* * File header flags. */ private final static int FTEXT = 1; // Extra text private final static int FHCRC = 2; // Header CRC private final static int FEXTRA = 4; // Extra field private final static int FNAME = 8; // File name private final static int FCOMMENT = 16; // File comment private int BUFFER_SIZE = 8192; private Inflater inflater = new Inflater(true); private CRC32 crc = new CRC32(); private OutputStream outputStream = null; private byte[] inflatedBytes = new byte[BUFFER_SIZE]; // Variables used to parse Header. private boolean finishedHeader = false; private byte[] headerBytes = new byte[156]; private int expectedHeaderLength = 0; private int headerLength = 0; private int headerOffset = 0; private int headerFlag = 0; // Variables used to parse tail. private byte[] trailerBytes = new byte[8]; // Can we assume trailer is only ever 8 bytes...? private int trailerOffset = 0; public GZipInflatingOutputStream(OutputStream outputStream) throws IOException { this.outputStream = outputStream; crc.reset(); expectedHeaderLength = 4; } private void inflateData() throws IOException { try { int bytesWritten = -1; while (bytesWritten != 0) { bytesWritten = inflater.inflate(inflatedBytes, 0, inflatedBytes.length); outputStream.write(inflatedBytes, 0, bytesWritten); crc.update(inflatedBytes, 0, bytesWritten); } } catch (IOException e) { outputStream.close(); throw e; } catch (DataFormatException e) { outputStream.close(); throw new IOException("Invalid GZip data output stream: " + e); } } private void parseHeader(byte[] b, int off, int len) throws IOException { // Store all potential header bytes in a buffer. for (int i = 0; i < len && headerLength < headerBytes.length; i++) { headerBytes[headerLength++] = b[off + i]; } // Once we have the first 4 bytes, check for validity and flag values. if (headerOffset == 0 && headerLength >= 4) { // Check header magic int GZIP_MAGIC = 0x8b1f; if (bytesToShort(headerBytes, 0) != GZIP_MAGIC) { outputStream.close(); throw new IOException("Not in GZIP format"); } // Check compression method if ((headerBytes[2] & 0xFF) != Deflater.DEFLATED) { outputStream.close(); throw new IOException("Unexpected compression method"); } // Read header content flags headerFlag = (headerBytes[3] & 0xFF); // Skip MTIME, XFL, and OS fields expectedHeaderLength += 6; headerOffset = 10; if ((headerFlag & FEXTRA) == FEXTRA) expectedHeaderLength += 2; if ((headerFlag & FNAME) == FNAME) expectedHeaderLength++; if ((headerFlag & FCOMMENT) == FCOMMENT) { expectedHeaderLength++; } if ((headerFlag & FHCRC) == FHCRC) { expectedHeaderLength += 2; } } // Once we have enough bytes to start checking flag values, do so. while (headerOffset != expectedHeaderLength && headerLength >= expectedHeaderLength) { // Skip optional extra field if ((headerFlag & FEXTRA) == FEXTRA) { // Skip past this variable-length field. int fieldLength = bytesToShort(headerBytes, headerOffset); expectedHeaderLength += fieldLength; headerOffset += 2 + fieldLength; } else // Skip optional file name if ((headerFlag & FNAME) == FNAME) { char fnameChar = (char) headerBytes[headerOffset++]; if (fnameChar != 0) { // More filename characters to come. expectedHeaderLength++; } } else // Skip optional file comment if ((headerFlag & FCOMMENT) == FCOMMENT) { // Consume bytes until we get to the end of the comments. while ((headerBytes[headerOffset] & 0xFF) != 0) { headerOffset++; expectedHeaderLength++; } } else // Check optional header CRC if ((headerFlag & FHCRC) == FHCRC) { crc.update(headerBytes, 0, headerOffset); int v = (int)crc.getValue() & 0xffff; if (bytesToShort(headerBytes, headerOffset) != v) { outputStream.close(); throw new IOException("Corrupt GZIP header"); } crc.reset(); headerOffset++; expectedHeaderLength++; } } if (headerOffset == expectedHeaderLength && headerLength >= expectedHeaderLength) { // Finished parsing the header. finishedHeader = true; // Pass any remaining bytes in the header buffer to the inflater. if (headerLength > headerOffset) { inflater.setInput(headerBytes, headerOffset, headerLength - headerOffset); } // Pass all other remaining bytes to the inflater. if (len > headerLength) { inflater.setInput(b, headerOffset, len - headerOffset); } } } public void write(int value) throws IOException { byte[] single = new byte[] { (byte) (value & 0xFF) }; write(single, 0, 1); } public void write(byte[] b, int off, int len) throws IOException { if (len <= 0) { return; } if (!finishedHeader) { // Keep parsing header data until the header is finished. parseHeader(b, off, len); } else { inflater.setInput(b, off, len); } if (!inflater.finished()) { inflateData(); if (inflater.finished() && inflater.getRemaining() > 0) { // Copy bytes left-over from inflater into trailer buffer. int trailerOffsetInInput = len - inflater.getRemaining(); while (trailerOffset < inflater.getRemaining()) { trailerBytes[trailerOffset++] = b[trailerOffsetInInput++]; } } } else { // Inflator has all the input bytes it needs, anything left over is for the tailer fields. if (trailerOffset + len > trailerBytes.length) { outputStream.close(); throw new IOException("Corrupt GZIP trailer, too many trailer bytes (only 8 expected)"); } System.arraycopy(b, off, trailerBytes, trailerOffset, len); trailerOffset += len; } } public void flush() throws IOException { outputStream.flush(); } public void close() throws IOException { outputStream.close(); if (inflater != null) { // Check that the data stream has been correctly unzipped. if (trailerOffset < trailerBytes.length) { throw new IOException("Corrupt GZIP trailer, trailer is incomplete. Expected 8 bytes, only have " + trailerOffset); } // Check CRC from trail long trailerCrc = bytesToInt(trailerBytes, 0); if (trailerCrc != crc.getValue()) { throw new IOException("Corrupt GZIP trailer, CRC values mismatch"); } long trailerByteCount = bytesToInt(trailerBytes, 4); if (trailerByteCount != inflater.getTotalOut()) { throw new IOException("Corrupt GZIP trailer, actual size of inflated data mismatch"); } inflater.end(); inflater = null; } } private int bytesToShort(byte[] b, int offset) { int low = (b[offset] & 0xFF); int high = (b[offset + 1] & 0xFF); return (high << 8) | low; } private long bytesToInt(byte[] b, int offset) { int low = bytesToShort(b, offset); int high = bytesToShort(b, offset + 2); return ((long)high << 16) | low; } public OutputStream getWrappedOutputStream() { return this.outputStream; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/io/UnrecoverableIOException.java0000644000000000000000000000230711427702124024111 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.io; import java.io.IOException; /** * Indicates an IOException that cannot, or should not, be recovered from. For example, if a user * deliberately cancels an upload this exception should be thrown to indicate to JetS3t that the * error was intentional. * * @author James Murty */ public class UnrecoverableIOException extends IOException { private static final long serialVersionUID = 1423979730178522822L; public UnrecoverableIOException(String message) { super(message); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/io/ProgressMonitoredInputStream.java0000644000000000000000000000661711427702124025077 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.io; import java.io.IOException; import java.io.InputStream; /** * Input stream wrapper that tracks the number of bytes that have been read through the stream. * When data is read through this stream the count of bytes is increased and the associated * {@link BytesProgressWatcher} object is notified of the count of bytes read. * * @author James Murty */ public class ProgressMonitoredInputStream extends InputStream implements InputStreamWrapper { private InputStream inputStream = null; private BytesProgressWatcher progressWatcher = null; /** * Construts the input stream around an underlying stream and sends notification messages * to a progress watcher when bytes are read from the stream. * * @param inputStream * the input stream to wrap, whose byte transfer count will be monitored. * @param progressWatcher * a watcher object that stores information about the bytes read from a stream, and * allows calculations to be perfomed using this information. */ public ProgressMonitoredInputStream(InputStream inputStream, BytesProgressWatcher progressWatcher) { if (inputStream == null) { throw new IllegalArgumentException( "ProgressMonitoredInputStream cannot run with a null InputStream"); } this.inputStream = inputStream; this.progressWatcher = progressWatcher; } /** * Checks how many bytes have been transferred since the last notification, and sends a notification * message if this number exceeds the minimum bytes transferred value. * * @param bytesTransmitted */ public void sendNotificationUpdate(long bytesTransmitted) { progressWatcher.updateBytesTransferred(bytesTransmitted); } public void resetProgressMonitor() { progressWatcher.resetWatcher(); } public int read() throws IOException { int read = inputStream.read(); if (read != -1) { sendNotificationUpdate(1); } return read; } public int read(byte[] b, int off, int len) throws IOException { int read = inputStream.read(b, off, len); if (read != -1) { sendNotificationUpdate(read); } return read; } public int read(byte[] b) throws IOException { int read = inputStream.read(b); if (read != -1) { sendNotificationUpdate(read); } return read; } public int available() throws IOException { return inputStream.available(); } public void close() throws IOException { inputStream.close(); } public InputStream getWrappedInputStream() { return inputStream; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/io/RepeatableFileInputStream.java0000644000000000000000000001011111537563564024255 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.io; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * A repeatable input stream for files. This input stream can be repeated an unlimited number of * times, without any limitation on when a repeat can occur. * * @author James Murty */ public class RepeatableFileInputStream extends InputStream implements InputStreamWrapper { private static final Log log = LogFactory.getLog(RepeatableFileInputStream.class); protected File file = null; protected FileInputStream fis = null; protected long bytesReadPastMarkPoint = 0; protected long markPoint = 0; /** * Creates a repeatable input stream based on a file. * * @param file * @throws FileNotFoundException */ public RepeatableFileInputStream(File file) throws FileNotFoundException { if (file == null) { throw new IllegalArgumentException("File cannot be null"); } this.fis = new FileInputStream(file); this.file = file; } @Override public long skip(long toSkip) throws IOException { long skipped = this.fis.skip(toSkip); bytesReadPastMarkPoint += skipped; return skipped; } /** * Resets the input stream to the last mark point, or the beginning of the stream if * there is no mark point, by creating a new FileInputStream based on the * underlying file. * * @throws UnrecoverableIOException * when the FileInputStream cannot be re-created. */ @Override public void reset() throws IOException { try { this.fis.close(); this.fis = new FileInputStream(file); long skipped = 0; long toSkip = markPoint; while (toSkip > 0) { skipped = skip(toSkip); toSkip -= skipped; } if (log.isDebugEnabled()) { log.debug("Reset to mark point " + markPoint + " after returning " + bytesReadPastMarkPoint + " bytes"); } this.bytesReadPastMarkPoint = 0; } catch (IOException e) { throw new UnrecoverableIOException("Input stream is not repeatable: " + e.getMessage()); } } @Override public boolean markSupported() { return true; } @Override public void mark(int readlimit) { this.markPoint += bytesReadPastMarkPoint; this.bytesReadPastMarkPoint = 0; if (log.isDebugEnabled()) { log.debug("Input stream marked at " + this.markPoint + " bytes"); } } @Override public int available() throws IOException { return fis.available(); } @Override public void close() throws IOException { fis.close(); } @Override public int read() throws IOException { int byteRead = fis.read(); if (byteRead != -1) { bytesReadPastMarkPoint++; return byteRead; } else { return -1; } } @Override public int read(byte[] arg0, int arg1, int arg2) throws IOException { int count = fis.read(arg0, arg1, arg2); bytesReadPastMarkPoint += count; return count; } public InputStream getWrappedInputStream() { return this.fis; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/io/SegmentedRepeatableFileInputStream.java0000644000000000000000000000760211537563564026124 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2011 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.io; import java.io.File; import java.io.IOException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * A repeatable input stream for files. This input stream can be repeated an unlimited number of * times, without any limitation on when a repeat can occur. * * @author James Murty */ public class SegmentedRepeatableFileInputStream extends RepeatableFileInputStream { private static final Log log = LogFactory.getLog(SegmentedRepeatableFileInputStream.class); protected long offset = 0; protected long segmentLength = 0; /** * Creates a repeatable input stream based on a file. * * @param file * @throws IOException */ public SegmentedRepeatableFileInputStream(File file, long offset, long segmentLength) throws IOException { super(file); this.offset = offset; this.segmentLength = segmentLength; if (segmentLength < 1) { throw new IllegalArgumentException( "Segment length " + segmentLength + " must be greater than 0"); } // Sanity check segment bounds against underlying file if (file.length() < this.offset + this.segmentLength) { throw new IllegalArgumentException( "Offset " + offset + " plus segment length " + segmentLength + "exceed length of file " + file); } // Skip forward to requested offset in file input stream. skipToOffset(); } private void skipToOffset() throws IOException { long skipped = 0; long toSkip = offset; while (toSkip > 0) { skipped = skip(toSkip); toSkip -= skipped; } // Mark the offset location so we will return here on reset super.mark(0); if (log.isDebugEnabled()) { log.debug("Skipped to segment offset " + offset); } } @Override public int available() throws IOException { // Nobody will ever need an input stream longer that 2^31 - 1 bytes... D'oh! long reallyAvailable = this.segmentLength - (bytesReadPastMarkPoint + getRelativeMarkPoint()); if (reallyAvailable > Integer.MAX_VALUE) { return Integer.MAX_VALUE; } return (int) reallyAvailable; } @Override public int read() throws IOException { // Ensure we don't read beyond the segment length if (bytesReadPastMarkPoint + getRelativeMarkPoint() >= segmentLength) { return -1; } else { return super.read(); } } @Override public int read(byte[] bytes, int off, int len) throws IOException { bytesReadPastMarkPoint += off; // Ensure we don't read beyond the segment length if (bytesReadPastMarkPoint + getRelativeMarkPoint() >= segmentLength) { return -1; } if (bytesReadPastMarkPoint + getRelativeMarkPoint() + len > segmentLength) { len = (int) (segmentLength - (bytesReadPastMarkPoint + getRelativeMarkPoint() + off)); } return super.read(bytes, off, len); } private long getRelativeMarkPoint() { return markPoint - this.offset; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/io/ProgressMonitoredOutputStream.java0000644000000000000000000000634411427702124025275 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2007 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.io; import java.io.IOException; import java.io.OutputStream; /** * Output stream wrapper that tracks the number of bytes that have been written through the stream. * When data is written through this stream the count of bytes is increased, and at a set minimum * interval (eg after at least 1024 bytes) a {@link BytesProgressWatcher} implementation * is notified of the count of bytes read since the last notification. * * @author James Murty */ public class ProgressMonitoredOutputStream extends OutputStream implements OutputStreamWrapper { private OutputStream outputStream = null; private BytesProgressWatcher progressWatcher = null; /** * Construts the input stream around an underlying stream and sends notification messages * to a progress watcher when bytes are read from the stream. * * @param outputStream * the output stream to wrap, whose byte transfer count will be monitored. * @param progressWatcher * a watcher object that stores information about the bytes read from a stream, and * allows calculations to be perfomed using this information. */ public ProgressMonitoredOutputStream(OutputStream outputStream, BytesProgressWatcher progressWatcher) { if (outputStream == null) { throw new IllegalArgumentException( "ProgressMonitoredOutputStream cannot run with a null OutputStream"); } this.outputStream = outputStream; this.progressWatcher = progressWatcher; } /** * Checks how many bytes have been transferred since the last notification, and sends a notification * message if this number exceeds the minimum bytes transferred value. * * @param bytesTransmitted */ public void sendNotificationUpdate(long bytesTransmitted) { progressWatcher.updateBytesTransferred(bytesTransmitted); } public void resetProgressMonitor() { progressWatcher.resetWatcher(); } public void write(int b) throws IOException { outputStream.write(b); sendNotificationUpdate(1); } public void write(byte[] b, int off, int len) throws IOException { outputStream.write(b, off, len); sendNotificationUpdate(len - off); } public void write(byte[] b) throws IOException { outputStream.write(b.length); sendNotificationUpdate(b.length); } public void close() throws IOException { outputStream.close(); } public OutputStream getWrappedOutputStream() { return outputStream; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/io/TempFile.java0000644000000000000000000000203011427702124020704 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.io; import java.io.File; /** * A wrapper class for a File, that makes it possible to recognize a temporary * file. * * @author James Murty */ public class TempFile extends File { private static final long serialVersionUID = 1971413408549070295L; public TempFile(File file) { super(file.getAbsolutePath()); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/io/GZipDeflatingInputStream.java0000644000000000000000000001410711441613550024072 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.io; import java.io.IOException; import java.io.InputStream; import java.util.zip.CRC32; import java.util.zip.Deflater; /** * Input stream that wraps another stream and deflates (compresses) the underlying stream's * data on-the-fly. This class provides only a basic implementation of GZip functionality. * * @author James Murty */ public class GZipDeflatingInputStream extends InputStream implements InputStreamWrapper { private int BUFFER_SIZE = 8192; Deflater deflater = new Deflater(Deflater.DEFAULT_COMPRESSION, true); private InputStream inputStream = null; private byte[] buffer = new byte[BUFFER_SIZE]; private byte[] deflatedBytes = new byte[BUFFER_SIZE]; private CRC32 crc = new CRC32(); int bufferOffset = 0; int bufferEnd = 0; boolean EOFInput = false; boolean EOFDeflated = false; boolean EOFTail = false; public GZipDeflatingInputStream(InputStream inputStream) throws IOException { this.inputStream = inputStream; crc.reset(); // Write the GZip Header. int GZIP_MAGIC = 0x8b1f; writeShort(GZIP_MAGIC); // Magic number deflatedBytes[bufferEnd++] = (byte) Deflater.DEFLATED; // Compression method (CM) deflatedBytes[bufferEnd++] = 0; // Flags (FLG) writeInt(0); // Modification time (MTIME) deflatedBytes[bufferEnd++] = 0; // Extra flags (XFL) deflatedBytes[bufferEnd++] = 0; // Operating system (OS) } private void primeDeflateBuffer() throws IOException { bufferEnd = 0; while (bufferEnd == 0) { if (!deflater.needsInput()) { // Do pending deflation. bufferEnd = deflater.deflate(deflatedBytes); bufferOffset = 0; } else { if (!EOFInput) { // Obtain more data from the input stream. int byteCount = inputStream.read(buffer, 0, buffer.length); if (byteCount > 0) { crc.update(buffer, 0, byteCount); deflater.setInput(buffer, 0, byteCount); bufferEnd = deflater.deflate(deflatedBytes); bufferOffset = 0; } else if (byteCount == 0) { // The underlying input stream must be non-blocking. Do nothing. } else { // EOF of the underlying Input Stream. deflater.finish(); EOFInput = true; bufferEnd = 0; bufferOffset = 0; } } else { // No more input data available, time to finish up. if (!deflater.finished()) { bufferEnd = deflater.deflate(deflatedBytes); bufferOffset = 0; } else if (!EOFDeflated) { EOFDeflated = true; bufferOffset = 0; bufferEnd = 0; writeInt((int)crc.getValue()); // CRC-32 of uncompressed data writeInt(deflater.getTotalIn()); // Number of uncompressed bytes } else { EOFTail = true; return; } } } } } private int getDeflatedBufferAvail() { return bufferEnd - bufferOffset; } public int read() throws IOException { if (getDeflatedBufferAvail() == 0) { primeDeflateBuffer(); } if (EOFTail) { return -1; } else { return (int) deflatedBytes[bufferOffset++] & 0xFF; } } public int read(byte[] b, int off, int len) throws IOException { if (getDeflatedBufferAvail() == 0) { primeDeflateBuffer(); } if (EOFTail) { return -1; } else { if (len > getDeflatedBufferAvail()) { // More data requested than is available in the buffer, return everything we have. int bytesAvailable = getDeflatedBufferAvail(); System.arraycopy(deflatedBytes, bufferOffset, b, off, bytesAvailable); bufferOffset = 0; bufferEnd = 0; return bytesAvailable; } else { // Return some of the data we have buffered. System.arraycopy(deflatedBytes, bufferOffset, b, off, len); bufferOffset += len; return len; } } } public int available() throws IOException { if (EOFTail) { return -1; } else if (getDeflatedBufferAvail() == 0) { primeDeflateBuffer(); } return getDeflatedBufferAvail(); } public void close() throws IOException { EOFTail = true; inputStream.close(); } public InputStream getWrappedInputStream() { return inputStream; } /* * Writes integer in Intel byte order. */ private void writeInt(int i) { writeShort(i & 0xffff); writeShort((i >> 16) & 0xffff); } /* * Writes short integer in Intel byte order. */ private void writeShort(int s) { deflatedBytes[bufferEnd++] = (byte) (s & 0xff); deflatedBytes[bufferEnd++] = (byte) ((s >> 8) & 0xff); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/io/InputStreamWrapper.java0000644000000000000000000000207511427702124023024 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.io; import java.io.InputStream; /** * Interface used by input streams that wrap other input streams, so that the underlying input * stream can be retrieved. * * @author James Murty */ public interface InputStreamWrapper { /** * @return * the underlying input stream wrapped by this class. */ public InputStream getWrappedInputStream(); } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/io/BytesProgressWatcher.java0000644000000000000000000003204611452170542023343 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.io; import java.util.Map; import java.util.TreeMap; /** * Utility class that tracks the number of bytes transferred from a source, and uses this * information to calculate transfer rates and estimate end times. The watcher stores the * number of bytes that will be transferred, the number of bytes that have been transferred * in the current session and the time this has taken, and the number of bytes and time taken * overal (eg for transfers that have been restarted). * * @author James Murty */ public class BytesProgressWatcher { /** * The number of seconds worth of historical byte transfer information that will be * stored and used to calculate the recent transfer rate. */ public static final int SECONDS_OF_HISTORY = 5; private boolean isStarted = false; private long bytesToTransfer = 0; private long startTimeAllTransfersMS = -1; private long totalBytesInAllTransfers = 0; private long startTimeCurrentTransferMS = -1; private long totalBytesInCurrentTransfer = 0; private long endTimeCurrentTransferMS = -1; private Map historyOfBytesBySecond = new TreeMap(); private long earliestHistorySecond = Long.MAX_VALUE; /** * Construct a watcher for a transfer that will involve a given number of bytes. * * @param bytesToTransfer * the number of bytes that will be transferred, eg the size of a file being uploaded. */ public BytesProgressWatcher(long bytesToTransfer) { this.bytesToTransfer = bytesToTransfer; } /** * @return * the count of bytes that will be transferred by the object watched by this class. */ public synchronized long getBytesToTransfer() { return bytesToTransfer; } /** * Resets the byte count and timer variables for a watcher. This method is called * automatically when a transfer is started (ie the first bytes are registered in * the method {@link #updateBytesTransferred(long)}), or * when a transfer is restarted (eg due to transmission errors). * */ public synchronized void resetWatcher() { startTimeCurrentTransferMS = System.currentTimeMillis(); if (startTimeAllTransfersMS == -1) { startTimeAllTransfersMS = startTimeCurrentTransferMS; } endTimeCurrentTransferMS = -1; totalBytesInCurrentTransfer = 0; isStarted = true; } /** * Notifies this watcher that bytes have been transferred. * * @param byteCount * the number of bytes that have been transferred. */ public synchronized void updateBytesTransferred(long byteCount) { // Start the monitor when we are notified of the first bytes transferred. if (!isStarted) { resetWatcher(); } // Store the total byte count for the current transfer, and for all transfers. totalBytesInCurrentTransfer += byteCount; totalBytesInAllTransfers += byteCount; // Recognise when all the expected bytes have been transferred and mark the end time. if (totalBytesInCurrentTransfer >= bytesToTransfer) { endTimeCurrentTransferMS = System.currentTimeMillis(); } // Keep historical records of the byte counts transferred in a given second. Long currentSecond = new Long(System.currentTimeMillis() / 1000); Long bytesInSecond = historyOfBytesBySecond.get(currentSecond); if (bytesInSecond != null) { historyOfBytesBySecond.put(currentSecond, new Long(byteCount + bytesInSecond.longValue())); } else { historyOfBytesBySecond.put(currentSecond, new Long(byteCount)); } // Remember the earliest second value for which we have historical info. if (currentSecond.longValue() < earliestHistorySecond) { earliestHistorySecond = currentSecond.longValue(); } // Remove any history records we are no longer interested in. long removeHistoryBeforeSecond = currentSecond.longValue() - SECONDS_OF_HISTORY; for (long sec = earliestHistorySecond; sec < removeHistoryBeforeSecond; sec++) { historyOfBytesBySecond.remove(new Long(sec)); } earliestHistorySecond = removeHistoryBeforeSecond; } /** * @return * the number of bytes that have so far been transferred in the most recent transfer session. */ public synchronized long getBytesTransferred() { return totalBytesInCurrentTransfer; } /** * @return * the number of bytes that are remaining to be transferred. */ public synchronized long getBytesRemaining() { return bytesToTransfer - totalBytesInCurrentTransfer; } /** * @return * an estimate of the time (in seconds) it will take for the transfer to completed, based * on the number of bytes remaining to transfer and the overall bytes/second rate. */ public synchronized long getRemainingTime() { BytesProgressWatcher[] progressWatchers = new BytesProgressWatcher[1]; progressWatchers[0] = this; long bytesRemaining = bytesToTransfer - totalBytesInCurrentTransfer; double remainingSecs = bytesRemaining / calculateOverallBytesPerSecond(progressWatchers); return Math.round(remainingSecs); } /** * @return * the byte rate (per second) based on the historical information for the last * {@link #SECONDS_OF_HISTORY} seconds before the current time. */ public synchronized double getRecentByteRatePerSecond() { if (!isStarted) { return 0; } long currentSecond = System.currentTimeMillis() / 1000; long startSecond = 1 + (currentSecond - SECONDS_OF_HISTORY); long endSecond = (endTimeCurrentTransferMS != -1 ? endTimeCurrentTransferMS / 1000 : currentSecond); if (currentSecond - SECONDS_OF_HISTORY > endSecond) { // This item finished too long ago, ignore it now. historyOfBytesBySecond.clear(); return 0; } // Count the number of bytes transferred from SECONDS_OF_HISTORY ago to the second before now. long sumOfBytes = 0; long numberOfSecondsInHistory = 0; for (long sec = startSecond; sec <= endSecond; sec++) { numberOfSecondsInHistory++; Long bytesInSecond = historyOfBytesBySecond.get(new Long(sec)); if (bytesInSecond != null) { sumOfBytes += bytesInSecond.longValue(); } } return (numberOfSecondsInHistory == 0 ? 0 : (double)sumOfBytes / numberOfSecondsInHistory); } /////////////////////////////////////////////////////////////////////////// // These methods are only used to make information available to the public // static utility methods in this class. /////////////////////////////////////////////////////////////////////////// /** * @return * the number of milliseconds time elapsed for a transfer. The value returned is the time * elapsed so far if the transfer is ongoing, the total time taken for the transfer if it * is complete, or 0 if the transfer has not yet started. */ protected synchronized long getElapsedTimeMS() { if (!isStarted) { return 0; } if (endTimeCurrentTransferMS != -1) { // Transfer is complete, report the time it took. return endTimeCurrentTransferMS - startTimeCurrentTransferMS; } else { return System.currentTimeMillis() - startTimeCurrentTransferMS; } } /** * @return * the number of bytes that have been transferred over all sessions, including any sessions * that have been restarted. */ protected synchronized long getTotalBytesInAllTransfers() { return totalBytesInAllTransfers; } protected synchronized boolean isStarted() { return isStarted; } /** * @return * the time (in milliseconds) when the first bytes were transferred, regardless of how many * times the transfer was reset. */ protected synchronized long getHistoricStartTimeMS() { return startTimeAllTransfersMS; } /////////////////////////////////////////////////////////////////////////// // Methods below this point are public static utility methods that perform // calculations over a set of BytesProgressWatcher objects. /////////////////////////////////////////////////////////////////////////// /** * @param progressWatchers * all the watchers involved in the same byte transfer operation. * @return * the total number of bytes to transfer. */ public static long sumBytesToTransfer(BytesProgressWatcher[] progressWatchers) { long sumOfBytes = 0; for (int i = 0; i < progressWatchers.length; i++) { sumOfBytes += progressWatchers[i].getBytesToTransfer(); } return sumOfBytes; } /** * @param progressWatchers * all the watchers involved in the same byte transfer operation. * @return * the total number of bytes already transferred. */ public static long sumBytesTransferred(BytesProgressWatcher[] progressWatchers) { long sumOfBytes = 0; for (int i = 0; i < progressWatchers.length; i++) { sumOfBytes += progressWatchers[i].getBytesTransferred(); } return sumOfBytes; } /** * @param progressWatchers * all the watchers involved in the same byte transfer operation. * @return * an estimate of the time (in seconds) it will take for the transfer to completed, based * on the number of bytes remaining to transfer and the overall bytes/second rate. */ public static long calculateRemainingTime(BytesProgressWatcher[] progressWatchers) { long bytesRemaining = sumBytesToTransfer(progressWatchers) - sumBytesTransferred(progressWatchers); double bytesPerSecond = calculateOverallBytesPerSecond(progressWatchers); if (Math.abs(bytesPerSecond) < 0.001d) { // No transfer has occurred yet. return 0; } double remainingSecs = bytesRemaining / bytesPerSecond; return Math.round(remainingSecs); } /** * @param progressWatchers * all the watchers involved in the same byte transfer operation. * @return * the overall rate of bytes/second over all transfers for all watchers. */ public static double calculateOverallBytesPerSecond(BytesProgressWatcher[] progressWatchers) { long initialStartTime = Long.MAX_VALUE; // The oldest start time of any monitor. long bytesTotal = 0; for (int i = 0; i < progressWatchers.length; i++) { // Ignore any watchers that have not yet started. if (!progressWatchers[i].isStarted()) { continue; } // Add up all the bytes transferred by all started watchers. bytesTotal += progressWatchers[i].getTotalBytesInAllTransfers(); // Find the earliest starting time of any monitor. if (progressWatchers[i].getHistoricStartTimeMS() < initialStartTime) { initialStartTime = progressWatchers[i].getHistoricStartTimeMS(); } } // Determine how much time has elapsed since the earliest watcher start time. long elapsedTimeSecs = (System.currentTimeMillis() - initialStartTime) / 1000; // Calculate the overall rate of bytes/second over all transfers for all watchers. double bytesPerSecondOverall = (elapsedTimeSecs == 0 ? bytesTotal : (double)bytesTotal / elapsedTimeSecs); return bytesPerSecondOverall; } /** * @param progressWatchers * all the watchers involved in the same byte transfer operation. * @return * the rate of bytes/second that has been achieved recently (ie within the last * {@link #SECONDS_OF_HISTORY} seconds). */ public static long calculateRecentByteRatePerSecond(BytesProgressWatcher[] progressWatchers) { double sumOfRates = 0; for (int i = 0; i < progressWatchers.length; i++) { if (progressWatchers[i].isStarted()) { sumOfRates += progressWatchers[i].getRecentByteRatePerSecond(); } } return Math.round(sumOfRates); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/utils/0002755000000000000000000000000011550421156017074 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/utils/FileComparerResults.java0000644000000000000000000001130111537563564023702 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.utils; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * A simple container class to store the results generated by * {@link FileComparer#buildDiscrepancyLists(Map, Map)}. *

* The following key lists are available: *

    *
  • onlyOnServerKeys: objects with these keys exist only in S3, not on the local computer
  • *
  • updatedOnServerKeys: objects with these keys exist in S3 and on the local computer, but the * contents of the objects are different and the S3 version is newer than the local one.
  • *
  • onlyOnClientKeys: objects with these keys exist only on the local computer, not in S3
  • *
  • updatedOnClientKeys: objects with these keys exist in S3 and on the local computer, but the * contents of the objects are different and the local version is newer than the S3 one.
  • *
  • alreadySynchronisedKeys: identical objects with these keys exist in S3 and on the local computer
  • *
* * * @author James Murty */ public class FileComparerResults { public List onlyOnServerKeys, updatedOnServerKeys, updatedOnClientKeys, onlyOnClientKeys, alreadySynchronisedKeys, alreadySynchronisedLocalPaths; public FileComparerResults( List onlyOnServerKeys, List updatedOnServerKeys, List updatedOnClientKeys, List onlyOnClientKeys, List alreadySynchronisedKeys, List alreadySynchronisedLocalPaths) { this.onlyOnServerKeys = onlyOnServerKeys; this.updatedOnServerKeys = updatedOnServerKeys; this.updatedOnClientKeys = updatedOnClientKeys; this.onlyOnClientKeys = onlyOnClientKeys; this.alreadySynchronisedKeys = alreadySynchronisedKeys; this.alreadySynchronisedLocalPaths = alreadySynchronisedLocalPaths; } public FileComparerResults() { this(new ArrayList(), new ArrayList(), new ArrayList(), new ArrayList(), new ArrayList(), new ArrayList()); } public void merge(FileComparerResults resultsToAdd) { this.updatedOnServerKeys.addAll(resultsToAdd.updatedOnServerKeys); this.updatedOnClientKeys.addAll(resultsToAdd.updatedOnClientKeys); this.alreadySynchronisedKeys.addAll(resultsToAdd.alreadySynchronisedKeys); this.alreadySynchronisedLocalPaths.addAll(resultsToAdd.alreadySynchronisedLocalPaths); this.onlyOnServerKeys.addAll(resultsToAdd.onlyOnServerKeys); // Only keys present on S3 and no-where else should remain in server keys list. onlyOnServerKeys.removeAll(updatedOnServerKeys); onlyOnServerKeys.removeAll(updatedOnClientKeys); onlyOnServerKeys.removeAll(onlyOnClientKeys); onlyOnServerKeys.removeAll(alreadySynchronisedKeys); onlyOnServerKeys.removeAll(alreadySynchronisedLocalPaths); this.onlyOnClientKeys.addAll(resultsToAdd.onlyOnClientKeys); // Only keys present on client and no-where else should remain in client keys list. onlyOnClientKeys.removeAll(updatedOnServerKeys); onlyOnClientKeys.removeAll(updatedOnClientKeys); onlyOnClientKeys.removeAll(onlyOnServerKeys); onlyOnClientKeys.removeAll(alreadySynchronisedKeys); onlyOnServerKeys.removeAll(alreadySynchronisedLocalPaths); } public long getCountOfItemsCompared() { return this.updatedOnServerKeys.size() + this.updatedOnClientKeys.size() + this.onlyOnServerKeys.size() + this.onlyOnClientKeys.size() + this.alreadySynchronisedKeys.size(); } @Override public String toString() { return "onlyOnServerKeys: " + onlyOnServerKeys + ", updatedOnServerKeys: " + updatedOnServerKeys + ", updatedOnClientKeys: " + updatedOnClientKeys + ", onlyOnClientKeys: " + onlyOnClientKeys + ", alreadySynchronisedKeys: " + alreadySynchronisedKeys + ", alreadySynchronisedLocalPaths: " + alreadySynchronisedLocalPaths; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/utils/Mimetypes.java0000644000000000000000000002126611550442040021713 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.utils; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; import java.util.StringTokenizer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Utility class that maintains a listing of known Mimetypes, and determines the mimetype of files * based on file extensions. *

* This class is obtained with the {#link {@link #getInstance()} method that recognised loads mime * types from the file mime.types if this file is available at the root of the * classpath. The mime.types file format, and most of the content, is taken from the Apache HTTP * server's mime.types file. *

* The format for mime type setting documents is: * mimetype + extension (+ extension)*. * Any blank lines in the file are ignored, as are lines starting with # which are * considered comments. Lines that have a mimetype but no associated extensions are also ignored. *

* For more information about Mimetype settings please see: * JetS3t Configuration * * @author James Murty */ public class Mimetypes { private static final Log log = LogFactory.getLog(Mimetypes.class); // Mimetypes used frequently in jets3t. /** * The default XML mimetype: application/xml */ public static final String MIMETYPE_XML = "application/xml"; /** * The default HTML mimetype: text/html */ public static final String MIMETYPE_HTML = "text/html"; /** * The default binary mimetype: application/octet-stream */ public static final String MIMETYPE_OCTET_STREAM = "application/octet-stream"; /** * A binary mimetype: binary/octet-stream */ public static final String MIMETYPE_BINARY_OCTET_STREAM = "binary/octet-stream"; /** * The default gzip mimetype: application/x-gzip */ public static final String MIMETYPE_GZIP = "application/x-gzip"; // Mimetypes specific to jetS3T. /** * A JetS3t-specific mimetype used to indicate that an S3 object actually represents * a directory on the local file system. * @deprecated 0.8.0 */ @Deprecated public static final String MIMETYPE_JETS3T_DIRECTORY = "application/x-directory"; private static Mimetypes mimetypes = null; /** * Map that stores file extensions as keys, and the corresponding mimetype as values. */ private final Map extensionToMimetypeMap = new HashMap(); private Mimetypes() { } /** * Loads mime type settings from the file 'mime.types' in the classpath, if it's available. */ public static synchronized Mimetypes getInstance() { if (mimetypes != null) { return mimetypes; } mimetypes = new Mimetypes(); InputStream mimetypesFile = mimetypes.getClass().getResourceAsStream("/mime.types"); if (mimetypesFile != null) { if (log.isDebugEnabled()) { log.debug("Loading mime types from file in the classpath: mime.types"); } try { mimetypes.loadAndReplaceMimetypes(mimetypesFile); } catch (IOException e) { if (log.isErrorEnabled()) { log.error("Failed to load mime types from file in the classpath: mime.types", e); } } } else { if (log.isWarnEnabled()) { log.warn("Unable to find 'mime.types' file in classpath"); } } return mimetypes; } /** * Reads and stores the mime type setting corresponding to a file extension, by reading * text from an InputStream. If a mime type setting already exists when this method is run, * the mime type value is replaced with the newer one. * * @param is * * @throws IOException */ public void loadAndReplaceMimetypes(InputStream is) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(is)); String line = null; while ((line = br.readLine()) != null) { line = line.trim(); if (line.startsWith("#") || line.length() == 0) { // Ignore comments and empty lines. } else { StringTokenizer st = new StringTokenizer(line, " \t"); if (st.countTokens() > 1) { String mimetype = st.nextToken(); while (st.hasMoreTokens()) { String extension = st.nextToken(); extensionToMimetypeMap.put(extension, mimetype); if (log.isDebugEnabled()) { log.debug("Setting mime type for extension '" + extension + "' to '" + mimetype + "'"); } } } else { if (log.isDebugEnabled()) { log.debug("Ignoring mimetype with no associated file extensions: '" + line + "'"); } } } } } /** * Determines the mimetype of a file by looking up the file's extension in an internal listing * to find the corresponding mime type. If the file has no extension, or the extension is not * available in the listing contained in this class, the default mimetype * application/octet-stream is returned. *

* A file extension is one or more characters that occur after the last period (.) in the file's name. * If a file has no extension, * Guesses the mimetype of file data based on the file's extension. * * @param fileName * the name of the file whose extension may match a known mimetype. * * @return * the file's mimetype based on its extension, or a default value of * application/octet-stream if a mime type value cannot be found. */ public String getMimetype(String fileName) { int lastPeriodIndex = fileName.lastIndexOf("."); if (lastPeriodIndex > 0 && lastPeriodIndex + 1 < fileName.length()) { String ext = fileName.substring(lastPeriodIndex + 1); if (extensionToMimetypeMap.keySet().contains(ext)) { String mimetype = extensionToMimetypeMap.get(ext); if (log.isDebugEnabled()) { log.debug("Recognised extension '" + ext + "', mimetype is: '" + mimetype + "'"); } return mimetype; } else { if (log.isDebugEnabled()) { log.debug("Extension '" + ext + "' is unrecognized in mime type listing" + ", using default mime type: '" + MIMETYPE_OCTET_STREAM + "'"); } } } else { if (log.isDebugEnabled()) { log.debug("File name has no extension, mime type cannot be recognised for: " + fileName); } } return MIMETYPE_OCTET_STREAM; } /** * Determines the mimetype of a file by looking up the file's extension in an internal listing * to find the corresponding mime type. If the file has no extension, or the extension is not * available in the listing contained in this class, the default mimetype * application/octet-stream is returned. *

* A file extension is one or more characters that occur after the last period (.) in the file's name. * If a file has no extension, * Guesses the mimetype of file data based on the file's extension. * * @param file * the file whose extension may match a known mimetype. * * @return * the file's mimetype based on its extension, or a default value of * application/octet-stream if a mime type value cannot be found. */ public String getMimetype(File file) { return getMimetype(file.getName()); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/utils/MultipartUtils.java0000644000000000000000000002610711550421156022745 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2011 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.utils; import java.io.File; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.S3Service; import org.jets3t.service.ServiceException; import org.jets3t.service.io.SegmentedRepeatableFileInputStream; import org.jets3t.service.model.MultipartUpload; import org.jets3t.service.model.S3Object; import org.jets3t.service.model.StorageObject; import org.jets3t.service.multi.StorageServiceEventAdaptor; import org.jets3t.service.multi.event.ServiceEvent; import org.jets3t.service.multi.s3.MultipartStartsEvent; import org.jets3t.service.multi.s3.MultipartUploadAndParts; import org.jets3t.service.multi.s3.S3ServiceEventAdaptor; import org.jets3t.service.multi.s3.S3ServiceEventListener; import org.jets3t.service.multi.s3.ThreadedS3Service; /** * Tool to simplify working with the multipart uploads feature offered by * Amazon S3. * * @author jmurty */ public class MultipartUtils { private static final Log log = LogFactory.getLog(MultipartUtils.class); /** * Minimum multipart upload part size supported by S3: 5 MB. * NOTE: This minimum size does not apply to the last part in a * multipart upload, which may be 1 byte or larger. */ public static final long MIN_PART_SIZE = 5 * (1024 * 1024); /** * Maximum object size supported by S3: 5 GB */ public static final long MAX_OBJECT_SIZE = 5 * (1024 * 1024 * 1024); protected long maxPartSize = MAX_OBJECT_SIZE; /** * @param maxPartSize * the maximum size of objects that will be generated or upload by this instance, * must be between {@link #MIN_PART_SIZE} and {@link #MAX_OBJECT_SIZE}. */ public MultipartUtils(long maxPartSize) { if (maxPartSize < MIN_PART_SIZE) { throw new IllegalArgumentException("Maximum part size parameter " + maxPartSize + " is less than the minimum legal part size " + MIN_PART_SIZE); } if (maxPartSize > MAX_OBJECT_SIZE) { throw new IllegalArgumentException("Maximum part size parameter " + maxPartSize + " is greater than the maximum legal upload object size " + MAX_OBJECT_SIZE); } this.maxPartSize = maxPartSize; } /** * Use default value for maximum part size: {@link #MAX_OBJECT_SIZE}. */ public MultipartUtils() { } /** * @return * maximum part size as set in constructor. */ public long getMaxPartSize() { return maxPartSize; } /** * @param file * @return * true if the given file is larger than the maximum part size defined in this instances. */ public boolean isFileLargerThanMaxPartSize(File file) { return file.length() > maxPartSize; } /** * Split the given file into objects such that no object has a size greater than * the defined maximum part size. Each object uses a * {@link SegmentedRepeatableFileInputStream} input stream to manage its own * byte range within the underlying file. * * @param objectKey * the object key name to apply to all objects returned by this method. * @param file * a file to split into multiple parts. * @return * an ordered list of objects that can be uploaded as multipart parts to S3 to * re-constitute the given file in the service. * * @throws IOException * @throws NoSuchAlgorithmException */ public List splitFileIntoObjectsByMaxPartSize(String objectKey, File file) throws IOException, NoSuchAlgorithmException { long fileLength = file.length(); long partCount = fileLength / maxPartSize + (fileLength % maxPartSize > 0 ? 1 : 0); if (log.isDebugEnabled()) { log.debug("Splitting file " + file.getAbsolutePath() + " of " + fileLength + " bytes into " + partCount + " object parts with a maximum part size of " + maxPartSize); } ArrayList multipartPartList = new ArrayList(); SegmentedRepeatableFileInputStream segFIS = null; for (long offset = 0; offset < partCount; offset++) { S3Object object = new S3Object(objectKey); if (offset < partCount - 1) { object.setContentLength(maxPartSize); segFIS = new SegmentedRepeatableFileInputStream( file, offset * maxPartSize, maxPartSize); } else { // Last part, may not be full size. long partLength = fileLength % maxPartSize; // Handle edge-case where last part is exactly the size of maxPartSize if (partLength == 0) { partLength = maxPartSize; } object.setContentLength(partLength); segFIS = new SegmentedRepeatableFileInputStream( file, offset * maxPartSize, partLength); } object.setContentLength(segFIS.available()); object.setDataInputStream(segFIS); // Calculate part's MD5 hash and reset stream object.setMd5Hash(ServiceUtils.computeMD5Hash(segFIS)); segFIS.reset(); multipartPartList.add(object); } return multipartPartList; } /** * Upload one or more file-based objects to S3 as multipart uploads, where each * object's underlying file is split into parts based on the value of * {@link #maxPartSize}. * * Objects are uploaded in parallel using a {@link ThreadedS3Service} class * that is created within this method, so uploads will take place using as * many connections and threads as are configured in your service's * {@link Jets3tProperties}. * * This method can upload small files that don't need to be split into parts, * but because there is extra overhead in performing unnecessary multipart upload * operations you should avoid doing so unless it's really necessary. * * @param bucketName * the target bucket name * @param s3Service * the S3 service that will perform the work * @param objectsForMultipartUpload * a list of one or more objects that will be uploaded, potentially in multiple * parts if the object's underlying file is larger than {@link #maxPartSize} * @param eventListener * an event listener to monitor progress event notifications, which should * recognize and handle error events. May be null, in which case a standard * {@link S3ServiceEventAdaptor} is used which won't report on events but will * throw an exception if there is a failure. * * @throws Exception */ public void uploadObjects(String bucketName, S3Service s3Service, List objectsForMultipartUpload, S3ServiceEventListener eventListener) throws Exception { if (objectsForMultipartUpload == null || objectsForMultipartUpload.size() < 1) { return; } final List multipartUploadList = new ArrayList(); final List uploadAndPartsList = new ArrayList(); if (eventListener == null) { eventListener = new S3ServiceEventAdaptor(); } // Adaptor solely to capture newly-created MultipartUpload objects, which we // will need when it comes time to upload parts or complete the uploads. StorageServiceEventAdaptor captureMultipartUploadObjectsEventAdaptor = new S3ServiceEventAdaptor() { @Override public void event(MultipartStartsEvent event) { if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { for (MultipartUpload upload: event.getStartedUploads()) { multipartUploadList.add(upload); } } } }; try { ThreadedS3Service threadedS3Service = new ThreadedS3Service(s3Service, eventListener); threadedS3Service.addServiceEventListener( captureMultipartUploadObjectsEventAdaptor); // Build map from object key to storage object final Map objectsByKey = new HashMap(); for (StorageObject object: objectsForMultipartUpload) { objectsByKey.put(object.getKey(), object); } // Start all multipart uploads threadedS3Service.multipartStartUploads(bucketName, objectsForMultipartUpload); throwServiceEventAdaptorErrorIfPresent(eventListener); // Build upload and part lists from new multipart uploads, where new // MultipartUpload objects were captured by this method's // captureMultipartUploadObjectsEventAdaptor) for (MultipartUpload upload: multipartUploadList) { StorageObject object = objectsByKey.get(upload.getObjectKey()); if (object.getDataInputFile() == null) { throw new ServiceException(); } List partObjects = splitFileIntoObjectsByMaxPartSize( upload.getObjectKey(), object.getDataInputFile()); uploadAndPartsList.add( new MultipartUploadAndParts(upload, partObjects)); } // Upload all parts for all multipart uploads threadedS3Service.multipartUploadParts(uploadAndPartsList); throwServiceEventAdaptorErrorIfPresent(eventListener); // Complete all multipart uploads threadedS3Service.multipartCompleteUploads(multipartUploadList); throwServiceEventAdaptorErrorIfPresent(eventListener); } catch (Exception e) { throw new Exception("Multipart upload failed", e); } } protected void throwServiceEventAdaptorErrorIfPresent( S3ServiceEventListener eventListener) throws Exception { if (eventListener instanceof S3ServiceEventAdaptor) { ((S3ServiceEventAdaptor)eventListener).throwErrorIfPresent(); } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/utils/gatekeeper/0002755000000000000000000000000011550406652021214 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/utils/gatekeeper/SignatureRequest.java0000644000000000000000000001452611427702124025373 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.utils.gatekeeper; import java.util.HashMap; import java.util.Map; import org.jets3t.service.model.S3Object; /** * Represents a signature request - that is, a request that a Gatekeeper allow a specific operation * (signature type) on a specific object in S3. The operations that may be requested are: get, head, put. * * @author James Murty * */ public class SignatureRequest { public static final String SIGNATURE_TYPE_GET = "get"; public static final String SIGNATURE_TYPE_HEAD = "head"; public static final String SIGNATURE_TYPE_PUT = "put"; public static final String SIGNATURE_TYPE_DELETE = "delete"; public static final String SIGNATURE_TYPE_ACL_LOOKUP = "acl-lookup"; public static final String SIGNATURE_TYPE_ACL_UPDATE = "acl-update"; private String signatureType = null; private String objectKey = null; private String bucketName = null; private Map objectMetadata = new HashMap(); private String signedUrl = null; private String declineReason = null; /** * Constructs an empty signature request. */ public SignatureRequest() { } /** * Constructs a signature request for an operation on a specific object key. * * @param signatureType * @param objectKey */ public SignatureRequest(String signatureType, String objectKey) { setSignatureType(signatureType); this.objectKey = objectKey; } /** * @return * the name of the bucket in which an object is stored, may be null. */ public String getBucketName() { return bucketName; } /** * Sets the name of the bucket in which an object is stored - this is not generally required. * * @param bucketName */ public void setBucketName(String bucketName) { this.bucketName = bucketName; } /** * @return * the key name of the object on which the operation will be performed. */ public String getObjectKey() { return objectKey; } /** * Sets the key name of the object on which the operation will be performed. * * @param objectKey */ public void setObjectKey(String objectKey) { this.objectKey = objectKey; } /** * @return * the object's metadata as included in the Gatekeeer message. */ public Map getObjectMetadata() { return objectMetadata; } /** * Sets the object's metadata, that will be included in the Gatekeeer message. * * @param objectMetadata */ public void setObjectMetadata(Map objectMetadata) { this.objectMetadata.putAll(objectMetadata); } /** * Adds to the object's metadata, that will be included in the Gatekeeer message. * * @param metadataName * @param metadataValue */ public void addObjectMetadata(String metadataName, String metadataValue) { this.objectMetadata.put(metadataName, metadataValue); } /** * @return * the operation being requested. */ public String getSignatureType() { return signatureType; } /** * Sets the signature type (operation) being requested for the object in this request. * * @param signatureType * the operation being requested, must match one of the SIGNATURE_TYPE_xyz constants * in this class. */ public void setSignatureType(String signatureType) { if (!SIGNATURE_TYPE_GET.equals(signatureType) && !SIGNATURE_TYPE_HEAD.equals(signatureType) && !SIGNATURE_TYPE_PUT.equals(signatureType) && !SIGNATURE_TYPE_DELETE.equals(signatureType) && !SIGNATURE_TYPE_ACL_LOOKUP.equals(signatureType) && !SIGNATURE_TYPE_ACL_UPDATE.equals(signatureType)) { throw new IllegalArgumentException("Illegal signature type: " + signatureType); } this.signatureType = signatureType; } /** * Approve the request by setting the signed URL for this request - performed by a * Gatekeeper service when a request has been allowed. * * @param signedUrl * a URL signed to allow the requested operation on the S3 object. */ public void signRequest(String signedUrl) { this.signedUrl = signedUrl; } /** * @return * the signed URL for this request, if available. If this method is called before a * Gatekeeper service has provided a signed URL, or the the Gatekeeper has refused to provide * a signed URL, this method will return null. */ public String getSignedUrl() { return this.signedUrl; } /** * Decline the request by setting the decline reason for this request - performed by a * Gatekeeper service when a request has been disallowed. * * @param reason * a short explanation for why the request was not allowed, such as "Unrecognised user". */ public void declineRequest(String reason) { this.declineReason = reason; } /** * @return * the reason this request was declined. */ public String getDeclineReason() { return this.declineReason; } /** * Returns true if this request has been allowed and includes a signed URL, false otherwise. */ public boolean isSigned() { return getSignedUrl() != null; } public S3Object buildObject() { S3Object object = new S3Object(getObjectKey()); object.addAllMetadata(getObjectMetadata()); return object; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/utils/gatekeeper/GatekeeperMessage.java0000644000000000000000000003436411550442032025440 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.utils.gatekeeper; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.StringTokenizer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.utils.ServiceUtils; /** * Represents a set of properties that will be sent to or received from a Gatekeeper service as * a message document. This class includes utility methods to generate and parse plain text * encodings of messages. *

* For more information about the Gatekeeper message format, please see: * * Gatekeeper Concepts * * @author James Murty */ public class GatekeeperMessage { private static final Log log = LogFactory.getLog(GatekeeperMessage.class); /** * All message property names are delimited with a vertical bar (|). */ public static final String DELIM = "|"; /** * The property name for message-specific transaction IDs: transactionId */ public static final String PROPERTY_TRANSACTION_ID = "transactionId"; /** * The property name for storing information about prior failures in the gatekeeper client application. */ public static final String PROPERTY_PRIOR_FAILURE_MESSAGE = "priorFailureMessage"; /** * The property name for storing information about a client application such as its version * number. This information can be useful to server-side components to confirm compatibility * with the client. */ public static final String PROPERTY_CLIENT_VERSION_ID = "clientVersionId"; /** * The property name for storing error codes a Gatekeeper can return to a client. * The error codes can be any string value. */ public static final String APP_PROPERTY_GATEKEEPER_ERROR_CODE = "gatekeeperErrorCode"; /** * A flag name used to indicate when an S3Object is a summary XML document, as generated * by the Uploader application. */ public static final String SUMMARY_DOCUMENT_METADATA_FLAG = "jets3t-uploader-summary-doc"; /** * A flag name that indicates the Gatekeeper servlet should perform a bucket listing - * for example as used by CockpitLite */ public static final String LIST_OBJECTS_IN_BUCKET_FLAG = "list-objects-in-bucket"; private Properties applicationProperties = new Properties(); private Properties messageProperties = new Properties(); private List signatureRequestList = new ArrayList(); /** * Constructs a message with no properties. */ public GatekeeperMessage() { } /** * Adds a Signature Request to the message, indicating a request that a particular * operation be allowed on a particular object. * * @param signatureRequest */ public void addSignatureRequest(SignatureRequest signatureRequest) { signatureRequestList.add(signatureRequest); } /** * Adds multiple signature requests to the message. * * @param signatureRequests */ public void addSignatureRequests(SignatureRequest[] signatureRequests) { for (int i = 0; i < signatureRequests.length; i++) { addSignatureRequest(signatureRequests[i]); } } /** * Returns the signature requests in a message. When this method is called on a request message, * this list will include only the requested operations. When this method is called on a * message that is a response from a Gatekeeper service, the resulting list will include the * signed URLs or reasons why requests were declined. * * @return * the set of signature requests in this message. */ public SignatureRequest[] getSignatureRequests() { return (SignatureRequest[]) signatureRequestList .toArray(new SignatureRequest[signatureRequestList.size()]); } /** * Adds an application-specific property to the message. * * @param propertyName * @param propertyValue */ public void addApplicationProperty(String propertyName, String propertyValue) { applicationProperties.put(propertyName, propertyValue); } /** * Adds a set of application-specific properties to the message. * * @param propertiesMap */ public void addApplicationProperties(Map propertiesMap) { applicationProperties.putAll(propertiesMap); } /** * @return * the application-specific properties in this message. */ public Properties getApplicationProperties() { return applicationProperties; } /** * Adds a message-specific property to the message. * * @param propertyName * @param propertyValue */ public void addMessageProperty(String propertyName, String propertyValue) { messageProperties.put(propertyName, propertyValue); } /** * Adds a set of message-specific properties to the message. * * @param propertiesMap */ public void addMessageProperties(Map propertiesMap) { messageProperties.putAll(propertiesMap); } /** * @return * the message-specific properties in this message. */ public Properties getMessageProperties() { return messageProperties; } private void encodeProperty(Properties properties, String propertyName, Object value) { if (value != null) { if (value instanceof Date) { properties.put(propertyName, ServiceUtils.formatIso8601Date((Date)value)); } else { properties.put(propertyName, value.toString()); } if (log.isDebugEnabled()) { log.debug("Encoded property: " + propertyName + "=" + properties.getProperty(propertyName)); } } } /** * Encodes a Gatekeeper message as a properties object, with all signature requests identified * with a unique zero-based index number. * * @return * all the properties of the message. */ public Properties encodeToProperties() { if (log.isDebugEnabled()) { log.debug("Encoding GatekeeperMessage to properties"); } Properties encodedProperties = new Properties(); Iterator iter = null; String prefix = "application"; iter = applicationProperties.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); String key = (String) entry.getKey(); String value = (String) entry.getValue(); encodeProperty(encodedProperties, prefix + DELIM + key, value); } prefix = "message"; iter = messageProperties.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); String key = (String) entry.getKey(); String value = (String) entry.getValue(); encodeProperty(encodedProperties, prefix + DELIM + key, value); } prefix = "request"; SignatureRequest[] requests = getSignatureRequests(); for (int i = 0; i < requests.length; i++) { SignatureRequest request = requests[i]; String propertyPrefix = prefix + DELIM + i + DELIM; encodeProperty(encodedProperties, propertyPrefix + "signatureType", request.getSignatureType()); encodeProperty(encodedProperties, propertyPrefix + "objectKey", request.getObjectKey()); encodeProperty(encodedProperties, propertyPrefix + "bucketName", request.getBucketName()); encodeProperty(encodedProperties, propertyPrefix + "signedUrl", request.getSignedUrl()); encodeProperty(encodedProperties, propertyPrefix + "declineReason", request.getDeclineReason()); propertyPrefix += "metadata" + DELIM; Map metadata = request.getObjectMetadata(); iter = metadata.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); String metadataName = (String) entry.getKey(); Object metadataValue = entry.getValue(); encodeProperty(encodedProperties, propertyPrefix + metadataName, metadataValue); } } return encodedProperties; } /** * Decodes (parses) a Gatekeeper message from the given properties. Any properties that are * not part of the message format are ignored. * * @param postProperties * * @return * a Gatekeeper message object representing the contents of the properties. */ public static GatekeeperMessage decodeFromProperties(Map postProperties) { if (log.isDebugEnabled()) { log.debug("Decoding GatekeeperMessage from properties"); } GatekeeperMessage gatekeeperMessage = new GatekeeperMessage(); Map signatureRequestMap = new HashMap(); Iterator propsIter = postProperties.entrySet().iterator(); while (propsIter.hasNext()) { Map.Entry entry = (Map.Entry) propsIter.next(); String key = (String) entry.getKey(); Object value = entry.getValue(); String propertyValue = null; if (value instanceof String[]) { propertyValue = ((String[]) value)[0]; } else { propertyValue = (String) value; } if (key.startsWith("application")) { String propertyName = key.substring(key.lastIndexOf(DELIM) + 1); gatekeeperMessage.addApplicationProperty(propertyName, propertyValue); } else if (key.startsWith("message")) { String propertyName = key.substring(key.lastIndexOf(DELIM) + 1); gatekeeperMessage.addMessageProperty(propertyName, propertyValue); } else if (key.startsWith("request")) { StringTokenizer st = new StringTokenizer(key, DELIM); st.nextToken(); // Consume request prefix String objectIndexStr = st.nextToken(); boolean isMetadata = false; String propertyName = st.nextToken(); if (st.hasMoreTokens()) { isMetadata = true; propertyName = st.nextToken(); } Integer objectIndex = Integer.valueOf(objectIndexStr); SignatureRequest request = null; if (signatureRequestMap.containsKey(objectIndex)) { request = (SignatureRequest) signatureRequestMap.get(objectIndex); } else { request = new SignatureRequest(); signatureRequestMap.put(objectIndex, request); } if (isMetadata) { request.addObjectMetadata(propertyName, propertyValue); } else { if ("signatureType".equals(propertyName)) { request.setSignatureType(propertyValue); } else if ("objectKey".equals(propertyName)) { request.setObjectKey(propertyValue); } else if ("bucketName".equals(propertyName)) { request.setBucketName(propertyValue); } else if ("signedUrl".equals(propertyName)) { request.signRequest(propertyValue); } else if ("declineReason".equals(propertyName)) { request.declineRequest(propertyValue); } else { if (log.isWarnEnabled()) { log.warn("Ignoring unrecognised SignatureRequest property: " + propertyName); } } } } else { if (log.isWarnEnabled()) { log.warn("Ignoring unrecognised property name: " + key); } } } for (int i = 0; i < signatureRequestMap.size(); i++) { Integer objectIndex = new Integer(i); SignatureRequest request = (SignatureRequest) signatureRequestMap.get(objectIndex); gatekeeperMessage.addSignatureRequest(request); } return gatekeeperMessage; } // public static void main(String[] args) { // SignatureRequest requests[] = new SignatureRequest[12]; // for (int i = 0; i < requests.length; i++) { // requests[i] = new SignatureRequest(SignatureRequest.SIGNATURE_TYPE_PUT, "Request " + i); // requests[i].addObjectMetadata("object-index", String.valueOf(i)); // } // // GatekeeperMessage request = new GatekeeperMessage(); // request.addSignatureRequests(requests); // request.addMessageProperty("id", "123"); // request.addMessageProperty("date", (new Date()).toString()); // request.addApplicationProperty("username", "jmurty"); // // System.err.println("=== Original WRITE"); // Properties properties = request.encodeToProperties(); // // GatekeeperMessage response = GatekeeperMessage.decodeFromProperties(properties); // // System.err.println("=== Second WRITE"); // response.encodeToProperties(); // } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/utils/ServiceUtils.java0000644000000000000000000006767211550421156022400 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.utils; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.security.InvalidKeyException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.SimpleTimeZone; import java.util.regex.Pattern; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.Constants; import org.jets3t.service.S3Service; import org.jets3t.service.ServiceException; import org.jets3t.service.model.S3Object; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.XMLReaderFactory; /** * General utility methods used throughout the jets3t project. * * @author James Murty */ public class ServiceUtils { private static final Log log = LogFactory.getLog(ServiceUtils.class); protected static final SimpleDateFormat iso8601DateParser = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); // The Eucalyptus Walrus storage service returns short, non-UTC date time values. protected static final SimpleDateFormat iso8601DateParser_Walrus = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss"); protected static final SimpleDateFormat rfc822DateParser = new SimpleDateFormat( "EEE, dd MMM yyyy HH:mm:ss z", Locale.US); static { iso8601DateParser.setTimeZone(new SimpleTimeZone(0, "GMT")); rfc822DateParser.setTimeZone(new SimpleTimeZone(0, "GMT")); } public static Date parseIso8601Date(String dateString) throws ParseException { ParseException exception = null; synchronized (iso8601DateParser) { try { return iso8601DateParser.parse(dateString); } catch (ParseException e) { exception = e; } } // Work-around to parse datetime value returned by Walrus synchronized (iso8601DateParser_Walrus) { try { return iso8601DateParser_Walrus.parse(dateString); } catch (ParseException e) { // Ignore work-around exceptions } } // Throw original exception if the Walrus work-around doesn't save us. throw exception; } public static String formatIso8601Date(Date date) { synchronized (iso8601DateParser) { return iso8601DateParser.format(date); } } public static Date parseRfc822Date(String dateString) throws ParseException { synchronized (rfc822DateParser) { return rfc822DateParser.parse(dateString); } } public static String formatRfc822Date(Date date) { synchronized (rfc822DateParser) { return rfc822DateParser.format(date); } } /** * Calculate the HMAC/SHA1 on a string. * * @param awsSecretKey * AWS secret key. * @param canonicalString * canonical string representing the request to sign. * @return Signature * @throws ServiceException */ public static String signWithHmacSha1(String awsSecretKey, String canonicalString) throws ServiceException { if (awsSecretKey == null) { if (log.isDebugEnabled()) { log.debug("Canonical string will not be signed, as no AWS Secret Key was provided"); } return null; } // The following HMAC/SHA1 code for the signature is taken from the // AWS Platform's implementation of RFC2104 (amazon.webservices.common.Signature) // // Acquire an HMAC/SHA1 from the raw key bytes. SecretKeySpec signingKey = null; try { signingKey = new SecretKeySpec(awsSecretKey.getBytes(Constants.DEFAULT_ENCODING), Constants.HMAC_SHA1_ALGORITHM); } catch (UnsupportedEncodingException e) { throw new ServiceException("Unable to get bytes from secret string", e); } // Acquire the MAC instance and initialize with the signing key. Mac mac = null; try { mac = Mac.getInstance(Constants.HMAC_SHA1_ALGORITHM); } catch (NoSuchAlgorithmException e) { // should not happen throw new RuntimeException("Could not find sha1 algorithm", e); } try { mac.init(signingKey); } catch (InvalidKeyException e) { // also should not happen throw new RuntimeException("Could not initialize the MAC algorithm", e); } // Compute the HMAC on the digest, and set it. try { byte[] b64 = Base64.encodeBase64(mac.doFinal( canonicalString.getBytes(Constants.DEFAULT_ENCODING))); return new String(b64); } catch (UnsupportedEncodingException e) { throw new ServiceException("Unable to get bytes from canonical string", e); } } /** * Reads text data from an input stream and returns it as a String. * * @param is * input stream from which text data is read. * @param encoding * the character encoding of the textual data in the input stream. If this * parameter is null, the default system encoding will be used. * * @return * text data read from the input stream. * * @throws IOException */ public static String readInputStreamToString(InputStream is, String encoding) throws IOException { StringBuffer sb = new StringBuffer(); BufferedReader br = null; if (encoding != null) { br = new BufferedReader(new InputStreamReader(is, encoding)); } else { br = new BufferedReader(new InputStreamReader(is)); } String line = null; try { boolean firstLine = true; while ((line = br.readLine()) != null) { if (!firstLine) { sb.append("\n"); } sb.append(line); firstLine = false; } } catch (Exception e) { if (log.isWarnEnabled()) { log.warn("Unable to read String from Input Stream", e); } } return sb.toString(); } /** * Reads from an input stream until a newline character or the end of the stream is reached. * * @param is * @return * text data read from the input stream, not including the newline character. * @throws IOException */ public static String readInputStreamLineToString(InputStream is, String encoding) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); int b = -1; while ((b = is.read()) != -1) { if ('\n' == (char) b) { break; } else { baos.write(b); } } return new String(baos.toByteArray(), encoding); } /** * Reads binary data from an input stream and returns it as a byte array. * * @param is * input stream from which data is read. * * @return * byte array containing data read from the input stream. * * @throws IOException */ public static byte[] readInputStreamToBytes(InputStream is) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); int b = -1; while ((b = is.read()) != -1) { baos.write(b); } return baos.toByteArray(); } /** * Counts the total number of bytes in a set of S3Objects by summing the * content length of each. * * @param objects * @return * total number of bytes in all S3Objects. */ public static long countBytesInObjects(S3Object[] objects) { long byteTotal = 0; for (int i = 0; objects != null && i < objects.length; i++) { byteTotal += objects[i].getContentLength(); } return byteTotal; } /** * From a map of metadata returned from a REST GET or HEAD request, returns a map * of metadata with the HTTP-connection-specific metadata items removed. * * @param metadata * @return * metadata map with HTTP-connection-specific items removed. */ public static Map cleanRestMetadataMap( Map metadata, String headerPrefix, String metadataPrefix) { if (log.isDebugEnabled()) { log.debug("Cleaning up REST metadata items"); } Map cleanMap = new HashMap(); if (metadata != null) { for (Map.Entry entry: metadata.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); // Trim prefixes from keys. String keyStr = (key != null ? key.toString() : ""); if (keyStr.startsWith(metadataPrefix)) { key = keyStr .substring(metadataPrefix.length(), keyStr.length()); if (log.isDebugEnabled()) { log.debug("Removed meatadata header prefix " + headerPrefix + " from key: " + keyStr + "=>" + key); } } else if (keyStr.startsWith(headerPrefix)) { key = keyStr.substring(headerPrefix.length(), keyStr.length()); if (log.isDebugEnabled()) { log.debug("Removed Amazon header prefix " + headerPrefix + " from key: " + keyStr + "=>" + key); } } else if (RestUtils.HTTP_HEADER_METADATA_NAMES.contains(keyStr.toLowerCase(Locale.getDefault()))) { key = keyStr; if (log.isDebugEnabled()) { log.debug("Leaving HTTP header item unchanged: " + key + "=" + value); } } else if ("ETag".equalsIgnoreCase(keyStr) || "Date".equalsIgnoreCase(keyStr) || "Last-Modified".equalsIgnoreCase(keyStr) || "Content-Range".equalsIgnoreCase(keyStr)) { key = keyStr; if (log.isDebugEnabled()) { log.debug("Leaving header item unchanged: " + key + "=" + value); } } else { if (log.isDebugEnabled()) { log.debug("Ignoring metadata item: " + keyStr + "=" + value); } continue; } // Convert connection header string Collections into simple strings (where // appropriate) if (value instanceof Collection) { Collection coll = (Collection) value; if (coll.size() == 1) { if (log.isDebugEnabled()) { log.debug("Converted metadata single-item Collection " + coll.getClass() + " " + coll + " for key: " + key); } value = coll.iterator().next(); } else { if (log.isWarnEnabled()) { log.warn("Collection " + coll + " has too many items to convert to a single string"); } } } // Parse date strings into Date objects, if necessary. if ("Date".equals(key) || "Last-Modified".equals(key)) { if (!(value instanceof Date)) { if (log.isDebugEnabled()) { log.debug("Parsing date string '" + value + "' into Date object for key: " + key); } try { value = ServiceUtils.parseRfc822Date(value.toString()); } catch (ParseException pe) { // Try ISO-8601 date format, just in case try { value = ServiceUtils.parseIso8601Date(value.toString()); } catch (ParseException pe2) { // Log original exception if the work-around fails. if (log.isWarnEnabled()) { log.warn("Date string is not RFC 822 compliant for metadata field " + key, pe); } } } } } cleanMap.put(key, value); } } return cleanMap; } /** * Converts byte data to a Hex-encoded string. * * @param data * data to hex encode. * @return * hex-encoded string. */ public static String toHex(byte[] data) { StringBuffer sb = new StringBuffer(data.length * 2); for (int i = 0; i < data.length; i++) { String hex = Integer.toHexString(data[i]); if (hex.length() == 1) { // Append leading zero. sb.append("0"); } else if (hex.length() == 8) { // Remove ff prefix from negative numbers. hex = hex.substring(6); } sb.append(hex); } return sb.toString().toLowerCase(Locale.getDefault()); } /** * Converts a Hex-encoded data string to the original byte data. * * @param hexData * hex-encoded data to decode. * @return * decoded data from the hex string. */ public static byte[] fromHex(String hexData) { if ((hexData.length() & 1) != 0 || hexData.replaceAll("[a-fA-F0-9]", "").length() > 0) { throw new java.lang.IllegalArgumentException("'" + hexData + "' is not a hex string"); } byte[] result = new byte[(hexData.length() + 1) / 2]; String hexNumber = null; int stringOffset = 0; int byteOffset = 0; while (stringOffset < hexData.length()) { hexNumber = hexData.substring(stringOffset, stringOffset + 2); stringOffset += 2; result[byteOffset++] = (byte) Integer.parseInt(hexNumber, 16); } return result; } /** * Converts byte data to a Base64-encoded string. * * @param data * data to Base64 encode. * @return * encoded Base64 string. */ public static String toBase64(byte[] data) { byte[] b64 = Base64.encodeBase64(data); return new String(b64); } /** * Joins a list of items into a delimiter-separated string. Each item * is converted to a string value with the toString() method before being * added to the final delimited list. * * @param items * the items to include in a delimited string * @param delimiter * the delimiter character or string to insert between each item in the list * @return * a delimited string */ public static String join(List items, String delimiter) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < items.size(); i++) { sb.append(items.get(i).toString()); if (i < items.size() - 1) { sb.append(delimiter); } } return sb.toString(); } /** * Joins a list of items into a delimiter-separated string. Each item * is converted to a string value with the toString() method before being * added to the final delimited list. * * @param items * the items to include in a delimited string * @param delimiter * the delimiter character or string to insert between each item in the list * @return * a delimited string */ public static String join(Object[] items, String delimiter) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < items.length; i++) { sb.append(items[i]); if (i < items.length - 1) { sb.append(delimiter); } } return sb.toString(); } /** * Joins a list of ints into a delimiter-separated string. * * @param ints * the ints to include in a delimited string * @param delimiter * the delimiter character or string to insert between each item in the list * @return * a delimited string */ public static String join(int[] ints, String delimiter) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < ints.length; i++) { sb.append(ints[i]); if (i < ints.length - 1) { sb.append(delimiter); } } return sb.toString(); } /** * Converts a Base64-encoded string to the original byte data. * * @param b64Data * a Base64-encoded string to decode. * * @return * bytes decoded from a Base64 string. */ public static byte[] fromBase64(String b64Data) { byte[] decoded = Base64.decodeBase64(b64Data.getBytes()); return decoded; } /** * Computes the MD5 hash of the data in the given input stream and returns it as a hex string. * The provided input stream is consumed and closed by this method. * * @param is * @return * MD5 hash * @throws NoSuchAlgorithmException * @throws IOException */ public static byte[] computeMD5Hash(InputStream is) throws NoSuchAlgorithmException, IOException { BufferedInputStream bis = new BufferedInputStream(is); try { MessageDigest messageDigest = MessageDigest.getInstance("MD5"); byte[] buffer = new byte[16384]; int bytesRead = -1; while ((bytesRead = bis.read(buffer, 0, buffer.length)) != -1) { messageDigest.update(buffer, 0, bytesRead); } return messageDigest.digest(); } finally { try { bis.close(); } catch (Exception e) { System.err.println("Unable to close input stream of hash candidate: " + e); } } } /** * Computes the MD5 hash of the given data and returns it as a hex string. * * @param data * @return * MD5 hash. * @throws NoSuchAlgorithmException * @throws IOException */ public static byte[] computeMD5Hash(byte[] data) throws NoSuchAlgorithmException, IOException { return computeMD5Hash(new ByteArrayInputStream(data)); } /** * Guess whether the given ETag value is also an MD5 hash of an underlying object * in a storage service, as opposed to being some other kind of opaque hash. *

* This test was made necessary by Amazon S3's multipart upload feature, where * the ETag value returned after a re-assembled multipart upload is completed * is no longer the same as an MD5 hash of the assembled data. *

* An ETag is considered also an MD5 when: *

    *
  • The length is exactly 16 characters (excluding surrounding quote characters)
  • *
  • All characters in the string are hexadecimal values, i.e. [0-9a-f] when lowercased
  • *
*

* These rules are drawn from the post by Carl@AWS on Nov 11, 2010 10:40 AM here: * https://forums.aws.amazon.com/thread.jspa?messageID=222158&tstart=0 * * @return * true if the ETag value can be assumed to also be an MD5 hash. */ public static boolean isEtagAlsoAnMD5Hash(String etag) { if (etag == null || etag.length() != 32) { return false; } String nonHexChars = etag.toLowerCase().replaceAll("[a-f0-9]", ""); if (nonHexChars.length() > 0) { return false; } return true; } /** * Identifies the name of a bucket from a given host name, if available. * Returns null if the bucket name cannot be identified, as might happen * when a bucket name is represented by the path component of a URL instead * of the host name component. * * @param host * the host name component of a URL that may include the bucket name, * if an alternative host name is in use. * * @return * The S3 bucket name represented by the DNS host name, or null if none. */ public static String findBucketNameInHostname(String host, String s3Endpoint) { String bucketName = null; // Bucket name is available in URL's host name. if (host.endsWith(s3Endpoint)) { // Bucket name is available as S3 subdomain bucketName = host.substring(0, host.length() - s3Endpoint.length() - 1); } else { // URL refers to a virtual host name bucketName = host; } return bucketName; } /** * Builds an object based on the bucket name and object key information * available in the components of a URL. * * @param host * the host name component of a URL that may include the bucket name, * if an alternative host name is in use. * @param urlPath * the path of a URL that references an S3 object, and which may or may * not include the bucket name. * * @return * the object referred to by the URL components. */ public static S3Object buildObjectFromUrl(String host, String urlPath, String s3Endpoint) throws UnsupportedEncodingException { if (urlPath.startsWith("/")) { urlPath = urlPath.substring(1); // Ignore first '/' character in url path. } String bucketName = null; String objectKey = null; if (!s3Endpoint.equals(host)) { bucketName = findBucketNameInHostname(host, s3Endpoint); } else { // Bucket name must be first component of URL path int slashIndex = urlPath.indexOf("/"); bucketName = URLDecoder.decode( urlPath.substring(0, slashIndex), Constants.DEFAULT_ENCODING); // Remove the bucket name component of the host name urlPath = urlPath.substring(bucketName.length() + 1); } objectKey = URLDecoder.decode( urlPath, Constants.DEFAULT_ENCODING); S3Object object = new S3Object(objectKey); object.setBucketName(bucketName); return object; } /** * Returns true if the given bucket name can be used as a component of a valid * DNS name. If so, the bucket can be accessed using requests with the bucket name * as part of an S3 sub-domain. If not, the old-style bucket reference URLs must be * used, in which case the bucket name must be the first component of the resource * path. * * @param bucketName * the name of the bucket to test for DNS compatibility. */ public static boolean isBucketNameValidDNSName(String bucketName) { if (bucketName == null || bucketName.length() > 63 || bucketName.length() < 3) { return false; } // Only lower-case letters, numbers, '.' or '-' characters allowed if (!Pattern.matches("^[a-z0-9][a-z0-9.-]+$", bucketName)) { return false; } // Cannot be an IP address, i.e. must not contain four '.'-delimited // sections with 1 to 3 digits each. if (Pattern.matches("([0-9]{1,3}\\.){3}[0-9]{1,3}", bucketName)) { return false; } // Components of name between '.' characters cannot start or end with '-', // and cannot be empty String[] fragments = bucketName.split("\\."); for (int i = 0; i < fragments.length; i++) { if (Pattern.matches("^-.*", fragments[i]) || Pattern.matches(".*-$", fragments[i]) || Pattern.matches("^$", fragments[i])) { return false; } } return true; } public static String generateS3HostnameForBucket(String bucketName, boolean isDnsBucketNamingDisabled, String s3Endpoint) { if (isBucketNameValidDNSName(bucketName) && !isDnsBucketNamingDisabled) { return bucketName + "." + s3Endpoint; } else { return s3Endpoint; } } /** * Returns a user agent string describing the jets3t library, and optionally the application * using it, to server-side services. * * @param applicationDescription * a description of the application using the jets3t toolkit, included at the end of the * user agent string. This value may be null. * @return * a string built with the following components (some elements may not be available): * JetS3t/{@link Constants#JETS3T_VERSION} * (os.name/os.version; os.arch; user.region; * user.region; user.language) applicationDescription * */ public static String getUserAgentDescription(String applicationDescription) { return "JetS3t/" + Constants.JETS3T_VERSION + " (" + System.getProperty("os.name") + "/" + System.getProperty("os.version") + ";" + " " + System.getProperty("os.arch") + (System.getProperty("user.region") != null ? "; " + System.getProperty("user.region") : "") + (System.getProperty("user.language") != null ? "; " + System.getProperty("user.language") : "") + (System.getProperty("java.version") != null ? "; JVM " + System.getProperty("java.version") : "") + ")" + (applicationDescription != null ? " " + applicationDescription : ""); } /** * Find a SAX XMLReader by hook or by crook, with work-arounds for * non-standard platforms. * * @return an initialized XML SAX reader */ public static XMLReader loadXMLReader() throws ServiceException { // Try loading the default SAX reader try { return XMLReaderFactory.createXMLReader(); } catch (SAXException e) { // Ignore failure } // No dice using the standard approach, try loading alternatives... String[] altXmlReaderClasspaths = new String[] { "org.apache.crimson.parser.XMLReaderImpl", // JDK 1.4 "org.xmlpull.v1.sax2.Driver", // Android }; for (int i = 0; i < altXmlReaderClasspaths.length; i++) { String xmlReaderClasspath = altXmlReaderClasspaths[i]; try { return XMLReaderFactory.createXMLReader(xmlReaderClasspath); } catch (SAXException e) { // Ignore failure } } // If we haven't found and returned an XMLReader yet, give up. throw new ServiceException("Failed to initialize a SAX XMLReader"); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/utils/RestUtils.java0000644000000000000000000005657011537563564021727 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.utils; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URL; import java.net.URLDecoder; import java.net.URLEncoder; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HostConfiguration; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.HttpVersion; import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; import org.apache.commons.httpclient.NTCredentials; import org.apache.commons.httpclient.ProxyHost; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.httpclient.auth.AuthScope; import org.apache.commons.httpclient.auth.CredentialsProvider; import org.apache.commons.httpclient.contrib.proxy.PluginProxyUtil; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.params.HttpClientParams; import org.apache.commons.httpclient.params.HttpConnectionManagerParams; import org.apache.commons.httpclient.params.HttpMethodParams; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.ServiceException; import org.jets3t.service.impl.rest.httpclient.AWSRequestAuthorizer; import org.jets3t.service.impl.rest.httpclient.HttpClientAndConnectionManager; import org.jets3t.service.impl.rest.httpclient.RestS3Service; import org.jets3t.service.io.UnrecoverableIOException; /** * Utilities useful for REST/HTTP S3Service implementations. * * @author James Murty */ public class RestUtils { private static final Log log = LogFactory.getLog(RestUtils.class); /** * A list of HTTP-specific header names, that may be present in S3Objects as metadata but * which should be treated as plain HTTP headers during transmission (ie not converted into * S3 Object metadata items). All items in this list are in lower case. *

* This list includes the items: * * * * * * * * * * *
Unchanged metadata names
content-type
content-md5
content-length
content-language
expires
cache-control
content-disposition
content-encoding
*/ public static final List HTTP_HEADER_METADATA_NAMES = Arrays.asList(new String[] { "content-type", "content-md5", "content-length", "content-language", "expires", "cache-control", "content-disposition", "content-encoding" }); /** * Encodes a URL string, and ensures that spaces are encoded as "%20" instead of "+" to keep * fussy web browsers happier. * * @param path * @return * encoded URL. * @throws ServiceException */ public static String encodeUrlString(String path) throws ServiceException { try { String encodedPath = URLEncoder.encode(path, Constants.DEFAULT_ENCODING); // Web browsers do not always handle '+' characters well, use the well-supported '%20' instead. encodedPath = encodedPath.replaceAll("\\+", "%20"); // '@' character need not be URL encoded and Google Chrome balks on signed URLs if it is. encodedPath = encodedPath.replaceAll("%40", "@"); return encodedPath; } catch (UnsupportedEncodingException uee) { throw new ServiceException("Unable to encode path: " + path, uee); } } /** * Encodes a URL string but leaves a delimiter string unencoded. * Spaces are encoded as "%20" instead of "+". * * @param path * @param delimiter * @return * encoded URL string. * @throws ServiceException */ public static String encodeUrlPath(String path, String delimiter) throws ServiceException { StringBuffer result = new StringBuffer(); String tokens[] = path.split(delimiter); for (int i = 0; i < tokens.length; i++) { result.append(encodeUrlString(tokens[i])); if (i < tokens.length - 1) { result.append(delimiter); } } return result.toString(); } /** * Calculate the canonical string for a REST/HTTP request to a storage service. * * When expires is non-null, it will be used instead of the Date header. * @throws UnsupportedEncodingException */ public static String makeServiceCanonicalString(String method, String resource, Map headersMap, String expires, String headerPrefix, List serviceResourceParameterNames) throws UnsupportedEncodingException { StringBuffer canonicalStringBuf = new StringBuffer(); canonicalStringBuf.append(method + "\n"); // Add all interesting headers to a list, then sort them. "Interesting" // is defined as Content-MD5, Content-Type, Date, and x-amz- SortedMap interestingHeaders = new TreeMap(); if (headersMap != null && headersMap.size() > 0) { for (Map.Entry entry: headersMap.entrySet()) { Object key = entry.getKey(); Object value = entry.getValue(); if (key == null) { continue; } String lk = key.toString().toLowerCase(Locale.getDefault()); // Ignore any headers that are not particularly interesting. if (lk.equals("content-type") || lk.equals("content-md5") || lk.equals("date") || lk.startsWith(headerPrefix)) { interestingHeaders.put(lk, value); } } } // Remove default date timestamp if "x-amz-date" is set. if (interestingHeaders.containsKey(Constants.REST_METADATA_ALTERNATE_DATE)) { interestingHeaders.put("date", ""); } // Use the expires value as the timestamp if it is available. This trumps both the default // "date" timestamp, and the "x-amz-date" header. if (expires != null) { interestingHeaders.put("date", expires); } // these headers require that we still put a new line in after them, // even if they don't exist. if (! interestingHeaders.containsKey("content-type")) { interestingHeaders.put("content-type", ""); } if (! interestingHeaders.containsKey("content-md5")) { interestingHeaders.put("content-md5", ""); } // Finally, add all the interesting headers (i.e.: all that start with x-amz- ;-)) for (Map.Entry entry: interestingHeaders.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); if (key.startsWith(headerPrefix)) { canonicalStringBuf.append(key).append(':').append(value); } else { canonicalStringBuf.append(value); } canonicalStringBuf.append("\n"); } // don't include the query parameters... int queryIndex = resource.indexOf('?'); if (queryIndex == -1) { canonicalStringBuf.append(resource); } else { canonicalStringBuf.append(resource.substring(0, queryIndex)); } // ...unless the parameter(s) are in the set of special params // that actually identify a service resource. if (queryIndex >= 0) { SortedMap sortedResourceParams = new TreeMap(); // Parse parameters from resource string String query = resource.substring(queryIndex + 1); for (String paramPair: query.split("&")) { String[] paramNameValue = paramPair.split("="); String name = URLDecoder.decode(paramNameValue[0], "UTF-8"); String value = null; if (paramNameValue.length > 1) { value = URLDecoder.decode(paramNameValue[1], "UTF-8"); } // Only include parameter (and its value if present) in canonical // string if it is a resource-identifying parameter if (serviceResourceParameterNames.contains(name)) { sortedResourceParams.put(name, value); } } // Add resource parameters if (sortedResourceParams.size() > 0) { canonicalStringBuf.append("?"); } boolean addedParam = false; for (Map.Entry entry: sortedResourceParams.entrySet()) { if (addedParam) { canonicalStringBuf.append("&"); } canonicalStringBuf.append(entry.getKey()); if (entry.getValue() != null) { canonicalStringBuf.append("=" + entry.getValue()); } addedParam = true; } } return canonicalStringBuf.toString(); } /** * Initialises, or re-initialises, the underlying HttpConnectionManager and * HttpClient objects a service will use to communicate with an AWS service. * If proxy settings are specified in this service's {@link Jets3tProperties} object, * these settings will also be passed on to the underlying objects. * * @param hostConfig * Custom HTTP host configuration; e.g to register a custom Protocol Socket Factory. * This parameter may be null, in which case a default host configuration will be * used. */ public static HttpClientAndConnectionManager initHttpConnection(final AWSRequestAuthorizer awsRequestAuthorizer, HostConfiguration hostConfig, Jets3tProperties jets3tProperties, String userAgentDescription, CredentialsProvider credentialsProvider) { // Configure HttpClient properties based on Jets3t Properties. HttpConnectionManagerParams connectionParams = new HttpConnectionManagerParams(); connectionParams.setConnectionTimeout(jets3tProperties. getIntProperty("httpclient.connection-timeout-ms", 60000)); connectionParams.setSoTimeout(jets3tProperties. getIntProperty("httpclient.socket-timeout-ms", 60000)); connectionParams.setStaleCheckingEnabled(jets3tProperties. getBoolProperty("httpclient.stale-checking-enabled", true)); // Set the maximum connections per host for the HTTP connection manager, // *and* also set the maximum number of total connections (new in 0.7.1). // The max connections per host setting is made the same value as the max // global connections if there is no per-host property. int maxConnections = jets3tProperties.getIntProperty("httpclient.max-connections", 20); int maxConnectionsPerHost = jets3tProperties.getIntProperty("httpclient.max-connections-per-host", 0); if (maxConnectionsPerHost == 0) { maxConnectionsPerHost = maxConnections; } connectionParams.setMaxConnectionsPerHost( HostConfiguration.ANY_HOST_CONFIGURATION, maxConnectionsPerHost); connectionParams.setMaxTotalConnections(maxConnections); // Connection properties to take advantage of S3 window scaling. if (jets3tProperties.containsKey("httpclient.socket-receive-buffer")) { connectionParams.setReceiveBufferSize(jets3tProperties. getIntProperty("httpclient.socket-receive-buffer", 0)); } if (jets3tProperties.containsKey("httpclient.socket-send-buffer")) { connectionParams.setSendBufferSize(jets3tProperties. getIntProperty("httpclient.socket-send-buffer", 0)); } connectionParams.setTcpNoDelay(true); MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager(); connectionManager.setParams(connectionParams); // Set user agent string. HttpClientParams clientParams = new HttpClientParams(); String userAgent = jets3tProperties.getStringProperty("httpclient.useragent", null); if (userAgent == null) { userAgent = ServiceUtils.getUserAgentDescription(userAgentDescription); } if (log.isDebugEnabled()) { log.debug("Setting user agent string: " + userAgent); } clientParams.setParameter(HttpMethodParams.USER_AGENT, userAgent); clientParams.setParameter(HttpMethodParams.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); clientParams.setBooleanParameter(HttpMethodParams.USE_EXPECT_CONTINUE, true); // Replace default error retry handler. final int retryMaxCount = jets3tProperties.getIntProperty("httpclient.retry-max", 5); clientParams.setParameter(HttpClientParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(retryMaxCount, false) { @Override public boolean retryMethod(HttpMethod httpMethod, IOException ioe, int executionCount) { if (super.retryMethod(httpMethod, ioe, executionCount)) { if (ioe instanceof UnrecoverableIOException) { if (log.isDebugEnabled()) { log.debug("Deliberate interruption, will not retry"); } return false; } // Release underlying connection so we will get a new one (hopefully) when we retry. httpMethod.releaseConnection(); if (log.isDebugEnabled()) { log.debug("Retrying " + httpMethod.getName() + " request with path '" + httpMethod.getPath() + "' - attempt " + executionCount + " of " + retryMaxCount); } // Build the authorization string for the method. try { awsRequestAuthorizer.authorizeHttpRequest(httpMethod); } catch (Exception e) { if (log.isWarnEnabled()) { log.warn("Unable to generate updated authorization string for retried request", e); } } return true; } return false; } }); long connectionManagerTimeout = jets3tProperties.getLongProperty( "httpclient.connection-manager-timeout", 0); clientParams.setConnectionManagerTimeout(connectionManagerTimeout); HttpClient httpClient = new HttpClient(clientParams, connectionManager); httpClient.setHostConfiguration(hostConfig); if (credentialsProvider != null) { if (log.isDebugEnabled()) { log.debug("Using credentials provider class: " + credentialsProvider.getClass().getName()); } httpClient.getParams().setParameter(CredentialsProvider.PROVIDER, credentialsProvider); if (jets3tProperties.getBoolProperty("httpclient.authentication-preemptive", false)) { httpClient.getParams().setAuthenticationPreemptive(true); } } return new HttpClientAndConnectionManager(httpClient, connectionManager); } /** * Initialises this service's HTTP proxy by auto-detecting the proxy settings. */ public static void initHttpProxy(HttpClient httpClient, Jets3tProperties jets3tProperties) { initHttpProxy(httpClient, jets3tProperties, true, null, -1, null, null, null); } /** * Initialises this service's HTTP proxy by auto-detecting the proxy settings using the given endpoint. */ public static void initHttpProxy(HttpClient httpClient, Jets3tProperties jets3tProperties, String endpoint) { initHttpProxy(httpClient, jets3tProperties, true, null, -1, null, null, null, endpoint); } /** * Initialises this service's HTTP proxy with the given proxy settings. * * @param proxyHostAddress * @param proxyPort */ public static void initHttpProxy(HttpClient httpClient, String proxyHostAddress, int proxyPort, Jets3tProperties jets3tProperties) { initHttpProxy(httpClient, jets3tProperties, false, proxyHostAddress, proxyPort, null, null, null); } /** * Initialises this service's HTTP proxy for authentication using the given * proxy settings. * * @param proxyHostAddress * @param proxyPort * @param proxyUser * @param proxyPassword * @param proxyDomain * if a proxy domain is provided, an {@link NTCredentials} credential provider * will be used. If the proxy domain is null, a * {@link UsernamePasswordCredentials} credentials provider will be used. */ public static void initHttpProxy(HttpClient httpClient, Jets3tProperties jets3tProperties, String proxyHostAddress, int proxyPort, String proxyUser, String proxyPassword, String proxyDomain) { initHttpProxy(httpClient, jets3tProperties, false, proxyHostAddress, proxyPort, proxyUser, proxyPassword, proxyDomain); } /** * @param httpClient * @param proxyAutodetect * @param proxyHostAddress * @param proxyPort * @param proxyUser * @param proxyPassword * @param proxyDomain */ public static void initHttpProxy(HttpClient httpClient, Jets3tProperties jets3tProperties, boolean proxyAutodetect, String proxyHostAddress, int proxyPort, String proxyUser, String proxyPassword, String proxyDomain) { String s3Endpoint = jets3tProperties.getStringProperty( "s3service.s3-endpoint", Constants.S3_DEFAULT_HOSTNAME); initHttpProxy(httpClient, jets3tProperties, proxyAutodetect, proxyHostAddress, proxyPort, proxyUser, proxyPassword, proxyDomain, s3Endpoint); } /** * @param httpClient * @param proxyAutodetect * @param proxyHostAddress * @param proxyPort * @param proxyUser * @param proxyPassword * @param proxyDomain * @param endpoint */ public static void initHttpProxy(HttpClient httpClient, Jets3tProperties jets3tProperties, boolean proxyAutodetect, String proxyHostAddress, int proxyPort, String proxyUser, String proxyPassword, String proxyDomain, String endpoint) { HostConfiguration hostConfig = httpClient.getHostConfiguration(); // Use explicit proxy settings, if available. if (proxyHostAddress != null && proxyPort != -1) { if (log.isInfoEnabled()) { log.info("Using Proxy: " + proxyHostAddress + ":" + proxyPort); } hostConfig.setProxy(proxyHostAddress, proxyPort); if (proxyUser != null && !proxyUser.trim().equals("")) { if (proxyDomain != null) { httpClient.getState().setProxyCredentials( new AuthScope(proxyHostAddress, proxyPort), new NTCredentials(proxyUser, proxyPassword, proxyHostAddress, proxyDomain)); } else { httpClient.getState().setProxyCredentials( new AuthScope(proxyHostAddress, proxyPort), new UsernamePasswordCredentials(proxyUser, proxyPassword)); } } } // If no explicit settings are available, try autodetecting proxies (unless autodetect is disabled) else if (proxyAutodetect) { // Try to detect any proxy settings from applet. ProxyHost proxyHost = null; try { proxyHost = PluginProxyUtil.detectProxy(new URL("http://" + endpoint)); if (proxyHost != null) { if (log.isInfoEnabled()) { log.info("Using Proxy: " + proxyHost.getHostName() + ":" + proxyHost.getPort()); } hostConfig.setProxyHost(proxyHost); } } catch (Throwable t) { if (log.isDebugEnabled()) { log.debug("Unable to set proxy configuration", t); } } } } /** * Calculates a time offset value to reflect the time difference between your * computer's clock and the current time according to an AWS server, and * returns the calculated time difference. * * Ideally you should not rely on this method to overcome clock-related * disagreements between your computer and AWS. If you computer is set * to update its clock periodically and has the correct timezone setting * you should never have to resort to this work-around. */ public static long getAWSTimeAdjustment() throws Exception { RestS3Service restService = new RestS3Service(null); HttpClient client = restService.getHttpClient(); long timeOffset = 0; // Connect to an AWS server to obtain response headers. GetMethod getMethod = new GetMethod("http://aws.amazon.com/"); int result = client.executeMethod(getMethod); if (result == 200) { Header dateHeader = getMethod.getResponseHeader("Date"); // Retrieve the time according to AWS, based on the Date header Date awsTime = ServiceUtils.parseRfc822Date(dateHeader.getValue()); // Calculate the difference between the current time according to AWS, // and the current time according to your computer's clock. Date localTime = new Date(); timeOffset = awsTime.getTime() - localTime.getTime(); if (log.isDebugEnabled()) { log.debug("Calculated time offset value of " + timeOffset + " milliseconds between the local machine and an AWS server"); } } else { if (log.isWarnEnabled()) { log.warn("Unable to calculate value of time offset between the " + "local machine and AWS server"); } } return timeOffset; } public static Map convertHeadersToMap(Header[] headers) { Map s3Headers = new HashMap(); for (Header header: headers) { s3Headers.put(header.getName(), header.getValue()); } return s3Headers; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/utils/TimeFormatter.java0000644000000000000000000001203111427702124022514 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.utils; /** * Formats time values into human-readable strings. * * @author James Murty */ public class TimeFormatter { private String hourSuffix = null; private String hoursSuffix = null; private String minuteSuffix = null; private String minutesSuffix = null; private String secondSuffix = null; private String secondsSuffix = null; public TimeFormatter() { this(" hour", " hours", " minute", " minutes", " second", " seconds"); } public TimeFormatter(String hourSuffix, String hoursSuffix, String minuteSuffix, String minutesSuffix, String secondSuffix, String secondsSuffix) { this.hourSuffix = hourSuffix; this.hoursSuffix = hoursSuffix; this.minuteSuffix = minuteSuffix; this.minutesSuffix = minutesSuffix; this.secondSuffix = secondSuffix; this.secondsSuffix = secondsSuffix; } /** * Formats a seconds time value into a brief representation, such as 37 minutes. * Unicode characters are used to represent 1/4, 1/2 and 3/4 fractions. * * @param seconds * the number of seconds time value. * * @return * a representation of the time. */ public String formatTime(long seconds) { return formatTime(seconds, true); } /** * Formats a seconds time value into a brief representation, such as 37 minutes. * * @param seconds * the number of seconds time value. * @param useUnicodeChars * if true, special unicode characters are used to represent 1/4, 1/2 and 3/4 fractions. * If false, the fractions are displayed in standard text. * * @return * a representation of the time. */ public String formatTime(long seconds, boolean useUnicodeChars) { int hours = 0; if (seconds > 3600) { hours = (int) seconds / 3600; seconds = seconds - (hours * 3600L); } int mins = (int) seconds / 60; seconds = seconds - (mins * 60L); if (hours > 0) { if (mins > 45) { return (hours + 1) + hourSuffix; } else if (mins > 30) { if (useUnicodeChars) { return hours + "\u00BE" + hoursSuffix; // Three quarters } else { return hours + " 3/4" + hoursSuffix; } } else if (mins > 15) { if (useUnicodeChars) { return hours + "\u00BD" + hoursSuffix; // One half } else { return hours + " 1/2" + hoursSuffix; } } else if (mins > 0) { if (useUnicodeChars) { return hours + "\u00BC" + hoursSuffix; // One quarter } else { return hours + " 1/4" + hoursSuffix; } } else { return hours + " hour" + (hours > 1? "s" : ""); } } else if (mins > 0) { if (seconds > 45) { return (mins + 1) + minutesSuffix; } else if (seconds > 30) { if (useUnicodeChars) { return mins + "\u00BE" + minutesSuffix; // Three quarters } else { return mins + " 3/4" + minutesSuffix; } } else if (seconds > 15) { if (useUnicodeChars) { return mins + "\u00BD" + minutesSuffix; // One half } else { return mins + " 1/2" + minutesSuffix; } } else if (seconds > 0) { if (useUnicodeChars) { return mins + "\u00BC" + minutesSuffix; // One quarter } else { return mins + " 1/4" + minutesSuffix; } } else { return mins + (mins > 1? minutesSuffix : minuteSuffix); } } else { return seconds + (seconds != 1? secondsSuffix : secondSuffix); } } // public static void main(String[] args) throws Exception { // TimeFormatter formatter = new TimeFormatter(); // long seconds = 2 * 60 * 60; // // while (seconds >= 0) { // System.out.println(formatter.formatTime(seconds)); // Thread.sleep(5); // seconds--; // } // // } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/utils/signedurl/0002755000000000000000000000000011550421156021070 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/utils/signedurl/SignedUrlAndObject.java0000644000000000000000000000236711427702124025407 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.utils.signedurl; import org.jets3t.service.model.S3Object; /** * A package containing an object and a signed URL associated with the object. * * @author James Murty */ public class SignedUrlAndObject { private String signedUrl = null; private S3Object object = null; public SignedUrlAndObject(String signedUrl, S3Object object) { this.signedUrl = signedUrl; this.object = object; } public S3Object getObject() { return object; } public String getSignedUrl() { return signedUrl; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/utils/signedurl/GatekeeperClientUtils.java0000644000000000000000000002721111441613550026170 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2007 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.utils.signedurl; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Iterator; import java.util.Map; import java.util.Properties; import java.util.zip.GZIPInputStream; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HostConfiguration; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.HttpMethodRetryHandler; import org.apache.commons.httpclient.ProxyHost; import org.apache.commons.httpclient.auth.CredentialsProvider; import org.apache.commons.httpclient.contrib.proxy.PluginProxyUtil; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.params.HttpClientParams; import org.apache.commons.httpclient.params.HttpConnectionManagerParams; import org.apache.commons.httpclient.params.HttpMethodParams; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.model.S3Object; import org.jets3t.service.utils.ServiceUtils; import org.jets3t.service.utils.gatekeeper.GatekeeperMessage; import org.jets3t.service.utils.gatekeeper.SignatureRequest; /** * Utility class to handle common operations performed by Gatekeeper client applications. * * @author James Murty */ public class GatekeeperClientUtils { private HttpClient httpClientGatekeeper = null; private static final Log log = LogFactory.getLog(GatekeeperClientUtils.class); /** * Variable to store application exceptions, so that client failure information can be * included in the information provided to the Gatekeeper when uploads are retried. */ private Exception priorFailureException = null; private String gatekeeperUrl = null; private String userAgentDescription; private int maxRetryCount; private int connectionTimeout; private CredentialsProvider credentialsProvider = null; /** * @param gatekeeperUrl * @param userAgentDescription * @param maxRetryCount * @param connectionTimeoutMS * @param credentialsProvider */ public GatekeeperClientUtils(String gatekeeperUrl, String userAgentDescription, int maxRetryCount, int connectionTimeoutMS, CredentialsProvider credentialsProvider) { this.gatekeeperUrl = gatekeeperUrl; this.userAgentDescription = userAgentDescription; this.maxRetryCount = maxRetryCount; this.connectionTimeout = connectionTimeoutMS; this.credentialsProvider = credentialsProvider; } /** * Prepares objects for HTTP communications with the Gatekeeper servlet. * @return */ private HttpClient initHttpConnection() { // Set client parameters. HttpClientParams clientParams = new HttpClientParams(); clientParams.setParameter(HttpMethodParams.USER_AGENT, ServiceUtils.getUserAgentDescription(userAgentDescription)); // Replace default error retry handler. clientParams.setParameter(HttpClientParams.RETRY_HANDLER, new HttpMethodRetryHandler() { public boolean retryMethod(HttpMethod httpMethod, IOException ioe, int executionCount) { if (executionCount > maxRetryCount) { if (log.isErrorEnabled()) { log.error("Retried connection " + executionCount + " times, which exceeds the maximum retry count of " + maxRetryCount); } return false; } if (log.isWarnEnabled()) { log.warn("Retrying request - attempt " + executionCount + " of " + maxRetryCount); } return true; } }); // Set connection parameters. HttpConnectionManagerParams connectionParams = new HttpConnectionManagerParams(); connectionParams.setConnectionTimeout(connectionTimeout); connectionParams.setSoTimeout(connectionTimeout); connectionParams.setStaleCheckingEnabled(false); HttpClient httpClient = new HttpClient(clientParams); httpClient.getHttpConnectionManager().setParams(connectionParams); // httpClient.getParams().setAuthenticationPreemptive(true); httpClient.getParams().setParameter(CredentialsProvider.PROVIDER, credentialsProvider); return httpClient; } /** * Request permission from the Gatekeeper for a particular operation. * * @param operationType * @param bucketName * @param objects * @param applicationPropertiesMap * @throws HttpException * @throws Exception */ public GatekeeperMessage requestActionThroughGatekeeper(String operationType, String bucketName, S3Object[] objects, Map applicationPropertiesMap) throws HttpException, Exception { /* * Build Gatekeeper request. */ GatekeeperMessage gatekeeperMessage = new GatekeeperMessage(); gatekeeperMessage.addApplicationProperties(applicationPropertiesMap); gatekeeperMessage.addApplicationProperty( GatekeeperMessage.PROPERTY_CLIENT_VERSION_ID, userAgentDescription); // If a prior failure has occurred, add information about this failure. if (priorFailureException != null) { gatekeeperMessage.addApplicationProperty(GatekeeperMessage.PROPERTY_PRIOR_FAILURE_MESSAGE, priorFailureException.getMessage()); // Now reset the prior failure variable. priorFailureException = null; } // Add all S3 objects as candiates for PUT signing. for (int i = 0; i < objects.length; i++) { SignatureRequest signatureRequest = new SignatureRequest( operationType, objects[i].getKey()); signatureRequest.setObjectMetadata(objects[i].getMetadataMap()); signatureRequest.setBucketName(bucketName); gatekeeperMessage.addSignatureRequest(signatureRequest); } /* * Build HttpClient POST message. */ // Add all properties/parameters to credentials POST request. PostMethod postMethod = new PostMethod(gatekeeperUrl); Properties properties = gatekeeperMessage.encodeToProperties(); Iterator propsIter = properties.entrySet().iterator(); while (propsIter.hasNext()) { Map.Entry entry = (Map.Entry) propsIter.next(); String fieldName = (String) entry.getKey(); String fieldValue = (String) entry.getValue(); postMethod.setParameter(fieldName, fieldValue); } // Create Http Client if necessary, and include User Agent information. if (httpClientGatekeeper == null) { httpClientGatekeeper = initHttpConnection(); } // Try to detect any necessary proxy configurations. try { ProxyHost proxyHost = PluginProxyUtil.detectProxy(new URL(gatekeeperUrl)); if (proxyHost != null) { HostConfiguration hostConfig = new HostConfiguration(); hostConfig.setProxyHost(proxyHost); httpClientGatekeeper.setHostConfiguration(hostConfig); } } catch (Throwable t) { if (log.isDebugEnabled()) { log.debug("No proxy detected"); } } // Perform Gateway request. if (log.isDebugEnabled()) { log.debug("Contacting Gatekeeper at: " + gatekeeperUrl); } try { int responseCode = httpClientGatekeeper.executeMethod(postMethod); String contentType = postMethod.getResponseHeader("Content-Type").getValue(); if (responseCode == 200) { InputStream responseInputStream = null; Header encodingHeader = postMethod.getResponseHeader("Content-Encoding"); if (encodingHeader != null && "gzip".equalsIgnoreCase(encodingHeader.getValue())) { if (log.isDebugEnabled()) { log.debug("Inflating gzip-encoded response"); } responseInputStream = new GZIPInputStream(postMethod.getResponseBodyAsStream()); } else { responseInputStream = postMethod.getResponseBodyAsStream(); } if (responseInputStream == null) { throw new IOException("No response input stream available from Gatekeeper"); } Properties responseProperties = new Properties(); try { responseProperties.load(responseInputStream); } finally { responseInputStream.close(); } GatekeeperMessage gatekeeperResponseMessage = GatekeeperMessage.decodeFromProperties(responseProperties); // Check for Gatekeeper Error Code in response. String gatekeeperErrorCode = gatekeeperResponseMessage.getApplicationProperties() .getProperty(GatekeeperMessage.APP_PROPERTY_GATEKEEPER_ERROR_CODE); if (gatekeeperErrorCode != null) { if (log.isWarnEnabled()) { log.warn("Received Gatekeeper error code: " + gatekeeperErrorCode); } } return gatekeeperResponseMessage; } else { if (log.isDebugEnabled()) { log.debug("The Gatekeeper did not permit a request. Response code: " + responseCode + ", Response content type: " + contentType); } throw new IOException("The Gatekeeper did not permit your request"); } } catch (IOException e) { throw e; } catch (Exception e) { throw new Exception("Gatekeeper did not respond", e); } finally { postMethod.releaseConnection(); } } /** * Parse the data in a set of SignatureRequest objects and build the corresponding * S3Objects represented by that data. * * @param srs * signature requests that represent S3 objects. * @return * objects reconstructed from the provided signature requests. */ public S3Object[] buildS3ObjectsFromSignatureRequests(SignatureRequest[] srs) { S3Object[] objects = new S3Object[srs.length]; for (int i = 0; i < srs.length; i++) { objects[i] = new S3Object(srs[i].getObjectKey()); objects[i].addAllMetadata(srs[i].getObjectMetadata()); } return objects; } public String getGatekeeperUrl() { return gatekeeperUrl; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/utils/signedurl/SignedUrlHandler.java0000644000000000000000000001256411550421156025133 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.utils.signedurl; import org.jets3t.service.ServiceException; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.model.S3Object; /** * An interface implemented by JetS3t services or utilities that can perform operations on objects * in S3 using only signed URLs - that is, without any knowledge of the user's AWS credentials. *

* Implementation classes need no knowledge of S3 as such, but merely have to be able to perform * standard HTTP requests for PUT, GET, HEAD and DELETE operation using signed URLs. *

* The {@link org.jets3t.service.impl.rest.httpclient.RestS3Service} implements this interface * using the HttpClient library. * * @author James Murty */ public interface SignedUrlHandler { /** * Puts an object using a pre-signed PUT URL generated for that object. * This method is an implementation of the interface {@link SignedUrlHandler}. *

* This operation does not required any S3 functionality as it merely * uploads the object by performing a standard HTTP PUT using the signed URL. * * @param signedPutUrl * a signed PUT URL generated. * @param object * the object to upload, which must correspond to the object for which the URL was signed. * The object must have the correct content length set, and to apply a non-standard * ACL policy only the REST canned ACLs can be used * (eg {@link AccessControlList#REST_CANNED_PUBLIC_READ_WRITE}). * * @return * the S3Object put to S3. The S3Object returned will be identical to the object provided, * except that the data input stream (if any) will have been consumed. * * @throws ServiceException */ public S3Object putObjectWithSignedUrl(String signedPutUrl, S3Object object) throws ServiceException; /** * Deletes an object using a pre-signed DELETE URL generated for that object. * This method is an implementation of the interface {@link SignedUrlHandler}. *

* This operation does not required any S3 functionality as it merely * deletes the object by performing a standard HTTP DELETE using the signed URL. * * @param signedDeleteUrl * a signed DELETE URL. * * @throws ServiceException */ public void deleteObjectWithSignedUrl(String signedDeleteUrl) throws ServiceException; /** * Gets an object using a pre-signed GET URL generated for that object. * This method is an implementation of the interface {@link SignedUrlHandler}. *

* This operation does not required any S3 functionality as it merely * uploads the object by performing a standard HTTP GET using the signed URL. * * @param signedGetUrl * a signed GET URL. * * @return * the S3Object in S3 including all metadata and the object's data input stream. * * @throws ServiceException */ public S3Object getObjectWithSignedUrl(String signedGetUrl) throws ServiceException; /** * Gets an object's details using a pre-signed HEAD URL generated for that object. * This method is an implementation of the interface {@link SignedUrlHandler}. *

* This operation does not required any S3 functionality as it merely * uploads the object by performing a standard HTTP HEAD using the signed URL. * * @param signedHeadUrl * a signed HEAD URL. * * @return * the S3Object in S3 including all metadata, but without the object's data input stream. * * @throws ServiceException */ public S3Object getObjectDetailsWithSignedUrl(String signedHeadUrl) throws ServiceException; /** * Gets an object's ACL details using a pre-signed GET URL generated for that object. * This method is an implementation of the interface {@link SignedUrlHandler}. * * @param signedAclUrl * a signed URL. * * @return * the AccessControlList settings of the object in S3. * * @throws ServiceException */ public AccessControlList getObjectAclWithSignedUrl(String signedAclUrl) throws ServiceException; /** * Sets an object's ACL details using a pre-signed PUT URL generated for that object. * This method is an implementation of the interface {@link SignedUrlHandler}. * * @param signedAclUrl * a signed URL. * @param acl * the ACL settings to apply to the object represented by the signed URL. * * @throws ServiceException */ public void putObjectAclWithSignedUrl(String signedAclUrl, AccessControlList acl) throws ServiceException; } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/utils/ObjectUtils.java0000644000000000000000000004272011534522600022167 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.utils; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.Date; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.Constants; import org.jets3t.service.ServiceException; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.io.BytesProgressWatcher; import org.jets3t.service.io.GZipDeflatingInputStream; import org.jets3t.service.io.ProgressMonitoredInputStream; import org.jets3t.service.io.TempFile; import org.jets3t.service.model.S3Object; import org.jets3t.service.model.StorageObject; import org.jets3t.service.multi.DownloadPackage; import org.jets3t.service.security.EncryptionUtil; /** * Utility class for preparing files for upload into S3, or for download from * S3. The methods in this class build the appropriate objects to wrap uploaded * files or objects in S3 that will be downloaded to a local file. * * @author James Murty */ public class ObjectUtils { private static final Log log = LogFactory.getLog(ObjectUtils.class); /** * Prepares a file for upload to a named object in S3, potentially transforming it if * zipping or encryption is requested. *

* The file will have the following metadata items added: *

    *
  • {@link Constants#METADATA_JETS3T_LOCAL_FILE_DATE}: The local file's last modified date * in ISO 8601 format
  • *
  • Content-Type : A content type guessed from the file's extension, or * {@link Mimetypes#MIMETYPE_BINARY_OCTET_STREAM} if the file is a directory
  • *
  • Content-Length : The size of the file
  • *
  • MD5-Hash : An MD5 hash of the file's data
  • *
  • {@link StorageObject#METADATA_HEADER_ORIGINAL_HASH_MD5}: An MD5 hash of the * original file's data (added if gzipping or encryption is applied)
  • *
* * @param objectKey * the object key name to use in S3 * @param dataFile * the file to prepare for upload. * @param encryptionUtil * if this variable is null no encryption will be applied, otherwise the provided * encryption utility object will be used to encrypt the file's data. * @param gzipFile * if true the file will be Gzipped. * @param progressWatcher * watcher to monitor progress of file transformation and hash generation. * * @return * an S3Object representing the file, or a transformed copy of the file, complete with * all JetS3t-specific metadata items set and ready for upload to S3. * * @throws Exception * exceptions could include IO failures, gzipping and encryption failures. */ public static S3Object createObjectForUpload(String objectKey, File dataFile, EncryptionUtil encryptionUtil, boolean gzipFile, BytesProgressWatcher progressWatcher) throws Exception { S3Object s3Object = new S3Object(objectKey); // Set object explicitly to private access by default. s3Object.setAcl(AccessControlList.REST_CANNED_PRIVATE); s3Object.addMetadata(Constants.METADATA_JETS3T_LOCAL_FILE_DATE, ServiceUtils.formatIso8601Date(new Date(dataFile.lastModified()))); if (dataFile.isDirectory()) { s3Object.setContentLength(0); s3Object.setContentType(Mimetypes.MIMETYPE_BINARY_OCTET_STREAM); } else { s3Object.setContentType(Mimetypes.getInstance().getMimetype(dataFile)); File uploadFile = transformUploadFile(dataFile, s3Object, encryptionUtil, gzipFile, progressWatcher); s3Object.setContentLength(uploadFile.length()); s3Object.setDataInputFile(uploadFile); // Compute the upload file's MD5 hash. InputStream inputStream = new BufferedInputStream(new FileInputStream(uploadFile)); if (progressWatcher != null) { inputStream = new ProgressMonitoredInputStream(inputStream, progressWatcher); } s3Object.setMd5Hash(ServiceUtils.computeMD5Hash(inputStream)); if (!uploadFile.equals(dataFile)) { // Compute the MD5 hash of the *original* file, if upload file has been altered // through encryption or gzipping. inputStream = new BufferedInputStream(new FileInputStream(dataFile)); if (progressWatcher != null) { inputStream = new ProgressMonitoredInputStream(inputStream, progressWatcher); } s3Object.addMetadata( S3Object.METADATA_HEADER_ORIGINAL_HASH_MD5, ServiceUtils.toBase64(ServiceUtils.computeMD5Hash(inputStream))); } } return s3Object; } /** * Prepares a file for upload to a named object in S3, potentially transforming it if * zipping or encryption is requested. *

* The file will have the following metadata items added: *

    *
  • {@link Constants#METADATA_JETS3T_LOCAL_FILE_DATE}: The local file's last modified date * in ISO 8601 format
  • *
  • Content-Type : A content type guessed from the file's extension, or * {@link Mimetypes#MIMETYPE_BINARY_OCTET_STREAM} if the file is a directory
  • *
  • Content-Length : The size of the file
  • *
  • MD5-Hash : An MD5 hash of the file's data
  • *
  • {@link StorageObject#METADATA_HEADER_ORIGINAL_HASH_MD5}: An MD5 hash of the original file's * data (added if gzipping or encryption is applied)
  • *
* * @param objectKey * the object key name to use in S3 * @param dataFile * the file to prepare for upload. * @param encryptionUtil * if this variable is null no encryption will be applied, otherwise the provided * encryption utility object will be used to encrypt the file's data. * @param gzipFile * if true the file will be Gzipped. * * @return * an S3Object representing the file, or a transformed copy of the file, complete with * all JetS3t-specific metadata items set and ready for upload to S3. * * @throws Exception * exceptions could include IO failures, gzipping and encryption failures. */ public static S3Object createObjectForUpload(String objectKey, File dataFile, EncryptionUtil encryptionUtil, boolean gzipFile) throws Exception { return createObjectForUpload(objectKey, dataFile, encryptionUtil, gzipFile, null); } /** * Prepares a file prior to upload by encrypting and/or gzipping it according to the * options specified by the user, and returning the transformed file. If no * transformations are required, the original dataFile will be returned. * * @param dataFile * the file to prepare for upload. * @param s3Object * the object that will be created in S3 to store the file. * @param encryptionUtil * if this variable is null no encryption will be applied, otherwise the provided * encryption utility object will be used to encrypt the file's data. * @param gzipFile * if true the file will be Gzipped. * @param progressWatcher * watcher to monitor progress of file transformation and hash generation. Note * that if encryption and/or gzipping is enabled, the underlying file will be * read 3 times instead of once. * * @return * the original file if no encryption/gzipping options are set, otherwise a * temporary file with encrypted and/or gzipped data from the original file. * * @throws Exception * exceptions could include IO failures, gzipping and encryption failures. */ private static File transformUploadFile(File dataFile, S3Object s3Object, EncryptionUtil encryptionUtil, boolean gzipFile, BytesProgressWatcher progressWatcher) throws Exception { if (!gzipFile && (encryptionUtil == null)) { // No file pre-processing required. return dataFile; } String actionText = ""; // Create a temporary file to hold data transformed from the original file. final File tempUploadFile = new TempFile(File.createTempFile("JetS3t",".tmp")); tempUploadFile.deleteOnExit(); // Transform data from original file, gzipping or encrypting as specified in user's options. OutputStream outputStream = null; InputStream inputStream = null; try { inputStream = new BufferedInputStream(new FileInputStream(dataFile)); outputStream = new BufferedOutputStream(new FileOutputStream(tempUploadFile)); String contentEncoding = null; if (gzipFile) { inputStream = new GZipDeflatingInputStream(inputStream); contentEncoding = "gzip"; s3Object.addMetadata(Constants.METADATA_JETS3T_COMPRESSED, "gzip"); actionText += "Compressing"; } if (encryptionUtil != null) { inputStream = encryptionUtil.encrypt(inputStream); contentEncoding = null; s3Object.setContentType(Mimetypes.MIMETYPE_OCTET_STREAM); s3Object.addMetadata(Constants.METADATA_JETS3T_CRYPTO_ALGORITHM, encryptionUtil.getAlgorithm()); s3Object.addMetadata(Constants.METADATA_JETS3T_CRYPTO_VERSION, EncryptionUtil.DEFAULT_VERSION); actionText += (actionText.length() == 0? "Encrypting" : " and encrypting"); } if (contentEncoding != null) { s3Object.addMetadata("Content-Encoding", contentEncoding); } if (log.isDebugEnabled()) { log.debug("Transforming upload file '" + dataFile + "' to temporary file '" + tempUploadFile.getAbsolutePath() + "': " + actionText); } if (progressWatcher != null) { inputStream = new ProgressMonitoredInputStream(inputStream, progressWatcher); } // Write transformed data to temporary file. byte[] buffer = new byte[8192]; int c = -1; while ((c = inputStream.read(buffer)) >= 0) { outputStream.write(buffer, 0, c); } } finally { if (inputStream != null) { inputStream.close(); } if (outputStream != null) { outputStream.close(); } } return tempUploadFile; } /** * Creates a download package representing an S3Object that will be downloaded, and the * target file the downloaded data will be written to. *

* Downloaded data may be transformed if the S3Object is encrypted or gzipped and the * appropriate options are set. * * @param object * the object * @param fileTarget * the file to which downloaded (and possibly transformed) data will be written. * @param automaticUnzip * if true, gzipped objects will be decrypted on-the-fly as they are downloaded. * @param automaticDecrypt * if true, encrypted files will be decrypted on-the-fly as they are downloaded (in which * case the encryptionPassword must be correct) * @param encryptionPassword * the password required to decrypt encrypted objects. * * @return * a download package representing an S3Object and a taret file for the object's data. * @throws Exception */ public static DownloadPackage createPackageForDownload(StorageObject object, File fileTarget, boolean automaticUnzip, boolean automaticDecrypt, String encryptionPassword) throws Exception { // Recognize directory place-holder objects and ignore them if (object.isDirectoryPlaceholder()) { return null; } else { boolean isZipped = false; EncryptionUtil encryptionUtil = null; if (automaticUnzip && ("gzip".equalsIgnoreCase(object.getContentEncoding()) || object.containsMetadata(Constants.METADATA_JETS3T_COMPRESSED))) { // Object data is gzipped. isZipped = true; } if (automaticDecrypt && object.containsMetadata(Constants.METADATA_JETS3T_CRYPTO_ALGORITHM)) { // Object is encrypted. if (encryptionPassword == null) { throw new ServiceException( "One or more objects are encrypted, and cannot be downloaded unless " + " the encyption password is provided"); } String algorithm = (String) object.getMetadata( Constants.METADATA_JETS3T_CRYPTO_ALGORITHM); String version = (String) object.getMetadata( Constants.METADATA_JETS3T_CRYPTO_VERSION); if (version == null) { version = EncryptionUtil.DEFAULT_VERSION; } encryptionUtil = new EncryptionUtil(encryptionPassword, algorithm, version); } return new DownloadPackage(object, fileTarget, isZipped, encryptionUtil); } } /** * Creates a download package representing an S3Object that will be downloaded, and the * target file the downloaded data will be written to. *

* Downloaded data may be transformed if the S3Object is encrypted or gzipped and the * appropriate options are set. * * @param object * the object * @param fileTarget * the file to which downloaded (and possibly transformed) data will be written. * @param automaticUnzip * if true, gzipped objects will be decrypted on-the-fly as they are downloaded. * @param automaticDecrypt * if true, encrypted files will be decrypted on-the-fly as they are downloaded (in which * case the encryptionPassword must be correct) * @param encryptionPassword * the password required to decrypt encrypted objects. * * @deprecated 0.8.0 use * {@link #createPackageForDownload(StorageObject, File, boolean, boolean, String)} instead. * * @return * a download package representing an S3Object and a taret file for the object's data. * @throws Exception */ @Deprecated public static org.jets3t.service.multithread.DownloadPackage createPackageForDownload( S3Object object, File fileTarget, boolean automaticUnzip, boolean automaticDecrypt, String encryptionPassword) throws Exception { // Recognize directory place-holder objects and ignore them if (object.isDirectoryPlaceholder()) { return null; } else { boolean isZipped = false; EncryptionUtil encryptionUtil = null; if (automaticUnzip && ("gzip".equalsIgnoreCase(object.getContentEncoding()) || object.containsMetadata(Constants.METADATA_JETS3T_COMPRESSED))) { // Object data is gzipped. isZipped = true; } if (automaticDecrypt && object.containsMetadata(Constants.METADATA_JETS3T_CRYPTO_ALGORITHM)) { // Object is encrypted. if (encryptionPassword == null) { throw new ServiceException( "One or more objects are encrypted, and cannot be downloaded unless " + " the encyption password is provided"); } String algorithm = (String) object.getMetadata( Constants.METADATA_JETS3T_CRYPTO_ALGORITHM); String version = (String) object.getMetadata( Constants.METADATA_JETS3T_CRYPTO_VERSION); if (version == null) { version = EncryptionUtil.DEFAULT_VERSION; } encryptionUtil = new EncryptionUtil(encryptionPassword, algorithm, version); } return new org.jets3t.service.multithread.DownloadPackage( object, fileTarget, isZipped, encryptionUtil); } } public static String convertDirPlaceholderKeyNameToDirName(String objectKey) { String dirPlaceholderKey = objectKey; if (dirPlaceholderKey.endsWith("_$folder$")) { int suffixPos = dirPlaceholderKey.indexOf("_$"); dirPlaceholderKey = dirPlaceholderKey.substring(0, suffixPos); } if (!dirPlaceholderKey.endsWith(Constants.FILE_PATH_DELIM)) { dirPlaceholderKey = dirPlaceholderKey + Constants.FILE_PATH_DELIM; } return dirPlaceholderKey; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/utils/ByteFormatter.java0000644000000000000000000001040511427702124022524 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.utils; import java.text.DecimalFormat; import java.text.ParseException; import javax.swing.text.NumberFormatter; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Formats numeric byte values into human-readable strings. * * @author James Murty */ public class ByteFormatter { private static final Log log = LogFactory.getLog(ByteFormatter.class); private String gigabyteSuffix = null; private String megabyteSuffix = null; private String kilobyteSuffix = null; private String byteSuffix = null; private NumberFormatter nf = null; /** * Constructs a formatter that will use default text to represent byte amounts. * Default values used: *

    *
  • Gigabyte suffix: " GB"
  • *
  • Megabyte suffix: " MB"
  • *
  • Kilobyte suffix: " KB"
  • *
  • Byte suffix: " B"
  • *
  • Precision: 2 decimal places
  • *
* */ public ByteFormatter() { this(" GB", " MB", " KB", " B", 2); } /** * Constructs a formatter that will use the given values when formatting byte values. * * @param gigabyteSuffix * string to display at the end of gigabyte values. * @param megabyteSuffix * string to display at the end of megabyte values. * @param kilobyteSuffix * string to display at the end of kilobyte values. * @param byteSuffix * string to display at the end of byte values. * @param decimalPlaces * the number of decimal places to use when converting byte amounts into kilo, mega or giga * byte values. */ public ByteFormatter(String gigabyteSuffix, String megabyteSuffix, String kilobyteSuffix, String byteSuffix, int decimalPlaces) { this.gigabyteSuffix = gigabyteSuffix; this.megabyteSuffix = megabyteSuffix; this.kilobyteSuffix = kilobyteSuffix; this.byteSuffix = byteSuffix; StringBuffer numberFormatString = new StringBuffer(); numberFormatString.append("0").append((decimalPlaces > 0? "." : "")); for (int i = 0; i < decimalPlaces; i++) { numberFormatString.append("0"); } nf = new NumberFormatter(new DecimalFormat(numberFormatString.toString())); } /** * Converts a byte size into a human-readable string, such as "1.43 MB" or "27 KB". * The values used are based on powers of 1024, ie 1 KB = 1024 bytes, not 1000 bytes. * * @param byteSize * the byte size of some item * @return * a human-readable description of the byte size */ public String formatByteSize(long byteSize) { String result = null; try { if (byteSize > Math.pow(1024,3)) { // Report gigabytes result = nf.valueToString(new Double(byteSize / Math.pow(1024,3))) + gigabyteSuffix; } else if (byteSize > Math.pow(1024,2)) { // Report megabytes result = nf.valueToString(new Double(byteSize / Math.pow(1024,2))) + megabyteSuffix; } else if (byteSize > 1024) { // Report kilobytes result = nf.valueToString(new Double(byteSize / Math.pow(1024,1))) + kilobyteSuffix; } else if (byteSize >= 0) { // Report bytes result = byteSize + byteSuffix; } } catch (ParseException e) { if (log.isErrorEnabled()) { log.error("Unable to format byte size " + byteSize, e); } return byteSize + byteSuffix; } return result; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/utils/FileComparer.java0000644000000000000000000015674511550421156022327 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.utils; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.security.NoSuchAlgorithmException; import java.text.Normalizer; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import java.util.TreeMap; import java.util.regex.Pattern; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.ServiceException; import org.jets3t.service.StorageObjectsChunk; import org.jets3t.service.StorageService; import org.jets3t.service.io.BytesProgressWatcher; import org.jets3t.service.io.ProgressMonitoredInputStream; import org.jets3t.service.model.StorageObject; import org.jets3t.service.multi.StorageServiceEventAdaptor; import org.jets3t.service.multi.StorageServiceEventListener; import org.jets3t.service.multi.ThreadedStorageService; import org.jets3t.service.multi.event.GetObjectHeadsEvent; import org.jets3t.service.multi.event.ListObjectsEvent; /** * File comparison utility to compare files on the local computer with objects present in a service * account and determine whether there are any differences. This utility contains methods to * build maps of the contents of the local file system or service account for comparison, and * methods to find differences in these maps. *

* File comparisons are based primarily on MD5 hashes of the files' contents. If a local file does * not match an object in the service with the same name, this utility determine which of the items is * newer by comparing the last modified dates. * * @author James Murty */ public class FileComparer { private static final Log log = LogFactory.getLog(FileComparer.class); private Jets3tProperties jets3tProperties = null; /** * Constructs the class. * * @param jets3tProperties * the object containing the properties that will be applied in this class. */ public FileComparer(Jets3tProperties jets3tProperties) { this.jets3tProperties = jets3tProperties; } /** * @param jets3tProperties * the object containing the properties that will be applied in the instance. * @return * a FileComparer instance. */ public static FileComparer getInstance(Jets3tProperties jets3tProperties) { return new FileComparer(jets3tProperties); } /** * @return * a FileComparer instance initialized with the default JetS3tProperties * object. */ public static FileComparer getInstance() { return new FileComparer( Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME)); } /** * If a .jets3t-ignore file is present in the given directory, the file is read * and all the paths contained in it are coverted to regular expression Pattern objects. * If the parent directory's list of patterns is provided, any relevant patterns are also * added to the ignore listing. Relevant parent patterns are those with a directory prefix * that matches the current directory, or with the wildcard depth pattern (*.*./). * * @param directory * a directory that may contain a .jets3t-ignore file. If this parameter is null * or is actually a file and not a directory, an empty list will be returned. * @param parentIgnorePatternList * a list of Patterns that were applied to the parent directory of the given directory. If this * parameter is null, no parent ignore patterns are applied. * * @return * a list of Pattern objects representing the paths in the ignore file. If there is no ignore * file, or if it has no contents, the list returned will be empty. */ protected List buildIgnoreRegexpList(File directory, List parentIgnorePatternList) { List ignorePatternList = new ArrayList(); // Add any applicable ignore patterns found in ancestor directories if (parentIgnorePatternList != null) { Iterator parentIgnorePatternIter = parentIgnorePatternList.iterator(); while (parentIgnorePatternIter.hasNext()) { Pattern parentPattern = parentIgnorePatternIter.next(); String parentIgnorePatternString = parentPattern.pattern(); // If parent ignore pattern contains a slash, it is eligible for inclusion. int slashOffset = parentIgnorePatternString.indexOf(Constants.FILE_PATH_DELIM); if (slashOffset >= 0 && parentIgnorePatternString.length() > (slashOffset + 1)) { // Ensure there is at least 1 char after slash // Chop pattern into header and tail around first slash character. String patternHeader = parentIgnorePatternString.substring(0, slashOffset); String patternTail = parentIgnorePatternString.substring(slashOffset + 1); if (".*.*".equals(patternHeader)) { // ** patterns are special and apply to any directory depth, so add both the // pattern's tail to match in this directory, and the original pattern to match // again in descendent directories. ignorePatternList.add(Pattern.compile(patternTail)); ignorePatternList.add(parentPattern); } else if (Pattern.compile(patternHeader).matcher(directory.getName()).matches()) { // Adds pattern's tail section to ignore list for this directory, provided // the pre-slash pattern matches the current directory's name. ignorePatternList.add(Pattern.compile(patternTail)); } } } } if (directory == null || !directory.isDirectory()) { return ignorePatternList; } File jets3tIgnoreFile = new File(directory, Constants.JETS3T_IGNORE_FILENAME); if (jets3tIgnoreFile.exists() && jets3tIgnoreFile.canRead()) { if (log.isDebugEnabled()) { log.debug("Found ignore file: " + jets3tIgnoreFile.getPath()); } try { String ignorePaths = ServiceUtils.readInputStreamToString( new FileInputStream(jets3tIgnoreFile), null); StringTokenizer st = new StringTokenizer(ignorePaths.trim(), "\n"); while (st.hasMoreTokens()) { String ignorePath = st.nextToken(); // Convert path to RegExp. String ignoreRegexp = ignorePath; ignoreRegexp = ignoreRegexp.replaceAll("\\.", "\\\\."); ignoreRegexp = ignoreRegexp.replaceAll("\\*", ".*"); ignoreRegexp = ignoreRegexp.replaceAll("\\?", "."); Pattern pattern = Pattern.compile(ignoreRegexp); if (log.isDebugEnabled()) { log.debug("Ignore path '" + ignorePath + "' has become the regexp: " + pattern.pattern()); } ignorePatternList.add(pattern); if (pattern.pattern().startsWith(".*.*/") && pattern.pattern().length() > 5) { // **/ patterns are special and apply to any directory depth, including the current // directory. So add the pattern's after-slash tail to match in this directory as well. ignorePatternList.add(Pattern.compile(pattern.pattern().substring(5))); } } } catch (IOException e) { if (log.isErrorEnabled()) { log.error("Failed to read contents of ignore file '" + jets3tIgnoreFile.getPath() + "'", e); } } } if (isSkipMd5FileUpload()) { Pattern pattern = Pattern.compile(".*\\.md5"); if (log.isDebugEnabled()) { log.debug("Skipping upload of pre-computed MD5 files with path '*.md5' using the regexp: " + pattern.pattern()); } ignorePatternList.add(pattern); } return ignorePatternList; } /** * Determines whether a file should be ignored when building a file map. A file may be ignored * in two situations: 1) if it matches a regular expression pattern in the given list of * ignore patterns, or 2) if it is a symlink/alias and the JetS3tProperties setting * "filecomparer.skip-symlinks" is true. * * @param ignorePatternList * a list of Pattern objects representing the file names to ignore. * @param file * a file that will either be ignored or not, depending on whether it matches an ignore Pattern * or is a symlink/alias. * * @return * true if the file should be ignored, false otherwise. */ protected boolean isIgnored(List ignorePatternList, File file) { if (isSkipSymlinks()) { /* * Check whether this file is actually a symlink/alias, and skip it if so. * Since Java IO libraries do not provide an official way to determine whether * a file is a symlink, we rely on a property of symlinks where the absolute * path to the symlink differs from the canonical path. This is hacky, but * mostly seems to work... */ try { if (!file.getAbsolutePath().equals(file.getCanonicalPath())) { if (log.isDebugEnabled()) { log.debug("Ignoring symlink " + (file.isDirectory() ? "directory" : "file") + ": " + file.getPath()); } // Skip symlink. return true; } } catch (IOException e) { log.warn("Unable to determine whether " + (file.isDirectory() ? "directory" : "file") + " '" + file.getAbsolutePath() + "' is a symlink", e); } } // Skip 'special' files that are neither files nor directories if (!file.isFile() && !file.isDirectory()) { if (log.isDebugEnabled()) { log.debug("Ignoring special file: " + file.getPath()); } return true; } Iterator patternIter = ignorePatternList.iterator(); while (patternIter.hasNext()) { Pattern pattern = patternIter.next(); if (pattern.matcher(file.getName()).matches()) { if (log.isDebugEnabled()) { log.debug("Ignoring " + (file.isDirectory() ? "directory" : "file") + " matching pattern '" + pattern.pattern() + "': " + file.getPath()); } return true; } } return false; } /** * Normalize string into "Normalization Form Canonical Decomposition" (NFD). * * References: * http://stackoverflow.com/questions/3610013 * http://en.wikipedia.org/wiki/Unicode_equivalence * * @param str * @return string normalized into NFC form. */ protected String normalizeUnicode(String str) { Normalizer.Form form = Normalizer.Form.NFD; if (!Normalizer.isNormalized(str, form)) { return Normalizer.normalize(str, form); } return str; } /** * Builds a map of files and directories that exist on the local system, where the map * keys are the object key names that will be used for the files in a remote storage * service, and the map values are absolute paths (Strings) to that file in the local * file system. The entire local file hierarchy within the given set of files and * directories is traversed (i.e. sub-directories are included.) *

* A file/directory hierarchy is represented using '/' delimiter characters in * object key names. *

* Any file or directory matching a path in a .jets3t-ignore file will be ignored. * * @param fileList * the set of files and directories to include in the file map. * @param fileKeyPrefix * A prefix added to each file path key in the map, e.g. the name of the root directory the * files belong to. If provided, a '/' suffix is always added to the end of the prefix. If null * or empty, no prefix is used. * @param includeDirectories * If true all directories, including empty ones, will be included in the Map. These directories * will be mere place-holder objects with a trailing slash (/) character in the name and the * content type {@link Mimetypes#MIMETYPE_BINARY_OCTET_STREAM}. * If this variable is false directory objects will not be included in the Map, and it will not * be possible to store empty directories in the service. * * @return * a Map of file path keys to File objects. */ public Map buildObjectKeyToFilepathMap( File[] fileList, String fileKeyPrefix, boolean includeDirectories) { if (fileKeyPrefix == null || fileKeyPrefix.trim().length() == 0) { fileKeyPrefix = ""; } // Build map of files proposed for upload or download. Map objectKeyToFilepathMap = new TreeMap(); List ignorePatternList = null; List ignorePatternListForCurrentDir = null; for (File file: fileList) { if (file.getParentFile() == null) { // For direct references to a file or dir, look for a .jets3t-ignore file // in the current directory - only do this once for the current dir. if (ignorePatternListForCurrentDir == null) { ignorePatternListForCurrentDir = buildIgnoreRegexpList(new File("."), null); } ignorePatternList = ignorePatternListForCurrentDir; } else { ignorePatternList = buildIgnoreRegexpList(file.getParentFile(), null); } if (!isIgnored(ignorePatternList, file)) { if (!file.exists()) { continue; } String objectKeyName = normalizeUnicode(file.getName()); if (!file.isDirectory()) { objectKeyToFilepathMap.put(objectKeyName, file.getAbsolutePath()); } else { objectKeyName += Constants.FILE_PATH_DELIM; if (includeDirectories) { objectKeyToFilepathMap.put(objectKeyName, file.getAbsolutePath()); } buildObjectKeyToFilepathMapForDirectory( file, objectKeyName, objectKeyToFilepathMap, includeDirectories, ignorePatternList); } } } return objectKeyToFilepathMap; } /** * Recursively builds a map of object key names to file paths that contains * all the files and directories inside the given directory. The map * keys are the object key names that will be used for the files in a remote storage * service, and the map values are absolute paths (Strings) to that file in the local * file system. *

* A file/directory hierarchy is represented using '/' delimiter characters in * object key names. *

* Any file or directory matching a path in a .jets3t-ignore file will be ignored. * * @param directory * The directory containing the files/directories of interest. The directory is not * included in the result map. * @param fileKeyPrefix * A prefix added to each file path key in the map, e.g. the name of the root directory the * files belong to. This prefix must end with a '/' character. * @param objectKeyToFilepathMap * map of '/'-delimited object key names to local file absolute paths, to which this method adds items. * @param includeDirectories * If true all directories, including empty ones, will be included in the Map. These directories * will be mere place-holder objects with a trailing slash (/) character in the name and the * content type {@link Mimetypes#MIMETYPE_BINARY_OCTET_STREAM}. * If this variable is false directory objects will not be included in the Map, and it will not * be possible to store empty directories in the service. * @param parentIgnorePatternList * a list of Patterns that were applied to the parent directory of the given directory. This list * will be checked to see if any of the parent's patterns should apply to the current directory. * See {@link #buildIgnoreRegexpList(File, List)} for more information. * If this parameter is null, no parent ignore patterns are applied. */ protected void buildObjectKeyToFilepathMapForDirectory(File directory, String fileKeyPrefix, Map objectKeyToFilepathMap, boolean includeDirectories, List parentIgnorePatternList) { List ignorePatternList = buildIgnoreRegexpList(directory, parentIgnorePatternList); for (File childFile: directory.listFiles()) { if (!isIgnored(ignorePatternList, childFile)) { String objectKeyName = normalizeUnicode(fileKeyPrefix + childFile.getName()); if (!childFile.isDirectory()) { objectKeyToFilepathMap.put(objectKeyName, childFile.getAbsolutePath()); } else { objectKeyName += Constants.FILE_PATH_DELIM; if (includeDirectories) { objectKeyToFilepathMap.put(objectKeyName, childFile.getAbsolutePath()); } buildObjectKeyToFilepathMapForDirectory( childFile, objectKeyName, objectKeyToFilepathMap, includeDirectories, ignorePatternList); } } } } /** * Lists the objects in a bucket using a partitioning technique to divide * the object namespace into separate partitions that can be listed by * multiple simultaneous threads. This method divides the object namespace * using the given delimiter, traverses this space up to the specified * depth to identify prefix names for multiple "partitions", and * then lists the objects in each partition. It returns the complete list * of objects in the bucket path. *

* This partitioning technique will work best for buckets with many objects * that are divided into a number of virtual subdirectories of roughly equal * size. * * @param service * the service object that will be used to perform listing requests. * @param bucketName * the name of the bucket whose contents will be listed. * @param targetPath * a root path within the bucket to be listed. If this parameter is null, all * the bucket's objects will be listed. Otherwise, only the objects below the * virtual path specified will be listed. * @param delimiter * the delimiter string used to identify virtual subdirectory partitions * in a bucket. If this parameter is null, or it has a value that is not * present in your object names, no partitioning will take place. * @param toDepth * the number of delimiter levels this method will traverse to identify * subdirectory partions. If this value is zero, no partitioning will take * place. * * @return * the list of objects under the target path in the bucket. * * @throws ServiceException */ public StorageObject[] listObjectsThreaded(StorageService service, final String bucketName, String targetPath, final String delimiter, int toDepth) throws ServiceException { final List allObjects = Collections.synchronizedList(new ArrayList()); final List lastCommonPrefixes = Collections.synchronizedList(new ArrayList()); final ServiceException serviceExceptions[] = new ServiceException[1]; /* * Create a ThreadedStorageService object with an event listener that responds to * ListObjectsEvent notifications and populates a complete object listing. */ final ThreadedStorageService threadedService = new ThreadedStorageService(service, new StorageServiceEventAdaptor() { @Override public void event(ListObjectsEvent event) { if (ListObjectsEvent.EVENT_IN_PROGRESS == event.getEventCode()) { Iterator chunkIter = event.getChunkList().iterator(); while (chunkIter.hasNext()) { StorageObjectsChunk chunk = chunkIter.next(); if (log.isDebugEnabled()) { log.debug("Listed " + chunk.getObjects().length + " objects and " + chunk.getCommonPrefixes().length + " common prefixes in bucket '" + bucketName + "' using prefix=" + chunk.getPrefix() + ", delimiter=" + chunk.getDelimiter()); } allObjects.addAll(Arrays.asList(chunk.getObjects())); lastCommonPrefixes.addAll(Arrays.asList(chunk.getCommonPrefixes())); } } else if (ListObjectsEvent.EVENT_ERROR == event.getEventCode()) { serviceExceptions[0] = new ServiceException( "Failed to list all objects in bucket", event.getErrorCause()); } } }); // The first listing partition we use as a starting point is the target path. String[] prefixesToList = new String[] {targetPath}; int currentDepth = 0; while (currentDepth <= toDepth && prefixesToList.length > 0) { if (log.isDebugEnabled()) { log.debug("Listing objects in '" + bucketName + "' using " + prefixesToList.length + " prefixes: " + Arrays.asList(prefixesToList)); } // Initialize the variables that will be used, or populated, by the // multi-threaded listing. lastCommonPrefixes.clear(); final String[] finalPrefixes = prefixesToList; final String finalDelimiter = (currentDepth < toDepth ? delimiter : null); /* * Perform a multi-threaded listing, where each prefix string * will be used as a unique partition to be listed in a separate thread. */ (new Thread() { @Override public void run() { threadedService.listObjects(bucketName, finalPrefixes, finalDelimiter, Constants.DEFAULT_OBJECT_LIST_CHUNK_SIZE); }; }).run(); // Throw any exceptions that occur inside the threads. if (serviceExceptions[0] != null) { throw serviceExceptions[0]; } // We use the common prefix paths identified in the last listing // iteration, if any, to identify partitions for follow-up listings. prefixesToList = lastCommonPrefixes .toArray(new String[lastCommonPrefixes.size()]); currentDepth++; } return allObjects.toArray(new StorageObject[allObjects.size()]); } /** * Lists the objects in a bucket using a partitioning technique to divide * the object namespace into separate partitions that can be listed by * multiple simultaneous threads. This method divides the object namespace * using the given delimiter, traverses this space up to the specified * depth to identify prefix names for multiple "partitions", and * then lists the objects in each partition. It returns the complete list * of objects in the bucket path. *

* This partitioning technique will work best for buckets with many objects * that are divided into a number of virtual subdirectories of roughly equal * size. *

* The delimiter and depth properties that define how this method will * partition the bucket's namespace are set in the jets3t.properties file * with the setting: * filecomparer.bucket-listing.<bucketname>=<delim>,<depth>
* For example: filecomparer.bucket-listing.my-bucket=/,2 * * @param service * the service object that will be used to perform listing requests. * @param bucketName * the name of the bucket whose contents will be listed. * @param targetPath * a root path within the bucket to be listed. If this parameter is null, all * the bucket's objects will be listed. Otherwise, only the objects below the * virtual path specified will be listed. * * @return * the list of objects under the target path in the bucket. * * @throws ServiceException */ public StorageObject[] listObjectsThreaded(StorageService service, final String bucketName, String targetPath) throws ServiceException { String delimiter = null; int toDepth = 0; // Find bucket-specific listing properties, if any. String bucketListingProperties = jets3tProperties.getStringProperty( "filecomparer.bucket-listing." + bucketName, null); if (bucketListingProperties != null) { String splits[] = bucketListingProperties.split(","); if (splits.length != 2) { throw new ServiceException( "Invalid setting for bucket listing property " + "filecomparer.bucket-listing." + bucketName + ": '" + bucketListingProperties + "'"); } delimiter = splits[0].trim(); toDepth = Integer.parseInt(splits[1]); } return listObjectsThreaded(service, bucketName, targetPath, delimiter, toDepth); } /** * Builds a service Object Map containing all the objects within the given target path, * where the map's key for each object is the relative path to the object. * * @see #lookupObjectMetadataForPotentialClashes(StorageService, String, String, StorageObject[], Map, BytesProgressWatcher, StorageServiceEventListener) * * @param service * @param bucketName * @param targetPath * @param objectKeyToFilepathMap * map of '/'-delimited object key names to local file absolute paths * @param progressWatcher * watcher to monitor bytes read during comparison operations, may be null. * @param eventListener * @return * mapping of keys to StorageObjects * @throws ServiceException */ public Map buildObjectMap(StorageService service, String bucketName, String targetPath, Map objectKeyToFilepathMap, BytesProgressWatcher progressWatcher, StorageServiceEventListener eventListener) throws ServiceException { String prefix = (targetPath.length() > 0 ? targetPath : null); StorageObject[] objectsIncomplete = this.listObjectsThreaded( service, bucketName, prefix); return lookupObjectMetadataForPotentialClashes( service, bucketName, targetPath, objectsIncomplete, objectKeyToFilepathMap, progressWatcher, eventListener); } /** * Builds a service Object Map containing a partial set of objects within the given target path, * where the map's key for each object is the relative path to the object. *

* If the method is asked to perform a complete listing, it will use the * {@link #listObjectsThreaded(StorageService, String, String)} method to list the objects * in the bucket, potentially taking advantage of any bucket name partitioning * settings you have applied. *

* If the method is asked to perform only a partial listing, no bucket name * partitioning will be applied. * * @see #lookupObjectMetadataForPotentialClashes(StorageService, String, String, StorageObject[], Map, BytesProgressWatcher, StorageServiceEventListener) * * @param service * @param bucketName * @param targetPath * @param priorLastKey * the prior last key value returned by a prior invocation of this method, if any. * @param objectKeyToFilepathMap * map of '/'-delimited object key names to local file absolute paths * @param completeListing * if true, this method will perform a complete listing of a service target. * If false, the method will list a partial set of objects commencing from the * given prior last key. * @param progressWatcher * watcher to monitor bytes read during comparison operations, may be null. * @param eventListener * * @return * an object containing a mapping of key names to StorageObjects, and the prior last * key (if any) that should be used to perform follow-up method calls. * @throws ServiceException */ public PartialObjectListing buildObjectMapPartial(StorageService service, String bucketName, String targetPath, String priorLastKey, Map objectKeyToFilepathMap, boolean completeListing, BytesProgressWatcher progressWatcher, StorageServiceEventListener eventListener) throws ServiceException { String prefix = (targetPath.length() > 0 ? targetPath : null); StorageObject[] objects = null; String resultPriorLastKey = null; if (completeListing) { objects = listObjectsThreaded(service, bucketName, prefix); } else { StorageObjectsChunk chunk = service.listObjectsChunked( bucketName, prefix, null, Constants.DEFAULT_OBJECT_LIST_CHUNK_SIZE, priorLastKey, completeListing); objects = chunk.getObjects(); resultPriorLastKey = chunk.getPriorLastKey(); } Map objectsMap = lookupObjectMetadataForPotentialClashes( service, bucketName, targetPath, objects, objectKeyToFilepathMap, progressWatcher, eventListener); return new PartialObjectListing(objectsMap, resultPriorLastKey); } /** * Given a set of storage objects for which only minimal information is available, * retrieve metadata information for any objects that potentially clash with * local files. An object is considered a potential clash when it has the same * object key name as a local file pending upload/download, and when the hash * value of the object data contents either differs from the local file's hash * or the hash comparison cannot be performed without the metadata information. * * @see #populateObjectMap(String, StorageObject[]) * * @param service * @param bucketName * @param targetPath * @param objectsWithoutMetadata * @param objectKeyToFilepathMap * @param progressWatcher * watcher to monitor bytes read during comparison operations, may be null. * @param eventListener * @return * mapping of keys to StorageObjects * @throws ServiceException */ public Map lookupObjectMetadataForPotentialClashes( StorageService service, String bucketName, String targetPath, StorageObject[] objectsWithoutMetadata, Map objectKeyToFilepathMap, BytesProgressWatcher progressWatcher, StorageServiceEventListener eventListener) throws ServiceException { Map objectMap = populateObjectMap(targetPath, objectsWithoutMetadata); // Identify objects that might clash with local files Set objectsForMetadataRetrieval = new HashSet(); for (StorageObject object: objectsWithoutMetadata) { String objectKey = object.getKey(); if (!ServiceUtils.isEtagAlsoAnMD5Hash(object.getETag())) { // Always retrieve metadata for objects whose ETags are // not MD5 hash values (e.g. multipart uploads) objectsForMetadataRetrieval.add(object); continue; } if (object.isMetadataComplete()) { // We already have this object's metadata continue; } String filepath = objectKeyToFilepathMap.get(objectKey); // Backwards-compatibility with JetS3t's old directory place-holders // key names that do not end with a slash (/). if (filepath == null && object.getContentLength() == 0 && !objectKey.endsWith("/") && "d41d8cd98f00b204e9800998ecf8427e".equals(object.getETag())) { // Reasonable chance this is a directory place-holder, see if // there's a matching local directory. filepath = objectKeyToFilepathMap.get(objectKey + "/"); // If not, bail out. if (filepath == null || !(new File(filepath).isDirectory())) { continue; } } if (filepath == null) { // Give up continue; } // Compare object's minimal ETag value against File's MD5 hash. File file = new File(filepath); String fileHashAsHex = null; try { if (file.isDirectory()) { // Dummy value, always retrieve metadata for directory place-holder objects fileHashAsHex = ""; } else { fileHashAsHex = ServiceUtils.toHex( generateFileMD5Hash(file, objectKey, progressWatcher)); } } catch (Exception e) { throw new ServiceException( "Unable to generate MD5 hash for file " + file.getPath(), e); } if (object.getETag() != null && object.getETag().equals(fileHashAsHex)) { // Object's ETag value is available and matches the MD5 hex hash of the file continue; } // Cannot tell whether local file and object are the same, // we will need all the object's metadata. objectsForMetadataRetrieval.add(object); } if (objectsForMetadataRetrieval.size() > 0) { // Retrieve the complete metadata information for selected objects final List objectsCompleteList = new ArrayList(objectsWithoutMetadata.length); final ServiceException serviceExceptions[] = new ServiceException[1]; ThreadedStorageService threadedService = new ThreadedStorageService(service, new StorageServiceEventAdaptor() { @Override public void event(GetObjectHeadsEvent event) { if (GetObjectHeadsEvent.EVENT_IN_PROGRESS == event.getEventCode()) { StorageObject[] finishedObjects = event.getCompletedObjects(); if (finishedObjects.length > 0) { objectsCompleteList.addAll(Arrays.asList(finishedObjects)); } } else if (GetObjectHeadsEvent.EVENT_ERROR == event.getEventCode()) { serviceExceptions[0] = new ServiceException( "Failed to retrieve detailed information about all objects", event.getErrorCause()); } } }); if (eventListener != null) { threadedService.addServiceEventListener(eventListener); } threadedService.getObjectsHeads(bucketName, objectsForMetadataRetrieval.toArray(new StorageObject[] {})); if (serviceExceptions[0] != null) { throw serviceExceptions[0]; } StorageObject[] objectsWithMetadata = objectsCompleteList.toArray(new StorageObject[objectsCompleteList.size()]); objectMap.putAll(populateObjectMap(targetPath, objectsWithMetadata)); } return objectMap; } /** * Builds a map of key/object pairs each object is associated with a key based on its location * in the service target path. * * @param targetPath * @param objects * @return * a map of keys to StorageObjects. */ public Map populateObjectMap(String targetPath, StorageObject[] objects) { Map map = new TreeMap(); for (int i = 0; i < objects.length; i++) { String relativeKey = objects[i].getKey(); if (targetPath.length() > 0) { relativeKey = relativeKey.substring(targetPath.length()); int slashIndex = relativeKey.indexOf(Constants.FILE_PATH_DELIM); if (slashIndex == 0) { relativeKey = relativeKey.substring(slashIndex + 1, relativeKey.length()); } else { // This object is the result of a prefix search, not an explicit directory. // Base the relative key on the last full subdirectory in the // target path if available... slashIndex = targetPath.lastIndexOf(Constants.FILE_PATH_DELIM); if (slashIndex >= 0) { relativeKey = objects[i].getKey().substring(slashIndex + 1); } // ...otherwise, use the full object key name. else { relativeKey = objects[i].getKey(); } } } if (relativeKey.length() > 0) { map.put(normalizeUnicode(relativeKey), objects[i]); } } return map; } /** * * @param file * @param relativeFilePath * @param progressWatcher * watcher to monitor bytes read during comparison operations, may be null. * @return * MD5 hash as bytes * @throws IOException * @throws NoSuchAlgorithmException */ public byte[] generateFileMD5Hash(File file, String relativeFilePath, BytesProgressWatcher progressWatcher) throws IOException, NoSuchAlgorithmException { byte[] computedHash = null; // Check whether a pre-computed MD5 hash file is available File computedHashFile = (getMd5FilesRootDirectoryFile() != null ? new File(getMd5FilesRootDirectoryFile(), relativeFilePath + ".md5") : new File(file.getPath() + ".md5")); if (isUseMd5Files() && computedHashFile.canRead() && computedHashFile.lastModified() > file.lastModified()) { BufferedReader br = null; try { // A pre-computed MD5 hash file is available, try to read this hash value br = new BufferedReader(new FileReader(computedHashFile)); computedHash = ServiceUtils.fromHex(br.readLine().split("\\s")[0]); } catch (Exception e) { if (log.isWarnEnabled()) { log.warn("Unable to read hash from computed MD5 file", e); } } finally { if (br != null) { br.close(); } } } if (computedHash == null) { // A pre-computed hash file was not available, or could not be read. // Calculate the hash value anew. InputStream hashInputStream = null; if (progressWatcher != null) { hashInputStream = new ProgressMonitoredInputStream( // Report on MD5 hash progress. new FileInputStream(file), progressWatcher); } else { hashInputStream = new FileInputStream(file); } computedHash = ServiceUtils.computeMD5Hash(hashInputStream); } if (isGenerateMd5Files() && !file.getName().endsWith(".md5") && (!computedHashFile.exists() || computedHashFile.lastModified() < file.lastModified())) { // Create parent directory for new hash file if necessary File parentDir = computedHashFile.getParentFile(); if (parentDir != null && !parentDir.exists()) { parentDir.mkdirs(); } // Create or update a pre-computed MD5 hash file. FileWriter fw = null; try { fw = new FileWriter(computedHashFile); fw.write(ServiceUtils.toHex(computedHash)); } catch (Exception e) { if (log.isWarnEnabled()) { log.warn("Unable to write computed MD5 hash to a file", e); } } finally { if (fw != null) { fw.close(); } } } return computedHash; } /** * Compares the contents of a directory on the local file system with the contents of a service * resource. This comparison is performed on a map of files and a map of service objects previously * generated using other methods in this class. * * @param objectKeyToFilepathMap * map of '/'-delimited object key names to local file absolute paths * @param objectsMap * a map of keys to StorageObjects. * @return * an object containing the results of the file comparison. * * @throws NoSuchAlgorithmException * @throws FileNotFoundException * @throws IOException * @throws ParseException */ public FileComparerResults buildDiscrepancyLists( Map objectKeyToFilepathMap, Map objectsMap) throws NoSuchAlgorithmException, FileNotFoundException, IOException, ParseException { return buildDiscrepancyLists(objectKeyToFilepathMap, objectsMap, null); } /** * Compares the contents of a directory on the local file system with the contents of a service * resource. This comparison is performed on a map of files and a map of service objects previously * generated using other methods in this class. * * @param objectKeyToFilepathMap * map of '/'-delimited object key names to local file absolute paths * @param objectsMap * a map of keys to StorageObjects. * @param progressWatcher * watcher to monitor bytes read during comparison operations, may be null. * @return * an object containing the results of the file comparison. * * @throws NoSuchAlgorithmException * @throws FileNotFoundException * @throws IOException * @throws ParseException */ public FileComparerResults buildDiscrepancyLists(Map objectKeyToFilepathMap, Map objectsMap, BytesProgressWatcher progressWatcher) throws NoSuchAlgorithmException, FileNotFoundException, IOException, ParseException { List onlyOnServerKeys = new ArrayList(); List updatedOnServerKeys = new ArrayList(); List updatedOnClientKeys = new ArrayList(); List onlyOnClientKeys = new ArrayList(); List alreadySynchronisedKeys = new ArrayList(); List alreadySynchronisedLocalPaths = new ArrayList(); // Start by assuming all items are local to client. Items will be removed // from this set as we proceed. onlyOnClientKeys.addAll(objectKeyToFilepathMap.keySet()); // Check files on server against local client files. Iterator> objectsMapIter = objectsMap.entrySet().iterator(); while (objectsMapIter.hasNext()) { Map.Entry entry = objectsMapIter.next(); String keyPath = entry.getKey(); StorageObject storageObject = entry.getValue(); String[] splitPathComponents = splitFilePathIntoDirPaths( keyPath, storageObject.isDirectoryPlaceholder()); int componentCount = 0; for (String localPath: splitPathComponents) { componentCount += 1; String filepath = objectKeyToFilepathMap.get(localPath); // Check whether local file is already on server if (filepath != null) { // File has been backed up in the past, is it still up-to-date? File file = new File(filepath); // We don't care about directory date changes, as long as it's present. if (file.isDirectory()) { // Only flag key path as already synced if the current localPath // is also equivalent to the *full* path of the object in the storage // service, not just an object's parent directory. (Issue #69) if (componentCount == splitPathComponents.length) { alreadySynchronisedKeys.add(keyPath); alreadySynchronisedLocalPaths.add(localPath); boolean wasRemoved = onlyOnClientKeys.remove(keyPath); // Backwards-compatibility with JetS3t directory place-holders // without trailing slash (/) suffixes if (!wasRemoved && !keyPath.endsWith("/") && storageObject.isDirectoryPlaceholder()) { onlyOnClientKeys.remove(keyPath + "/"); } } } // Compare file hashes. else { String fileHashAsBase64 = ServiceUtils.toBase64( generateFileMD5Hash(file, localPath, progressWatcher)); // Get the service object's Base64 hash. String objectHash = null; if (storageObject.containsMetadata(StorageObject.METADATA_HEADER_ORIGINAL_HASH_MD5)) { // Use the object's *original* hash, as it is an encoded version of a local file. objectHash = (String) storageObject.getMetadata( StorageObject.METADATA_HEADER_ORIGINAL_HASH_MD5); if (log.isDebugEnabled()) { log.debug("Object in service is encoded, using the object's original hash value for: " + storageObject.getKey()); } } else { // The object wasn't altered when uploaded, so use its current hash. objectHash = storageObject.getMd5HashAsBase64(); } if (fileHashAsBase64.equals(objectHash)) { // Hashes match so file is already synchronised. alreadySynchronisedKeys.add(keyPath); alreadySynchronisedLocalPaths.add(localPath); onlyOnClientKeys.remove(keyPath); } else { // File is out-of-synch. Check which version has the latest date. Date objectLastModified = null; String metadataLocalFileDate = (String) storageObject.getMetadata( Constants.METADATA_JETS3T_LOCAL_FILE_DATE); if (metadataLocalFileDate == null) { // This is risky as local file times and service times don't match! if (!isAssumeLocalLatestInMismatch() && log.isWarnEnabled()) { log.warn("Using service last modified date as file date. This is not reliable " + "as the time according to service can differ from your local system time. " + "Please use the metadata item " + Constants.METADATA_JETS3T_LOCAL_FILE_DATE); } objectLastModified = storageObject.getLastModifiedDate(); } else { objectLastModified = ServiceUtils .parseIso8601Date(metadataLocalFileDate); } if (objectLastModified.getTime() > file.lastModified()) { updatedOnServerKeys.add(keyPath); onlyOnClientKeys.remove(keyPath); } else if (objectLastModified.getTime() < file.lastModified()) { updatedOnClientKeys.add(keyPath); onlyOnClientKeys.remove(keyPath); } else { // Local file date and service object date values match exactly, yet the // local file has a different hash. This shouldn't ever happen, but // sometimes does with Excel files. if (isAssumeLocalLatestInMismatch()) { if (log.isWarnEnabled()) { log.warn("Backed-up object " + storageObject.getKey() + " and local file " + file.getName() + " have the same date but different hash values. " + "Assuming local file is the latest version."); } updatedOnClientKeys.add(keyPath); onlyOnClientKeys.remove(keyPath); } else { throw new IOException("Backed-up object " + storageObject.getKey() + " and local file " + file.getName() + " have the same date but different hash values. " + "This shouldn't happen!"); } } } } } else { // File is not in local file system, so it's only on the service. // Only flag key path as already synced if the current localPath // is also equivalent to the *full* path of the object in the storage // service, not just an object's parent directory. if (componentCount == splitPathComponents.length) { onlyOnServerKeys.add(keyPath); onlyOnClientKeys.remove(keyPath); } } } } return new FileComparerResults(onlyOnServerKeys, updatedOnServerKeys, updatedOnClientKeys, onlyOnClientKeys, alreadySynchronisedKeys, alreadySynchronisedLocalPaths); } private String[] splitFilePathIntoDirPaths(String path, boolean isDirectoryPlaceholder) { String[] pathComponents = path.split(Constants.FILE_PATH_DELIM); String[] dirPathsInOrder = new String[pathComponents.length]; String myPath = ""; for (int i = 0; i < pathComponents.length; i++) { String pathComponent = pathComponents[i]; myPath = myPath + pathComponent; if (i < pathComponents.length - 1 || isDirectoryPlaceholder) { myPath += Constants.FILE_PATH_DELIM; } dirPathsInOrder[i] = myPath; } return dirPathsInOrder; } /** * @return * true if the "filecomparer.skip-symlinks" configuration option is set. */ public boolean isSkipSymlinks() { return jets3tProperties.getBoolProperty("filecomparer.skip-symlinks", false); } /** * @return * true if the "filecomparer.use-md5-files" configuration option is set. */ public boolean isUseMd5Files() { return jets3tProperties.getBoolProperty("filecomparer.use-md5-files", false); } /** * @return * true if the "filecomparer.generate-md5-files" configuration option is set. */ public boolean isGenerateMd5Files() { return jets3tProperties.getBoolProperty("filecomparer.generate-md5-files", false); } /** * @return * true if the "filecomparer.skip-upload-of-md5-files" configuration option is set. */ public boolean isSkipMd5FileUpload() { return jets3tProperties.getBoolProperty("filecomparer.skip-upload-of-md5-files", false); } /** * @return * true if the "filecomparer.assume-local-latest-in-mismatch" configuration option is set. */ public boolean isAssumeLocalLatestInMismatch() { return jets3tProperties.getBoolProperty( "filecomparer.assume-local-latest-in-mismatch", false); } /** * @return * the file represented by the configuration option "filecomparer.md5-files-root-dir" * or null if this option is not specified. * @throws FileNotFoundException */ public File getMd5FilesRootDirectoryFile() throws FileNotFoundException { String dirPath = jets3tProperties.getStringProperty( "filecomparer.md5-files-root-dir", null); if (dirPath != null) { File dirFile = new File(dirPath); if (!dirFile.isDirectory()) { throw new FileNotFoundException( "filecomparer.md5-files-root-dir path is not a directory: " + dirPath); } return dirFile; } return null; } public class PartialObjectListing { private Map objectsMap = null; private String priorLastKey = null; public PartialObjectListing(Map objectsMap, String priorLastKey) { this.objectsMap = objectsMap; this.priorLastKey = priorLastKey; } public Map getObjectsMap() { return objectsMap; } public String getPriorLastKey() { return priorLastKey; } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/impl/0002755000000000000000000000000011441613550016675 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/impl/rest/0002755000000000000000000000000011550421156017652 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/impl/rest/httpclient/0002755000000000000000000000000011547515660022042 5ustar ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootjets3t-0.8.1+dfsg.orig/src/org/jets3t/service/impl/rest/httpclient/HttpClientAndConnectionManager.javajets3t-0.8.1+dfsg.orig/src/org/jets3t/service/impl/rest/httpclient/HttpClientAndConnectionManager.ja0000644000000000000000000000260411427702124030360 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.impl.rest.httpclient; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpConnectionManager; public class HttpClientAndConnectionManager { protected HttpClient httpClient = null; protected HttpConnectionManager httpConnectionManager = null; public HttpClientAndConnectionManager(HttpClient httpClient, HttpConnectionManager httpConnectionManager) { this.httpClient = httpClient; this.httpConnectionManager = httpConnectionManager; } public HttpClient getHttpClient() { return httpClient; } public HttpConnectionManager getHttpConnectionManager() { return httpConnectionManager; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/impl/rest/httpclient/RepeatableRequestEntity.java0000644000000000000000000002642011450004446027505 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.impl.rest.httpclient; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Random; import org.apache.commons.httpclient.methods.RequestEntity; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.io.InputStreamWrapper; import org.jets3t.service.io.ProgressMonitoredInputStream; import org.jets3t.service.io.RepeatableInputStream; import org.jets3t.service.utils.ServiceUtils; /** * An HttpClient request entity whose underlying data can be re-read (that is, repeated) * if necessary to retry failed transmissions. This class also provides basic byte-rate * throttling by throttling the reading of request bodies, the throttling value is set * with the JetS3t property httpclient.read-throttle. If Logging is enabled * for this class the MD5 hash values (Base64 and Hex) are logged after all data has * been written to the output stream. *

* This class works by taking advantage of the reset capability of the original * data input stream, or by wrapping the input stream in a reset-able class if * it is not so capable. *

* When data is repeated, any attached {@link ProgressMonitoredInputStream} is notified * that a repeat transmission is occurring. * * @author James Murty */ public class RepeatableRequestEntity implements RequestEntity { private static final Log log = LogFactory.getLog(RepeatableRequestEntity.class); private String name = null; private InputStream is = null; private String contentType = null; private long contentLength = 0; private long bytesWritten = 0; private InputStream repeatableInputStream = null; private ProgressMonitoredInputStream progressMonitoredIS = null; protected static long MAX_BYTES_PER_SECOND = 0; private static volatile long bytesWrittenThisSecond = 0; private static volatile long currentSecondMonitored = 0; private static final Random random = new Random(); private boolean isLiveMD5HashingEnabled = true; private byte[] dataMD5Hash = null; /** * Creates a repeatable request entity for the input stream provided. *

* If the input stream provided, or any underlying wrapped input streams, supports the * {@link InputStream#reset()} method then it will be capable of repeating data * transmission. If the input stream provided does not supports this method, it will * automatically be wrapped in a {@link RepeatableInputStream} -- in this case, the data * read from the wrapped input stream will be buffered up to the limit set by the JetS3t * property uploads.stream-retry-buffer-size (default: 131072 bytes). * *

* This constructor also detects when an underlying {@link ProgressMonitoredInputStream} is * present, and will notify this monitor if a repeat occurs. *

* If the JetS3t properties option httpclient.read-throttle is set to a * non-zero value, all simultaneous uploads performed by this class will be throttled * to the specified speed. * * * @param is * the input stream that supplies the data to be made repeatable. * @param contentType * @param contentLength * @param enableLiveMD5Hashing * if true, data that passes through the object will be hashed to an MD5 digest * and this digest will be available from {@link #getMD5DigestOfData()}. If false, * the digest will not be calculated. */ public RepeatableRequestEntity(String name, InputStream is, String contentType, long contentLength, Jets3tProperties jets3tProperties, boolean enableLiveMD5Hashing) { if (is == null) { throw new IllegalArgumentException("InputStream cannot be null"); } this.is = is; this.name = name; this.contentLength = contentLength; this.contentType = contentType; this.isLiveMD5HashingEnabled = enableLiveMD5Hashing; InputStream inputStream = is; while (true) { if (inputStream instanceof ProgressMonitoredInputStream) { progressMonitoredIS = (ProgressMonitoredInputStream) inputStream; } if (inputStream.markSupported()) { repeatableInputStream = inputStream; // Mark the start of this input stream so we can reset it if necessary. repeatableInputStream.mark(Integer.MAX_VALUE); } if (inputStream instanceof InputStreamWrapper) { inputStream = ((InputStreamWrapper) inputStream).getWrappedInputStream(); } else { break; } } if (this.repeatableInputStream == null) { if (log.isDebugEnabled()) { log.debug("Wrapping non-repeatable input stream in a RepeatableInputStream"); } int bufferSize = jets3tProperties.getIntProperty( "uploads.stream-retry-buffer-size", 131072); this.is = new RepeatableInputStream(is, bufferSize); this.repeatableInputStream = this.is; } MAX_BYTES_PER_SECOND = 1024 * jets3tProperties.getLongProperty("httpclient.read-throttle", 0); } public long getContentLength() { return contentLength; } public String getContentType() { return contentType; } /** * @return * always returns true. * If the input stream is not actually repeatable, an IOException will be thrown * later by the {@link #writeRequest(OutputStream)} method when the repeat is attempted. */ public boolean isRepeatable() { return true; } /** * Writes the request to the output stream. If the request is being repeated, the underlying * repeatable input stream will be reset with a call to {@link InputStream#reset()}. *

* If a {@link ProgressMonitoredInputStream} is attached, this monitor will be notified that * data is being repeated by being reset with * {@link ProgressMonitoredInputStream#resetProgressMonitor()}. */ public void writeRequest(OutputStream out) throws IOException { if (bytesWritten > 0) { // This entity is being repeated. repeatableInputStream.reset(); if (log.isWarnEnabled()) { log.warn("Repeating transmission of " + bytesWritten + " bytes"); } // Notify progress monitored input stream that we've gone backwards (if one is attached) if (progressMonitoredIS != null) { progressMonitoredIS.resetProgressMonitor(); } bytesWritten = 0; } MessageDigest messageDigest = null; if (isLiveMD5HashingEnabled) { try { messageDigest = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { if (log.isWarnEnabled()) { log.warn("Unable to calculate MD5 hash of data sent as algorithm is not available", e); } } } byte[] tmp = new byte[16384]; int count = 0; while ((count = this.is.read(tmp)) >= 0) { throttle(count); bytesWritten += count; out.write(tmp, 0, count); if (messageDigest != null) { messageDigest.update(tmp, 0, count); } } if (messageDigest != null) { dataMD5Hash = messageDigest.digest(); if (log.isDebugEnabled()) { log.debug("MD5 digest of data sent for '" + name + "' - B64:" + ServiceUtils.toBase64(dataMD5Hash) + " Hex:" + ServiceUtils.toHex(dataMD5Hash)); } } } /** * @return * The MD5 digest of the data transmitted by this RequestEntity. */ public byte[] getMD5DigestOfData() { if (dataMD5Hash != null) { return dataMD5Hash; } else { return new byte[0]; } } /** * Throttles the speed at which data is written by this request entity to the * maximum rate in KB/s specified by {@link #MAX_BYTES_PER_SECOND}. The method * works by repeatedly delaying its completion until writing the requested number * of bytes will not exceed the imposed limit for the current second. The delay * imposed each time the completion is deferred is a random value between 0-250ms. *

* This method is static and is shared by all instances of this class, so the byte * rate limit applies for all currently active RepeatableRequestEntity instances. * * @param bytesToWrite * the count of bytes that will be written once this method returns. * @throws IOException * an exception is thrown if the sleep delay is interrupted. */ protected static void throttle(int bytesToWrite) throws IOException { if (MAX_BYTES_PER_SECOND <= 0) { // No throttling is applied. return; } // All calculations are based on the current second time interval. long currentSecond = System.currentTimeMillis() / 1000; boolean willExceedThrottle; // All calculations are synchronized as this method can be called by multiple threads. synchronized (random) { // Check whether a new second has ticked over. boolean isCurrentSecond = currentSecond == currentSecondMonitored; // If a new second hasn't ticked over, we must limit the number of extra bytes // written this second. willExceedThrottle = isCurrentSecond && bytesWrittenThisSecond + bytesToWrite > MAX_BYTES_PER_SECOND; if (!isCurrentSecond) { // We are in a brand new second, it is safe to write some bytes. currentSecondMonitored = currentSecond; bytesWrittenThisSecond = bytesToWrite; } if (!willExceedThrottle) { // We can write bytes without exceeding the limit. bytesWrittenThisSecond += bytesToWrite; } } if (willExceedThrottle) { // Sleep for a random interval, then make a recursive call to see if we // will be allowed to write bytes then. try { Thread.sleep(random.nextInt(250)); } catch (InterruptedException e) { throw new IOException("Throttling of transmission was interrupted"); } throttle(bytesToWrite); } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/impl/rest/httpclient/RestS3Service.java0000644000000000000000000013526011550441744025351 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.impl.rest.httpclient; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.httpclient.HostConfiguration; import org.apache.commons.httpclient.HttpMethodBase; import org.apache.commons.httpclient.auth.CredentialsProvider; import org.apache.commons.httpclient.methods.InputStreamRequestEntity; import org.apache.commons.httpclient.methods.RequestEntity; import org.apache.commons.httpclient.methods.StringRequestEntity; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.S3Service; import org.jets3t.service.S3ServiceException; import org.jets3t.service.ServiceException; import org.jets3t.service.VersionOrDeleteMarkersChunk; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.impl.rest.XmlResponsesSaxParser.CompleteMultipartUploadResultHandler; import org.jets3t.service.impl.rest.XmlResponsesSaxParser.ListMultipartPartsResultHandler; import org.jets3t.service.impl.rest.XmlResponsesSaxParser.ListMultipartUploadsResultHandler; import org.jets3t.service.impl.rest.XmlResponsesSaxParser.ListVersionsResultsHandler; import org.jets3t.service.model.BaseVersionOrDeleteMarker; import org.jets3t.service.model.MultipartCompleted; import org.jets3t.service.model.MultipartPart; import org.jets3t.service.model.MultipartUpload; import org.jets3t.service.model.NotificationConfig; import org.jets3t.service.model.S3BucketLoggingStatus; import org.jets3t.service.model.S3BucketVersioningStatus; import org.jets3t.service.model.S3Object; import org.jets3t.service.model.StorageObject; import org.jets3t.service.model.WebsiteConfig; import org.jets3t.service.security.AWSDevPayCredentials; import org.jets3t.service.security.ProviderCredentials; import org.jets3t.service.utils.RestUtils; import com.jamesmurty.utils.XMLBuilder; /** * REST/HTTP implementation of an S3Service based on the * HttpClient library. *

* This class uses properties obtained through {@link Jets3tProperties}. For more information on * these properties please refer to * JetS3t Configuration *

* * @author James Murty */ public class RestS3Service extends S3Service { private static final Log log = LogFactory.getLog(RestS3Service.class); private static final String AWS_SIGNATURE_IDENTIFIER = "AWS"; private static final String AWS_REST_HEADER_PREFIX = "x-amz-"; private static final String AWS_REST_METADATA_PREFIX = "x-amz-meta-"; private String awsDevPayUserToken = null; private String awsDevPayProductToken = null; private boolean isRequesterPaysEnabled = false; /** * Constructs the service and initialises the properties. * * @param credentials * the user credentials to use when communicating with S3, may be null in which case the * communication is done as an anonymous user. * * @throws S3ServiceException */ public RestS3Service(ProviderCredentials credentials) throws S3ServiceException { this(credentials, null, null); } /** * Constructs the service and initialises the properties. * * @param credentials * the S3 user credentials to use when communicating with S3, may be null in which case the * communication is done as an anonymous user. * @param invokingApplicationDescription * a short description of the application using the service, suitable for inclusion in a * user agent string for REST/HTTP requests. Ideally this would include the application's * version number, for example: Cockpit/0.7.3 or My App Name/1.0 * @param credentialsProvider * an implementation of the HttpClient CredentialsProvider interface, to provide a means for * prompting for credentials when necessary. * * @throws S3ServiceException */ public RestS3Service(ProviderCredentials credentials, String invokingApplicationDescription, CredentialsProvider credentialsProvider) throws S3ServiceException { this(credentials, invokingApplicationDescription, credentialsProvider, Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME)); } /** * Constructs the service and initialises the properties. * * @param credentials * the S3 user credentials to use when communicating with S3, may be null in which case the * communication is done as an anonymous user. * @param invokingApplicationDescription * a short description of the application using the service, suitable for inclusion in a * user agent string for REST/HTTP requests. Ideally this would include the application's * version number, for example: Cockpit/0.7.3 or My App Name/1.0 * @param credentialsProvider * an implementation of the HttpClient CredentialsProvider interface, to provide a means for * prompting for credentials when necessary. * @param jets3tProperties * JetS3t properties that will be applied within this service. * * @throws S3ServiceException */ public RestS3Service(ProviderCredentials credentials, String invokingApplicationDescription, CredentialsProvider credentialsProvider, Jets3tProperties jets3tProperties) throws S3ServiceException { this(credentials, invokingApplicationDescription, credentialsProvider, jets3tProperties, new HostConfiguration()); } /** * Constructs the service and initialises the properties. * * @param credentials * the S3 user credentials to use when communicating with S3, may be null in which case the * communication is done as an anonymous user. * @param invokingApplicationDescription * a short description of the application using the service, suitable for inclusion in a * user agent string for REST/HTTP requests. Ideally this would include the application's * version number, for example: Cockpit/0.7.3 or My App Name/1.0 * @param credentialsProvider * an implementation of the HttpClient CredentialsProvider interface, to provide a means for * prompting for credentials when necessary. * @param jets3tProperties * JetS3t properties that will be applied within this service. * @param hostConfig * Custom HTTP host configuration; e.g to register a custom Protocol Socket Factory * * @throws S3ServiceException */ public RestS3Service(ProviderCredentials credentials, String invokingApplicationDescription, CredentialsProvider credentialsProvider, Jets3tProperties jets3tProperties, HostConfiguration hostConfig) throws S3ServiceException { super(credentials, invokingApplicationDescription, credentialsProvider, jets3tProperties, hostConfig); if (credentials instanceof AWSDevPayCredentials) { AWSDevPayCredentials awsDevPayCredentials = (AWSDevPayCredentials) credentials; this.awsDevPayUserToken = awsDevPayCredentials.getUserToken(); this.awsDevPayProductToken = awsDevPayCredentials.getProductToken(); } else { this.awsDevPayUserToken = jets3tProperties.getStringProperty("devpay.user-token", null); this.awsDevPayProductToken = jets3tProperties.getStringProperty("devpay.product-token", null); } this.setRequesterPaysEnabled( this.jets3tProperties.getBoolProperty("httpclient.requester-pays-buckets-enabled", false)); } @Override protected boolean isTargettingGoogleStorageService() { return Constants.GS_DEFAULT_HOSTNAME.equals( this.getJetS3tProperties().getStringProperty("s3service.s3-endpoint", null)); } /** * Set the User Token value to use for requests to a DevPay S3 account. * The user token is not required for DevPay web products for which the * user token was created after 15th May 2008. * * @param userToken * the user token value provided by the AWS DevPay activation service. */ public void setDevPayUserToken(String userToken) { this.awsDevPayUserToken = userToken; } /** * @return * the user token value to use in requests to a DevPay S3 account, or null * if no such token value has been set. */ public String getDevPayUserToken() { return this.awsDevPayUserToken; } /** * Set the Product Token value to use for requests to a DevPay S3 account. * * @param productToken * the token that identifies your DevPay product. */ public void setDevPayProductToken(String productToken) { this.awsDevPayProductToken = productToken; } /** * @return * the product token value to use in requests to a DevPay S3 account, or * null if no such token value has been set. */ public String getDevPayProductToken() { return this.awsDevPayProductToken; } /** * Instruct the service whether to generate Requester Pays requests when * uploading data to S3, or retrieving data from the service. The default * value for the Requester Pays Enabled setting is set according to the * jets3t.properties setting * httpclient.requester-pays-buckets-enabled. * * @param isRequesterPays * if true, all subsequent S3 service requests will include the Requester * Pays flag. */ public void setRequesterPaysEnabled(boolean isRequesterPays) { this.isRequesterPaysEnabled = isRequesterPays; } /** * Is this service configured to generate Requester Pays requests when * uploading data to S3, or retrieving data from the service. The default * value for the Requester Pays Enabled setting is set according to the * jets3t.properties setting * httpclient.requester-pays-buckets-enabled. * * @return * true if S3 service requests will include the Requester Pays flag, false * otherwise. */ public boolean isRequesterPaysEnabled() { return this.isRequesterPaysEnabled; } /** * Creates an {@link org.apache.commons.httpclient.HttpMethod} object to handle a particular connection method. * * @param method * the HTTP method/connection-type to use, must be one of: PUT, HEAD, GET, DELETE * @param bucketName * the bucket's name * @param objectKey * the object's key name, may be null if the operation is on a bucket only. * @return * the HTTP method object used to perform the request * * @throws org.jets3t.service.S3ServiceException */ @Override protected HttpMethodBase setupConnection(HTTP_METHOD method, String bucketName, String objectKey, Map requestParameters) throws S3ServiceException { HttpMethodBase httpMethod; try { httpMethod = super.setupConnection(method, bucketName, objectKey, requestParameters); } catch (ServiceException se) { throw new S3ServiceException(se); } // Set DevPay request headers. if (getDevPayUserToken() != null || getDevPayProductToken() != null) { // DevPay tokens have been provided, include these with the request. if (getDevPayProductToken() != null) { String securityToken = getDevPayUserToken() + "," + getDevPayProductToken(); httpMethod.setRequestHeader(Constants.AMZ_SECURITY_TOKEN, securityToken); if (log.isDebugEnabled()) { log.debug("Including DevPay user and product tokens in request: " + Constants.AMZ_SECURITY_TOKEN + "=" + securityToken); } } else { httpMethod.setRequestHeader(Constants.AMZ_SECURITY_TOKEN, getDevPayUserToken()); if (log.isDebugEnabled()) { log.debug("Including DevPay user token in request: " + Constants.AMZ_SECURITY_TOKEN + "=" + getDevPayUserToken()); } } } // Set Requester Pays header to allow access to these buckets. if (this.isRequesterPaysEnabled()) { String[] requesterPaysHeaderAndValue = Constants.REQUESTER_PAYS_BUCKET_FLAG.split("="); httpMethod.setRequestHeader(requesterPaysHeaderAndValue[0], requesterPaysHeaderAndValue[1]); if (log.isDebugEnabled()) { log.debug("Including Requester Pays header in request: " + Constants.REQUESTER_PAYS_BUCKET_FLAG); } } return httpMethod; } /** * @return * the endpoint to be used to connect to S3. */ @Override public String getEndpoint() { return this.jets3tProperties.getStringProperty( "s3service.s3-endpoint", Constants.S3_DEFAULT_HOSTNAME); } /** * @return * the virtual path inside the S3 server. */ @Override protected String getVirtualPath() { return this.jets3tProperties.getStringProperty( "s3service.s3-endpoint-virtual-path", ""); } /** * @return * the identifier for the signature algorithm. */ @Override protected String getSignatureIdentifier() { return AWS_SIGNATURE_IDENTIFIER; } /** * @return * header prefix for general Amazon headers: x-amz-. */ @Override public String getRestHeaderPrefix() { return AWS_REST_HEADER_PREFIX; } @Override public List getResourceParameterNames() { // Special HTTP parameter names that refer to resources in S3 return Arrays.asList(new String[] { "acl", "policy", "torrent", "logging", "location", "requestPayment", "versions", "versioning", "versionId", "uploads", "uploadId", "partNumber", "website", "notification" }); } /** * @return * header prefix for Amazon metadata headers: x-amz-meta-. */ @Override public String getRestMetadataPrefix() { return AWS_REST_METADATA_PREFIX; } /** * @return * the port number to be used for insecure connections over HTTP. */ @Override protected int getHttpPort() { return this.jets3tProperties.getIntProperty("s3service.s3-endpoint-http-port", 80); } /** * @return * the port number to be used for secure connections over HTTPS. */ @Override protected int getHttpsPort() { return this.jets3tProperties.getIntProperty("s3service.s3-endpoint-https-port", 443); } /** * @return * If true, all communication with S3 will be via encrypted HTTPS connections, * otherwise communications will be sent unencrypted via HTTP. */ @Override protected boolean getHttpsOnly() { return this.jets3tProperties.getBoolProperty("s3service.https-only", true); } /** * @return * If true, JetS3t will specify bucket names in the request path of the HTTP message * instead of the Host header. */ @Override protected boolean getDisableDnsBuckets() { return this.jets3tProperties.getBoolProperty("s3service.disable-dns-buckets", false); } /** * @return * If true, JetS3t will enable support for Storage Classes. */ @Override protected boolean getEnableStorageClasses() { return this.jets3tProperties.getBoolProperty("s3service.enable-storage-classes", // Enable non-standard storage classes by default for AWS, not for Google endpoints. isTargettingGoogleStorageService() ? false : true); } @Override protected BaseVersionOrDeleteMarker[] listVersionedObjectsImpl(String bucketName, String prefix, String delimiter, String keyMarker, String versionMarker, long maxListingLength) throws S3ServiceException { return listVersionedObjectsInternal(bucketName, prefix, delimiter, maxListingLength, true, keyMarker, versionMarker).getItems(); } @Override protected void updateBucketVersioningStatusImpl(String bucketName, boolean enabled, boolean multiFactorAuthDeleteEnabled, String multiFactorSerialNumber, String multiFactorAuthCode) throws S3ServiceException { if (log.isDebugEnabled()) { log.debug( (enabled ? "Enabling" : "Suspending") + " versioning for bucket " + bucketName + (multiFactorAuthDeleteEnabled ? " with Multi-Factor Auth enabled" : "")); } try { XMLBuilder builder = XMLBuilder .create("VersioningConfiguration").a("xmlns", Constants.XML_NAMESPACE) .e("Status").t( (enabled ? "Enabled" : "Suspended") ).up() .e("MfaDelete").t( (multiFactorAuthDeleteEnabled ? "Enabled" : "Disabled")); Map requestParams = new HashMap(); requestParams.put("versioning", null); Map metadata = new HashMap(); if (multiFactorSerialNumber != null || multiFactorAuthCode != null) { metadata.put(Constants.AMZ_MULTI_FACTOR_AUTH_CODE, multiFactorSerialNumber + " " + multiFactorAuthCode); } try { performRestPutWithXmlBuilder(bucketName, null, metadata, requestParams, builder); } catch (ServiceException se) { throw new S3ServiceException(se); } } catch (ParserConfigurationException e) { throw new S3ServiceException("Failed to build XML document for request", e); } } @Override protected S3BucketVersioningStatus getBucketVersioningStatusImpl(String bucketName) throws S3ServiceException { try { if (log.isDebugEnabled()) { log.debug( "Checking status of versioning for bucket " + bucketName); } Map requestParams = new HashMap(); requestParams.put("versioning", null); HttpMethodBase method = performRestGet(bucketName, null, requestParams, null); return getXmlResponseSaxParser() .parseVersioningConfigurationResponse(new HttpMethodReleaseInputStream(method)); } catch (ServiceException se) { throw new S3ServiceException(se); } } protected VersionOrDeleteMarkersChunk listVersionedObjectsInternal( String bucketName, String prefix, String delimiter, long maxListingLength, boolean automaticallyMergeChunks, String nextKeyMarker, String nextVersionIdMarker) throws S3ServiceException { Map parameters = new HashMap(); parameters.put("versions", null); if (prefix != null) { parameters.put("prefix", prefix); } if (delimiter != null) { parameters.put("delimiter", delimiter); } if (maxListingLength > 0) { parameters.put("max-keys", String.valueOf(maxListingLength)); } List items = new ArrayList(); List commonPrefixes = new ArrayList(); boolean incompleteListing = true; int ioErrorRetryCount = 0; while (incompleteListing) { if (nextKeyMarker != null) { parameters.put("key-marker", nextKeyMarker); } else { parameters.remove("key-marker"); } if (nextVersionIdMarker != null) { parameters.put("version-id-marker", nextVersionIdMarker); } else { parameters.remove("version-id-marker"); } HttpMethodBase httpMethod; try { httpMethod = performRestGet(bucketName, null, parameters, null); } catch (ServiceException se) { throw new S3ServiceException(se); } ListVersionsResultsHandler handler = null; try { handler = getXmlResponseSaxParser() .parseListVersionsResponse( new HttpMethodReleaseInputStream(httpMethod)); ioErrorRetryCount = 0; } catch (ServiceException se) { if (se.getCause() instanceof IOException && ioErrorRetryCount < 5) { ioErrorRetryCount++; if (log.isWarnEnabled()) { log.warn("Retrying bucket listing failure due to IO error", se); } continue; } else { throw new S3ServiceException(se); } } BaseVersionOrDeleteMarker[] partialItems = handler.getItems(); if (log.isDebugEnabled()) { log.debug("Found " + partialItems.length + " items in one batch"); } items.addAll(Arrays.asList(partialItems)); String[] partialCommonPrefixes = handler.getCommonPrefixes(); if (log.isDebugEnabled()) { log.debug("Found " + partialCommonPrefixes.length + " common prefixes in one batch"); } commonPrefixes.addAll(Arrays.asList(partialCommonPrefixes)); incompleteListing = handler.isListingTruncated(); nextKeyMarker = handler.getNextKeyMarker(); nextVersionIdMarker = handler.getNextVersionIdMarker(); if (incompleteListing) { if (log.isDebugEnabled()) { log.debug("Yet to receive complete listing of bucket versions, " + "continuing with key-marker=" + nextKeyMarker + " and version-id-marker=" + nextVersionIdMarker); } } if (!automaticallyMergeChunks) { break; } } if (automaticallyMergeChunks) { if (log.isDebugEnabled()) { log.debug("Found " + items.size() + " items in total"); } return new VersionOrDeleteMarkersChunk( prefix, delimiter, items.toArray(new BaseVersionOrDeleteMarker[items.size()]), commonPrefixes.toArray(new String[commonPrefixes.size()]), null, null); } else { return new VersionOrDeleteMarkersChunk( prefix, delimiter, items.toArray(new BaseVersionOrDeleteMarker[items.size()]), commonPrefixes.toArray(new String[commonPrefixes.size()]), nextKeyMarker, nextVersionIdMarker); } } @Override protected VersionOrDeleteMarkersChunk listVersionedObjectsChunkedImpl(String bucketName, String prefix, String delimiter, long maxListingLength, String priorLastKey, String priorLastVersion, boolean completeListing) throws S3ServiceException { return listVersionedObjectsInternal(bucketName, prefix, delimiter, maxListingLength, completeListing, priorLastKey, priorLastVersion); } @Override protected String getBucketLocationImpl(String bucketName) throws S3ServiceException { if (log.isDebugEnabled()) { log.debug("Retrieving location of Bucket: " + bucketName); } Map requestParameters = new HashMap(); requestParameters.put("location", ""); try { HttpMethodBase httpMethod = performRestGet(bucketName, null, requestParameters, null); return getXmlResponseSaxParser() .parseBucketLocationResponse( new HttpMethodReleaseInputStream(httpMethod)); } catch (ServiceException se) { throw new S3ServiceException(se); } } @Override protected S3BucketLoggingStatus getBucketLoggingStatusImpl(String bucketName) throws S3ServiceException { if (log.isDebugEnabled()) { log.debug("Retrieving Logging Status for Bucket: " + bucketName); } Map requestParameters = new HashMap(); requestParameters.put("logging", ""); try { HttpMethodBase httpMethod = performRestGet(bucketName, null, requestParameters, null); return getXmlResponseSaxParser() .parseLoggingStatusResponse( new HttpMethodReleaseInputStream(httpMethod)).getBucketLoggingStatus(); } catch (ServiceException se) { throw new S3ServiceException(se); } } @Override protected void setBucketLoggingStatusImpl(String bucketName, S3BucketLoggingStatus status) throws S3ServiceException { if (log.isDebugEnabled()) { log.debug("Setting Logging Status for bucket: " + bucketName); } Map requestParameters = new HashMap(); requestParameters.put("logging", ""); Map metadata = new HashMap(); metadata.put("Content-Type", "text/plain"); String statusAsXml = null; try { statusAsXml = status.toXml(); } catch (Exception e) { throw new S3ServiceException("Unable to generate LoggingStatus XML document", e); } try { metadata.put("Content-Length", String.valueOf(statusAsXml.length())); performRestPut(bucketName, null, metadata, requestParameters, new StringRequestEntity(statusAsXml, "text/plain", Constants.DEFAULT_ENCODING), true); } catch (ServiceException se) { throw new S3ServiceException(se); } catch (UnsupportedEncodingException e) { throw new S3ServiceException("Unable to encode LoggingStatus XML document", e); } } @Override protected String getBucketPolicyImpl(String bucketName) throws S3ServiceException { try { Map requestParameters = new HashMap(); requestParameters.put("policy", ""); HttpMethodBase httpMethod = performRestGet(bucketName, null, requestParameters, null); return httpMethod.getResponseBodyAsString(); } catch (ServiceException se) { throw new S3ServiceException(se); } catch (IOException e) { throw new S3ServiceException(e); } } @Override protected void setBucketPolicyImpl(String bucketName, String policyDocument) throws S3ServiceException { Map requestParameters = new HashMap(); requestParameters.put("policy", ""); Map metadata = new HashMap(); metadata.put("Content-Type", "text/plain"); try { metadata.put("Content-Length", String.valueOf(policyDocument.length())); performRestPut(bucketName, null, metadata, requestParameters, new StringRequestEntity(policyDocument, "text/plain", Constants.DEFAULT_ENCODING), true); } catch (ServiceException se) { throw new S3ServiceException(se); } catch (UnsupportedEncodingException e) { throw new S3ServiceException("Unable to encode LoggingStatus XML document", e); } } @Override protected void deleteBucketPolicyImpl(String bucketName) throws S3ServiceException { try { Map requestParameters = new HashMap(); requestParameters.put("policy", ""); performRestDelete(bucketName, null, requestParameters, null, null); } catch (ServiceException se) { throw new S3ServiceException(se); } } @Override protected boolean isRequesterPaysBucketImpl(String bucketName) throws S3ServiceException { if (log.isDebugEnabled()) { log.debug("Retrieving Request Payment Configuration settings for Bucket: " + bucketName); } Map requestParameters = new HashMap(); requestParameters.put("requestPayment", ""); try { HttpMethodBase httpMethod = performRestGet(bucketName, null, requestParameters, null); return getXmlResponseSaxParser() .parseRequestPaymentConfigurationResponse( new HttpMethodReleaseInputStream(httpMethod)); } catch (ServiceException se) { throw new S3ServiceException(se); } } @Override protected void setRequesterPaysBucketImpl(String bucketName, boolean requesterPays) throws S3ServiceException { if (log.isDebugEnabled()) { log.debug("Setting Request Payment Configuration settings for bucket: " + bucketName); } Map requestParameters = new HashMap(); requestParameters.put("requestPayment", ""); Map metadata = new HashMap(); metadata.put("Content-Type", "text/plain"); try { String xml = "" + "" + (requesterPays ? "Requester" : "BucketOwner") + "" + ""; metadata.put("Content-Length", String.valueOf(xml.length())); performRestPut(bucketName, null, metadata, requestParameters, new StringRequestEntity(xml, "text/plain", Constants.DEFAULT_ENCODING), true); } catch (ServiceException se) { throw new S3ServiceException(se); } catch (UnsupportedEncodingException e) { throw new S3ServiceException("Unable to encode RequestPaymentConfiguration XML document", e); } } @Override protected MultipartUpload multipartStartUploadImpl(String bucketName, String objectKey, Map metadataProvided, AccessControlList acl, String storageClass) throws S3ServiceException { Map requestParameters = new HashMap(); requestParameters.put("uploads", ""); Map metadata = new HashMap(); // Use metadata provided, but ignore some items that don't make sense if (metadataProvided != null) { for (Map.Entry entry: metadataProvided.entrySet()) { if (!entry.getKey().toLowerCase().equals("content-length")) { metadata.put(entry.getKey(), entry.getValue()); } } } // Apply per-object or default storage class when uploading object prepareStorageClass(metadata, storageClass, objectKey); try { HttpMethodBase postMethod = performRestPost( bucketName, objectKey, metadata, requestParameters, null, false); MultipartUpload multipartUpload = getXmlResponseSaxParser() .parseInitiateMultipartUploadResult( new HttpMethodReleaseInputStream(postMethod)); multipartUpload.setMetadata(metadata); // Add object's known metadata to result object. return multipartUpload; } catch (ServiceException se) { throw new S3ServiceException(se); } } @Override protected MultipartPart multipartUploadPartImpl(String uploadId, String bucketName, Integer partNumber, S3Object object) throws S3ServiceException { Map requestParameters = new HashMap(); requestParameters.put("uploadId", uploadId); requestParameters.put("partNumber", "" + partNumber); // Remove all non-HTTP headers from object metadata for multipart part uploads List metadataNamesToRemove = new ArrayList(); for (String name: object.getMetadataMap().keySet()) { if (!RestUtils.HTTP_HEADER_METADATA_NAMES.contains(name.toLowerCase())) { // Actual metadata name in object does not include the prefix metadataNamesToRemove.add(name); } } for (String name: metadataNamesToRemove) { object.removeMetadata(name); } try { // We do not need to calculate the data MD5 hash during upload if the // expected hash value was provided as the object's Content-MD5 header. boolean isLiveMD5HashingRequired = (object.getMetadata(StorageObject.METADATA_HEADER_CONTENT_MD5) == null); RequestEntity requestEntity = null; if (object.getDataInputStream() != null) { if (object.containsMetadata(StorageObject.METADATA_HEADER_CONTENT_LENGTH)) { if (log.isDebugEnabled()) { log.debug("Uploading multipart part data with Content-Length: " + object.getContentLength()); } requestEntity = new RepeatableRequestEntity(object.getKey(), object.getDataInputStream(), object.getContentType(), object.getContentLength(), this.jets3tProperties, isLiveMD5HashingRequired); } else { // Use InputStreamRequestEntity for objects with an unknown content length, as the // entity will cache the results and doesn't need to know the data length in advance. if (log.isWarnEnabled()) { log.warn("Content-Length of multipart part stream not set, " + "will automatically determine data length in memory"); } requestEntity = new InputStreamRequestEntity( object.getDataInputStream(), InputStreamRequestEntity.CONTENT_LENGTH_AUTO); } } this.putObjectWithRequestEntityImpl(bucketName, object, requestEntity, requestParameters); // Populate part with response data that is accessible via the object's metadata MultipartPart part = new MultipartPart(partNumber, object.getLastModifiedDate(), object.getETag(), object.getContentLength()); return part; } catch (ServiceException se) { throw new S3ServiceException(se); } } @Override protected void multipartAbortUploadImpl(String uploadId, String bucketName, String objectKey) throws S3ServiceException { Map requestParameters = new HashMap(); requestParameters.put("uploadId", uploadId); try { performRestDelete(bucketName, objectKey, requestParameters, null, null); } catch (ServiceException se) { throw new S3ServiceException(se); } } @Override protected MultipartCompleted multipartCompleteUploadImpl(String uploadId, String bucketName, String objectKey, List parts) throws S3ServiceException { Map requestParameters = new HashMap(); requestParameters.put("uploadId", uploadId); // Ensure part list is sorted by part number MultipartPart[] sortedParts = parts.toArray(new MultipartPart[parts.size()]); Arrays.sort(sortedParts, new MultipartPart.PartNumberComparator()); try { XMLBuilder builder = XMLBuilder .create("CompleteMultipartUpload").a("xmlns", Constants.XML_NAMESPACE); for (MultipartPart part: sortedParts) { builder.e("Part") .e("PartNumber").t("" + part.getPartNumber()).up() .e("ETag").t(part.getEtag()); } HttpMethodBase postMethod = performRestPostWithXmlBuilder( bucketName, objectKey, null, requestParameters, builder); CompleteMultipartUploadResultHandler handler = getXmlResponseSaxParser() .parseCompleteMultipartUploadResult( new HttpMethodReleaseInputStream(postMethod)); // Check whether completion actually succeeded if (handler.getServiceException() != null) { ServiceException e = handler.getServiceException(); e.setResponseHeaders(RestUtils.convertHeadersToMap( postMethod.getResponseHeaders())); throw e; } return handler.getMultipartCompleted(); } catch (S3ServiceException se) { throw se; } catch (ServiceException se) { throw new S3ServiceException(se); } catch (ParserConfigurationException e) { throw new S3ServiceException(e); } catch (FactoryConfigurationError e) { throw new S3ServiceException(e); } } @Override protected List multipartListUploadsImpl(String bucketName, String nextKeyMarker, String nextUploadIdMarker, Integer maxUploads) throws S3ServiceException { if (bucketName == null || bucketName.length()==0) { throw new IllegalArgumentException( "The bucket name parameter must be specified when listing multipart uploads"); } Map requestParameters = new HashMap(); requestParameters.put("uploads", ""); requestParameters.put("max-uploads", (maxUploads == null ? "1000" : maxUploads.toString())); try { List uploads = new ArrayList(); boolean incompleteListing = true; do { if (nextKeyMarker != null) { requestParameters.put("key-marker", nextKeyMarker); } else { requestParameters.remove("key-marker"); } if (nextUploadIdMarker != null) { requestParameters.put("upload-id-marker", nextUploadIdMarker); } else { requestParameters.remove("upload-id-marker"); } HttpMethodBase getMethod = performRestGet( bucketName, null, requestParameters, null); ListMultipartUploadsResultHandler handler = getXmlResponseSaxParser() .parseListMultipartUploadsResult( new HttpMethodReleaseInputStream(getMethod)); uploads.addAll(handler.getMultipartUploadList()); incompleteListing = handler.isTruncated(); nextKeyMarker = handler.getNextKeyMarker(); nextUploadIdMarker = handler.getNextUploadIdMarker(); // Sanity check for valid pagination values. if (incompleteListing && nextKeyMarker == null && nextUploadIdMarker == null) { throw new ServiceException("Unable to retrieve paginated " + "ListMultipartUploadsResult without valid NextKeyMarker " + " or NextUploadIdMarker value."); } } while (incompleteListing); return uploads; } catch (ServiceException se) { throw new S3ServiceException(se); } } @Override protected List multipartListPartsImpl(String uploadId, String bucketName, String objectKey) throws S3ServiceException { Map requestParameters = new HashMap(); requestParameters.put("uploadId", uploadId); requestParameters.put("max-parts", "1000"); try { List parts = new ArrayList(); String nextPartNumberMarker = null; boolean incompleteListing = true; do { if (nextPartNumberMarker != null) { requestParameters.put("part-number-marker", nextPartNumberMarker); } else { requestParameters.remove("part-number-marker"); } HttpMethodBase getMethod = performRestGet(bucketName, objectKey, requestParameters, null); ListMultipartPartsResultHandler handler = getXmlResponseSaxParser() .parseListMultipartPartsResult( new HttpMethodReleaseInputStream(getMethod)); parts.addAll(handler.getMultipartPartList()); incompleteListing = handler.isTruncated(); nextPartNumberMarker = handler.getNextPartNumberMarker(); // Sanity check for valid pagination values. if (incompleteListing && nextPartNumberMarker == null) { throw new ServiceException("Unable to retrieve paginated " + "ListMultipartPartsResult without valid NextKeyMarker value."); } } while (incompleteListing); return parts; } catch (ServiceException se) { throw new S3ServiceException(se); } } @Override protected WebsiteConfig getWebsiteConfigImpl(String bucketName) throws S3ServiceException { try { Map requestParameters = new HashMap(); requestParameters.put("website", ""); HttpMethodBase getMethod = performRestGet(bucketName, null, requestParameters, null); return getXmlResponseSaxParser().parseWebsiteConfigurationResponse( new HttpMethodReleaseInputStream(getMethod)); } catch (ServiceException se) { throw new S3ServiceException(se); } } @Override protected void setWebsiteConfigImpl(String bucketName, WebsiteConfig config) throws S3ServiceException { Map requestParameters = new HashMap(); requestParameters.put("website", ""); Map metadata = new HashMap(); String xml = null; try { xml = config.toXml(); } catch (Exception e) { throw new S3ServiceException("Unable to build WebsiteConfig XML document", e); } try { metadata.put("Content-Length", xml.length()); performRestPut(bucketName, null, metadata, requestParameters, new StringRequestEntity(xml, "text/plain", Constants.DEFAULT_ENCODING), true); } catch (ServiceException se) { throw new S3ServiceException(se); } catch (UnsupportedEncodingException e) { throw new S3ServiceException("Unable to encode XML document", e); } } @Override protected void deleteWebsiteConfigImpl(String bucketName) throws S3ServiceException { try { Map requestParameters = new HashMap(); requestParameters.put("website", ""); performRestDelete(bucketName, null, requestParameters, null, null); } catch (ServiceException se) { throw new S3ServiceException(se); } } @Override protected NotificationConfig getNotificationConfigImpl(String bucketName) throws S3ServiceException { try { Map requestParameters = new HashMap(); requestParameters.put("notification", ""); HttpMethodBase getMethod = performRestGet(bucketName, null, requestParameters, null); return getXmlResponseSaxParser().parseNotificationConfigurationResponse( new HttpMethodReleaseInputStream(getMethod)); } catch (ServiceException se) { throw new S3ServiceException(se); } } @Override protected void setNotificationConfigImpl(String bucketName, NotificationConfig config) throws S3ServiceException { Map requestParameters = new HashMap(); requestParameters.put("notification", ""); Map metadata = new HashMap(); String xml = null; try { xml = config.toXml(); } catch (Exception e) { throw new S3ServiceException("Unable to build NotificationConfig XML document", e); } try { metadata.put("Content-Length", xml.length()); performRestPut(bucketName, null, metadata, requestParameters, new StringRequestEntity(xml, "text/plain", Constants.DEFAULT_ENCODING), true); } catch (ServiceException se) { throw new S3ServiceException(se); } catch (UnsupportedEncodingException e) { throw new S3ServiceException("Unable to encode XML document", e); } } } ././@LongLink0000000000000000000000000000014500000000000011565 Lustar rootrootjets3t-0.8.1+dfsg.orig/src/org/jets3t/service/impl/rest/httpclient/HttpMethodReleaseInputStream.javajets3t-0.8.1+dfsg.orig/src/org/jets3t/service/impl/rest/httpclient/HttpMethodReleaseInputStream.java0000644000000000000000000001771111441613550030455 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.impl.rest.httpclient; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.io.InputStreamWrapper; import org.jets3t.service.io.InterruptableInputStream; /** * Utility class to wrap InputStreams obtained from an HttpClient library's HttpMethod object, and * ensure the stream and HTTP connection is cleaned up properly. *

* This input stream wrapper is used to ensure that input streams obtained through HttpClient * connections are cleaned up correctly once the caller has read all the contents of the * connection's input stream, or closed that input stream. *

*

* Important! This input stream must be completely consumed or closed to ensure the necessary * cleanup operations can be performed. *

* * @author James Murty * */ public class HttpMethodReleaseInputStream extends InputStream implements InputStreamWrapper { private static final Log log = LogFactory.getLog(HttpMethodReleaseInputStream.class); private InputStream inputStream = null; private HttpMethod httpMethod = null; private boolean alreadyReleased = false; private boolean underlyingStreamConsumed = false; /** * Constructs an input stream based on an {@link HttpMethod} object representing an HTTP connection. * If a connection input stream is available, this constructor wraps the underlying input stream * in an {@link InterruptableInputStream} and makes that stream available. If no underlying connection * is available, an empty {@link ByteArrayInputStream} is made available. * * @param httpMethod */ public HttpMethodReleaseInputStream(HttpMethod httpMethod) { this.httpMethod = httpMethod; try { this.inputStream = new InterruptableInputStream(httpMethod.getResponseBodyAsStream()); } catch (IOException e) { if (log.isWarnEnabled()) { log.warn("Unable to obtain HttpMethod's response data stream", e); } httpMethod.releaseConnection(); this.inputStream = new ByteArrayInputStream(new byte[] {}); // Empty input stream; } } /** * Returns the underlying HttpMethod object that contains/manages the actual HTTP connection. * * @return * the HTTPMethod object that provides the data input stream. */ public HttpMethod getHttpMethod() { return httpMethod; } /** * Forces the release of an HttpMethod's connection in a way that will perform all the necessary * cleanup through the correct use of HttpClient methods. * * @throws IOException */ protected void releaseConnection() throws IOException { if (!alreadyReleased) { if (!underlyingStreamConsumed) { // Underlying input stream has not been consumed, abort method // to force connection to be closed and cleaned-up. httpMethod.abort(); } httpMethod.releaseConnection(); alreadyReleased = true; } } /** * Standard input stream read method, except it calls {@link #releaseConnection} when the underlying * input stream is consumed. */ public int read() throws IOException { try { int read = inputStream.read(); if (read == -1) { underlyingStreamConsumed = true; if (!alreadyReleased) { releaseConnection(); if (log.isDebugEnabled()) { log.debug("Released HttpMethod as its response data stream is fully consumed"); } } } return read; } catch (IOException e) { releaseConnection(); if (log.isDebugEnabled()) { log.debug("Released HttpMethod as its response data stream threw an exception", e); } throw e; } } /** * Standard input stream read method, except it calls {@link #releaseConnection} when the underlying * input stream is consumed. */ public int read(byte[] b, int off, int len) throws IOException { try { int read = inputStream.read(b, off, len); if (read == -1) { underlyingStreamConsumed = true; if (!alreadyReleased) { releaseConnection(); if (log.isDebugEnabled()) { log.debug("Released HttpMethod as its response data stream is fully consumed"); } } } return read; } catch (IOException e) { releaseConnection(); if (log.isDebugEnabled()) { log.debug("Released HttpMethod as its response data stream threw an exception", e); } throw e; } } public int available() throws IOException { try { return inputStream.available(); } catch (IOException e) { releaseConnection(); if (log.isDebugEnabled()) { log.debug("Released HttpMethod as its response data stream threw an exception", e); } throw e; } } /** * Standard input stream close method, except it ensures that {@link #releaseConnection()} is called * before the input stream is closed. */ public void close() throws IOException { if (!alreadyReleased) { releaseConnection(); if (log.isDebugEnabled()) { log.debug("Released HttpMethod as its response data stream is closed"); } } inputStream.close(); } /** * Tries to ensure a connection is always cleaned-up correctly by calling {@link #releaseConnection()} * on class destruction if the cleanup hasn't already been done. *

* This desperate cleanup act will only be necessary if the user of this class does not completely * consume or close this input stream prior to object destruction. This method will log Warning * messages if a forced cleanup is required, hopefully reminding the user to close their streams * properly. */ protected void finalize() throws Throwable { if (!alreadyReleased) { if (log.isWarnEnabled()) { log.warn("Attempting to release HttpMethod in finalize() as its response data stream has gone out of scope. " + "This attempt will not always succeed and cannot be relied upon! Please ensure S3 response data streams are " + "always fully consumed or closed to avoid HTTP connection starvation."); } releaseConnection(); if (log.isWarnEnabled()) { log.warn("Successfully released HttpMethod in finalize(). You were lucky this time... " + "Please ensure S3 response data streams are always fully consumed or closed."); } } super.finalize(); } /** * @return * the underlying input stream wrapped by this class. */ public InputStream getWrappedInputStream() { return inputStream; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/impl/rest/httpclient/RestStorageService.java0000644000000000000000000030542611550441750026470 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.impl.rest.httpclient; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HostConfiguration; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpConnectionManager; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.HttpMethodBase; import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; import org.apache.commons.httpclient.SimpleHttpConnectionManager; import org.apache.commons.httpclient.URI; import org.apache.commons.httpclient.URIException; import org.apache.commons.httpclient.auth.CredentialsProvider; import org.apache.commons.httpclient.methods.DeleteMethod; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.HeadMethod; import org.apache.commons.httpclient.methods.InputStreamRequestEntity; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.PutMethod; import org.apache.commons.httpclient.methods.RequestEntity; import org.apache.commons.httpclient.methods.StringRequestEntity; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.ServiceException; import org.jets3t.service.StorageObjectsChunk; import org.jets3t.service.StorageService; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.impl.rest.HttpException; import org.jets3t.service.impl.rest.XmlResponsesSaxParser.CopyObjectResultHandler; import org.jets3t.service.impl.rest.XmlResponsesSaxParser.ListBucketHandler; import org.jets3t.service.model.CreateBucketConfiguration; import org.jets3t.service.model.S3Bucket; import org.jets3t.service.model.S3Object; import org.jets3t.service.model.StorageBucket; import org.jets3t.service.model.StorageOwner; import org.jets3t.service.model.StorageObject; import org.jets3t.service.mx.MxDelegate; import org.jets3t.service.security.ProviderCredentials; import org.jets3t.service.utils.Mimetypes; import org.jets3t.service.utils.RestUtils; import org.jets3t.service.utils.ServiceUtils; import com.jamesmurty.utils.XMLBuilder; /** * Abstract REST/HTTP implementation of an S3Service based on the * HttpClient library. *

* This class uses properties obtained through {@link org.jets3t.service.Jets3tProperties}. For more information on * these properties please refer to * JetS3t Configuration *

* * @author James Murty, Google Developers */ public abstract class RestStorageService extends StorageService implements AWSRequestAuthorizer { private static final Log log = LogFactory.getLog(RestStorageService.class); protected static enum HTTP_METHOD {PUT, POST, HEAD, GET, DELETE}; protected HttpClient httpClient = null; protected HttpConnectionManager connectionManager = null; protected CredentialsProvider credentialsProvider = null; protected String defaultStorageClass = null; /** * Constructs the service and initialises the properties. * * @param credentials * the user credentials to use when communicating with S3, may be null in which case the * communication is done as an anonymous user. */ public RestStorageService(ProviderCredentials credentials) { this(credentials, null, null); } /** * Constructs the service and initialises the properties. * * @param credentials * the S3 user credentials to use when communicating with S3, may be null in which case the * communication is done as an anonymous user. * @param invokingApplicationDescription * a short description of the application using the service, suitable for inclusion in a * user agent string for REST/HTTP requests. Ideally this would include the application's * version number, for example: Cockpit/0.7.3 or My App Name/1.0 * @param credentialsProvider * an implementation of the HttpClient CredentialsProvider interface, to provide a means for * prompting for credentials when necessary. */ public RestStorageService(ProviderCredentials credentials, String invokingApplicationDescription, CredentialsProvider credentialsProvider) { this(credentials, invokingApplicationDescription, credentialsProvider, Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME)); } /** * Constructs the service and initialises the properties. * * @param credentials * the S3 user credentials to use when communicating with S3, may be null in which case the * communication is done as an anonymous user. * @param invokingApplicationDescription * a short description of the application using the service, suitable for inclusion in a * user agent string for REST/HTTP requests. Ideally this would include the application's * version number, for example: Cockpit/0.7.3 or My App Name/1.0 * @param credentialsProvider * an implementation of the HttpClient CredentialsProvider interface, to provide a means for * prompting for credentials when necessary. * @param jets3tProperties * JetS3t properties that will be applied within this service. */ public RestStorageService(ProviderCredentials credentials, String invokingApplicationDescription, CredentialsProvider credentialsProvider, Jets3tProperties jets3tProperties) { this(credentials, invokingApplicationDescription, credentialsProvider, jets3tProperties, new HostConfiguration()); } /** * Constructs the service and initialises the properties. * * @param credentials * the S3 user credentials to use when communicating with S3, may be null in which case the * communication is done as an anonymous user. * @param invokingApplicationDescription * a short description of the application using the service, suitable for inclusion in a * user agent string for REST/HTTP requests. Ideally this would include the application's * version number, for example: Cockpit/0.7.3 or My App Name/1.0 * @param credentialsProvider * an implementation of the HttpClient CredentialsProvider interface, to provide a means for * prompting for credentials when necessary. * @param jets3tProperties * JetS3t properties that will be applied within this service. * @param hostConfig * Custom HTTP host configuration; e.g to register a custom Protocol Socket Factory */ public RestStorageService(ProviderCredentials credentials, String invokingApplicationDescription, CredentialsProvider credentialsProvider, Jets3tProperties jets3tProperties, HostConfiguration hostConfig) { super(credentials, invokingApplicationDescription, jets3tProperties); this.credentialsProvider = credentialsProvider; HttpClientAndConnectionManager initHttpResult = initHttpConnection(hostConfig); this.httpClient = initHttpResult.getHttpClient(); this.connectionManager = initHttpResult.getHttpConnectionManager(); this.defaultStorageClass = this.jets3tProperties.getStringProperty( "s3service.default-storage-class", null); // Retrieve Proxy settings. if (this.jets3tProperties.getBoolProperty("httpclient.proxy-autodetect", true)) { RestUtils.initHttpProxy(httpClient, this.jets3tProperties, this.getEndpoint()); } else { String proxyHostAddress = this.jets3tProperties.getStringProperty("httpclient.proxy-host", null); int proxyPort = this.jets3tProperties.getIntProperty("httpclient.proxy-port", -1); String proxyUser = this.jets3tProperties.getStringProperty("httpclient.proxy-user", null); String proxyPassword = this.jets3tProperties.getStringProperty("httpclient.proxy-password", null); String proxyDomain = this.jets3tProperties.getStringProperty("httpclient.proxy-domain", null); RestUtils.initHttpProxy(httpClient, this.jets3tProperties, false, proxyHostAddress, proxyPort, proxyUser, proxyPassword, proxyDomain, this.getEndpoint()); } } protected abstract boolean isTargettingGoogleStorageService(); /** * Shut down all connections managed by the underlying HttpConnectionManager. */ @Override protected void shutdownImpl() throws ServiceException { HttpConnectionManager manager = this.getHttpConnectionManager(); if (manager instanceof SimpleHttpConnectionManager) { ((SimpleHttpConnectionManager) manager).shutdown(); } else if (manager instanceof MultiThreadedHttpConnectionManager) { ((MultiThreadedHttpConnectionManager) manager).shutdown(); } else { manager.closeIdleConnections(0); // Not much else we can do hear, since the HttpConnectionManager // interface doesn't have a #shutdown method. } } /** * Initialise HttpClient and HttpConnectionManager objects with the configuration settings * appropriate for communicating with S3. By default, this method simply delegates the * configuration task to {@link org.jets3t.service.utils.RestUtils#initHttpConnection(org.jets3t.service.impl.rest.httpclient.AWSRequestAuthorizer, * org.apache.commons.httpclient.HostConfiguration, org.jets3t.service.Jets3tProperties, String, org.apache.commons.httpclient.auth.CredentialsProvider)}. *

* To alter the low-level behaviour of the HttpClient library, override this method in * a subclass and apply your own settings before returning the objects. * * @param hostConfig * Custom HTTP host configuration; e.g to register a custom Protocol Socket Factory * * @return * configured HttpClient library client and connection manager objects. */ protected HttpClientAndConnectionManager initHttpConnection(HostConfiguration hostConfig) { HttpClientAndConnectionManager manager = RestUtils.initHttpConnection( this, hostConfig, jets3tProperties, getInvokingApplicationDescription(), credentialsProvider); // TODO: Google Storage Service does not work well with Expect: 100-Continue if (this.isTargettingGoogleStorageService()) { manager.getHttpClient().getParams().setBooleanParameter( "http.protocol.expect-continue", false); } return manager; } /** * @return * the manager of HTTP connections for this service. */ public HttpConnectionManager getHttpConnectionManager() { return this.connectionManager; } /** * Replaces the service's default HTTP connection manager. * This method should only be used by advanced users. * * @param httpConnectionManager * the connection manager that will replace the default manager created by * the class constructor. */ public void setHttpConnectionManager(HttpConnectionManager httpConnectionManager) { this.connectionManager = httpConnectionManager; } /** * @return * the HTTP client for this service. */ public HttpClient getHttpClient() { return this.httpClient; } /** * Replaces the service's default HTTP client. * This method should only be used by advanced users. * * @param httpClient * the client that will replace the default client created by * the class constructor. */ public void setHttpClient(HttpClient httpClient) { this.httpClient = httpClient; } /** * @return * the credentials provider this service will use to authenticate itself, or null * if no provider is set. */ public CredentialsProvider getCredentialsProvider() { return this.credentialsProvider; } /** * Sets the credentials provider this service will use to authenticate itself. * Changing the credentials provider with this method will have no effect until * the {@link #initHttpConnection(org.apache.commons.httpclient.HostConfiguration)} method * is called. * * @param credentialsProvider */ public void setCredentialsProvider(CredentialsProvider credentialsProvider) { this.credentialsProvider = credentialsProvider; } /** * @param contentType * @return true if the given Content-Type string represents an XML document. */ protected boolean isXmlContentType(String contentType) { if (contentType != null && contentType.toLowerCase().startsWith(Mimetypes.MIMETYPE_XML.toLowerCase())) { return true; } else { return false; } } /** * Performs an HTTP/S request by invoking the provided HttpMethod object. If the HTTP * response code doesn't match the expected value, an exception is thrown. * * @param httpMethod * the object containing a request target and all other information necessary to perform the * request * @param expectedResponseCodes * the HTTP response code(s) that indicates a successful request. If the response code received * does not match this value an error must have occurred, so an exception is thrown. * @throws org.jets3t.service.ServiceException * all exceptions are wrapped in a ServiceException. Depending on the kind of error that * occurred, this exception may contain additional error information available from an XML * error response document. */ protected void performRequest(HttpMethodBase httpMethod, int[] expectedResponseCodes) throws ServiceException { try { if (log.isDebugEnabled()) { log.debug("Performing " + httpMethod.getName() + " request for '" + httpMethod.getURI().toString() + "', expecting response codes: " + "[" + ServiceUtils.join(expectedResponseCodes, ",") + "]"); } // Variables to manage S3 Internal Server 500 or 503 Service Unavailable errors. boolean completedWithoutRecoverableError = true; int internalErrorCount = 0; int requestTimeoutErrorCount = 0; int redirectCount = 0; boolean wasRecentlyRedirected = false; // Perform the request, sleeping and retrying when S3 Internal Errors are encountered. int responseCode = -1; do { // Build the authorization string for the method (Unless we have just been redirected). if (!wasRecentlyRedirected) { authorizeHttpRequest(httpMethod); } else { // Reset redirection flag wasRecentlyRedirected = false; } responseCode = httpClient.executeMethod(httpMethod); if (responseCode == 307) { // Retry on Temporary Redirects, using new URI from location header authorizeHttpRequest(httpMethod); // Re-authorize *before* we change the URI Header locationHeader = httpMethod.getResponseHeader("location"); httpMethod.setURI(new URI(locationHeader.getValue(), true)); completedWithoutRecoverableError = false; redirectCount++; wasRecentlyRedirected = true; if (redirectCount > 5) { throw new ServiceException("Exceeded 307 redirect limit (5)."); } } else if (responseCode == 500 || responseCode == 503) { // Retry on S3 Internal Server 500 or 503 Service Unavailable errors. completedWithoutRecoverableError = false; sleepOnInternalError(++internalErrorCount); } else { completedWithoutRecoverableError = true; } String contentType = ""; if (httpMethod.getResponseHeader("Content-Type") != null) { contentType = httpMethod.getResponseHeader("Content-Type").getValue(); } if (log.isDebugEnabled()) { log.debug("Response for '" + httpMethod.getPath() + "'. Content-Type: " + contentType + ", Headers: " + Arrays.asList(httpMethod.getResponseHeaders())); } // Check we received the expected result code. boolean didReceiveExpectedResponseCode = false; for (int i = 0; i < expectedResponseCodes.length && !didReceiveExpectedResponseCode; i++) { if (responseCode == expectedResponseCodes[i]) { didReceiveExpectedResponseCode = true; } } if (!didReceiveExpectedResponseCode) { if (log.isWarnEnabled()) { String requestDescription = httpMethod.getName() + " '" + httpMethod.getPath() + (httpMethod.getQueryString() != null && httpMethod.getQueryString().length() > 0 ? "?" + httpMethod.getQueryString() : "") + "'" + " -- ResponseCode: " + httpMethod.getStatusCode() + ", ResponseStatus: " + httpMethod.getStatusText() + ", Request Headers: [" + ServiceUtils.join(httpMethod.getRequestHeaders(), ", ") + "]" + ", Response Headers: [" + ServiceUtils.join(httpMethod.getResponseHeaders(), ", ") + "]"; requestDescription = requestDescription.replaceAll("[\\n\\r\\f]", ""); // Remove any newlines. log.warn("Error Response: " + requestDescription); } if (isXmlContentType(contentType) && httpMethod.getResponseBodyAsStream() != null && httpMethod.getResponseContentLength() != 0) { if (log.isDebugEnabled()) { log.debug("Response '" + httpMethod.getPath() + "' - Received error response with XML message"); } StringBuffer sb = new StringBuffer(); BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader( new HttpMethodReleaseInputStream(httpMethod))); String line = null; while ((line = reader.readLine()) != null) { sb.append(line + "\n"); } } finally { if (reader != null) { reader.close(); } } httpMethod.releaseConnection(); // Throw exception containing the XML message document. ServiceException exception = new ServiceException("S3 Error Message.", sb.toString()); exception.setResponseHeaders(RestUtils.convertHeadersToMap( httpMethod.getResponseHeaders())); if ("RequestTimeout".equals(exception.getErrorCode())) { int retryMaxCount = jets3tProperties.getIntProperty("httpclient.retry-max", 5); if (requestTimeoutErrorCount < retryMaxCount) { requestTimeoutErrorCount++; if (log.isWarnEnabled()) { log.warn("Retrying connection that failed with RequestTimeout error" + ", attempt number " + requestTimeoutErrorCount + " of " + retryMaxCount); } completedWithoutRecoverableError = false; } else { if (log.isErrorEnabled()) { log.error("Exceeded maximum number of retries for RequestTimeout errors: " + retryMaxCount); } throw exception; } } else if ("RequestTimeTooSkewed".equals(exception.getErrorCode())) { this.timeOffset = RestUtils.getAWSTimeAdjustment(); if (log.isWarnEnabled()) { log.warn("Adjusted time offset in response to RequestTimeTooSkewed error. " + "Local machine and S3 server disagree on the time by approximately " + (this.timeOffset / 1000) + " seconds. Retrying connection."); } completedWithoutRecoverableError = false; } else if (responseCode == 500 || responseCode == 503) { // Retrying after 500 or 503 error, don't throw exception. } else if (responseCode == 307) { // Retrying after Temporary Redirect 307, don't throw exception. if (log.isDebugEnabled()) { log.debug("Following Temporary Redirect to: " + httpMethod.getURI().toString()); } } // Special handling for S3 object PUT failures causing NoSuchKey errors - Issue #85 else if (responseCode == 404 && "PUT".equalsIgnoreCase(httpMethod.getName()) && "NoSuchKey".equals(exception.getErrorCode())) { // Retrying after mysterious PUT NoSuchKey error caused by S3, don't throw exception. if (log.isDebugEnabled()) { log.debug("Ignoring NoSuchKey/404 error on PUT to: " + httpMethod.getURI().toString()); } } else { throw exception; } } else { // Consume response content and release connection. String responseText = null; byte[] responseBody = httpMethod.getResponseBody(); if (responseBody != null && responseBody.length > 0) { responseText = new String(responseBody); } if (log.isDebugEnabled()) { log.debug("Releasing error response without XML content"); } httpMethod.releaseConnection(); if (responseCode == 500 || responseCode == 503) { // Retrying after InternalError 500, don't throw exception. } else { // Throw exception containing the HTTP error fields. HttpException httpException = new HttpException( httpMethod.getStatusCode(), httpMethod.getStatusText()); ServiceException exception = new ServiceException("Request Error" + (responseText != null ? " [" + responseText + "]." : "."), httpException); exception.setResponseHeaders(RestUtils.convertHeadersToMap( httpMethod.getResponseHeaders())); throw exception; } } } } while (!completedWithoutRecoverableError); // Release immediately any connections without response bodies. if ((httpMethod.getResponseBodyAsStream() == null || httpMethod.getResponseBodyAsStream().available() == 0) && httpMethod.getResponseContentLength() == 0) { if (log.isDebugEnabled()) { log.debug("Releasing response without content"); } byte[] responseBody = httpMethod.getResponseBody(); if (responseBody != null && responseBody.length > 0) { throw new ServiceException("Oops, too keen to release connection with a non-empty response body"); } httpMethod.releaseConnection(); } } catch (Throwable t) { if (log.isDebugEnabled()) { log.debug("Releasing HttpClient connection after error: " + t.getMessage()); } httpMethod.releaseConnection(); ServiceException serviceException = null; if (t instanceof ServiceException) { serviceException = (ServiceException) t; } else { MxDelegate.getInstance().registerS3ServiceExceptionEvent(); serviceException = new ServiceException("Request Error: " + t, t); } // Add S3 request and host IDs from HTTP headers to exception, if they are available // and have not already been populated by parsing an XML error response. if (!serviceException.isParsedFromXmlMessage() && httpMethod.getResponseHeader(Constants.AMZ_REQUEST_ID_1) != null && httpMethod.getResponseHeader(Constants.AMZ_REQUEST_ID_2) != null) { serviceException.setRequestAndHostIds( httpMethod.getResponseHeader(Constants.AMZ_REQUEST_ID_1).getValue(), httpMethod.getResponseHeader(Constants.AMZ_REQUEST_ID_2).getValue()); } serviceException.setRequestVerb(httpMethod.getName()); serviceException.setRequestPath(httpMethod.getPath()); try { serviceException.setResponseCode(httpMethod.getStatusCode()); serviceException.setResponseStatus(httpMethod.getStatusText()); } catch (NullPointerException e) { // If no network connection is available, status info is not available } if (httpMethod.getRequestHeader("Host") != null) { serviceException.setRequestHost( httpMethod.getRequestHeader("Host").getValue()); } if (httpMethod.getResponseHeader("Date") != null) { serviceException.setResponseDate( httpMethod.getResponseHeader("Date").getValue()); } throw serviceException; } } /** * Authorizes an HTTP request by signing it. The signature is based on the target URL, and the * signed authorization string is added to the {@link org.apache.commons.httpclient.HttpMethod} object as an Authorization header. * * @param httpMethod * the request object * @throws org.jets3t.service.ServiceException */ public void authorizeHttpRequest(HttpMethod httpMethod) throws Exception { if (getProviderCredentials() != null) { if (log.isDebugEnabled()) { log.debug("Adding authorization for Access Key '" + getProviderCredentials().getAccessKey() + "'."); } } else { if (log.isDebugEnabled()) { log.debug("Service has no Credential and is un-authenticated, skipping authorization"); } return; } String hostname = null; try { hostname = httpMethod.getURI().getHost(); } catch (URIException e) { if (log.isErrorEnabled()) { log.error("Unable to determine hostname target for request", e); } } /* * Determine the complete URL for the S3 resource, including any S3-specific parameters. */ String fullUrl = httpMethod.getPath(); // If we are using an alternative hostname, include the hostname/bucketname in the resource path. String s3Endpoint = this.getEndpoint(); if (!s3Endpoint.equals(hostname)) { int subdomainOffset = hostname.lastIndexOf("." + s3Endpoint); if (subdomainOffset > 0) { // Hostname represents an S3 sub-domain, so the bucket's name is the CNAME portion fullUrl = "/" + hostname.substring(0, subdomainOffset) + httpMethod.getPath(); } else { // Hostname represents a virtual host, so the bucket's name is identical to hostname fullUrl = "/" + hostname + httpMethod.getPath(); } } String queryString = httpMethod.getQueryString(); if (queryString != null && queryString.length() > 0) { fullUrl += "?" + queryString; } // Set/update the date timestamp to the current time // Note that this will be over-ridden if an "x-amz-date" header is present. httpMethod.setRequestHeader("Date", ServiceUtils.formatRfc822Date( getCurrentTimeWithOffset())); // Generate a canonical string representing the operation. String canonicalString = RestUtils.makeServiceCanonicalString( httpMethod.getName(), fullUrl, convertHeadersToMap(httpMethod.getRequestHeaders()), null, this.getRestHeaderPrefix(), this.getResourceParameterNames()); if (log.isDebugEnabled()) { log.debug("Canonical string ('|' is a newline): " + canonicalString.replace('\n', '|')); } // Sign the canonical string. String signedCanonical = ServiceUtils.signWithHmacSha1( getProviderCredentials().getSecretKey(), canonicalString); // Add encoded authorization to connection as HTTP Authorization header. String authorizationString = getSignatureIdentifier() + " " + getProviderCredentials().getAccessKey() + ":" + signedCanonical; httpMethod.setRequestHeader("Authorization", authorizationString); } /** * Adds all the provided request parameters to a URL in GET request format. * * @param urlPath * the target URL * @param requestParameters * the parameters to add to the URL as GET request params. * @return * the target URL including the parameters. * @throws org.jets3t.service.ServiceException */ protected String addRequestParametersToUrlPath(String urlPath, Map requestParameters) throws ServiceException { if (requestParameters != null) { for (Map.Entry entry: requestParameters.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); urlPath += (urlPath.indexOf("?") < 0 ? "?" : "&") + RestUtils.encodeUrlString(key); if (value != null && value.length() > 0) { urlPath += "=" + RestUtils.encodeUrlString(value); if (log.isDebugEnabled()) { log.debug("Added request parameter: " + key + "=" + value); } } else { if (log.isDebugEnabled()) { log.debug("Added request parameter without value: " + key); } } } } return urlPath; } /** * Adds the provided request headers to the connection. * * @param httpMethod * the connection object * @param requestHeaders * the request headers to add as name/value pairs. */ protected void addRequestHeadersToConnection( HttpMethodBase httpMethod, Map requestHeaders) { if (requestHeaders != null) { for (Map.Entry entry: requestHeaders.entrySet()) { String key = entry.getKey().toString(); String value = entry.getValue().toString(); httpMethod.setRequestHeader(key, value); if (log.isDebugEnabled()) { log.debug("Added request header to connection: " + key + "=" + value); } } } } /** * Converts an array of Header objects to a map of name/value pairs. * * @param headers * @return */ private Map convertHeadersToMap(Header[] headers) { Map map = new HashMap(); for (int i = 0; headers != null && i < headers.length; i++) { map.put(headers[i].getName(), headers[i].getValue()); } return map; } /** * Adds all valid metadata name and value pairs as HTTP headers to the given HTTP method. * Null metadata names are ignored, as are metadata values that are not of type string. *

* The metadata values are verified to ensure that keys contain only ASCII characters, * and that items are not accidentally duplicated due to use of different capitalization. * If either of these verification tests fails, an {@link org.jets3t.service.ServiceException} is thrown. * * @param httpMethod * @param metadata * @throws org.jets3t.service.ServiceException */ protected void addMetadataToHeaders(HttpMethodBase httpMethod, Map metadata) throws ServiceException { Map headersAlreadySeenMap = new HashMap(metadata.size()); for (Map.Entry entry: metadata.entrySet()) { String key = entry.getKey(); Object objValue = entry.getValue(); if (key == null) { // Ignore invalid metadata. continue; } String value = objValue.toString(); // Ensure user-supplied metadata values are compatible with the REST interface. // Key must be ASCII text, non-ASCII characters are not allowed in HTTP header names. boolean validAscii = false; UnsupportedEncodingException encodingException = null; try { byte[] asciiBytes = key.getBytes("ASCII"); byte[] utf8Bytes = key.getBytes("UTF-8"); validAscii = Arrays.equals(asciiBytes, utf8Bytes); } catch (UnsupportedEncodingException e) { // Shouldn't ever happen encodingException = e; } if (!validAscii) { String message = "User metadata name is incompatible with the S3 REST interface, " + "only ASCII characters are allowed in HTTP headers: " + key; if (encodingException == null) { throw new ServiceException(message); } else { throw new ServiceException(message, encodingException); } } // Fail early if user-supplied metadata cannot be represented as valid HTTP headers, // rather than waiting for a SignatureDoesNotMatch error. // NOTE: These checks are very much incomplete. if (value.indexOf('\n') >= 0 || value.indexOf('\r') >= 0) { throw new ServiceException("The value of metadata item " + key + " cannot be represented as an HTTP header for the REST S3 interface: " + value); } // Ensure each AMZ header is uniquely identified according to the lowercase name. String duplicateValue = (String) headersAlreadySeenMap.get(key.toLowerCase()); if (duplicateValue != null && !duplicateValue.equals(value)) { throw new ServiceException( "HTTP header name occurs multiple times in request with different values, " + "probably due to mismatched capitalization when setting metadata names. " + "Duplicate metadata name: '" + key + "', All metadata: " + metadata); } httpMethod.setRequestHeader(key, value); headersAlreadySeenMap.put(key.toLowerCase(), value); } } /** * Compares the expected and actual ETag value for an uploaded object, and throws an * ServiceException if these values do not match. * * @param expectedETag * @param uploadedObject * @throws org.jets3t.service.ServiceException */ protected void verifyExpectedAndActualETagValues(String expectedETag, StorageObject uploadedObject) throws ServiceException { // Compare our locally-calculated hash with the ETag returned by S3. if (!expectedETag.equals(uploadedObject.getETag())) { throw new ServiceException("Mismatch between MD5 hash of uploaded data (" + expectedETag + ") and ETag returned by S3 (" + uploadedObject.getETag() + ") for object key: " + uploadedObject.getKey()); } else { if (log.isDebugEnabled()) { log.debug("Object upload was automatically verified, the calculated MD5 hash "+ "value matched the ETag returned by S3: " + uploadedObject.getKey()); } } } /** * Performs an HTTP HEAD request using the {@link #performRequest} method. * * @param bucketName * the bucket's name * @param objectKey * the object's key name, may be null if the operation is on a bucket only. * @param requestParameters * parameters to add to the request URL as GET params * @param requestHeaders * headers to add to the request * @return * the HTTP method object used to perform the request * @throws org.jets3t.service.ServiceException */ protected HttpMethodBase performRestHead(String bucketName, String objectKey, Map requestParameters, Map requestHeaders) throws ServiceException { HttpMethodBase httpMethod = setupConnection( HTTP_METHOD.HEAD, bucketName, objectKey, requestParameters); // Add all request headers. addRequestHeadersToConnection(httpMethod, requestHeaders); performRequest(httpMethod, new int[] {200}); return httpMethod; } /** * Performs an HTTP GET request using the {@link #performRequest} method. * * @param bucketName * the bucket's name * @param objectKey * the object's key name, may be null if the operation is on a bucket only. * @param requestParameters * parameters to add to the request URL as GET params * @param requestHeaders * headers to add to the request * @return * The HTTP method object used to perform the request. * * @throws org.jets3t.service.ServiceException */ protected HttpMethodBase performRestGet(String bucketName, String objectKey, Map requestParameters, Map requestHeaders) throws ServiceException { HttpMethodBase httpMethod = setupConnection( HTTP_METHOD.GET, bucketName, objectKey, requestParameters); // Add all request headers. addRequestHeadersToConnection(httpMethod, requestHeaders); int[] expectedStatusCodes = {200}; // 200 is normally the expected response code if (requestHeaders != null && requestHeaders.containsKey("Range")) { // Partial data responses have a status code of 206, or sometimes 200 // for complete responses (issue #80) expectedStatusCodes = new int[] {206, 200}; } performRequest(httpMethod, expectedStatusCodes); return httpMethod; } /** * Performs an HTTP PUT request using the {@link #performRequest} method. * * @param bucketName * the name of the bucket the object will be stored in. * @param objectKey * the key (name) of the object to be stored. * @param metadata * map of name/value pairs to add as metadata to any S3 objects created. * @param requestParameters * parameters to add to the request URL as GET params * @param requestEntity * an HttpClient object that encapsulates the object and data contents that will be * uploaded. This object supports the resending of object data, when possible. * @param autoRelease * if true, the HTTP Method object will be released after the request has * completed and the connection will be closed. If false, the object will * not be released and the caller must take responsibility for doing this. * @return * a package including the HTTP method object used to perform the request, and the * content length (in bytes) of the object that was PUT to S3. * * @throws org.jets3t.service.ServiceException */ protected HttpMethodAndByteCount performRestPut(String bucketName, String objectKey, Map metadata, Map requestParameters, RequestEntity requestEntity, boolean autoRelease) throws ServiceException { // Add any request parameters. HttpMethodBase httpMethod = setupConnection( HTTP_METHOD.PUT, bucketName, objectKey, requestParameters); Map renamedMetadata = renameMetadataKeys(metadata); addMetadataToHeaders(httpMethod, renamedMetadata); long contentLength = 0; if (requestEntity != null) { ((PutMethod)httpMethod).setRequestEntity(requestEntity); } else { // Need an explicit Content-Length even if no data is being uploaded. httpMethod.setRequestHeader("Content-Length", "0"); } performRequest(httpMethod, new int[] {200, 204}); if (requestEntity != null) { // Respond with the actual guaranteed content length of the uploaded data. contentLength = ((PutMethod)httpMethod).getRequestEntity().getContentLength(); } if (autoRelease) { httpMethod.releaseConnection(); } return new HttpMethodAndByteCount(httpMethod, contentLength); } /** * Performs an HTTP POST request using the {@link #performRequest} method. * * @param bucketName * the name of the bucket the object will be stored in. * @param objectKey * the key (name) of the object to be stored. * @param metadata * map of name/value pairs to add as metadata to any S3 objects created. * @param requestParameters * parameters to add to the request URL as GET params * @param requestEntity * an HttpClient object that encapsulates the object and data contents that will be * uploaded. This object supports the re-sending of object data, when possible. * @param autoRelease * if true, the HTTP Method object will be released after the request has * completed and the connection will be closed. If false, the object will * not be released and the caller must take responsibility for doing this. * @return * a package including the HTTP method object used to perform the request, and the * content length (in bytes) of the object that was POSTed to S3. * * @throws org.jets3t.service.ServiceException */ protected PostMethod performRestPost(String bucketName, String objectKey, Map metadata, Map requestParameters, RequestEntity requestEntity, boolean autoRelease) throws ServiceException { // Add any request parameters. HttpMethodBase postMethod = setupConnection( HTTP_METHOD.POST, bucketName, objectKey, requestParameters); Map renamedMetadata = renameMetadataKeys(metadata); addMetadataToHeaders(postMethod, renamedMetadata); if (requestEntity != null) { ((PostMethod)postMethod).setRequestEntity(requestEntity); } performRequest(postMethod, new int[] {200}); if (autoRelease) { postMethod.releaseConnection(); } return (PostMethod)postMethod; } /** * Performs an HTTP DELETE request using the {@link #performRequest} method. * * @param bucketName * the bucket's name * @param objectKey * the object's key name, may be null if the operation is on a bucket only. * @return * The HTTP method object used to perform the request. * * @throws org.jets3t.service.ServiceException */ protected HttpMethodBase performRestDelete(String bucketName, String objectKey, Map requestParameters, String multiFactorSerialNumber, String multiFactorAuthCode) throws ServiceException { HttpMethodBase httpMethod = setupConnection( HTTP_METHOD.DELETE, bucketName, objectKey, requestParameters); // Set Multi-Factor Serial Number and Authentication code if provided. if (multiFactorSerialNumber != null || multiFactorAuthCode != null) { httpMethod.setRequestHeader(Constants.AMZ_MULTI_FACTOR_AUTH_CODE, multiFactorSerialNumber + " " + multiFactorAuthCode); } performRequest(httpMethod, new int[] {204, 200}); // Release connection after DELETE (there's no response content) if (log.isDebugEnabled()) { log.debug("Releasing HttpMethod after delete"); } httpMethod.releaseConnection(); return httpMethod; } protected HttpMethodAndByteCount performRestPutWithXmlBuilder(String bucketName, String objectKey, Map metadata, Map requestParameters, XMLBuilder builder) throws ServiceException { try { if (metadata == null) { metadata = new HashMap(); } if (!metadata.containsKey("content-type")) { metadata.put("Content-Type", "text/plain"); } String xml = builder.asString(null); return performRestPut(bucketName, objectKey, metadata, requestParameters, new StringRequestEntity(xml, "text/plain", Constants.DEFAULT_ENCODING), true); } catch (Exception e) { if (e instanceof ServiceException) { throw (ServiceException) e; } else { throw new ServiceException("Failed to PUT request containing an XML document", e); } } } protected HttpMethodBase performRestPostWithXmlBuilder(String bucketName, String objectKey, Map metadata, Map requestParameters, XMLBuilder builder) throws ServiceException { try { if (metadata == null) { metadata = new HashMap(); } if (!metadata.containsKey("content-type")) { metadata.put("Content-Type", "text/plain"); } String xml = builder.asString(null); return performRestPost(bucketName, objectKey, metadata, requestParameters, new StringRequestEntity(xml, "text/plain", Constants.DEFAULT_ENCODING), false); } catch (Exception e) { if (e instanceof ServiceException) { throw (ServiceException) e; } else { throw new ServiceException("Failed to POST request containing an XML document", e); } } } /** * Creates an {@link org.apache.commons.httpclient.HttpMethod} object to handle a particular connection method. * * @param method * the HTTP method/connection-type to use, must be one of: PUT, HEAD, GET, DELETE * @param bucketName * the bucket's name * @param objectKey * the object's key name, may be null if the operation is on a bucket only. * @return * the HTTP method object used to perform the request * * @throws org.jets3t.service.ServiceException */ protected HttpMethodBase setupConnection(HTTP_METHOD method, String bucketName, String objectKey, Map requestParameters) throws ServiceException { if (bucketName == null) { throw new ServiceException("Cannot connect to S3 Service with a null path"); } boolean disableDnsBuckets = this.getDisableDnsBuckets(); String s3Endpoint = this.getEndpoint(); String hostname = ServiceUtils.generateS3HostnameForBucket(bucketName, disableDnsBuckets, s3Endpoint); // Allow for non-standard virtual directory paths on the server-side String virtualPath = this.getVirtualPath(); // Determine the resource string (ie the item's path in S3, including the bucket name) String resourceString = "/"; if (hostname.equals(s3Endpoint) && bucketName.length() > 0) { resourceString += bucketName + "/"; } resourceString += (objectKey != null? RestUtils.encodeUrlString(objectKey) : ""); // Construct a URL representing a connection for the S3 resource. String url = null; if (isHttpsOnly()) { int securePort = this.getHttpsPort(); url = "https://" + hostname + ":" + securePort + virtualPath + resourceString; } else { int insecurePort = this.getHttpPort(); url = "http://" + hostname + ":" + insecurePort + virtualPath + resourceString; } if (log.isDebugEnabled()) { log.debug("S3 URL: " + url); } // Add additional request parameters to the URL for special cases (eg ACL operations) url = addRequestParametersToUrlPath(url, requestParameters); HttpMethodBase httpMethod = null; if (HTTP_METHOD.PUT.equals(method)) { httpMethod = new PutMethod(url); } else if (HTTP_METHOD.POST.equals(method)) { httpMethod = new PostMethod(url); } else if (HTTP_METHOD.HEAD.equals(method)) { httpMethod = new HeadMethod(url); } else if (HTTP_METHOD.GET.equals(method)) { httpMethod = new GetMethod(url); } else if (HTTP_METHOD.DELETE.equals(method)) { httpMethod = new DeleteMethod(url); } else { throw new IllegalArgumentException("Unrecognised HTTP method name: " + method); } // Set mandatory Request headers. if (httpMethod.getRequestHeader("Date") == null) { httpMethod.setRequestHeader("Date", ServiceUtils.formatRfc822Date( getCurrentTimeWithOffset())); } if (httpMethod.getRequestHeader("Content-Type") == null) { httpMethod.setRequestHeader("Content-Type", ""); } return httpMethod; } //////////////////////////////////////////////////////////////// // Methods below this point implement S3Service abstract methods //////////////////////////////////////////////////////////////// @Override public boolean isBucketAccessible(String bucketName) throws ServiceException { if (log.isDebugEnabled()) { log.debug("Checking existence of bucket: " + bucketName); } HttpMethodBase httpMethod = null; try { // Ensure bucket exists and is accessible by performing a HEAD request httpMethod = performRestHead(bucketName, null, null, null); // This request may return an XML document that we're not interested in. Clean this up. if (httpMethod.getResponseBodyAsStream() != null) { httpMethod.getResponseBodyAsStream().close(); } } catch (ServiceException e) { if (log.isDebugEnabled()) { log.debug("Bucket does not exist: " + bucketName, e); } return false; } catch (IOException e) { if (log.isWarnEnabled()) { log.warn("Unable to close response body input stream", e); } } finally { if (log.isDebugEnabled()) { log.debug("Releasing un-wanted bucket HEAD response"); } if (httpMethod != null) { httpMethod.releaseConnection(); } } // If we get this far, the bucket exists. return true; } @Override public int checkBucketStatus(String bucketName) throws ServiceException { if (log.isDebugEnabled()) { log.debug("Checking availability of bucket name: " + bucketName); } HttpMethodBase httpMethod = null; // This request may return an XML document that we're not interested in. Clean this up. try { // Test bucket's status by performing a HEAD request against it. Map params = new HashMap(); params.put("max-keys", "0"); httpMethod = performRestHead(bucketName, null, params, null); if (httpMethod.getResponseBodyAsStream() != null) { httpMethod.getResponseBodyAsStream().close(); } } catch (ServiceException e) { if (e.getResponseCode() == 403) { if (log.isDebugEnabled()) { log.debug("Bucket named '" + bucketName + "' exists but is inaccessible, " + "probably belongs to another user"); } return BUCKET_STATUS__ALREADY_CLAIMED; } else if (e.getResponseCode() == 404) { if (log.isDebugEnabled()) { log.debug("Bucket does not exist: " + bucketName, e); } return BUCKET_STATUS__DOES_NOT_EXIST; } else { throw e; } } catch (IOException e) { if (log.isWarnEnabled()) { log.warn("Unable to close response body input stream", e); } } finally { if (log.isDebugEnabled()) { log.debug("Releasing un-wanted bucket HEAD response"); } if (httpMethod != null) { httpMethod.releaseConnection(); } } // If we get this far, the bucket exists and you own it. return BUCKET_STATUS__MY_BUCKET; } @Override protected StorageBucket[] listAllBucketsImpl() throws ServiceException { if (log.isDebugEnabled()) { log.debug("Listing all buckets for user: " + getProviderCredentials().getAccessKey()); } String bucketName = ""; // Root path of S3 service lists the user's buckets. HttpMethodBase httpMethod = performRestGet(bucketName, null, null, null); String contentType = httpMethod.getResponseHeader("Content-Type").getValue(); if (!isXmlContentType(contentType)) { throw new ServiceException("Expected XML document response from S3 but received content type " + contentType); } StorageBucket[] buckets = getXmlResponseSaxParser() .parseListMyBucketsResponse( new HttpMethodReleaseInputStream(httpMethod)).getBuckets(); return buckets; } @Override protected StorageOwner getAccountOwnerImpl() throws ServiceException { if (log.isDebugEnabled()) { log.debug("Looking up owner of S3 account via the ListAllBuckets response: " + getProviderCredentials().getAccessKey()); } String bucketName = ""; // Root path of S3 service lists the user's buckets. HttpMethodBase httpMethod = performRestGet(bucketName, null, null, null); String contentType = httpMethod.getResponseHeader("Content-Type").getValue(); if (!isXmlContentType(contentType)) { throw new ServiceException("Expected XML document response from S3 but received content type " + contentType); } StorageOwner owner = getXmlResponseSaxParser() .parseListMyBucketsResponse( new HttpMethodReleaseInputStream(httpMethod)).getOwner(); return owner; } @Override protected StorageObject[] listObjectsImpl(String bucketName, String prefix, String delimiter, long maxListingLength) throws ServiceException { return listObjectsInternal(bucketName, prefix, delimiter, maxListingLength, true, null, null).getObjects(); } @Override protected StorageObjectsChunk listObjectsChunkedImpl(String bucketName, String prefix, String delimiter, long maxListingLength, String priorLastKey, boolean completeListing) throws ServiceException { return listObjectsInternal(bucketName, prefix, delimiter, maxListingLength, completeListing, priorLastKey, null); } protected StorageObjectsChunk listObjectsInternal( String bucketName, String prefix, String delimiter, long maxListingLength, boolean automaticallyMergeChunks, String priorLastKey, String priorLastVersion) throws ServiceException { Map parameters = new HashMap(); if (prefix != null) { parameters.put("prefix", prefix); } if (delimiter != null) { parameters.put("delimiter", delimiter); } if (maxListingLength > 0) { parameters.put("max-keys", String.valueOf(maxListingLength)); } List objects = new ArrayList(); List commonPrefixes = new ArrayList(); boolean incompleteListing = true; int ioErrorRetryCount = 0; while (incompleteListing) { if (priorLastKey != null) { parameters.put("marker", priorLastKey); } else { parameters.remove("marker"); } HttpMethodBase httpMethod = performRestGet(bucketName, null, parameters, null); ListBucketHandler listBucketHandler = null; try { listBucketHandler = getXmlResponseSaxParser() .parseListBucketResponse( new HttpMethodReleaseInputStream(httpMethod)); ioErrorRetryCount = 0; } catch (ServiceException e) { if (e.getCause() instanceof IOException && ioErrorRetryCount < 5) { ioErrorRetryCount++; if (log.isWarnEnabled()) { log.warn("Retrying bucket listing failure due to IO error", e); } continue; } else { throw e; } } StorageObject[] partialObjects = listBucketHandler.getObjects(); if (log.isDebugEnabled()) { log.debug("Found " + partialObjects.length + " objects in one batch"); } objects.addAll(Arrays.asList(partialObjects)); String[] partialCommonPrefixes = listBucketHandler.getCommonPrefixes(); if (log.isDebugEnabled()) { log.debug("Found " + partialCommonPrefixes.length + " common prefixes in one batch"); } commonPrefixes.addAll(Arrays.asList(partialCommonPrefixes)); incompleteListing = listBucketHandler.isListingTruncated(); if (incompleteListing) { priorLastKey = listBucketHandler.getMarkerForNextListing(); if (log.isDebugEnabled()) { log.debug("Yet to receive complete listing of bucket contents, " + "last key for prior chunk: " + priorLastKey); } } else { priorLastKey = null; } if (!automaticallyMergeChunks) { break; } } if (automaticallyMergeChunks) { if (log.isDebugEnabled()) { log.debug("Found " + objects.size() + " objects in total"); } return new StorageObjectsChunk( prefix, delimiter, objects.toArray(new StorageObject[objects.size()]), commonPrefixes.toArray(new String[commonPrefixes.size()]), null); } else { return new StorageObjectsChunk( prefix, delimiter, objects.toArray(new StorageObject[objects.size()]), commonPrefixes.toArray(new String[commonPrefixes.size()]), priorLastKey); } } @Override protected void deleteObjectImpl(String bucketName, String objectKey, String versionId, String multiFactorSerialNumber, String multiFactorAuthCode) throws ServiceException { Map requestParameters = new HashMap(); if (versionId != null) { requestParameters.put("versionId", versionId); } performRestDelete(bucketName, objectKey, requestParameters, multiFactorSerialNumber, multiFactorAuthCode); } protected AccessControlList getObjectAclImpl(String bucketName, String objectKey) throws ServiceException { if (log.isDebugEnabled()) { log.debug("Retrieving Access Control List for bucketName=" + bucketName + ", objectKey=" + objectKey); } Map requestParameters = new HashMap(); requestParameters.put("acl",""); HttpMethodBase httpMethod = performRestGet(bucketName, objectKey, requestParameters, null); return getXmlResponseSaxParser() .parseAccessControlListResponse( new HttpMethodReleaseInputStream(httpMethod)).getAccessControlList(); } @Override protected AccessControlList getObjectAclImpl(String bucketName, String objectKey, String versionId) throws ServiceException { if (log.isDebugEnabled()) { log.debug("Retrieving versioned Access Control List for bucketName=" + bucketName + ", objectKey=" + objectKey); } Map requestParameters = new HashMap(); requestParameters.put("acl",""); if (versionId != null) { requestParameters.put("versionId", versionId); } HttpMethodBase httpMethod = performRestGet(bucketName, objectKey, requestParameters, null); return getXmlResponseSaxParser() .parseAccessControlListResponse( new HttpMethodReleaseInputStream(httpMethod)).getAccessControlList(); } @Override protected AccessControlList getBucketAclImpl(String bucketName) throws ServiceException { if (log.isDebugEnabled()) { log.debug("Retrieving Access Control List for Bucket: " + bucketName); } Map requestParameters = new HashMap(); requestParameters.put("acl",""); HttpMethodBase httpMethod = performRestGet(bucketName, null, requestParameters, null); return getXmlResponseSaxParser() .parseAccessControlListResponse( new HttpMethodReleaseInputStream(httpMethod)).getAccessControlList(); } @Override protected void putObjectAclImpl(String bucketName, String objectKey, AccessControlList acl, String versionId) throws ServiceException { putAclImpl(bucketName, objectKey, acl, versionId); } @Override protected void putBucketAclImpl(String bucketName, AccessControlList acl) throws ServiceException { String fullKey = bucketName; putAclImpl(fullKey, null, acl, null); } protected void putAclImpl(String bucketName, String objectKey, AccessControlList acl, String versionId) throws ServiceException { if (log.isDebugEnabled()) { log.debug("Setting Access Control List for bucketName=" + bucketName + ", objectKey=" + objectKey); } Map requestParameters = new HashMap(); requestParameters.put("acl",""); if (versionId != null) { requestParameters.put("versionId", versionId); } Map metadata = new HashMap(); metadata.put("Content-Type", "text/plain"); try { String aclAsXml = acl.toXml(); metadata.put("Content-Length", String.valueOf(aclAsXml.length())); performRestPut(bucketName, objectKey, metadata, requestParameters, new StringRequestEntity(aclAsXml, "text/plain", Constants.DEFAULT_ENCODING), true); } catch (UnsupportedEncodingException e) { throw new ServiceException("Unable to encode ACL XML document", e); } } @Override protected StorageBucket createBucketImpl(String bucketName, String location, AccessControlList acl) throws ServiceException { if (log.isDebugEnabled()) { log.debug("Creating bucket with name: " + bucketName); } Map metadata = new HashMap(); RequestEntity requestEntity = null; if (location != null && !"US".equalsIgnoreCase(location)) { metadata.put("Content-Type", "text/xml"); try { CreateBucketConfiguration config = new CreateBucketConfiguration(location); String configXml = config.toXml(); metadata.put("Content-Length", String.valueOf(configXml.length())); requestEntity = new StringRequestEntity(configXml, "text/xml", Constants.DEFAULT_ENCODING); } catch (Exception e) { throw new ServiceException("Unable to encode CreateBucketConfiguration XML document", e); } } Map map = createObjectImpl(bucketName, null, null, requestEntity, metadata, null, acl, null); StorageBucket bucket = newBucket(); bucket.setName(bucketName); if (bucket instanceof S3Bucket) { ((S3Bucket) bucket).setLocation(location); } bucket.setAcl(acl); bucket.replaceAllMetadata(map); return bucket; } @Override protected void deleteBucketImpl(String bucketName) throws ServiceException { performRestDelete(bucketName, null, null, null, null); } /** * Beware of high memory requirements when creating large S3 objects when the Content-Length * is not set in the object. */ @Override protected StorageObject putObjectImpl(String bucketName, StorageObject object) throws ServiceException { if (log.isDebugEnabled()) { log.debug("Creating Object with key " + object.getKey() + " in bucket " + bucketName); } // We do not need to calculate the data MD5 hash during upload if the // expected hash value was provided as the object's Content-MD5 header. boolean isLiveMD5HashingRequired = (object.getMetadata(StorageObject.METADATA_HEADER_CONTENT_MD5) == null); RequestEntity requestEntity = null; if (object.getDataInputStream() != null) { if (object.containsMetadata(StorageObject.METADATA_HEADER_CONTENT_LENGTH)) { if (log.isDebugEnabled()) { log.debug("Uploading object data with Content-Length: " + object.getContentLength()); } requestEntity = new RepeatableRequestEntity(object.getKey(), object.getDataInputStream(), object.getContentType(), object.getContentLength(), this.jets3tProperties, isLiveMD5HashingRequired); } else { // Use InputStreamRequestEntity for objects with an unknown content length, as the // entity will cache the results and doesn't need to know the data length in advance. if (log.isWarnEnabled()) { log.warn("Content-Length of data stream not set, will automatically determine data length in memory"); } requestEntity = new InputStreamRequestEntity( object.getDataInputStream(), InputStreamRequestEntity.CONTENT_LENGTH_AUTO); } } this.putObjectWithRequestEntityImpl(bucketName, object, requestEntity, null); return object; } protected void putObjectWithRequestEntityImpl(String bucketName, StorageObject object, RequestEntity requestEntity, Map requestParams) throws ServiceException { // We do not need to calculate the data MD5 hash during upload if the // expected hash value was provided as the object's Content-MD5 header. boolean isLiveMD5HashingRequired = (object.getMetadata(StorageObject.METADATA_HEADER_CONTENT_MD5) == null); Map map = createObjectImpl(bucketName, object.getKey(), object.getContentType(), requestEntity, object.getMetadataMap(), requestParams, object.getAcl(), object.getStorageClass()); try { object.closeDataInputStream(); } catch (IOException e) { if (log.isWarnEnabled()) { log.warn("Unable to close data input stream for object '" + object.getKey() + "'", e); } } // Populate object with result metadata. object.replaceAllMetadata(map); // Confirm that the data was not corrupted in transit by checking S3's calculated // hash value with the locally computed value. This is only necessary if the user // did not provide a Content-MD5 header with the original object. // Note that we can only confirm the data if we used a RepeatableRequestEntity to // upload it, if the user did not provide a content length with the original // object we are SOL. if (isLiveMD5HashingRequired && requestEntity instanceof RepeatableRequestEntity) { // Obtain locally-calculated MD5 hash from request entity. String hexMD5OfUploadedData = ServiceUtils.toHex( ((RepeatableRequestEntity)requestEntity).getMD5DigestOfData()); verifyExpectedAndActualETagValues(hexMD5OfUploadedData, object); } } protected Map createObjectImpl(String bucketName, String objectKey, String contentType, RequestEntity requestEntity, Map metadata, Map requestParams, AccessControlList acl, String storageClass) throws ServiceException { if (metadata == null) { metadata = new HashMap(); } else { // Use a new map object in case the one we were provided is immutable. metadata = new HashMap(metadata); } if (contentType != null) { metadata.put("Content-Type", contentType); } else { metadata.put("Content-Type", Mimetypes.MIMETYPE_OCTET_STREAM); } // Apply per-object or default storage class when uploading object, // unless object is part of a multipart upload if (requestParams == null || !requestParams.containsKey("uploadId")) { prepareStorageClass(metadata, storageClass, objectKey); } boolean isExtraAclPutRequired = !prepareCannedAcl(metadata, acl); if (log.isDebugEnabled()) { log.debug("Creating object bucketName=" + bucketName + ", objectKey=" + objectKey + ", storageClass=" + storageClass + "." + " Content-Type=" + metadata.get("Content-Type") + " Including data? " + (requestEntity != null) + " Metadata: " + metadata + " ACL: " + acl ); } HttpMethodAndByteCount methodAndByteCount = performRestPut( bucketName, objectKey, metadata, requestParams, requestEntity, true); // Consume response content. HttpMethodBase httpMethod = methodAndByteCount.getHttpMethod(); Map map = new HashMap(); map.putAll(metadata); // Keep existing metadata. map.putAll(convertHeadersToMap(httpMethod.getResponseHeaders())); map.put(StorageObject.METADATA_HEADER_CONTENT_LENGTH, String.valueOf(methodAndByteCount.getByteCount())); map = ServiceUtils.cleanRestMetadataMap( map, this.getRestHeaderPrefix(), this.getRestMetadataPrefix()); if (isExtraAclPutRequired) { if (log.isDebugEnabled()) { log.debug("Creating object with a non-canned ACL using REST, so an extra ACL Put is required"); } putAclImpl(bucketName, objectKey, acl, null); } return map; } /** * Prepares the metadata with a canned representation of the given ACL, if * an ACL is provided and can be represented with a HTTP header. * * @param metadata * @param acl * @return * false if an ACL was provided but it could not be applied as a canned ACL. */ protected boolean prepareCannedAcl(Map metadata, AccessControlList acl) { if (acl != null) { if (metadata == null) { throw new IllegalArgumentException("Null metadata not allowed."); } String restHeaderAclValue = acl.getValueForRESTHeaderACL(); if (restHeaderAclValue != null) { metadata.put(this.getRestHeaderPrefix() + "acl", restHeaderAclValue); } else { return false; } } return true; } protected void prepareStorageClass(Map metadata, String storageClass, String objectKey) { if (getEnableStorageClasses()) { if (metadata == null) { throw new IllegalArgumentException("Null metadata not allowed."); } if (storageClass == null && this.defaultStorageClass != null) { // Apply default storage class storageClass = this.defaultStorageClass; log.debug("Applied default storage class '" + storageClass + "' to object '" + objectKey + "'"); } if (storageClass != null) { metadata.put(this.getRestHeaderPrefix() + "storage-class", storageClass); } } } @Override protected Map copyObjectImpl(String sourceBucketName, String sourceObjectKey, String destinationBucketName, String destinationObjectKey, AccessControlList acl, Map destinationMetadata, Calendar ifModifiedSince, Calendar ifUnmodifiedSince, String[] ifMatchTags, String[] ifNoneMatchTags, String versionId, String destinationObjectStorageClass) throws ServiceException { if (log.isDebugEnabled()) { log.debug("Copying Object from " + sourceBucketName + ":" + sourceObjectKey + " to " + destinationBucketName + ":" + destinationObjectKey); } Map metadata = new HashMap(); String sourceKey = RestUtils.encodeUrlString(sourceBucketName + "/" + sourceObjectKey); if (versionId != null) { sourceKey += "?versionId=" + versionId; } metadata.put(this.getRestHeaderPrefix() + "copy-source", sourceKey); if (destinationObjectStorageClass != null) { prepareStorageClass(metadata, destinationObjectStorageClass, destinationObjectKey); } if (destinationMetadata != null) { metadata.put(this.getRestHeaderPrefix() + "metadata-directive", "REPLACE"); // Include any metadata provided with S3 object. metadata.putAll(destinationMetadata); // Set default content type. if (!metadata.containsKey("Content-Type")) { metadata.put("Content-Type", Mimetypes.MIMETYPE_OCTET_STREAM); } } else { metadata.put(this.getRestHeaderPrefix() + "metadata-directive", "COPY"); } boolean isExtraAclPutRequired = !prepareCannedAcl(metadata, acl); if (ifModifiedSince != null) { metadata.put(this.getRestHeaderPrefix() + "copy-source-if-modified-since", ServiceUtils.formatRfc822Date(ifModifiedSince.getTime())); if (log.isDebugEnabled()) { log.debug("Only copy object if-modified-since:" + ifModifiedSince); } } if (ifUnmodifiedSince != null) { metadata.put(this.getRestHeaderPrefix() + "copy-source-if-unmodified-since", ServiceUtils.formatRfc822Date(ifUnmodifiedSince.getTime())); if (log.isDebugEnabled()) { log.debug("Only copy object if-unmodified-since:" + ifUnmodifiedSince); } } if (ifMatchTags != null) { String tags = ServiceUtils.join(ifMatchTags, ","); metadata.put(this.getRestHeaderPrefix() + "copy-source-if-match", tags); if (log.isDebugEnabled()) { log.debug("Only copy object based on hash comparison if-match:" + tags); } } if (ifNoneMatchTags != null) { String tags = ServiceUtils.join(ifNoneMatchTags, ","); metadata.put(this.getRestHeaderPrefix() + "copy-source-if-none-match", tags); if (log.isDebugEnabled()) { log.debug("Only copy object based on hash comparison if-none-match:" + tags); } } HttpMethodAndByteCount methodAndByteCount = performRestPut( destinationBucketName, destinationObjectKey, metadata, null, null, false); CopyObjectResultHandler handler = getXmlResponseSaxParser() .parseCopyObjectResponse( new HttpMethodReleaseInputStream(methodAndByteCount.getHttpMethod())); // Release HTTP connection manually. This should already have been done by the // HttpMethodReleaseInputStream class, but you can never be too sure... methodAndByteCount.getHttpMethod().releaseConnection(); if (handler.isErrorResponse()) { throw new ServiceException( "Copy failed: Code=" + handler.getErrorCode() + ", Message=" + handler.getErrorMessage() + ", RequestId=" + handler.getErrorRequestId() + ", HostId=" + handler.getErrorHostId()); } Map map = new HashMap(); // Result fields returned when copy is successful. map.put("Last-Modified", handler.getLastModified()); map.put("ETag", handler.getETag()); // Include response headers in result map. map.putAll(convertHeadersToMap(methodAndByteCount.getHttpMethod().getResponseHeaders())); map = ServiceUtils.cleanRestMetadataMap( map, this.getRestHeaderPrefix(), this.getRestMetadataPrefix()); if (isExtraAclPutRequired) { if (log.isDebugEnabled()) { log.debug("Creating object with a non-canned ACL using REST, so an extra ACL Put is required"); } putAclImpl(destinationBucketName, destinationObjectKey, acl, null); } return map; } @Override protected StorageObject getObjectDetailsImpl(String bucketName, String objectKey, Calendar ifModifiedSince, Calendar ifUnmodifiedSince, String[] ifMatchTags, String[] ifNoneMatchTags, String versionId) throws ServiceException { return getObjectImpl(true, bucketName, objectKey, ifModifiedSince, ifUnmodifiedSince, ifMatchTags, ifNoneMatchTags, null, null, versionId); } @Override protected StorageObject getObjectImpl(String bucketName, String objectKey, Calendar ifModifiedSince, Calendar ifUnmodifiedSince, String[] ifMatchTags, String[] ifNoneMatchTags, Long byteRangeStart, Long byteRangeEnd, String versionId) throws ServiceException { return getObjectImpl(false, bucketName, objectKey, ifModifiedSince, ifUnmodifiedSince, ifMatchTags, ifNoneMatchTags, byteRangeStart, byteRangeEnd, versionId); } private StorageObject getObjectImpl(boolean headOnly, String bucketName, String objectKey, Calendar ifModifiedSince, Calendar ifUnmodifiedSince, String[] ifMatchTags, String[] ifNoneMatchTags, Long byteRangeStart, Long byteRangeEnd, String versionId) throws ServiceException { if (log.isDebugEnabled()) { log.debug("Retrieving " + (headOnly? "Head" : "All") + " information for bucket " + bucketName + " and object " + objectKey); } Map requestHeaders = new HashMap(); Map requestParameters = new HashMap(); if (ifModifiedSince != null) { requestHeaders.put("If-Modified-Since", ServiceUtils.formatRfc822Date(ifModifiedSince.getTime())); if (log.isDebugEnabled()) { log.debug("Only retrieve object if-modified-since:" + ifModifiedSince); } } if (ifUnmodifiedSince != null) { requestHeaders.put("If-Unmodified-Since", ServiceUtils.formatRfc822Date(ifUnmodifiedSince.getTime())); if (log.isDebugEnabled()) { log.debug("Only retrieve object if-unmodified-since:" + ifUnmodifiedSince); } } if (ifMatchTags != null) { String tags = ServiceUtils.join(ifMatchTags, ","); requestHeaders.put("If-Match", tags); if (log.isDebugEnabled()) { log.debug("Only retrieve object based on hash comparison if-match:" + tags); } } if (ifNoneMatchTags != null) { String tags = ServiceUtils.join(ifNoneMatchTags, ","); requestHeaders.put("If-None-Match", tags); if (log.isDebugEnabled()) { log.debug("Only retrieve object based on hash comparison if-none-match:" + tags); } } if (byteRangeStart != null || byteRangeEnd != null) { String range = "bytes=" + (byteRangeStart != null? byteRangeStart.toString() : "") + "-" + (byteRangeEnd != null? byteRangeEnd.toString() : ""); requestHeaders.put("Range", range); if (log.isDebugEnabled()) { log.debug("Only retrieve object if it is within range:" + range); } } if (versionId != null) { requestParameters.put("versionId", versionId); } HttpMethodBase httpMethod = null; if (headOnly) { httpMethod = performRestHead(bucketName, objectKey, requestParameters, requestHeaders); } else { httpMethod = performRestGet(bucketName, objectKey, requestParameters, requestHeaders); } Map map = new HashMap(); map.putAll(convertHeadersToMap(httpMethod.getResponseHeaders())); StorageObject responseObject = newObject(); responseObject.setKey(objectKey); responseObject.setBucketName(bucketName); responseObject.replaceAllMetadata(ServiceUtils.cleanRestMetadataMap( map, this.getRestHeaderPrefix(), this.getRestMetadataPrefix())); responseObject.setMetadataComplete(true); // Flag this object as having the complete metadata set. if (!headOnly) { HttpMethodReleaseInputStream releaseIS = new HttpMethodReleaseInputStream(httpMethod); responseObject.setDataInputStream(releaseIS); } else { // Release connection after HEAD (there's no response content) if (log.isDebugEnabled()) { log.debug("Releasing HttpMethod after HEAD"); } httpMethod.releaseConnection(); } return responseObject; } /** * Puts an object using a pre-signed PUT URL generated for that object. * This method is an implementation of the interface {@link org.jets3t.service.utils.signedurl.SignedUrlHandler}. *

* This operation does not required any S3 functionality as it merely * uploads the object by performing a standard HTTP PUT using the signed URL. * * @param signedPutUrl * a signed PUT URL generated with * {@link org.jets3t.service.S3Service#createSignedPutUrl(String, String, java.util.Map, org.jets3t.service.security.ProviderCredentials, java.util.Date)}. * @param object * the object to upload, which must correspond to the object for which the URL was signed. * The object must have the correct content length set, and to apply a non-standard * ACL policy only the REST canned ACLs can be used * (eg {@link org.jets3t.service.acl.AccessControlList#REST_CANNED_PUBLIC_READ_WRITE}). * * @return * the S3Object put to S3. The S3Object returned will represent the object created in S3. * * @throws org.jets3t.service.ServiceException */ public S3Object putObjectWithSignedUrl(String signedPutUrl, S3Object object) throws ServiceException { PutMethod putMethod = new PutMethod(signedPutUrl); Map renamedMetadata = renameMetadataKeys(object.getMetadataMap()); addMetadataToHeaders(putMethod, renamedMetadata); if (!object.containsMetadata("Content-Length")) { throw new IllegalStateException("Content-Length must be specified for objects put using signed PUT URLs"); } RepeatableRequestEntity repeatableRequestEntity = null; // We do not need to calculate the data MD5 hash during upload if the // expected hash value was provided as the object's Content-MD5 header. boolean isLiveMD5HashingRequired = (object.getMetadata(StorageObject.METADATA_HEADER_CONTENT_MD5) == null); String s3Endpoint = this.getEndpoint(); if (object.getDataInputStream() != null) { repeatableRequestEntity = new RepeatableRequestEntity(object.getKey(), object.getDataInputStream(), object.getContentType(), object.getContentLength(), this.jets3tProperties, isLiveMD5HashingRequired); putMethod.setRequestEntity(repeatableRequestEntity); } performRequest(putMethod, new int[] {200}); // Consume response data and release connection. putMethod.releaseConnection(); try { object.closeDataInputStream(); } catch (IOException e) { if (log.isWarnEnabled()) { log.warn("Unable to close data input stream for object '" + object.getKey() + "'", e); } } try { StorageObject uploadedObject = ServiceUtils.buildObjectFromUrl( putMethod.getURI().getHost(), putMethod.getPath(), s3Endpoint); uploadedObject.setBucketName(uploadedObject.getBucketName()); // Add all metadata returned by S3 to uploaded object. Map map = new HashMap(); map.putAll(convertHeadersToMap(putMethod.getResponseHeaders())); uploadedObject.replaceAllMetadata(ServiceUtils.cleanRestMetadataMap( map, this.getRestHeaderPrefix(), this.getRestMetadataPrefix())); // Confirm that the data was not corrupted in transit by checking S3's calculated // hash value with the locally computed value. This is only necessary if the user // did not provide a Content-MD5 header with the original object. // Note that we can only confirm the data if we used a RepeatableRequestEntity to // upload it, if the user did not provide a content length with the original // object we are SOL. if (repeatableRequestEntity != null && isLiveMD5HashingRequired) { // Obtain locally-calculated MD5 hash from request entity. String hexMD5OfUploadedData = ServiceUtils.toHex( (repeatableRequestEntity).getMD5DigestOfData()); verifyExpectedAndActualETagValues(hexMD5OfUploadedData, uploadedObject); } return (S3Object) uploadedObject; } catch (URIException e) { throw new ServiceException("Unable to lookup URI for object created with signed PUT", e); } catch (UnsupportedEncodingException e) { throw new ServiceException("Unable to determine name of object created with signed PUT", e); } } /** * Deletes an object using a pre-signed DELETE URL generated for that object. * This method is an implementation of the interface {@link org.jets3t.service.utils.signedurl.SignedUrlHandler}. *

* This operation does not required any S3 functionality as it merely * deletes the object by performing a standard HTTP DELETE using the signed URL. * * @param signedDeleteUrl * a signed DELETE URL generated with {@link org.jets3t.service.S3Service#createSignedDeleteUrl}. * * @throws org.jets3t.service.ServiceException */ public void deleteObjectWithSignedUrl(String signedDeleteUrl) throws ServiceException { DeleteMethod deleteMethod = new DeleteMethod(signedDeleteUrl); performRequest(deleteMethod, new int[] {204, 200}); deleteMethod.releaseConnection(); } /** * Gets an object using a pre-signed GET URL generated for that object. * This method is an implementation of the interface {@link org.jets3t.service.utils.signedurl.SignedUrlHandler}. *

* This operation does not required any S3 functionality as it merely * uploads the object by performing a standard HTTP GET using the signed URL. * * @param signedGetUrl * a signed GET URL generated with * {@link org.jets3t.service.S3Service#createSignedGetUrl(String, String, org.jets3t.service.security.ProviderCredentials, java.util.Date)}. * * @return * the S3Object in S3 including all metadata and the object's data input stream. * * @throws org.jets3t.service.ServiceException */ public S3Object getObjectWithSignedUrl(String signedGetUrl) throws ServiceException { return getObjectWithSignedUrlImpl(signedGetUrl, false); } /** * Gets an object's details using a pre-signed HEAD URL generated for that object. * This method is an implementation of the interface {@link org.jets3t.service.utils.signedurl.SignedUrlHandler}. *

* This operation does not required any S3 functionality as it merely * uploads the object by performing a standard HTTP HEAD using the signed URL. * * @param signedHeadUrl * a signed HEAD URL generated with * {@link org.jets3t.service.S3Service#createSignedHeadUrl(String, String, org.jets3t.service.security.ProviderCredentials, java.util.Date)}. * * @return * the S3Object in S3 including all metadata, but without the object's data input stream. * * @throws org.jets3t.service.ServiceException */ public S3Object getObjectDetailsWithSignedUrl(String signedHeadUrl) throws ServiceException { return getObjectWithSignedUrlImpl(signedHeadUrl, true); } /** * Gets an object's ACL details using a pre-signed GET URL generated for that object. * This method is an implementation of the interface {@link org.jets3t.service.utils.signedurl.SignedUrlHandler}. * * @param signedAclUrl * a signed URL generated with {@link org.jets3t.service.S3Service#createSignedUrl(String, String, String, String, java.util.Map, org.jets3t.service.security.ProviderCredentials, long, boolean)}. * * @return * the AccessControlList settings of the object in S3. * * @throws org.jets3t.service.ServiceException */ public AccessControlList getObjectAclWithSignedUrl(String signedAclUrl) throws ServiceException { HttpMethodBase httpMethod = new GetMethod(signedAclUrl); Map requestParameters = new HashMap(); requestParameters.put("acl",""); performRequest(httpMethod, new int[] {200}); return getXmlResponseSaxParser() .parseAccessControlListResponse( new HttpMethodReleaseInputStream(httpMethod)).getAccessControlList(); } /** * Sets an object's ACL details using a pre-signed PUT URL generated for that object. * This method is an implementation of the interface {@link org.jets3t.service.utils.signedurl.SignedUrlHandler}. * * @param signedAclUrl * a signed URL generated with {@link org.jets3t.service.S3Service#createSignedUrl(String, String, String, String, java.util.Map, org.jets3t.service.security.ProviderCredentials, long, boolean)}. * @param acl * the ACL settings to apply to the object represented by the signed URL. * * @throws org.jets3t.service.ServiceException */ public void putObjectAclWithSignedUrl(String signedAclUrl, AccessControlList acl) throws ServiceException { PutMethod putMethod = new PutMethod(signedAclUrl); if (acl != null) { String restHeaderAclValue = acl.getValueForRESTHeaderACL(); if (restHeaderAclValue != null) { putMethod.addRequestHeader(this.getRestHeaderPrefix() + "acl", restHeaderAclValue); } else { try { String aclAsXml = acl.toXml(); putMethod.setRequestEntity(new StringRequestEntity( aclAsXml, "text/xml", Constants.DEFAULT_ENCODING)); } catch (UnsupportedEncodingException e) { throw new ServiceException("Unable to encode ACL XML document", e); } } } performRequest(putMethod, new int[] {200}); // Consume response data and release connection. putMethod.releaseConnection(); } private S3Object getObjectWithSignedUrlImpl(String signedGetOrHeadUrl, boolean headOnly) throws ServiceException { String s3Endpoint = this.getEndpoint(); HttpMethodBase httpMethod = null; if (headOnly) { httpMethod = new HeadMethod(signedGetOrHeadUrl); } else { httpMethod = new GetMethod(signedGetOrHeadUrl); } performRequest(httpMethod, new int[] {200}); Map map = new HashMap(); map.putAll(convertHeadersToMap(httpMethod.getResponseHeaders())); S3Object responseObject = null; try { responseObject = ServiceUtils.buildObjectFromUrl( httpMethod.getURI().getHost(), httpMethod.getPath().substring(1), s3Endpoint); } catch (URIException e) { throw new ServiceException("Unable to lookup URI for object created with signed PUT", e); } catch (UnsupportedEncodingException e) { throw new ServiceException("Unable to determine name of object created with signed PUT", e); } responseObject.replaceAllMetadata(ServiceUtils.cleanRestMetadataMap( map, this.getRestHeaderPrefix(), this.getRestMetadataPrefix())); responseObject.setMetadataComplete(true); // Flag this object as having the complete metadata set. if (!headOnly) { HttpMethodReleaseInputStream releaseIS = new HttpMethodReleaseInputStream(httpMethod); responseObject.setDataInputStream(releaseIS); } else { // Release connection after HEAD (there's no response content) if (log.isDebugEnabled()) { log.debug("Releasing HttpMethod after HEAD"); } httpMethod.releaseConnection(); } return responseObject; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/impl/rest/httpclient/HttpMethodAndByteCount.java0000644000000000000000000000305011441613550027227 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.impl.rest.httpclient; import org.apache.commons.httpclient.HttpMethodBase; /** * Simple container object to store an HttpMethod object representing a request connection, and a * count of the byte size of the S3 object associated with the request. *

* This object is used when S3 objects are created to associate the connection and the actual size * of the object as reported back by S3. * * @author James Murty */ public class HttpMethodAndByteCount { private HttpMethodBase httpMethod = null; private long byteCount = 0; public HttpMethodAndByteCount(HttpMethodBase httpMethod, long byteCount) { this.httpMethod = httpMethod; this.byteCount = byteCount; } public HttpMethodBase getHttpMethod() { return httpMethod; } public long getByteCount() { return byteCount; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/impl/rest/httpclient/GoogleStorageService.java0000644000000000000000000003102711550441740026757 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.impl.rest.httpclient; import java.util.Arrays; import java.util.Calendar; import java.util.List; import org.apache.commons.httpclient.HostConfiguration; import org.apache.commons.httpclient.auth.CredentialsProvider; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.ServiceException; import org.jets3t.service.acl.gs.GSAccessControlList; import org.jets3t.service.model.GSBucket; import org.jets3t.service.model.GSObject; import org.jets3t.service.security.ProviderCredentials; /** * REST/HTTP implementation of Google Storage Service based on the * HttpClient library. *

* This class uses properties obtained through {@link org.jets3t.service.Jets3tProperties}. For more information on * these properties please refer to * JetS3t Configuration *

* * @author Google Developers */ public class GoogleStorageService extends RestStorageService { private static final String GOOGLE_SIGNATURE_IDENTIFIER = "GOOG1"; private static final String GOOGLE_REST_HEADER_PREFIX = "x-goog-"; private static final String GOOGLE_REST_METADATA_PREFIX = "x-goog-meta-"; /** * Constructs the service and initialises the properties. * * @param credentials * the user credentials to use when communicating with Google Storage, may be null in which case the * communication is done as an anonymous user. * * @throws ServiceException */ public GoogleStorageService(ProviderCredentials credentials) throws ServiceException { this(credentials, null, null); } /** * Constructs the service and initialises the properties. * * @param credentials * the user credentials to use when communicating with Google Storage, may be null in which case the * communication is done as an anonymous user. * @param invokingApplicationDescription * a short description of the application using the service, suitable for inclusion in a * user agent string for REST/HTTP requests. Ideally this would include the application's * version number, for example: Cockpit/0.7.3 or My App Name/1.0 * @param credentialsProvider * an implementation of the HttpClient CredentialsProvider interface, to provide a means for * prompting for credentials when necessary. * * @throws ServiceException */ public GoogleStorageService(ProviderCredentials credentials, String invokingApplicationDescription, CredentialsProvider credentialsProvider) throws ServiceException { this(credentials, invokingApplicationDescription, credentialsProvider, Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME)); } /** * Constructs the service and initialises the properties. * * @param credentials * the user credentials to use when communicating with Google Storage, may be null in which case the * communication is done as an anonymous user. * @param invokingApplicationDescription * a short description of the application using the service, suitable for inclusion in a * user agent string for REST/HTTP requests. Ideally this would include the application's * version number, for example: Cockpit/0.7.3 or My App Name/1.0 * @param credentialsProvider * an implementation of the HttpClient CredentialsProvider interface, to provide a means for * prompting for credentials when necessary. * @param jets3tProperties * JetS3t properties that will be applied within this service. * * @throws ServiceException */ public GoogleStorageService(ProviderCredentials credentials, String invokingApplicationDescription, CredentialsProvider credentialsProvider, Jets3tProperties jets3tProperties) throws ServiceException { this(credentials, invokingApplicationDescription, credentialsProvider, jets3tProperties, new HostConfiguration()); } /** * Constructs the service and initialises the properties. * * @param credentials * the user credentials to use when communicating with Google Storage, may be null in which case the * communication is done as an anonymous user. * @param invokingApplicationDescription * a short description of the application using the service, suitable for inclusion in a * user agent string for REST/HTTP requests. Ideally this would include the application's * version number, for example: Cockpit/0.7.3 or My App Name/1.0 * @param credentialsProvider * an implementation of the HttpClient CredentialsProvider interface, to provide a means for * prompting for credentials when necessary. * @param jets3tProperties * JetS3t properties that will be applied within this service. * @param hostConfig * Custom HTTP host configuration; e.g to register a custom Protocol Socket Factory * * @throws ServiceException */ public GoogleStorageService(ProviderCredentials credentials, String invokingApplicationDescription, CredentialsProvider credentialsProvider, Jets3tProperties jets3tProperties, HostConfiguration hostConfig) throws ServiceException { super(credentials, invokingApplicationDescription, credentialsProvider, jets3tProperties, hostConfig); } @Override protected boolean isTargettingGoogleStorageService() { return true; } /** * @return * the endpoint to be used to connect to Google Storage. */ @Override public String getEndpoint() { return this.jets3tProperties.getStringProperty( "gsservice.gs-endpoint", Constants.GS_DEFAULT_HOSTNAME); } /** * @return * the virtual path inside the service. */ @Override protected String getVirtualPath() { return this.jets3tProperties.getStringProperty( "gsservice.gs-endpoint-virtual-path", ""); } /** * @return * the identifier for the signature algorithm. */ @Override protected String getSignatureIdentifier() { return GOOGLE_SIGNATURE_IDENTIFIER; } /** * @return * header prefix for general Google Storage headers: x-goog-. */ @Override public String getRestHeaderPrefix() { return GOOGLE_REST_HEADER_PREFIX; } /** * @return * header prefix for Google Storage metadata headers: x-goog-meta-. */ @Override public String getRestMetadataPrefix() { return GOOGLE_REST_METADATA_PREFIX; } @Override public List getResourceParameterNames() { // Special HTTP parameter names that refer to resources in Google Storage return Arrays.asList(new String[] { "acl" }); } /** * @return * the port number to be used for insecure connections over HTTP. */ @Override protected int getHttpPort() { return this.jets3tProperties.getIntProperty("gsservice.gs-endpoint-http-port", 80); } /** * @return * the port number to be used for secure connections over HTTPS. */ @Override protected int getHttpsPort() { return this.jets3tProperties.getIntProperty("gsservice.gs-endpoint-https-port", 443); } /** * @return * If true, all communication with GS will be via encrypted HTTPS connections, * otherwise communications will be sent unencrypted via HTTP */ @Override protected boolean getHttpsOnly() { return this.jets3tProperties.getBoolProperty("gsservice.https-only", true); } /** * @return * If true, JetS3t will specify bucket names in the request path of the HTTP message * instead of the Host header. */ @Override protected boolean getDisableDnsBuckets() { return this.jets3tProperties.getBoolProperty("gsservice.disable-dns-buckets", false); } /** * @return * If true, JetS3t will enable support for Storage Classes. */ @Override protected boolean getEnableStorageClasses() { return false; } //////////////////////////////////////////////////////////// // Methods below this point perform actions in GoogleStorage //////////////////////////////////////////////////////////// @Override public GSBucket[] listAllBuckets() throws ServiceException { return GSBucket.cast(super.listAllBuckets()); } @Override public GSObject[] listObjects(String bucketName) throws ServiceException { return GSObject.cast(super.listObjects(bucketName)); } @Override public GSObject[] listObjects(String bucketName, String prefix, String delimiter) throws ServiceException { return GSObject.cast(super.listObjects(bucketName, prefix, delimiter)); } @Override public GSBucket createBucket(String bucketName) throws ServiceException { return (GSBucket) super.createBucket(bucketName); } @Override public GSAccessControlList getBucketAcl(String bucketName) throws ServiceException { return (GSAccessControlList) super.getBucketAcl(bucketName); } /** * Applies access control settings to a bucket. The ACL settings must be included * inside the bucket. * * This method can be performed by anonymous services, but can only succeed if the * bucket's existing ACL already allows write access by the anonymous user. * * @param bucketName * a name of the bucket with ACL settings to apply. * @throws ServiceException */ public void putBucketAcl(String bucketName, GSAccessControlList acl) throws ServiceException { if (acl == null) { throw new ServiceException("The bucket '" + bucketName + "' does not include ACL information"); } putBucketAclImpl(bucketName, acl); } /** * Applies access control settings to a bucket. The ACL settings must be included * inside the bucket. * * This method can be performed by anonymous services, but can only succeed if the * bucket's existing ACL already allows write access by the anonymous user. * * @param bucket * a bucket with ACL settings to apply. * @throws ServiceException */ public void putBucketAcl(GSBucket bucket) throws ServiceException { assertValidBucket(bucket, "Put Bucket Access Control List"); putBucketAcl(bucket.getName(), bucket.getAcl()); } @Override public GSObject getObject(String bucketName, String objectKey) throws ServiceException { return (GSObject) super.getObject(bucketName, objectKey); } public GSObject putObject(String bucketName, GSObject object) throws ServiceException { return (GSObject) super.putObject(bucketName, object); } @Override public GSObject getObject(String bucketName, String objectKey, Calendar ifModifiedSince, Calendar ifUnmodifiedSince, String[] ifMatchTags, String[] ifNoneMatchTags, Long byteRangeStart, Long byteRangeEnd) throws ServiceException { return (GSObject) super.getObject(bucketName, objectKey, ifModifiedSince, ifUnmodifiedSince, ifMatchTags, ifNoneMatchTags, byteRangeStart, byteRangeEnd); } @Override public GSObject getObjectDetails(String bucketName, String objectKey) throws ServiceException { return (GSObject) super.getObjectDetails(bucketName, objectKey); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/impl/rest/httpclient/AWSRequestAuthorizer.java0000644000000000000000000000161011427702124026747 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.impl.rest.httpclient; import org.apache.commons.httpclient.HttpMethod; public interface AWSRequestAuthorizer { public void authorizeHttpRequest(HttpMethod httpMethod) throws Exception; } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/impl/rest/DefaultXmlHandler.java0000644000000000000000000000327411441613550024064 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2007 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.impl.rest; import org.xml.sax.Attributes; import org.xml.sax.helpers.DefaultHandler; public class DefaultXmlHandler extends DefaultHandler { private StringBuffer currText = null; public void startDocument() {} public void endDocument() {} public void startElement(String uri, String name, String qName, Attributes attrs) { this.currText = new StringBuffer(); this.startElement(name, attrs); } public void startElement(String name, Attributes attrs) { this.startElement(name); } public void startElement(String name) { } public void endElement(String uri, String name, String qName) { String elementText = this.currText.toString(); this.endElement(name, elementText); } public void endElement(String name, String content) { } public void characters(char ch[], int start, int length) { this.currText.append(ch, start, length); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/impl/rest/HttpException.java0000644000000000000000000000264311441613550023316 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2007 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.impl.rest; /** * Simple exception to capture details of a failed HTTP operation, * including the response code and message. * * @author James Murty */ public class HttpException extends Exception { private static final long serialVersionUID = 1122712836821079256L; private int responseCode = 0; private String responseMessage = null; public HttpException(int responseCode, String responseMessage) { this.responseCode = responseCode; this.responseMessage = responseMessage; } public int getResponseCode() { return responseCode; } public String getResponseMessage() { return responseMessage; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/impl/rest/XmlResponsesSaxParser.java0000644000000000000000000014636511537563564025044 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2011 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.impl.rest; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.text.ParseException; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.S3ServiceException; import org.jets3t.service.ServiceException; import org.jets3t.service.acl.CanonicalGrantee; import org.jets3t.service.acl.EmailAddressGrantee; import org.jets3t.service.acl.GrantAndPermission; import org.jets3t.service.acl.GranteeInterface; import org.jets3t.service.acl.GroupGrantee; import org.jets3t.service.acl.Permission; import org.jets3t.service.model.BaseVersionOrDeleteMarker; import org.jets3t.service.model.GSBucket; import org.jets3t.service.model.GSObject; import org.jets3t.service.model.GSOwner; import org.jets3t.service.model.MultipartCompleted; import org.jets3t.service.model.MultipartPart; import org.jets3t.service.model.MultipartUpload; import org.jets3t.service.model.NotificationConfig; import org.jets3t.service.model.S3Bucket; import org.jets3t.service.model.S3BucketLoggingStatus; import org.jets3t.service.model.S3BucketVersioningStatus; import org.jets3t.service.model.S3DeleteMarker; import org.jets3t.service.model.S3Object; import org.jets3t.service.model.S3Owner; import org.jets3t.service.model.S3Version; import org.jets3t.service.model.StorageBucket; import org.jets3t.service.model.StorageObject; import org.jets3t.service.model.StorageOwner; import org.jets3t.service.model.WebsiteConfig; import org.jets3t.service.utils.ServiceUtils; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; /** * XML Sax parser to read XML documents returned by S3 via the REST interface, converting these * documents into JetS3t objects. * * @author James Murty */ public class XmlResponsesSaxParser { private static final Log log = LogFactory.getLog(XmlResponsesSaxParser.class); private XMLReader xr = null; private Jets3tProperties properties = null; private boolean isGoogleStorageMode = false; /** * Constructs the XML SAX parser. * * @param properties * the JetS3t properties that will be applied when parsing XML documents. * * @throws S3ServiceException */ public XmlResponsesSaxParser(Jets3tProperties properties, boolean returnGoogleStorageObjects) throws ServiceException { this.properties = properties; this.isGoogleStorageMode = returnGoogleStorageObjects; this.xr = ServiceUtils.loadXMLReader(); } protected StorageBucket newBucket() { if (isGoogleStorageMode) { return new GSBucket(); } else { return new S3Bucket(); } } protected StorageObject newObject() { if (isGoogleStorageMode) { return new GSObject(); } else { return new S3Object(); } } protected StorageOwner newOwner() { if (isGoogleStorageMode) { return new GSOwner(); } else { return new S3Owner(); } } /** * Parses an XML document from an input stream using a document handler. * @param handler * the handler for the XML document * @param inputStream * an input stream containing the XML document to parse * @throws ServiceException * any parsing, IO or other exceptions are wrapped in an ServiceException. */ protected void parseXmlInputStream(DefaultHandler handler, InputStream inputStream) throws ServiceException { try { if (log.isDebugEnabled()) { log.debug("Parsing XML response document with handler: " + handler.getClass()); } BufferedReader breader = new BufferedReader(new InputStreamReader(inputStream, Constants.DEFAULT_ENCODING)); xr.setContentHandler(handler); xr.setErrorHandler(handler); xr.parse(new InputSource(breader)); } catch (Throwable t) { try { inputStream.close(); } catch (IOException e) { if (log.isErrorEnabled()) { log.error("Unable to close response InputStream up after XML parse failure", e); } } throw new ServiceException("Failed to parse XML document with handler " + handler.getClass(), t); } } protected InputStream sanitizeXmlDocument(DefaultHandler handler, InputStream inputStream) throws ServiceException { if (!properties.getBoolProperty("xmlparser.sanitize-listings", true)) { // No sanitizing will be performed, return the original input stream unchanged. return inputStream; } else { if (log.isDebugEnabled()) { log.debug("Sanitizing XML document destined for handler " + handler.getClass()); } InputStream sanitizedInputStream = null; try { /* Read object listing XML document from input stream provided into a * string buffer, so we can replace troublesome characters before * sending the document to the XML parser. */ StringBuffer listingDocBuffer = new StringBuffer(); BufferedReader br = new BufferedReader( new InputStreamReader(inputStream, Constants.DEFAULT_ENCODING)); char[] buf = new char[8192]; int read = -1; while ((read = br.read(buf)) != -1) { listingDocBuffer.append(buf, 0, read); } br.close(); // Replace any carriage return (\r) characters with explicit XML // character entities, to prevent the SAX parser from // misinterpreting 0x0D characters as 0x0A. String listingDoc = listingDocBuffer.toString().replaceAll("\r", " "); sanitizedInputStream = new ByteArrayInputStream( listingDoc.getBytes(Constants.DEFAULT_ENCODING)); } catch (Throwable t) { try { inputStream.close(); } catch (IOException e) { if (log.isErrorEnabled()) { log.error("Unable to close response InputStream after failure sanitizing XML document", e); } } throw new ServiceException("Failed to sanitize XML document destined for handler " + handler.getClass(), t); } return sanitizedInputStream; } } /** * Parses a ListBucket response XML document from an input stream. * @param inputStream * XML data input stream. * @return * the XML handler object populated with data parsed from the XML stream. * @throws ServiceException */ public ListBucketHandler parseListBucketResponse(InputStream inputStream) throws ServiceException { ListBucketHandler handler = new ListBucketHandler(); parseXmlInputStream(handler, sanitizeXmlDocument(handler, inputStream)); return handler; } /** * Parses a ListAllMyBuckets response XML document from an input stream. * @param inputStream * XML data input stream. * @return * the XML handler object populated with data parsed from the XML stream. * @throws ServiceException */ public ListAllMyBucketsHandler parseListMyBucketsResponse(InputStream inputStream) throws ServiceException { ListAllMyBucketsHandler handler = new ListAllMyBucketsHandler(); parseXmlInputStream(handler, sanitizeXmlDocument(handler, inputStream)); return handler; } /** * Parses an AccessControlListHandler response XML document from an input stream. * * @param inputStream * XML data input stream. * @return * the XML handler object populated with data parsed from the XML stream. * * @throws ServiceException */ public AccessControlListHandler parseAccessControlListResponse(InputStream inputStream) throws ServiceException { AccessControlListHandler handler = null; if (this.isGoogleStorageMode) { handler = new GSAccessControlListHandler(); } else { handler = new AccessControlListHandler(); } return parseAccessControlListResponse(inputStream, handler); } /** * Parses an AccessControlListHandler response XML document from an input stream. * * @param inputStream * XML data input stream. * @param handler * the instance of AccessControlListHandler to be used. * @return * the XML handler object populated with data parsed from the XML stream. * * @throws ServiceException */ public AccessControlListHandler parseAccessControlListResponse(InputStream inputStream, AccessControlListHandler handler) throws ServiceException { parseXmlInputStream(handler, inputStream); return handler; } /** * Parses a LoggingStatus response XML document for a bucket from an input stream. * * @param inputStream * XML data input stream. * @return * the XML handler object populated with data parsed from the XML stream. * * @throws ServiceException */ public BucketLoggingStatusHandler parseLoggingStatusResponse(InputStream inputStream) throws ServiceException { BucketLoggingStatusHandler handler = new BucketLoggingStatusHandler(); parseXmlInputStream(handler, inputStream); return handler; } public String parseBucketLocationResponse(InputStream inputStream) throws ServiceException { BucketLocationHandler handler = new BucketLocationHandler(); parseXmlInputStream(handler, inputStream); return handler.getLocation(); } public CopyObjectResultHandler parseCopyObjectResponse(InputStream inputStream) throws ServiceException { CopyObjectResultHandler handler = new CopyObjectResultHandler(); parseXmlInputStream(handler, inputStream); return handler; } /** * @param inputStream * * @return * true if the bucket is configured as Requester Pays, false if it is * configured as Owner pays. * * @throws ServiceException */ public boolean parseRequestPaymentConfigurationResponse(InputStream inputStream) throws ServiceException { RequestPaymentConfigurationHandler handler = new RequestPaymentConfigurationHandler(); parseXmlInputStream(handler, inputStream); return handler.isRequesterPays(); } /** * @param inputStream * * @return * true if the bucket has versioning enabled, false otherwise. * * @throws ServiceException */ public S3BucketVersioningStatus parseVersioningConfigurationResponse( InputStream inputStream) throws ServiceException { VersioningConfigurationHandler handler = new VersioningConfigurationHandler(); parseXmlInputStream(handler, inputStream); return handler.getVersioningStatus(); } public ListVersionsResultsHandler parseListVersionsResponse(InputStream inputStream) throws ServiceException { ListVersionsResultsHandler handler = new ListVersionsResultsHandler(); parseXmlInputStream(handler, sanitizeXmlDocument(handler, inputStream)); return handler; } public MultipartUpload parseInitiateMultipartUploadResult(InputStream inputStream) throws ServiceException { MultipartUploadResultHandler handler = new MultipartUploadResultHandler(xr); parseXmlInputStream(handler, sanitizeXmlDocument(handler, inputStream)); return handler.getMultipartUpload(); } public ListMultipartUploadsResultHandler parseListMultipartUploadsResult( InputStream inputStream) throws ServiceException { ListMultipartUploadsResultHandler handler = new ListMultipartUploadsResultHandler(xr); parseXmlInputStream(handler, sanitizeXmlDocument(handler, inputStream)); return handler; } public ListMultipartPartsResultHandler parseListMultipartPartsResult( InputStream inputStream) throws ServiceException { ListMultipartPartsResultHandler handler = new ListMultipartPartsResultHandler(xr); parseXmlInputStream(handler, sanitizeXmlDocument(handler, inputStream)); return handler; } public CompleteMultipartUploadResultHandler parseCompleteMultipartUploadResult( InputStream inputStream) throws ServiceException { CompleteMultipartUploadResultHandler handler = new CompleteMultipartUploadResultHandler(xr); parseXmlInputStream(handler, sanitizeXmlDocument(handler, inputStream)); return handler; } public WebsiteConfig parseWebsiteConfigurationResponse( InputStream inputStream) throws ServiceException { WebsiteConfigurationHandler handler = new WebsiteConfigurationHandler(); parseXmlInputStream(handler, inputStream); return handler.getWebsiteConfig(); } public NotificationConfig parseNotificationConfigurationResponse( InputStream inputStream) throws ServiceException { NotificationConfigurationHandler handler = new NotificationConfigurationHandler(); parseXmlInputStream(handler, inputStream); return handler.getNotificationConfig(); } ////////////// // Handlers // ////////////// /** * Handler for ListBucket response XML documents. * The document is parsed into {@link S3Object}s available via the {@link #getObjects()} method. */ public class ListBucketHandler extends DefaultXmlHandler { private StorageObject currentObject = null; private StorageOwner currentOwner = null; private boolean insideCommonPrefixes = false; private final List objects = new ArrayList(); private final List commonPrefixes = new ArrayList(); // Listing properties. private String bucketName = null; private String requestPrefix = null; private String requestMarker = null; private long requestMaxKeys = 0; private boolean listingTruncated = false; private String lastKey = null; private String nextMarker = null; /** * If the listing is truncated this method will return the marker that should be used * in subsequent bucket list calls to complete the listing. * * @return * null if the listing is not truncated, otherwise the next marker if it's available or * the last object key seen if the next marker isn't available. */ public String getMarkerForNextListing() { if (listingTruncated) { if (nextMarker != null) { return nextMarker; } else if (lastKey != null) { return lastKey; } else { if (log.isWarnEnabled()) { log.warn("Unable to find Next Marker or Last Key for truncated listing"); } return null; } } else { return null; } } /** * @return * true if the listing document was truncated, and therefore only contained a subset of the * available S3 objects. */ public boolean isListingTruncated() { return listingTruncated; } /** * @return * the S3 objects contained in the listing. */ public StorageObject[] getObjects() { return objects.toArray(new StorageObject[objects.size()]); } public String[] getCommonPrefixes() { return commonPrefixes.toArray(new String[commonPrefixes.size()]); } public String getRequestPrefix() { return requestPrefix; } public String getRequestMarker() { return requestMarker; } public String getNextMarker() { return nextMarker; } public long getRequestMaxKeys() { return requestMaxKeys; } @Override public void startElement(String name) { if (name.equals("Contents")) { currentObject = newObject(); if (currentObject instanceof S3Object) { ((S3Object)currentObject).setBucketName(bucketName); } } else if (name.equals("Owner")) { currentOwner = newOwner(); currentObject.setOwner(currentOwner); } else if (name.equals("CommonPrefixes")) { insideCommonPrefixes = true; } } @Override public void endElement(String name, String elementText) { // Listing details if (name.equals("Name")) { bucketName = elementText; if (log.isDebugEnabled()) { log.debug("Examining listing for bucket: " + bucketName); } } else if (!insideCommonPrefixes && name.equals("Prefix")) { requestPrefix = elementText; } else if (name.equals("Marker")) { requestMarker = elementText; } else if (name.equals("NextMarker")) { nextMarker = elementText; } else if (name.equals("MaxKeys")) { requestMaxKeys = Long.parseLong(elementText); } else if (name.equals("IsTruncated")) { String isTruncatedStr = elementText.toLowerCase(Locale.getDefault()); if (isTruncatedStr.startsWith("false")) { listingTruncated = false; } else if (isTruncatedStr.startsWith("true")) { listingTruncated = true; } else { throw new RuntimeException("Invalid value for IsTruncated field: " + isTruncatedStr); } } // Object details. else if (name.equals("Contents")) { objects.add(currentObject); if (log.isDebugEnabled()) { log.debug("Created new object from listing: " + currentObject); } } else if (name.equals("Key")) { currentObject.setKey(elementText); lastKey = elementText; } else if (name.equals("LastModified")) { try { currentObject.setLastModifiedDate(ServiceUtils.parseIso8601Date(elementText)); } catch (ParseException e) { throw new RuntimeException( "Non-ISO8601 date for LastModified in bucket's object listing output: " + elementText, e); } } else if (name.equals("ETag")) { currentObject.setETag(elementText); } else if (name.equals("Size")) { currentObject.setContentLength(Long.parseLong(elementText)); } else if (name.equals("StorageClass")) { currentObject.setStorageClass(elementText); } // Owner details. else if (name.equals("ID")) { // Work-around to support Eucalyptus responses, which do not // contain Owner elements. if (currentOwner == null) { currentOwner = newOwner(); currentObject.setOwner(currentOwner); } currentOwner.setId(elementText); } else if (name.equals("DisplayName")) { currentOwner.setDisplayName(elementText); } // Common prefixes. else if (insideCommonPrefixes && name.equals("Prefix")) { commonPrefixes.add(elementText); } else if (name.equals("CommonPrefixes")) { insideCommonPrefixes = false; } } } /** * Handler for ListAllMyBuckets response XML documents. The document is parsed into * {@link StorageBucket}s available via the {@link #getBuckets()} method. * * @author James Murty * */ public class ListAllMyBucketsHandler extends DefaultXmlHandler { private StorageOwner bucketsOwner = null; private StorageBucket currentBucket = null; private final List buckets = new ArrayList(); /** * @return * the buckets listed in the document. */ public StorageBucket[] getBuckets() { return buckets.toArray(new StorageBucket[buckets.size()]); } /** * @return * the owner of the buckets. */ public StorageOwner getOwner() { return bucketsOwner; } @Override public void startElement(String name) { if (name.equals("Bucket")) { currentBucket = newBucket(); } else if (name.equals("Owner")) { bucketsOwner = newOwner(); } } @Override public void endElement(String name, String elementText) { // Listing details. if (name.equals("ID")) { bucketsOwner.setId(elementText); } else if (name.equals("DisplayName")) { bucketsOwner.setDisplayName(elementText); } // Bucket item details. else if (name.equals("Bucket")) { if (log.isDebugEnabled()) { log.debug("Created new bucket from listing: " + currentBucket); } currentBucket.setOwner(bucketsOwner); buckets.add(currentBucket); } else if (name.equals("Name")) { currentBucket.setName(elementText); } else if (name.equals("CreationDate")) { elementText += ".000Z"; try { currentBucket.setCreationDate(ServiceUtils.parseIso8601Date(elementText)); } catch (ParseException e) { throw new RuntimeException( "Non-ISO8601 date for CreationDate in list buckets output: " + elementText, e); } } } } /** * Handler for LoggingStatus response XML documents for a bucket. * The document is parsed into an {@link S3BucketLoggingStatus} object available via the * {@link #getBucketLoggingStatus()} method. * * @author James Murty * */ public class BucketLoggingStatusHandler extends DefaultXmlHandler { private S3BucketLoggingStatus bucketLoggingStatus = null; private String targetBucket = null; private String targetPrefix = null; private GranteeInterface currentGrantee = null; private Permission currentPermission = null; /** * @return * an object representing the bucket's LoggingStatus document. */ public S3BucketLoggingStatus getBucketLoggingStatus() { return bucketLoggingStatus; } @Override public void startElement(String name) { if (name.equals("BucketLoggingStatus")) { bucketLoggingStatus = new S3BucketLoggingStatus(); } } @Override public void endElement(String name, String elementText) { if (name.equals("TargetBucket")) { targetBucket = elementText; } else if (name.equals("TargetPrefix")) { targetPrefix = elementText; } else if (name.equals("LoggingEnabled")) { bucketLoggingStatus.setTargetBucketName(targetBucket); bucketLoggingStatus.setLogfilePrefix(targetPrefix); } // Handle TargetGrants ACLs else if (name.equals("ID")) { currentGrantee = new CanonicalGrantee(); currentGrantee.setIdentifier(elementText); } else if (name.equals("EmailAddress")) { currentGrantee = new EmailAddressGrantee(); currentGrantee.setIdentifier(elementText); } else if (name.equals("URI")) { currentGrantee = new GroupGrantee(); currentGrantee.setIdentifier(elementText); } else if (name.equals("DisplayName")) { ((CanonicalGrantee) currentGrantee).setDisplayName(elementText); } else if (name.equals("Permission")) { currentPermission = Permission.parsePermission(elementText); } else if (name.equals("Grant")) { GrantAndPermission grantAndPermission = new GrantAndPermission( currentGrantee, currentPermission); bucketLoggingStatus.addTargetGrant(grantAndPermission); } } } /** * Handler for CreateBucketConfiguration response XML documents for a bucket. * The document is parsed into a String representing the bucket's location, * available via the {@link #getLocation()} method. * * @author James Murty * */ public class BucketLocationHandler extends DefaultXmlHandler { private String location = null; /** * @return * the bucket's location. */ public String getLocation() { return location; } @Override public void endElement(String name, String elementText) { if (name.equals("LocationConstraint")) { if (elementText.length() == 0) { location = null; } else { location = elementText; } } } } public class CopyObjectResultHandler extends DefaultXmlHandler { // Data items for successful copy private String etag = null; private Date lastModified = null; // Data items for failed copy private String errorCode = null; private String errorMessage = null; private String errorRequestId = null; private String errorHostId = null; private boolean receivedErrorResponse = false; public Date getLastModified() { return lastModified; } public String getETag() { return etag; } public String getErrorCode() { return errorCode; } public String getErrorHostId() { return errorHostId; } public String getErrorMessage() { return errorMessage; } public String getErrorRequestId() { return errorRequestId; } public boolean isErrorResponse() { return receivedErrorResponse; } @Override public void startElement(String name) { if (name.equals("CopyObjectResult")) { receivedErrorResponse = false; } else if (name.equals("Error")) { receivedErrorResponse = true; } } @Override public void endElement(String name, String elementText) { if (name.equals("LastModified")) { try { lastModified = ServiceUtils.parseIso8601Date(elementText); } catch (ParseException e) { throw new RuntimeException( "Non-ISO8601 date for LastModified in copy object output: " + elementText, e); } } else if (name.equals("ETag")) { etag = elementText; } else if (name.equals("Code")) { errorCode = elementText; } else if (name.equals("Message")) { errorMessage = elementText; } else if (name.equals("RequestId")) { errorRequestId = elementText; } else if (name.equals("HostId")) { errorHostId = elementText; } } } /** * Handler for RequestPaymentConfiguration response XML documents for a bucket. * The document is parsed into a boolean value: true if the bucket is configured * as Requester Pays, false if it is configured as Owner pays. This boolean value * is available via the {@link #isRequesterPays()} method. * * @author James Murty */ public class RequestPaymentConfigurationHandler extends DefaultXmlHandler { private String payer = null; /** * @return * true if the bucket is configured as Requester Pays, false if it is * configured as Owner pays. */ public boolean isRequesterPays() { return "Requester".equals(payer); } @Override public void endElement(String name, String elementText) { if (name.equals("Payer")) { payer = elementText; } } } public class VersioningConfigurationHandler extends DefaultXmlHandler { private S3BucketVersioningStatus versioningStatus = null; private String status = null; private String mfaStatus = null; public S3BucketVersioningStatus getVersioningStatus() { return this.versioningStatus; } @Override public void endElement(String name, String elementText) { if (name.equals("Status")) { this.status = elementText; } else if (name.equals("MfaDelete")) { this.mfaStatus = elementText; } else if (name.equals("VersioningConfiguration")) { this.versioningStatus = new S3BucketVersioningStatus( "Enabled".equals(status), "Enabled".equals(mfaStatus)); } } } public class ListVersionsResultsHandler extends DefaultXmlHandler { private final List items = new ArrayList(); private final List commonPrefixes = new ArrayList(); private String key = null; private String versionId = null; private boolean isLatest = false; private Date lastModified = null; private StorageOwner owner = null; private String etag = null; private long size = 0; private String storageClass = null; private boolean insideCommonPrefixes = false; // Listing properties. private String bucketName = null; private String requestPrefix = null; private String keyMarker = null; private String versionIdMarker = null; private long requestMaxKeys = 0; private boolean listingTruncated = false; private String nextMarker = null; private String nextVersionIdMarker = null; /** * @return * true if the listing document was truncated, and therefore only contained a subset of the * available S3 objects. */ public boolean isListingTruncated() { return listingTruncated; } /** * @return * the S3 objects contained in the listing. */ public BaseVersionOrDeleteMarker[] getItems() { return items.toArray(new BaseVersionOrDeleteMarker[items.size()]); } public String[] getCommonPrefixes() { return commonPrefixes.toArray(new String[commonPrefixes.size()]); } public String getRequestPrefix() { return requestPrefix; } public String getKeyMarker() { return keyMarker; } public String getVersionIdMarker() { return versionIdMarker; } public String getNextKeyMarker() { return nextMarker; } public String getNextVersionIdMarker() { return nextVersionIdMarker; } public long getRequestMaxKeys() { return requestMaxKeys; } @Override public void startElement(String name) { if (name.equals("Owner")) { owner = null; } else if (name.equals("CommonPrefixes")) { insideCommonPrefixes = true; } } @Override public void endElement(String name, String elementText) { // Listing details if (name.equals("Name")) { bucketName = elementText; if (log.isDebugEnabled()) { log.debug("Examining listing for bucket: " + bucketName); } } else if (!insideCommonPrefixes && name.equals("Prefix")) { requestPrefix = elementText; } else if (name.equals("KeyMarker")) { keyMarker = elementText; } else if (name.equals("NextKeyMarker")) { nextMarker = elementText; } else if (name.equals("VersionIdMarker")) { versionIdMarker = elementText; } else if (name.equals("NextVersionIdMarker")) { nextVersionIdMarker = elementText; } else if (name.equals("MaxKeys")) { requestMaxKeys = Long.parseLong(elementText); } else if (name.equals("IsTruncated")) { String isTruncatedStr = elementText.toLowerCase(Locale.getDefault()); if (isTruncatedStr.startsWith("false")) { listingTruncated = false; } else if (isTruncatedStr.startsWith("true")) { listingTruncated = true; } else { throw new RuntimeException("Invalid value for IsTruncated field: " + isTruncatedStr); } } // Version/DeleteMarker finished. else if (name.equals("Version")) { BaseVersionOrDeleteMarker item = new S3Version(key, versionId, isLatest, lastModified, (S3Owner)owner, etag, size, storageClass); items.add(item); } else if (name.equals("DeleteMarker")) { BaseVersionOrDeleteMarker item = new S3DeleteMarker(key, versionId, isLatest, lastModified, (S3Owner)owner); items.add(item); // Version/DeleteMarker details } else if (name.equals("Key")) { key = elementText; } else if (name.equals("VersionId")) { versionId = elementText; } else if (name.equals("IsLatest")) { isLatest = "true".equals(elementText); } else if (name.equals("LastModified")) { try { lastModified = ServiceUtils.parseIso8601Date(elementText); } catch (ParseException e) { throw new RuntimeException( "Non-ISO8601 date for LastModified in bucket's versions listing output: " + elementText, e); } } else if (name.equals("ETag")) { etag = elementText; } else if (name.equals("Size")) { size = Long.parseLong(elementText); } else if (name.equals("StorageClass")) { storageClass = elementText; } // Owner details. else if (name.equals("ID")) { owner = newOwner(); owner.setId(elementText); } else if (name.equals("DisplayName")) { owner.setDisplayName(elementText); } // Common prefixes. else if (insideCommonPrefixes && name.equals("Prefix")) { commonPrefixes.add(elementText); } else if (name.equals("CommonPrefixes")) { insideCommonPrefixes = false; } } } public class OwnerHandler extends SimpleHandler { private String id; private String displayName; public OwnerHandler(XMLReader xr) { super(xr); } public StorageOwner getOwner() { StorageOwner owner = newOwner(); owner.setId(id); owner.setDisplayName(displayName); return owner; } public void endID(String text) { this.id = text; } public void endDisplayName(String text) { this.displayName = text; } public void endOwner(String text) { returnControlToParentHandler(); } // represents end of an owner item in ListMultipartUploadsResult/Upload public void endInitiator(String text) { returnControlToParentHandler(); } } public class MultipartUploadResultHandler extends SimpleHandler { private String uploadId; private String bucketName; private String objectKey; private String storageClass; private S3Owner owner; private S3Owner initiator; private Date initiatedDate; private boolean inInitiator = false; public MultipartUploadResultHandler(XMLReader xr) { super(xr); } public MultipartUpload getMultipartUpload() { if (initiatedDate != null) { // Return the contents from a ListMultipartUploadsResult response return new MultipartUpload(uploadId, objectKey, storageClass, initiator, owner, initiatedDate); } else { // Return the contents from an InitiateMultipartUploadsResult response return new MultipartUpload(uploadId, bucketName, objectKey); } } public void endUploadId(String text) { this.uploadId = text; } public void endBucket(String text) { this.bucketName = text; } public void endKey(String text) { this.objectKey = text; } public void endStorageClass(String text) { this.storageClass = text; } public void endInitiated(String text) throws ParseException { this.initiatedDate = ServiceUtils.parseIso8601Date(text); } public void startOwner() { inInitiator = false; transferControlToHandler(new OwnerHandler(xr)); } public void startInitiator() { inInitiator = true; transferControlToHandler(new OwnerHandler(xr)); } @Override public void controlReturned(SimpleHandler childHandler) { if (inInitiator) { this.owner = (S3Owner) ((OwnerHandler) childHandler).getOwner(); } else { this.initiator = (S3Owner) ((OwnerHandler) childHandler).getOwner(); } } // represents end of a MultipartUpload item in ListMultipartUploadsResult public void endUpload(String text) { returnControlToParentHandler(); } } public class ListMultipartUploadsResultHandler extends SimpleHandler { private final List uploads = new ArrayList(); private String bucketName = null; private String keyMarker = null; private String uploadIdMarker = null; private String nextKeyMarker = null; private String nextUploadIdMarker = null; private int maxUploads = 1000; private boolean isTruncated = false; public ListMultipartUploadsResultHandler(XMLReader xr) { super(xr); } public List getMultipartUploadList() { // Update multipart upload objects with overall bucket name for (MultipartUpload upload: uploads) { upload.setBucketName(bucketName); } return uploads; } public boolean isTruncated() { return isTruncated; } public String getKeyMarker() { return keyMarker; } public String getUploadIdMarker() { return uploadIdMarker; } public String getNextKeyMarker() { return nextKeyMarker; } public String getNextUploadIdMarker() { return nextUploadIdMarker; } public int getMaxUploads() { return maxUploads; } public void startUpload() { transferControlToHandler(new MultipartUploadResultHandler(xr)); } @Override public void controlReturned(SimpleHandler childHandler) { uploads.add( ((MultipartUploadResultHandler) childHandler).getMultipartUpload()); } public void endBucket(String text) { this.bucketName = text; } public void endKeyMarker(String text) { this.keyMarker = text; } public void endUploadIdMarker(String text) { this.uploadIdMarker = text; } public void endNextKeyMarker(String text) { this.nextKeyMarker = text; } public void endNextUploadIdMarker(String text) { this.nextUploadIdMarker = text; } public void endMaxUploads(String text) { this.maxUploads = Integer.parseInt(text); } public void endIsTruncated(String text) { this.isTruncated = "true".equalsIgnoreCase(text); } } public class MultipartPartResultHandler extends SimpleHandler { private Integer partNumber; private Date lastModified; private String etag; private Long size; public MultipartPartResultHandler(XMLReader xr) { super(xr); } public MultipartPart getMultipartPart() { return new MultipartPart(partNumber, lastModified, etag, size); } public void endPartNumber(String text) { this.partNumber = Integer.parseInt(text); } public void endLastModified(String text) throws ParseException { this.lastModified = ServiceUtils.parseIso8601Date(text); } public void endETag(String text) { this.etag = text; } public void endSize(String text) { this.size = Long.parseLong(text); } // represents end of a Part item in ListPartsResultHandler/Part public void endPart(String text) { returnControlToParentHandler(); } } public class ListMultipartPartsResultHandler extends SimpleHandler { private final List parts = new ArrayList(); private String bucketName = null; private String objectKey = null; private String uploadId = null; private S3Owner initiator = null; private S3Owner owner = null; private String storageClass = null; private String partNumberMarker = null; private String nextPartNumberMarker = null; private int maxParts = 1000; private boolean isTruncated = false; private boolean inInitiator = false; public ListMultipartPartsResultHandler(XMLReader xr) { super(xr); } public List getMultipartPartList() { return parts; } public boolean isTruncated() { return isTruncated; } public String getBucketName() { return bucketName; } public String getObjectKey() { return objectKey; } public String getUploadId() { return uploadId; } public S3Owner getInitiator() { return initiator; } public S3Owner getOwner() { return owner; } public String getStorageClass() { return storageClass; } public String getPartNumberMarker() { return partNumberMarker; } public String getNextPartNumberMarker() { return nextPartNumberMarker; } public int getMaxParts() { return maxParts; } public void startPart() { transferControlToHandler(new MultipartPartResultHandler(xr)); } @Override public void controlReturned(SimpleHandler childHandler) { if (childHandler instanceof MultipartPartResultHandler) { parts.add( ((MultipartPartResultHandler) childHandler).getMultipartPart()); } else { if (inInitiator) { initiator = (S3Owner)((OwnerHandler)childHandler).getOwner(); } else { owner = (S3Owner)((OwnerHandler)childHandler).getOwner(); } } } public void startInitiator() { inInitiator = true; transferControlToHandler(new OwnerHandler(xr)); } public void startOwner() { inInitiator = false; transferControlToHandler(new OwnerHandler(xr)); } public void endBucket(String text) { this.bucketName = text; } public void endKey(String text) { this.objectKey = text; } public void endStorageClass(String text) { this.storageClass = text; } public void endUploadId(String text) { this.uploadId = text; } public void endPartNumberMarker(String text) { this.partNumberMarker = text; } public void endNextPartNumberMarker(String text) { this.nextPartNumberMarker = text; } public void endMaxParts(String text) { this.maxParts = Integer.parseInt(text); } public void endIsTruncated(String text) { this.isTruncated = "true".equalsIgnoreCase(text); } } public class CompleteMultipartUploadResultHandler extends SimpleHandler { private String location; private String bucketName; private String objectKey; private String etag; private ServiceException serviceException = null; public CompleteMultipartUploadResultHandler(XMLReader xr) { super(xr); } public MultipartCompleted getMultipartCompleted() { return new MultipartCompleted(location, bucketName, objectKey, etag); } public ServiceException getServiceException() { return serviceException; } public void endLocation(String text) { this.location = text; } public void endBucket(String text) { this.bucketName = text; } public void endKey(String text) { this.objectKey = text; } public void endETag(String text) { this.etag = text; } public void startError() { transferControlToHandler(new CompleteMultipartUploadErrorHandler(xr)); } @Override public void controlReturned(SimpleHandler childHandler) { this.serviceException = ((CompleteMultipartUploadErrorHandler)childHandler) .getServiceException(); } } public class CompleteMultipartUploadErrorHandler extends SimpleHandler { private String code = null; private String message = null; private String etag = null; private Long minSizeAllowed = null; private Long proposedSize = null; private String hostId = null; private Integer partNumber = null; private String requestId = null; public CompleteMultipartUploadErrorHandler(XMLReader xr) { super(xr); } public ServiceException getServiceException() { String fullMessage = message + ": PartNumber=" + partNumber + ", MinSizeAllowed=" + minSizeAllowed + ", ProposedSize=" + proposedSize + ", ETag=" + etag; ServiceException e = new ServiceException(fullMessage); e.setErrorCode(code); e.setErrorMessage(message); e.setErrorHostId(hostId); e.setErrorRequestId(requestId); return e; } public void endCode(String text) { this.code = text; } public void endMessage(String text) { this.message = text; } public void endETag(String text) { this.etag = text; } public void endMinSizeAllowed(String text) { this.minSizeAllowed = Long.parseLong(text); } public void endProposedSize(String text) { this.proposedSize = Long.parseLong(text); } public void endHostId(String text) { this.hostId = text; } public void endPartNumber(String text) { this.partNumber = Integer.parseInt(text); } public void endRequestId(String text) { this.requestId = text; } public void endError(String text) { returnControlToParentHandler(); } } public class WebsiteConfigurationHandler extends DefaultXmlHandler { private WebsiteConfig config = null; private String indexDocumentSuffix = null; private String errorDocumentKey = null; public WebsiteConfig getWebsiteConfig() { return config; } @Override public void endElement(String name, String elementText) { if (name.equals("Suffix")) { this.indexDocumentSuffix = elementText; } else if (name.equals("Key")) { this.errorDocumentKey = elementText; } else if (name.equals("WebsiteConfiguration")) { this.config = new WebsiteConfig( indexDocumentSuffix, errorDocumentKey); } } } public class NotificationConfigurationHandler extends DefaultXmlHandler { private NotificationConfig config = new NotificationConfig(); private String lastTopic = null; private String lastEvent = null; public NotificationConfig getNotificationConfig() { return config; } @Override public void endElement(String name, String elementText) { if (name.equals("Topic")) { this.lastTopic = elementText; } else if (name.equals("Event")) { this.lastEvent = elementText; config.addTopicConfig(config.new TopicConfig( this.lastTopic, this.lastEvent)); } else if (name.equals("NotificationConfiguration")) { } } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/impl/rest/GSAccessControlListHandler.java0000644000000000000000000001065411452167414025654 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.impl.rest; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.acl.Permission; import org.jets3t.service.acl.gs.AllAuthenticatedUsersGrantee; import org.jets3t.service.acl.gs.AllUsersGrantee; import org.jets3t.service.acl.gs.GSAccessControlList; import org.jets3t.service.acl.gs.GroupByDomainGrantee; import org.jets3t.service.acl.gs.GroupByEmailAddressGrantee; import org.jets3t.service.acl.gs.GroupByIdGrantee; import org.jets3t.service.acl.gs.UserByEmailAddressGrantee; import org.jets3t.service.acl.gs.UserByIdGrantee; import org.jets3t.service.model.GSOwner; import org.xml.sax.Attributes; /** * Handler for GSAccessControlList response XML documents. * The document is parsed into an {@link AccessControlList} object available via the * {@link #getAccessControlList()} method. * * @author Google Developers * */ public class GSAccessControlListHandler extends AccessControlListHandler { protected String scopeType = null; @Override public void startElement(String name, Attributes attrs) { if (name.equals("Owner")) { owner = new GSOwner(); } else if (name.equals("Entries")) { accessControlList = new GSAccessControlList(); accessControlList.setOwner(owner); insideACL = true; } else if (name.equals("Scope")) { scopeType = attrs.getValue("type"); if (scopeType.equals("UserById")) { currentGrantee = new UserByIdGrantee(); } else if (scopeType.equals("UserByEmail")) { currentGrantee = new UserByEmailAddressGrantee(); } else if (scopeType.equals("GroupById")) { currentGrantee = new GroupByIdGrantee(); } else if (scopeType.equals("GroupByEmail")) { currentGrantee = new GroupByEmailAddressGrantee(); } else if (scopeType.equals("GroupByDomain")) { currentGrantee = new GroupByDomainGrantee(); } else if (scopeType.equals("AllUsers")) { currentGrantee = new AllUsersGrantee(); } else if (scopeType.equals("AllAuthenticatedUsers")) { currentGrantee = new AllAuthenticatedUsersGrantee(); } } } @Override public void endElement(String name, String elementText) { // Owner details. if (name.equals("ID") && !insideACL) { owner.setId(elementText); } else if (name.equals("Name") && !insideACL) { owner.setDisplayName(elementText); } // ACL details. else if (name.equals("ID")) { currentGrantee.setIdentifier(elementText); } else if (name.equals("EmailAddress")) { currentGrantee.setIdentifier(elementText); } else if (name.equals("URI")) { currentGrantee.setIdentifier(elementText); } else if (name.equals("Name")) { if (currentGrantee instanceof UserByIdGrantee) { ((UserByIdGrantee) currentGrantee).setName(elementText); } else if (currentGrantee instanceof UserByEmailAddressGrantee) { ((UserByEmailAddressGrantee) currentGrantee).setName(elementText); } else if (currentGrantee instanceof GroupByIdGrantee) { ((GroupByIdGrantee) currentGrantee).setName(elementText); } else if (currentGrantee instanceof GroupByEmailAddressGrantee) { ((GroupByEmailAddressGrantee) currentGrantee).setName(elementText); } } else if (name.equals("Permission")) { currentPermission = Permission.parsePermission(elementText); } else if (name.equals("Entry")) { accessControlList.grantPermission(currentGrantee, currentPermission); } else if (name.equals("Entries")) { insideACL = false; } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/impl/rest/CloudFrontXmlResponsesSaxParser.java0000644000000000000000000007073611550421156027023 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.impl.rest; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.text.ParseException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.CloudFrontServiceException; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.S3ServiceException; import org.jets3t.service.ServiceException; import org.jets3t.service.model.cloudfront.CustomOrigin; import org.jets3t.service.model.cloudfront.Distribution; import org.jets3t.service.model.cloudfront.DistributionConfig; import org.jets3t.service.model.cloudfront.Invalidation; import org.jets3t.service.model.cloudfront.InvalidationList; import org.jets3t.service.model.cloudfront.InvalidationSummary; import org.jets3t.service.model.cloudfront.LoggingStatus; import org.jets3t.service.model.cloudfront.Origin; import org.jets3t.service.model.cloudfront.OriginAccessIdentity; import org.jets3t.service.model.cloudfront.OriginAccessIdentityConfig; import org.jets3t.service.model.cloudfront.S3Origin; import org.jets3t.service.model.cloudfront.StreamingDistribution; import org.jets3t.service.model.cloudfront.StreamingDistributionConfig; import org.jets3t.service.utils.ServiceUtils; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; /** * XML Sax parser to read XML documents returned by the CloudFront service via * the REST interface, and convert these documents into JetS3t objects. * * @author James Murty */ public class CloudFrontXmlResponsesSaxParser { private static final Log log = LogFactory.getLog(CloudFrontXmlResponsesSaxParser.class); private XMLReader xr = null; private Jets3tProperties properties = null; /** * Constructs the XML SAX parser. * * @param properties * the JetS3t properties that will be applied when parsing XML documents. * * @throws S3ServiceException */ public CloudFrontXmlResponsesSaxParser(Jets3tProperties properties) throws ServiceException { this.properties = properties; this.xr = ServiceUtils.loadXMLReader(); } public Jets3tProperties getProperties() { return this.properties; } /** * Parses an XML document from an input stream using a document handler. * @param handler * the handler for the XML document * @param inputStream * an input stream containing the XML document to parse * @throws S3ServiceException * any parsing, IO or other exceptions are wrapped in an S3ServiceException. */ protected void parseXmlInputStream(DefaultHandler handler, InputStream inputStream) throws CloudFrontServiceException { try { if (log.isDebugEnabled()) { log.debug("Parsing XML response document with handler: " + handler.getClass()); } BufferedReader breader = new BufferedReader(new InputStreamReader(inputStream, Constants.DEFAULT_ENCODING)); xr.setContentHandler(handler); xr.setErrorHandler(handler); xr.parse(new InputSource(breader)); } catch (Throwable t) { try { inputStream.close(); } catch (IOException e) { if (log.isErrorEnabled()) { log.error("Unable to close response InputStream up after XML parse failure", e); } } throw new CloudFrontServiceException("Failed to parse XML document with handler " + handler.getClass(), t); } } /** * Parses a ListBucket response XML document from an input stream. * @param inputStream * XML data input stream. * @return * the XML handler object populated with data parsed from the XML stream. * @throws CloudFrontServiceException */ public DistributionListHandler parseDistributionListResponse(InputStream inputStream) throws CloudFrontServiceException { DistributionListHandler handler = new DistributionListHandler(xr); parseXmlInputStream(handler, inputStream); return handler; } public DistributionHandler parseDistributionResponse(InputStream inputStream) throws CloudFrontServiceException { DistributionHandler handler = new DistributionHandler(xr); parseXmlInputStream(handler, inputStream); return handler; } public DistributionConfigHandler parseDistributionConfigResponse(InputStream inputStream) throws CloudFrontServiceException { DistributionConfigHandler handler = new DistributionConfigHandler(xr); parseXmlInputStream(handler, inputStream); return handler; } public OriginAccessIdentityHandler parseOriginAccessIdentity( InputStream inputStream) throws CloudFrontServiceException { OriginAccessIdentityHandler handler = new OriginAccessIdentityHandler(xr); parseXmlInputStream(handler, inputStream); return handler; } public OriginAccessIdentityConfigHandler parseOriginAccessIdentityConfig( InputStream inputStream) throws CloudFrontServiceException { OriginAccessIdentityConfigHandler handler = new OriginAccessIdentityConfigHandler(xr); parseXmlInputStream(handler, inputStream); return handler; } public OriginAccessIdentityListHandler parseOriginAccessIdentityListResponse( InputStream inputStream) throws CloudFrontServiceException { OriginAccessIdentityListHandler handler = new OriginAccessIdentityListHandler(xr); parseXmlInputStream(handler, inputStream); return handler; } public InvalidationHandler parseInvalidationResponse( InputStream inputStream) throws CloudFrontServiceException { InvalidationHandler handler = new InvalidationHandler(xr); parseXmlInputStream(handler, inputStream); return handler; } public InvalidationListHandler parseInvalidationListResponse( InputStream inputStream) throws CloudFrontServiceException { InvalidationListHandler handler = new InvalidationListHandler(xr); parseXmlInputStream(handler, inputStream); return handler; } public ErrorHandler parseErrorResponse(InputStream inputStream) throws CloudFrontServiceException { ErrorHandler handler = new ErrorHandler(xr); parseXmlInputStream(handler, inputStream); return handler; } // //////////// // Handlers // // //////////// public class DistributionHandler extends SimpleHandler { private Distribution distribution = null; private String id = null; private String status = null; private Date lastModifiedTime = null; private String domainName = null; private final Map> activeTrustedSigners = new HashMap>(); private boolean inSignerElement; private String lastSignerIdentifier = null; public DistributionHandler(XMLReader xr) { super(xr); } public Distribution getDistribution() { return distribution; } public void endId(String text) { this.id = text; } public void endStatus(String text) { this.status = text; } public void endLastModifiedTime(String text) throws ParseException { this.lastModifiedTime = ServiceUtils.parseIso8601Date(text); } public void endDomainName(String text) { this.domainName = text; } // Handle ActiveTrustedSigner elements // public void startSigner() { inSignerElement = true; } public void endSigner(String text) { inSignerElement = false; lastSignerIdentifier = null; } public void endSelf(String text) { if (inSignerElement) { lastSignerIdentifier = "Self"; } } public void endAwsAccountNumber(String text) { if (inSignerElement) { lastSignerIdentifier = text; } } public void endKeyPairId(String text) { if (inSignerElement) { List keypairIdList = activeTrustedSigners.get(lastSignerIdentifier); if (keypairIdList == null) { keypairIdList = new ArrayList(); activeTrustedSigners.put(lastSignerIdentifier, keypairIdList); } keypairIdList.add(text); } } // End handle ActiveTrustedSigner elements // public void startDistributionConfig() { transferControlToHandler(new DistributionConfigHandler(xr)); } public void startStreamingDistributionConfig() { transferControlToHandler(new DistributionConfigHandler(xr)); } @Override public void controlReturned(SimpleHandler childHandler) { DistributionConfig config = ((DistributionConfigHandler) childHandler).getDistributionConfig(); if (config instanceof StreamingDistributionConfig) { this.distribution = new StreamingDistribution(id, status, lastModifiedTime, domainName, activeTrustedSigners, config); } else { this.distribution = new Distribution(id, status, lastModifiedTime, domainName, activeTrustedSigners, config); } } // End of a normal Distribution public void endDistribution(String text) { returnControlToParentHandler(); } // End of a StreamingDistribution public void endStreamingDistribution(String text) { returnControlToParentHandler(); } } public class DistributionConfigHandler extends SimpleHandler { private DistributionConfig distributionConfig = null; private String callerReference = ""; private Origin origin = null; private final List cnamesList = new ArrayList(); private String comment = ""; private boolean enabled = false; private LoggingStatus loggingStatus = null; private boolean trustedSignerSelf = false; private final List trustedSignerAwsAccountNumberList = new ArrayList(); private final List requiredProtocols = new ArrayList(); private String defaultRootObject = null; public DistributionConfigHandler(XMLReader xr) { super(xr); } public DistributionConfig getDistributionConfig() { return distributionConfig; } public void endCallerReference(String text) { this.callerReference = text; } public void startS3Origin() { transferControlToHandler(new OriginHandler(xr)); } public void startCustomOrigin() { transferControlToHandler(new OriginHandler(xr)); } @Override public void controlReturned(SimpleHandler childHandler) { this.origin = ((OriginHandler) childHandler).origin; } public void endCNAME(String text) { this.cnamesList.add(text); } public void endComment(String text) { this.comment = text; } public void endEnabled(String text) { this.enabled = "true".equalsIgnoreCase(text); } public void startLogging() { this.loggingStatus = new LoggingStatus(); } public void endBucket(String text) { this.loggingStatus.setBucket(text); } public void endPrefix(String text) { this.loggingStatus.setPrefix(text); } public void endSelf(String text) { this.trustedSignerSelf = true; } public void endAwsAccountNumber(String text) { this.trustedSignerAwsAccountNumberList.add(text); } public void endProtocol(String text) { this.requiredProtocols.add(text); } public void endDefaultRootObject(String text) { this.defaultRootObject = text; } public void endDistributionConfig(String text) { this.distributionConfig = new DistributionConfig( origin, callerReference, cnamesList.toArray(new String[cnamesList.size()]), comment, enabled, loggingStatus, trustedSignerSelf, trustedSignerAwsAccountNumberList.toArray( new String[trustedSignerAwsAccountNumberList.size()]), requiredProtocols.toArray( new String[requiredProtocols.size()]), defaultRootObject ); returnControlToParentHandler(); } public void endStreamingDistributionConfig(String text) { this.distributionConfig = new StreamingDistributionConfig( origin, callerReference, cnamesList.toArray(new String[cnamesList.size()]), comment, enabled, loggingStatus, trustedSignerSelf, trustedSignerAwsAccountNumberList.toArray( new String[trustedSignerAwsAccountNumberList.size()]), requiredProtocols.toArray( new String[requiredProtocols.size()]) ); returnControlToParentHandler(); } } public class DistributionSummaryHandler extends SimpleHandler { private Distribution distribution = null; private String id = null; private String status = null; private Date lastModifiedTime = null; private String domainName = null; private Origin origin = null; private final List cnamesList = new ArrayList(); private String comment = null; private boolean enabled = false; public DistributionSummaryHandler(XMLReader xr) { super(xr); } public Distribution getDistribution() { return distribution; } public void endId(String text) { this.id = text; } public void endStatus(String text) { this.status = text; } public void endLastModifiedTime(String text) throws ParseException { this.lastModifiedTime = ServiceUtils.parseIso8601Date(text); } public void endDomainName(String text) { this.domainName = text; } public void startS3Origin() { transferControlToHandler(new OriginHandler(xr)); } public void startCustomOrigin() { transferControlToHandler(new OriginHandler(xr)); } @Override public void controlReturned(SimpleHandler childHandler) { this.origin = ((OriginHandler) childHandler).origin; } public void endCNAME(String text) { this.cnamesList.add(text); } public void endComment(String text) { this.comment = text; } public void endEnabled(String text) { this.enabled = "true".equalsIgnoreCase(text); } public void endDistributionSummary(String text) { this.distribution = new Distribution(id, status, lastModifiedTime, domainName, origin, cnamesList.toArray(new String[cnamesList.size()]), comment, enabled); returnControlToParentHandler(); } public void endStreamingDistributionSummary(String text) { this.distribution = new StreamingDistribution(id, status, lastModifiedTime, domainName, origin, cnamesList.toArray(new String[cnamesList.size()]), comment, enabled); returnControlToParentHandler(); } } public class DistributionListHandler extends SimpleHandler { private final List distributions = new ArrayList(); private final List cnamesList = new ArrayList(); private String marker = null; private String nextMarker = null; private int maxItems = 100; private boolean isTruncated = false; public DistributionListHandler(XMLReader xr) { super(xr); } public List getDistributions() { return distributions; } public boolean isTruncated() { return isTruncated; } public String getMarker() { return marker; } public String getNextMarker() { return nextMarker; } public int getMaxItems() { return maxItems; } public void startDistributionSummary() { transferControlToHandler(new DistributionSummaryHandler(xr)); } public void startStreamingDistributionSummary() { transferControlToHandler(new DistributionSummaryHandler(xr)); } @Override public void controlReturned(SimpleHandler childHandler) { distributions.add( ((DistributionSummaryHandler) childHandler).getDistribution()); } public void endCNAME(String text) { this.cnamesList.add(text); } public void endMarker(String text) { this.marker = text; } public void endNextMarker(String text) { this.nextMarker = text; } public void endMaxItems(String text) { this.maxItems = Integer.parseInt(text); } public void endIsTruncated(String text) { this.isTruncated = "true".equalsIgnoreCase(text); } } public class OriginHandler extends SimpleHandler { protected Origin origin = null; private String dnsName = ""; private String originAccessIdentity = null; // S3Origin private String httpPort = null; // CustomOrigin private String httpsPort = null; // CustomOrigin private String originProtocolPolicy = null; // CustomOrigin public OriginHandler(XMLReader xr) { super(xr); } public void endDNSName(String text) { this.dnsName = text; } public void endOriginAccessIdentity(String text) { this.originAccessIdentity = text; } public void endHTTPPort(String text) { this.httpPort = text; } public void endHTTPSPort(String text) { this.httpsPort = text; } public void endOriginProtocolPolicy(String text) { this.originProtocolPolicy = text; } public void endS3Origin(String text) { this.origin = new S3Origin(this.dnsName, this.originAccessIdentity); returnControlToParentHandler(); } public void endCustomOrigin(String text) { this.origin = new CustomOrigin(this.dnsName, CustomOrigin.OriginProtocolPolicy.fromText(this.originProtocolPolicy), Integer.valueOf(this.httpPort), Integer.valueOf(this.httpsPort)); returnControlToParentHandler(); } } public class OriginAccessIdentityHandler extends SimpleHandler { private String id = null; private String s3CanonicalUserId = null; private String comment = null; private OriginAccessIdentity originAccessIdentity = null; private OriginAccessIdentityConfig originAccessIdentityConfig = null; public OriginAccessIdentityHandler(XMLReader xr) { super(xr); } public OriginAccessIdentity getOriginAccessIdentity() { return this.originAccessIdentity; } public void endId(String text) { this.id = text; } public void endS3CanonicalUserId(String text) { this.s3CanonicalUserId = text; } public void endComment(String text) { this.comment = text; } public void startCloudFrontOriginAccessIdentityConfig() { transferControlToHandler(new OriginAccessIdentityConfigHandler(xr)); } @Override public void controlReturned(SimpleHandler childHandler) { this.originAccessIdentityConfig = ((OriginAccessIdentityConfigHandler) childHandler).getOriginAccessIdentityConfig(); } public void endCloudFrontOriginAccessIdentity(String text) { this.originAccessIdentity = new OriginAccessIdentity( this.id, this.s3CanonicalUserId, this.originAccessIdentityConfig); } public void endCloudFrontOriginAccessIdentitySummary(String text) { this.originAccessIdentity = new OriginAccessIdentity( this.id, this.s3CanonicalUserId, this.comment); returnControlToParentHandler(); } } public class OriginAccessIdentityConfigHandler extends SimpleHandler { private String callerReference = null; private String comment = null; private OriginAccessIdentityConfig config = null; public OriginAccessIdentityConfigHandler(XMLReader xr) { super(xr); } public OriginAccessIdentityConfig getOriginAccessIdentityConfig() { return this.config; } public void endCallerReference(String text) { this.callerReference = text; } public void endComment(String text) { this.comment = text; } public void endCloudFrontOriginAccessIdentityConfig(String text) { this.config = new OriginAccessIdentityConfig(this.callerReference, this.comment); returnControlToParentHandler(); } } public class OriginAccessIdentityListHandler extends SimpleHandler { private final List originAccessIdentityList = new ArrayList(); private String marker = null; private String nextMarker = null; private int maxItems = 100; private boolean isTruncated = false; public OriginAccessIdentityListHandler(XMLReader xr) { super(xr); } public List getOriginAccessIdentityList() { return this.originAccessIdentityList; } public boolean isTruncated() { return isTruncated; } public String getMarker() { return marker; } public String getNextMarker() { return nextMarker; } public int getMaxItems() { return maxItems; } public void startCloudFrontOriginAccessIdentitySummary() { transferControlToHandler(new OriginAccessIdentityHandler(xr)); } @Override public void controlReturned(SimpleHandler childHandler) { originAccessIdentityList.add( ((OriginAccessIdentityHandler) childHandler).getOriginAccessIdentity()); } public void endMarker(String text) { this.marker = text; } public void endNextMarker(String text) { this.nextMarker = text; } public void endMaxItems(String text) { this.maxItems = Integer.parseInt(text); } public void endIsTruncated(String text) { this.isTruncated = "true".equalsIgnoreCase(text); } } public class InvalidationListHandler extends SimpleHandler { private String marker = null; private String nextMarker = null; private int maxItems = 100; private boolean isTruncated = false; private String invalidationSummaryId = null; private String invalidationSummaryStatus = null; private List invalidationSummaries = new ArrayList(); private InvalidationList invalidationList = null; public InvalidationListHandler(XMLReader xr) { super(xr); } public InvalidationList getInvalidationList() { return invalidationList; } public boolean isTruncated() { return isTruncated; } public String getMarker() { return marker; } public String getNextMarker() { return nextMarker; } public int getMaxItems() { return maxItems; } public void endMarker(String text) { this.marker = text; } public void endNextMarker(String text) { this.nextMarker = text; } public void endMaxItems(String text) { this.maxItems = Integer.parseInt(text); } public void endIsTruncated(String text) { this.isTruncated = "true".equalsIgnoreCase(text); } // Inside InvalidationSummary public void endId(String text) { this.invalidationSummaryId = text; } // Inside InvalidationSummary public void endStatus(String text) { this.invalidationSummaryStatus = text; this.invalidationSummaries.add(new InvalidationSummary( this.invalidationSummaryId, this.invalidationSummaryStatus)); } public void endInvalidationList(String ignore) { this.invalidationList = new InvalidationList( this.marker, this.nextMarker, this.maxItems, this.isTruncated, this.invalidationSummaries); } } public class InvalidationHandler extends SimpleHandler { private Invalidation invalidation = new Invalidation(); public InvalidationHandler(XMLReader xr) { super(xr); } public Invalidation getInvalidation() { return this.invalidation; } public void endId(String text) { this.invalidation.setId(text); } public void endStatus(String text) { this.invalidation.setStatus(text); } public void endCreateTime(String text) throws ParseException { this.invalidation.setCreateTime( ServiceUtils.parseIso8601Date(text)); } public void endPath(String text) { this.invalidation.getObjectKeys().add(text.substring(1)); } public void endCallerReference(String text) { this.invalidation.setCallerReference(text); } } public class ErrorHandler extends SimpleHandler { private String type = null; private String code = null; private String message = null; private String detail = null; private String requestId = null; public ErrorHandler(XMLReader xr) { super(xr); } public String getCode() { return code; } public String getDetail() { return detail; } public String getMessage() { return message; } public String getRequestId() { return requestId; } public String getType() { return type; } public void endType(String text) { this.type = text; } public void endCode(String text) { this.code = text; } public void endMessage(String text) { this.message = text; } public void endDetail(String text) { this.detail = text; } public void endRequestId(String text) { this.requestId = text; } // Handle annoying case where request id is in // the element "RequestID", not "RequestId" public void endRequestID(String text) { this.requestId = text; } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/impl/rest/AccessControlListHandler.java0000644000000000000000000000700311452167426025417 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2007 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.impl.rest; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.acl.CanonicalGrantee; import org.jets3t.service.acl.EmailAddressGrantee; import org.jets3t.service.acl.GranteeInterface; import org.jets3t.service.acl.GroupGrantee; import org.jets3t.service.acl.Permission; import org.jets3t.service.model.S3Owner; import org.jets3t.service.model.StorageOwner; /** * Handler for AccessControlList response XML documents. * The document is parsed into an {@link org.jets3t.service.acl.AccessControlList} object available via the * {@link #getAccessControlList()} method. * * @author James Murty * */ public class AccessControlListHandler extends DefaultXmlHandler { protected AccessControlList accessControlList = null; protected StorageOwner owner = null; protected GranteeInterface currentGrantee = null; protected Permission currentPermission = null; protected boolean insideACL = false; /** * @return * an object representing the ACL document. */ public AccessControlList getAccessControlList() { return accessControlList; } @Override public void startElement(String name) { if (name.equals("Owner")) { owner = new S3Owner(); } else if (name.equals("AccessControlList")) { accessControlList = new AccessControlList(); accessControlList.setOwner(owner); insideACL = true; } } @Override public void endElement(String name, String elementText) { // Owner details. if (name.equals("ID") && !insideACL) { owner.setId(elementText); } else if (name.equals("DisplayName") && !insideACL) { owner.setDisplayName(elementText); } // ACL details. else if (name.equals("ID")) { currentGrantee = new CanonicalGrantee(); currentGrantee.setIdentifier(elementText); } else if (name.equals("EmailAddress")) { currentGrantee = new EmailAddressGrantee(); currentGrantee.setIdentifier(elementText); } else if (name.equals("URI")) { currentGrantee = new GroupGrantee(); currentGrantee.setIdentifier(elementText); } else if (name.equals("DisplayName")) { // In some cases we may get a DisplayName field for non-canonical grantees. if (currentGrantee instanceof CanonicalGrantee) { ((CanonicalGrantee) currentGrantee).setDisplayName(elementText); } } else if (name.equals("Permission")) { currentPermission = Permission.parsePermission(elementText); } else if (name.equals("Grant")) { accessControlList.grantPermission(currentGrantee, currentPermission); } else if (name.equals("AccessControlList")) { insideACL = false; } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/impl/rest/SimpleHandler.java0000644000000000000000000000614311537563564023265 0ustar package org.jets3t.service.impl.rest; import java.lang.reflect.Method; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.xml.sax.Attributes; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; public class SimpleHandler extends DefaultHandler { private static final Log log = LogFactory.getLog(SimpleHandler.class); private XMLReader xr = null; private StringBuffer textContent = null; protected SimpleHandler currentHandler = null; protected SimpleHandler parentHandler = null; public SimpleHandler(XMLReader xr) { this.xr = xr; this.textContent = new StringBuffer(); currentHandler = this; } public void transferControlToHandler(SimpleHandler toHandler) { currentHandler = toHandler; toHandler.parentHandler = this; xr.setContentHandler(currentHandler); xr.setErrorHandler(currentHandler); } public void returnControlToParentHandler() { if (isChildHandler()) { parentHandler.currentHandler = parentHandler; parentHandler.controlReturned(this); currentHandler = parentHandler; xr.setContentHandler(currentHandler); xr.setErrorHandler(currentHandler); } else { log.debug("Ignoring call to return control to parent handler, as this class has no parent: " + this.getClass().getName()); } } public boolean isChildHandler() { return parentHandler != null; } public void controlReturned(SimpleHandler childHandler) {} @Override public void startElement(String uri, String name, String qName, Attributes attrs) { try { Method method = currentHandler.getClass().getMethod("start" + name, new Class[] {}); method.invoke(currentHandler, new Object[] {}); } catch (NoSuchMethodException e) { log.debug("Skipped non-existent SimpleHandler subclass's startElement method for '" + name + "' in " + this.getClass().getName()); } catch (Throwable t) { log.error("Unable to invoke SimpleHandler subclass's startElement method for '" + name + "' in " + this.getClass().getName(), t); } } @Override public void endElement(String uri, String name, String qName) { String elementText = this.textContent.toString().trim(); try { Method method = currentHandler.getClass().getMethod("end" + name, new Class[] {String.class}); method.invoke(currentHandler, new Object[] {elementText}); } catch (NoSuchMethodException e) { log.debug("Skipped non-existent SimpleHandler subclass's endElement method for '" + name + "' in " + this.getClass().getName()); } catch (Throwable t) { log.error("Unable to invoke SimpleHandler subclass's endElement method for '" + name + "' in " + this.getClass().getName(), t); } this.textContent = new StringBuffer(); } @Override public void characters(char ch[], int start, int length) { this.textContent.append(ch, start, length); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/S3ServiceException.java0000644000000000000000000000617011537563564022305 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service; /** * Exception for use by S3Services and related utilities. * This exception can hold useful additional information about errors that occur * when communicating with S3. * * @author James Murty */ public class S3ServiceException extends ServiceException { private static final long serialVersionUID = -4594639645399926038L; /** * Constructor that includes the XML error document returned by S3. * @param message * @param xmlMessage */ public S3ServiceException(String message, String xmlMessage) { super(message, xmlMessage); } public S3ServiceException() { super(); } public S3ServiceException(String message, Throwable cause) { super(message, cause); } public S3ServiceException(String message) { super(message); } public S3ServiceException(Throwable cause) { super(cause); } /** * Wrap a ServiceException as an S3ServiceException. * @param se */ public S3ServiceException(ServiceException se) { super(se.getMessage(), se.getXmlMessage(), se.getCause()); this.setResponseHeaders(se.getResponseHeaders()); this.setResponseCode(se.getResponseCode()); this.setResponseStatus(se.getResponseStatus()); this.setResponseDate(se.getResponseDate()); this.setRequestVerb(se.getRequestVerb()); this.setRequestPath(se.getRequestPath()); this.setRequestHost(se.getRequestHost()); } /** * @return The service-specific Error Code returned by S3, if an S3 response is available. * For example "AccessDenied", "InternalError" * Null otherwise. */ public String getS3ErrorCode() { return this.getErrorCode(); } /** * @return The service-specific Error Message returned by S3, if an S3 response is available. * For example: "Access Denied", "We encountered an internal error. Please try again." */ public String getS3ErrorMessage() { return this.getErrorMessage(); } /** * @return The Error Host ID returned by S3, if an S3 response is available. * Null otherwise. */ public String getS3ErrorHostId() { return this.getErrorHostId(); } /** * @return The Error Request ID returned by S3, if an S3 response is available. * Null otherwise. */ public String getS3ErrorRequestId() { return this.getErrorRequestId(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/CloudFrontServiceException.java0000644000000000000000000000565611441613550024070 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service; /** * Exception for use by CloudFrontService and related utilities. * This exception can hold useful additional information about errors that occur * when communicating with CloudFront. * * @author James Murty */ public class CloudFrontServiceException extends Exception { private static final long serialVersionUID = -3139479267586698970L; private int responseCode = -1; private String errorType = null; private String errorCode = null; private String errorMessage = null; private String errorDetail = null; private String errorRequestId = null; public CloudFrontServiceException(String message, int responseCode, String errorType, String errorCode, String errorMessage, String errorDetail, String errorRequestId) { super(message); this.responseCode = responseCode; this.errorType = errorType; this.errorCode = errorCode; this.errorMessage = errorMessage; this.errorDetail = errorDetail; this.errorRequestId = errorRequestId; } public CloudFrontServiceException() { super(); } public CloudFrontServiceException(String message, Throwable cause) { super(message, cause); } public CloudFrontServiceException(String message) { super(message); } public CloudFrontServiceException(Throwable cause) { super(cause); } public String getErrorCode() { return errorCode; } public String getErrorDetail() { return errorDetail; } public String getErrorMessage() { return errorMessage; } public String getErrorRequestId() { return errorRequestId; } public String getErrorType() { return errorType; } public int getResponseCode() { return responseCode; } public String toString() { if (responseCode == -1) { return super.toString(); } else { return "CloudFrontServiceException: httpResponseCode=" + responseCode + ", errorType=" + errorType + ", errorCode=" + errorCode + ", errorMessage=" + errorMessage + ", errorDetail=" + errorDetail + ", errorRequestId=" + errorRequestId; } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/mx/0002755000000000000000000000000011441613550016360 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/mx/MxDelegate.java0000644000000000000000000001342011441613550021240 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2009 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.mx; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.model.StorageBucket; import org.jets3t.service.model.StorageObject; public class MxDelegate implements MxInterface { private static final Log log = LogFactory.getLog(MxDelegate.class); private MxInterface handler = null; private static MxDelegate instance = null; public static MxDelegate getInstance() { if (instance == null) { instance = new MxDelegate(); } return instance; } protected MxDelegate() { } /** * Initialize, or reinitialize, the JMX instrumentation support in JetS3t. This method * must be invoked at least once within a JVM for the JMX instrumentation * to work. When JetS3t's instrumentation is enabled Service and Exception events are always * logged, whereas Bucket and Object event logging must be specifically enabled. *

* This method checks the given properties for the following System properties: * * * * * * *
PropertyEffect
com.sun.management.jmxremoteIf present, enable JMX instrumentation for JetS3t for Java 1.5. On Java 1.5 this * System setting is required to enable JMX in general, and if it is present then * we automatically enable instrumentation for JetS3t as well.
jets3t.mxIf present, enable JMX instrumentation for JetS3t for Java 1.6+. Because Java * 1.6+ no longer requires the "com.sun.management.jmxremote" System setting for JMX to * be enabled in general, this property can be used as a substitute that allows * users to decide whether JetS3t's JMX instrumentation should be turned on or off. *
*/ public void init() { if (System.getProperty("com.sun.management.jmxremote") == null && System.getProperty("jets3t.mx") == null) { this.handler = null; return; } try { // Load the contribs.mx.MxImpl implementation class, if available. Class impl = Class.forName("contribs.mx.MxImpl"); this.handler = (MxInterface) impl.newInstance(); } catch (ClassNotFoundException e) { log.error( "JMX instrumentation package 'contribs.mx' could not be found, " + " instrumentation will not available", e); } catch (RuntimeException e) { throw e; } catch (Exception e) { log.error( "JMX instrumentation implementation in package 'contribs.mx' " + " could not be loaded", e); } } /** * @return * true if the JetS3t's JMX delegate has been initialized and activated. */ public boolean isJmxDelegationActive() { return this.handler != null; } public void registerS3ServiceMBean() { if (handler != null) { handler.registerS3ServiceMBean(); } } public void registerS3ServiceExceptionMBean() { if (handler != null) { handler.registerS3ServiceExceptionMBean(); } } public void registerS3ServiceExceptionEvent() { if (handler != null) { handler.registerS3ServiceExceptionEvent(); } } public void registerS3ServiceExceptionEvent(String s3ErrorCode) { if (handler != null) { handler.registerS3ServiceExceptionEvent(s3ErrorCode); } } public void registerStorageBucketMBeans(StorageBucket[] buckets) { if (handler != null) { handler.registerStorageBucketMBeans(buckets); } } public void registerStorageBucketListEvent(String bucketName) { if (handler != null) { handler.registerStorageBucketListEvent(bucketName); } } public void registerStorageObjectMBean(String bucketName, StorageObject[] objects) { if (handler != null) { handler.registerStorageObjectMBean(bucketName, objects); } } public void registerStorageObjectPutEvent(String bucketName, String key) { if (handler != null) { handler.registerStorageObjectPutEvent(bucketName, key); } } public void registerStorageObjectGetEvent(String bucketName, String key) { if (handler != null) { handler.registerStorageObjectGetEvent(bucketName, key); } } public void registerStorageObjectHeadEvent(String bucketName, String key) { if (handler != null) { handler.registerStorageObjectHeadEvent(bucketName, key); } } public void registerStorageObjectDeleteEvent(String bucketName, String key) { if (handler != null) { handler.registerStorageObjectDeleteEvent(bucketName, key); } } public void registerStorageObjectCopyEvent(String bucketName, String key) { if (handler != null) { handler.registerStorageObjectCopyEvent(bucketName, key); } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/service/mx/MxInterface.java0000644000000000000000000000342511441613550021432 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2009 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.service.mx; import org.jets3t.service.model.StorageBucket; import org.jets3t.service.model.StorageObject; public interface MxInterface { public abstract void registerS3ServiceMBean(); public abstract void registerS3ServiceExceptionMBean(); public abstract void registerS3ServiceExceptionEvent(); public abstract void registerS3ServiceExceptionEvent(String s3ErrorCode); public abstract void registerStorageBucketMBeans(StorageBucket[] buckets); public abstract void registerStorageBucketListEvent(String bucketName); public abstract void registerStorageObjectMBean(String bucketName, StorageObject[] objects); public abstract void registerStorageObjectPutEvent(String bucketName, String key); public abstract void registerStorageObjectGetEvent(String bucketName, String key); public abstract void registerStorageObjectHeadEvent(String bucketName, String key); public abstract void registerStorageObjectDeleteEvent(String bucketName, String key); public abstract void registerStorageObjectCopyEvent(String bucketName, String key); } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/0002755000000000000000000000000011332474152015241 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/synchronize/0002755000000000000000000000000011550442512017611 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/synchronize/CommandLineCredentialsProvider.java0000644000000000000000000000715411427702124026541 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.synchronize; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.NTCredentials; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.httpclient.auth.AuthScheme; import org.apache.commons.httpclient.auth.CredentialsNotAvailableException; import org.apache.commons.httpclient.auth.CredentialsProvider; import org.apache.commons.httpclient.auth.NTLMScheme; import org.apache.commons.httpclient.auth.RFC2617Scheme; /** * Prompts for the user to enter HTTP Proxy authentication credentials via the * command line. * * @author James Murty */ public class CommandLineCredentialsProvider implements CredentialsProvider { /** * Implementation method for the CredentialsProvider interface. *

* Based on sample code: * InteractiveAuthenticationExample * */ public Credentials getCredentials(AuthScheme authscheme, String host, int port, boolean proxy) throws CredentialsNotAvailableException { if (authscheme == null) { return null; } try { Credentials credentials = null; BufferedReader inputReader = new BufferedReader(new InputStreamReader(System.in)); if (authscheme instanceof NTLMScheme) { System.out.println("Proxy Authentication Required -- " + "Host " + host + ":" + port + " requires Windows authentication"); System.out.print("Username: "); String username = inputReader.readLine(); System.out.print("Password: "); String password = inputReader.readLine(); System.out.print("Domain: "); String domain = inputReader.readLine(); credentials = new NTCredentials(username, password, host, domain); } else if (authscheme instanceof RFC2617Scheme) { System.out.println("Proxy Authentication Required -- " + "Host " + host + ":" + port + " requires authentication for the realm: " + authscheme.getRealm()); System.out.print("Username: "); String username = inputReader.readLine(); System.out.print("Password: "); String password = inputReader.readLine(); credentials = new UsernamePasswordCredentials(username, password); } else { throw new CredentialsNotAvailableException("Unsupported authentication scheme: " + authscheme.getSchemeName()); } return credentials; } catch (IOException e) { throw new CredentialsNotAvailableException(e.getMessage(), e); } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/synchronize/Synchronize.java0000644000000000000000000023216411550441162022775 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.synchronize; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.security.NoSuchAlgorithmException; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.S3Service; import org.jets3t.service.ServiceException; import org.jets3t.service.StorageService; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.impl.rest.httpclient.GoogleStorageService; import org.jets3t.service.impl.rest.httpclient.RestS3Service; import org.jets3t.service.io.BytesProgressWatcher; import org.jets3t.service.model.StorageBucket; import org.jets3t.service.model.StorageObject; import org.jets3t.service.multi.DownloadPackage; import org.jets3t.service.multi.ThreadWatcher; import org.jets3t.service.multi.ThreadedStorageService; import org.jets3t.service.multi.event.CreateObjectsEvent; import org.jets3t.service.multi.event.DeleteObjectsEvent; import org.jets3t.service.multi.event.DownloadObjectsEvent; import org.jets3t.service.multi.event.GetObjectHeadsEvent; import org.jets3t.service.multi.event.ServiceEvent; import org.jets3t.service.multi.s3.MultipartCompletesEvent; import org.jets3t.service.multi.s3.MultipartStartsEvent; import org.jets3t.service.multi.s3.MultipartUploadsEvent; import org.jets3t.service.multi.s3.S3ServiceEventAdaptor; import org.jets3t.service.security.AWSCredentials; import org.jets3t.service.security.EncryptionUtil; import org.jets3t.service.security.GSCredentials; import org.jets3t.service.security.ProviderCredentials; import org.jets3t.service.utils.ByteFormatter; import org.jets3t.service.utils.FileComparer; import org.jets3t.service.utils.FileComparerResults; import org.jets3t.service.utils.Mimetypes; import org.jets3t.service.utils.MultipartUtils; import org.jets3t.service.utils.ObjectUtils; import org.jets3t.service.utils.TimeFormatter; import org.jets3t.service.utils.FileComparer.PartialObjectListing; /** * Console application to synchronize the local file system with a storage service. * For more information and help please see the * Synchronize Guide. * * @author James Murty */ public class Synchronize { /** * String provided to service as User-Agent description. */ public static final String APPLICATION_DESCRIPTION = "Synchronize/" + Constants.JETS3T_VERSION; protected static final int REPORT_LEVEL_NONE = 0; protected static final int REPORT_LEVEL_ACTIONS = 1; protected static final int REPORT_LEVEL_DIFFERENCES = 2; protected static final int REPORT_LEVEL_ALL = 3; private StorageService storageService = null; private boolean doAction = false; // Files will only be transferred if true. private boolean isQuiet = false; // Report will only include summary of actions if true. private boolean isNoProgress = false; // Progress messages are not displayed if true. private boolean isForce = false; // Files will be overwritten when unchanged if true. private boolean isKeepFiles = false; // Files will not be replaced/deleted if true. private boolean isNoDelete = false; // Files will not be deleted if true, but may be replaced. private boolean isGzipEnabled = false; // Files will be gzipped prior to upload if true. private boolean isEncryptionEnabled = false; // Files will be encrypted prior to upload if true. private boolean isMoveEnabled = false; private boolean isBatchMode = false; private int reportLevel = REPORT_LEVEL_ALL; private String cryptoPassword = null; private Jets3tProperties properties = null; private final ByteFormatter byteFormatter = new ByteFormatter(); private final TimeFormatter timeFormatter = new TimeFormatter(); private FileComparer fileComparer = null; private int maxTemporaryStringLength = 0; private final Map customMetadata = new HashMap(); /** * Constructs the application with a pre-initialised service and the user-specified options. * * @param service * a pre-initialised service (including Provider credentials) * @param doAction * Files will only be transferred if true. * @param isQuiet * Report will only include summary of actions if true. * @param isNoProgress * Upload/download progress updates will not be printed. * @param isForce * Files will be overwritten when unchanged if true. * @param isKeepFiles * Files will not be replaced/deleted if true. * @param isMoveEnabled * If true, items will be moved rather than just copied. Files will be * deleted after they have been uploaded, and objects will be deleted * after they have been downloaded. * @param isBatchMode * If true, uploads or downloads will proceed in batches rather than all at * once. This mode is useful for large buckets where listing all the * objects and their details at once may consume a large amount of time * and memory. * @param isNoDelete * Files will not be deleted if true, but may be replaced. * @param isGzipEnabled * Files will be gzipped prior to upload if true. * @param isEncryptionEnabled * Files will be encrypted prior to upload if true. * @param reportLevel * The level or amount of reporting to perform. The default value is * {@link #REPORT_LEVEL_ALL}. * @param properties * The configuration properties that will be used by this instance. */ public Synchronize(StorageService service, boolean doAction, boolean isQuiet, boolean isNoProgress, boolean isForce, boolean isKeepFiles, boolean isNoDelete, boolean isMoveEnabled, boolean isBatchMode, boolean isGzipEnabled, boolean isEncryptionEnabled, int reportLevel, Jets3tProperties properties) { this.storageService = service; this.doAction = doAction; this.isQuiet = isQuiet; this.isNoProgress = isNoProgress; this.isForce = isForce; this.isKeepFiles = isKeepFiles; this.isNoDelete = isNoDelete; this.isMoveEnabled = isMoveEnabled; this.isBatchMode = isBatchMode; this.isGzipEnabled = isGzipEnabled; this.isEncryptionEnabled = isEncryptionEnabled; this.reportLevel = reportLevel; this.properties = properties; this.fileComparer = FileComparer.getInstance(properties); // Find any custom metadata items specified in property files Iterator> myPropertiesIter = this.properties.getProperties().entrySet().iterator(); while (myPropertiesIter.hasNext()) { Entry entry = myPropertiesIter.next(); String keyName = entry.getKey().toString().toLowerCase(); if (entry.getKey() != null && keyName.startsWith("upload.metadata.")) { String metadataName = entry.getKey().toString() .substring("upload.metadata.".length()); String metadataValue = entry.getValue().toString(); this.customMetadata.put(metadataName, metadataValue); } } } /** * Prepares a file to be uploaded to the service, creating an object with the * appropriate key and with some jets3t-specific metadata items set. */ class LazyPreparedUploadObject { private final String targetKey; private final File file; private final String aclString; private final EncryptionUtil encryptionUtil; /** * @param targetKey * the key name for the object * @param file * the file to upload * @param aclString * the ACL to apply to the uploaded object * @param encryptionUtil * the object to apply encryption, or null if no encryption is required */ public LazyPreparedUploadObject(String targetKey, File file, String aclString, EncryptionUtil encryptionUtil) { this.targetKey = targetKey; this.file = file; this.aclString = aclString; this.encryptionUtil = encryptionUtil; } public StorageObject prepareUploadObject() throws Exception { StorageObject newObject = ObjectUtils .createObjectForUpload(targetKey, file, encryptionUtil, isGzipEnabled, null); if ("PUBLIC_READ".equalsIgnoreCase(aclString)) { newObject.setAcl(AccessControlList.REST_CANNED_PUBLIC_READ); } else if ("PUBLIC_READ_WRITE".equalsIgnoreCase(aclString)) { newObject.setAcl(AccessControlList.REST_CANNED_PUBLIC_READ_WRITE); } else if ("PRIVATE".equalsIgnoreCase(aclString)) { // Private is the default, no need to add an ACL } else { throw new Exception("Invalid value for ACL string: " + aclString); } // Apply custom metadata items to upload object. newObject.addAllMetadata(customMetadata); return newObject; } public File getFile() { return file; } } private String formatTransferDetails(ThreadWatcher watcher) { String detailsText = ""; long bytesPerSecond = watcher.getBytesPerSecond(); detailsText = byteFormatter.formatByteSize(bytesPerSecond) + "/s"; if (watcher.isTimeRemainingAvailable()) { if (detailsText.trim().length() > 0) { detailsText += " - "; } long secondsRemaining = watcher.getTimeRemaining(); detailsText += "ETA: " + timeFormatter.formatTime(secondsRemaining, false); } return detailsText; } private void printOutputLine(String line, int level) { if ((isQuiet && level > REPORT_LEVEL_NONE) || reportLevel < level) { return; } String blanks = ""; for (int i = line.length(); i < maxTemporaryStringLength; i++) { blanks += " "; } System.out.println(line + blanks); maxTemporaryStringLength = 0; } /** * Prints text to StdOut provided the isQuiet and isNoProgress flags are not set. * * @param line the text to print */ private void printProgressLine(String line) { if (isQuiet || isNoProgress) { return; } String temporaryLine = " " + line; if (temporaryLine.length() > maxTemporaryStringLength) { maxTemporaryStringLength = temporaryLine.length(); } String blanks = ""; for (int i = temporaryLine.length(); i < maxTemporaryStringLength; i++) { blanks += " "; } System.out.print(temporaryLine + blanks + "\r"); } protected ComparisonResult compareLocalAndRemoteFiles( FileComparerResults mergedDiscrepancyResults, String bucketName, String rootObjectPath, String priorLastKey, Map objectKeyToFilepathMap, BytesProgressWatcher md5GenerationProgressWatcher) throws ServiceException, NoSuchAlgorithmException, FileNotFoundException, IOException, ParseException { // List objects in service. Listing may be complete, or partial. printProgressLine("Listing objects in service" + (isBatchMode && mergedDiscrepancyResults.getCountOfItemsCompared() > 0 ? " (Continuing in batches, objects listed previously: " + mergedDiscrepancyResults.getCountOfItemsCompared() + ")" : "")); PartialObjectListing partialListing = fileComparer.buildObjectMapPartial( storageService, bucketName, rootObjectPath, priorLastKey, objectKeyToFilepathMap, !isBatchMode, md5GenerationProgressWatcher, serviceEventAdaptor); if (serviceEventAdaptor.wasErrorThrown()) { throw new ServiceException("Unable to build map of objects", serviceEventAdaptor.getErrorThrown()); } md5GenerationProgressWatcher.resetWatcher(); // Retrieve details from listing. priorLastKey = partialListing.getPriorLastKey(); Map objectsMap = partialListing.getObjectsMap(); // Compare the listed objects with the local system. printProgressLine("Comparing service contents with local system"); FileComparerResults discrepancyResults = fileComparer.buildDiscrepancyLists( objectKeyToFilepathMap, objectsMap, md5GenerationProgressWatcher); // Merge objects and discrepancies to track overall changes. mergedDiscrepancyResults.merge(discrepancyResults); ComparisonResult result = new ComparisonResult(); result.priorLastKey = priorLastKey; result.objectsMap = objectsMap; result.discrepancyResults = discrepancyResults; return result; } /** * Copies the contents of a local directory to a service, storing them in the given root path. *

* A set of comparisons is used to determine exactly how the local files differ from the * contents of the service location, and files are transferred based on these comparisons and * options set by the user. *

* The following object properties are set when a file is uploaded: *

    *
  • The object's key name
  • *
  • Content-Length: The size of the uploaded file. This will be 0 for directories, and will * differ from the original file if gzip or encryption options are set.
  • *
  • Content-Type: {@link Mimetypes#MIMETYPE_BINARY_OCTET_STREAM} for directories, otherwise a * mimetype determined by {@link Mimetypes#getMimetype} unless the gzip option is * set, in which case the Content-Type is set to application/x-gzip. *
*

* The following jets3t-specific metadata items are also set: *

    *
  • The local file's last-modified date, as {@link Constants#METADATA_JETS3T_LOCAL_FILE_DATE}
  • *
  • An MD5 hash of file data, as {@link StorageObject#METADATA_HEADER_HASH_MD5}
  • *
* * @param objectKeyToFilepathMap * map of '/'-delimited object key names to local file absolute paths * @param bucket * the bucket to put the objects in (will be created if necessary) * @param rootObjectPath * the root path where objects are put (will be created if necessary) * @param aclString * the ACL to apply to the uploaded object * @param md5GenerationProgressWatcher * a class that reports on the progress of this method * * @throws Exception */ public void uploadLocalDirectory(Map objectKeyToFilepathMap, StorageBucket bucket, String rootObjectPath, String aclString, BytesProgressWatcher md5GenerationProgressWatcher) throws Exception { FileComparerResults mergedDiscrepancyResults = new FileComparerResults(); String priorLastKey = null; String lastFileKeypathChecked = ""; boolean skipMissingFiles = this.properties.getBoolProperty("upload.ignoreMissingPaths", false); EncryptionUtil encryptionUtil = null; if (isEncryptionEnabled) { String algorithm = properties .getStringProperty("crypto.algorithm", "PBEWithMD5AndDES"); encryptionUtil = new EncryptionUtil(cryptoPassword, algorithm, EncryptionUtil.DEFAULT_VERSION); } // Support for multipart uploads -- currently available for Amazon S3 only MultipartUtils multipartUtils = null; if (storageService instanceof S3Service) { long maxUploadPartSize = properties.getLongProperty( "upload.max-part-size", MultipartUtils.MAX_OBJECT_SIZE); multipartUtils = new MultipartUtils(maxUploadPartSize); } // Repeat list and upload actions until all objects in bucket have been listed. do { ComparisonResult result = compareLocalAndRemoteFiles(mergedDiscrepancyResults, bucket.getName(), rootObjectPath, priorLastKey, objectKeyToFilepathMap, md5GenerationProgressWatcher); priorLastKey = result.priorLastKey; FileComparerResults discrepancyResults = result.discrepancyResults; // Repeat upload actions until all local files have been uploaded (or we repeat listing loop) Iterator objectKeyIter = objectKeyToFilepathMap.keySet().iterator(); do { List objectsToUpload = new ArrayList(); // Iterate through local files and perform the necessary action to synchronize them. while (objectKeyIter.hasNext()) { String relativeKeyPath = objectKeyIter.next(); String targetKey = relativeKeyPath; if (rootObjectPath.length() > 0) { if (rootObjectPath.endsWith(Constants.FILE_PATH_DELIM)) { targetKey = rootObjectPath + targetKey; } else { targetKey = rootObjectPath + Constants.FILE_PATH_DELIM + targetKey; } } if (isBatchMode) { if (priorLastKey != null && targetKey.compareTo(priorLastKey) > 0) { // We do not yet have the object listing to compare this file. continue; } if (targetKey.compareTo(lastFileKeypathChecked) <= 0) { // We have already handled this file in a prior batch. continue; } else { lastFileKeypathChecked = targetKey; } } File file = new File(objectKeyToFilepathMap.get(relativeKeyPath)); if (discrepancyResults.onlyOnClientKeys.contains(relativeKeyPath)) { printOutputLine("N " + targetKey, REPORT_LEVEL_ACTIONS); objectsToUpload.add(new LazyPreparedUploadObject(targetKey, file, aclString, encryptionUtil)); } else if (discrepancyResults.updatedOnClientKeys.contains(relativeKeyPath)) { printOutputLine("U " + targetKey, REPORT_LEVEL_ACTIONS); objectsToUpload.add(new LazyPreparedUploadObject(targetKey, file, aclString, encryptionUtil)); } else if (discrepancyResults.alreadySynchronisedKeys.contains(relativeKeyPath) || discrepancyResults.alreadySynchronisedLocalPaths.contains(relativeKeyPath)) { if (isForce) { printOutputLine("F " + targetKey, REPORT_LEVEL_ACTIONS); objectsToUpload.add(new LazyPreparedUploadObject(targetKey, file, aclString, encryptionUtil)); } else { printOutputLine("- " + targetKey, REPORT_LEVEL_ALL); } } else if (discrepancyResults.updatedOnServerKeys.contains(relativeKeyPath)) { // This file has been updated on the server-side. if (isKeepFiles) { printOutputLine("r " + targetKey, REPORT_LEVEL_DIFFERENCES); } else { printOutputLine("R " + targetKey, REPORT_LEVEL_ACTIONS); objectsToUpload.add(new LazyPreparedUploadObject(targetKey, file, aclString, encryptionUtil)); } } else { // Uh oh, program error here. The safest thing to do is abort! throw new SynchronizeException("Invalid discrepancy comparison details for file " + file.getPath() + ". Sorry, this is a program error - aborting to keep your data safe"); } // If we're batching, break out of upload preparation loop and // actually upload files once we have our quota. if (isBatchMode && objectsToUpload.size() >= Constants.DEFAULT_OBJECT_LIST_CHUNK_SIZE) { printOutputLine( "Uploading batch of " + objectsToUpload.size() + " files", REPORT_LEVEL_ACTIONS); break; } } // Break uploads into (smaller) batches if we are transforming files during upload int uploadBatchSize = objectsToUpload.size(); if ((isEncryptionEnabled || isGzipEnabled) && properties.containsKey("upload.transformed-files-batch-size")) { // Limit uploads to small batches in batch mode -- based on the // number of upload threads that are available. uploadBatchSize = properties.getIntProperty("upload.transformed-files-batch-size", 1000); } // Upload New/Updated/Forced/Replaced objects. while (doAction && objectsToUpload.size() > 0) { List objectsForStandardPut = new ArrayList(); List objectsForMultipartUpload = new ArrayList(); // Invoke lazy upload object creator. for (int i = 0; i < uploadBatchSize; i++) { LazyPreparedUploadObject lazyObj = objectsToUpload.remove(0); StorageObject object = null; try { object = lazyObj.prepareUploadObject(); } catch (FileNotFoundException e) { if (skipMissingFiles) { printOutputLine( "WARNING: Skipping unreadable file: " + lazyObj.getFile().getAbsolutePath(), REPORT_LEVEL_NONE); continue; } else { throw e; } } if (multipartUtils != null && multipartUtils.isFileLargerThanMaxPartSize(lazyObj.getFile())) { objectsForMultipartUpload.add(object); } else { objectsForStandardPut.add(object); } } // Perform standard object uploads if (objectsForStandardPut.size() > 0) { (new ThreadedStorageService(storageService, serviceEventAdaptor)).putObjects( bucket.getName(), objectsForStandardPut.toArray(new StorageObject[] {})); serviceEventAdaptor.throwErrorIfPresent(); } // Perform multipart uploads if (objectsForMultipartUpload.size() > 0) { multipartUtils.uploadObjects( bucket.getName(), (S3Service)storageService, objectsForMultipartUpload, serviceEventAdaptor); } } } while (objectKeyIter.hasNext()); // End of upload loop } while (priorLastKey != null); // End of list and upload loop // Delete objects that don't correspond with local files. List objectsToDelete = new ArrayList(); Iterator serverOnlyIter = mergedDiscrepancyResults.onlyOnServerKeys.iterator(); while (serverOnlyIter.hasNext()) { // Relative key String relativeKeyPath = serverOnlyIter.next(); // Build absolute key path for object. String targetKey = relativeKeyPath; if (rootObjectPath.length() > 0) { if (rootObjectPath.endsWith(Constants.FILE_PATH_DELIM)) { targetKey = rootObjectPath + targetKey; } else { targetKey = rootObjectPath + Constants.FILE_PATH_DELIM + targetKey; } } StorageObject object = new StorageObject(targetKey); if (isKeepFiles || isNoDelete) { printOutputLine("d " + relativeKeyPath, REPORT_LEVEL_DIFFERENCES); } else { printOutputLine("D " + relativeKeyPath, REPORT_LEVEL_ACTIONS); if (doAction) { objectsToDelete.add(object); } } } if (objectsToDelete.size() > 0) { StorageObject[] objects = objectsToDelete.toArray(new StorageObject[objectsToDelete.size()]); (new ThreadedStorageService(storageService, serviceEventAdaptor)).deleteObjects(bucket.getName(), objects); serviceEventAdaptor.throwErrorIfPresent(); } // Delete local files that have been moved to service. List filesMoved = new ArrayList(); if (isMoveEnabled) { filesMoved.addAll(mergedDiscrepancyResults.onlyOnClientKeys); filesMoved.addAll(mergedDiscrepancyResults.updatedOnClientKeys); filesMoved.addAll(mergedDiscrepancyResults.updatedOnServerKeys); filesMoved.addAll(mergedDiscrepancyResults.alreadySynchronisedKeys); List dirsToDelete = new ArrayList(); Iterator filesMovedIter = filesMoved.iterator(); while (filesMovedIter.hasNext()) { String keyPath = filesMovedIter.next(); File file = new File(objectKeyToFilepathMap.get(keyPath)); printOutputLine("M " + keyPath, REPORT_LEVEL_ACTIONS); if (doAction) { if (file.isDirectory()) { // Delete directories later, as they may still contain // files until this loop completes. dirsToDelete.add(file); } else { file.delete(); } } } Iterator dirIter = dirsToDelete.iterator(); while (dirIter.hasNext()) { File dir = dirIter.next(); dir.delete(); } } printOutputLine( (doAction ? "" : "[No Action] ") + "New files: " + mergedDiscrepancyResults.onlyOnClientKeys.size() + ", Updated: " + mergedDiscrepancyResults.updatedOnClientKeys.size() + (isKeepFiles? ", Kept: " + (mergedDiscrepancyResults.updatedOnServerKeys.size()) : ", Reverted: " + mergedDiscrepancyResults.updatedOnServerKeys.size() ) + (isNoDelete || isKeepFiles? ", Not Deleted: " + mergedDiscrepancyResults.onlyOnServerKeys.size() : ", Deleted: " + mergedDiscrepancyResults.onlyOnServerKeys.size() ) + (isForce ? ", Forced updates: " + mergedDiscrepancyResults.alreadySynchronisedKeys.size() : ", Unchanged: " + mergedDiscrepancyResults.alreadySynchronisedKeys.size() ) + (isMoveEnabled ? ", Moved: " + filesMoved.size() : "" ), REPORT_LEVEL_NONE ); } /** * Copies the contents of a root path in service to the local file system. *

* A set of comparisons is used to determine exactly how the service objects differ from the * local target, and files are transferred based on these comparisons and options set by the user. *

* If an object is gzipped (according to its Content-Type) and the gzip option is set, the object * is inflated. If an object is encrypted (according to the metadata item * {@link Constants#METADATA_JETS3T_CRYPTO_ALGORITHM}) and the crypt option is set, the object * is decrypted. If encrypted and/or gzipped objects are restored without the corresponding option * being set, the user will be responsible for inflating or decrypting the data. *

* Note: If a file was backed-up with both encryption and gzip options it cannot be * restored with only the gzip option set, as files are gzipped prior to being encrypted and cannot * be inflated without first being decrypted. * * @param objectKeyToFilepathMap * map of '/'-delimited object key names to local file absolute paths * @param rootObjectPath * the root path in service where backed-up objects were stored * @param localDirectory the directory to which the objects will be restored * @param bucket * the bucket into which files were backed up * @param md5GenerationProgressWatcher * a class that reports on the progress of this method * * @throws Exception */ public void restoreToLocalDirectory(Map objectKeyToFilepathMap, String rootObjectPath, File localDirectory, StorageBucket bucket, BytesProgressWatcher md5GenerationProgressWatcher) throws Exception { FileComparerResults mergedDiscrepancyResults = new FileComparerResults(); String priorLastKey = null; // Repeat download actions until all objects in bucket have been listed. do { ComparisonResult result = compareLocalAndRemoteFiles(mergedDiscrepancyResults, bucket.getName(), rootObjectPath, priorLastKey, objectKeyToFilepathMap, md5GenerationProgressWatcher); priorLastKey = result.priorLastKey; FileComparerResults discrepancyResults = result.discrepancyResults; Map objectsMap = result.objectsMap; // Download objects to local files/directories. Iterator objectKeyIter = objectsMap.keySet().iterator(); // Optionally download objects in batches to minimize memory use do { List downloadPackagesList = new ArrayList(); while (objectKeyIter.hasNext()) { String keyPath = objectKeyIter.next(); StorageObject object = objectsMap.get(keyPath); String localPath = keyPath; // If object metadata is not available, skip zero-byte objects that // are not definitively directory place-holders, since we can't tell // whether they are directory place-holders or normal empty files. if (!object.isMetadataComplete() && object.getContentLength() == 0 && !object.isDirectoryPlaceholder()) { continue; } File fileTarget = new File(localDirectory, keyPath); // Create local directories corresponding to objects flagged as dirs. if (object.isDirectoryPlaceholder()) { localPath = ObjectUtils.convertDirPlaceholderKeyNameToDirName(keyPath); fileTarget = new File(localDirectory, localPath); if (doAction) { fileTarget.mkdirs(); } } if (discrepancyResults.onlyOnServerKeys.contains(keyPath)) { printOutputLine("N " + localPath, REPORT_LEVEL_ACTIONS); DownloadPackage downloadPackage = ObjectUtils.createPackageForDownload( object, fileTarget, isGzipEnabled, isEncryptionEnabled, cryptoPassword); if (downloadPackage != null) { downloadPackagesList.add(downloadPackage); } } else if (discrepancyResults.updatedOnServerKeys.contains(keyPath)) { printOutputLine("U " + localPath, REPORT_LEVEL_ACTIONS); DownloadPackage downloadPackage = ObjectUtils.createPackageForDownload( object, fileTarget, isGzipEnabled, isEncryptionEnabled, cryptoPassword); if (downloadPackage != null) { downloadPackagesList.add(downloadPackage); } } else if (discrepancyResults.alreadySynchronisedKeys.contains(keyPath)) { if (isForce) { printOutputLine("F " + localPath, REPORT_LEVEL_ACTIONS); DownloadPackage downloadPackage = ObjectUtils.createPackageForDownload( object, fileTarget, isGzipEnabled, isEncryptionEnabled, cryptoPassword); if (downloadPackage != null) { downloadPackagesList.add(downloadPackage); } } else { printOutputLine("- " + localPath, REPORT_LEVEL_ALL); } } else if (discrepancyResults.updatedOnClientKeys.contains(keyPath)) { // This file has been updated on the client-side. if (isKeepFiles) { printOutputLine("r " + localPath, REPORT_LEVEL_DIFFERENCES); } else { printOutputLine("R " + localPath, REPORT_LEVEL_ACTIONS); DownloadPackage downloadPackage = ObjectUtils.createPackageForDownload( object, fileTarget, isGzipEnabled, isEncryptionEnabled, cryptoPassword); if (downloadPackage != null) { downloadPackagesList.add(downloadPackage); } } } else { // Uh oh, program error here. The safest thing to do is abort! throw new SynchronizeException("Invalid discrepancy comparison details for object " + localPath + ". Sorry, this is a program error - aborting to keep your data safe"); } // Optionally break up download sets into batches if (isBatchMode && downloadPackagesList.size() >= Constants.DEFAULT_OBJECT_LIST_CHUNK_SIZE) { printOutputLine( "Downloading batch of " + downloadPackagesList.size() + " objects", REPORT_LEVEL_ACTIONS); break; } } // Download New/Updated/Forced/Replaced objects from service. if (doAction && downloadPackagesList.size() > 0) { DownloadPackage[] downloadPackages = downloadPackagesList.toArray( new DownloadPackage[downloadPackagesList.size()]); (new ThreadedStorageService(storageService, serviceEventAdaptor)).downloadObjects( bucket.getName(), downloadPackages); serviceEventAdaptor.throwErrorIfPresent(); } } while (objectKeyIter.hasNext()); } while (priorLastKey != null); // Delete local files that don't correspond with service objects. List dirsToDelete = new ArrayList(); Iterator clientOnlyIter = mergedDiscrepancyResults.onlyOnClientKeys.iterator(); while (clientOnlyIter.hasNext()) { String keyPath = clientOnlyIter.next(); File file = new File(objectKeyToFilepathMap.get(keyPath)); if (isKeepFiles || isNoDelete) { printOutputLine("d " + keyPath, REPORT_LEVEL_DIFFERENCES); } else { printOutputLine("D " + keyPath, REPORT_LEVEL_ACTIONS); if (doAction) { if (file.isDirectory()) { // Delete directories later, as they may still have files // inside until this loop completes. dirsToDelete.add(file); } else { file.delete(); } } } } Iterator dirIter = dirsToDelete.iterator(); while (dirIter.hasNext()) { File dir = dirIter.next(); dir.delete(); } // Delete objects in service that have been moved to the local computer. List objectsMoved = new ArrayList(); if (isMoveEnabled) { objectsMoved.addAll(mergedDiscrepancyResults.onlyOnServerKeys); objectsMoved.addAll(mergedDiscrepancyResults.updatedOnServerKeys); objectsMoved.addAll(mergedDiscrepancyResults.updatedOnClientKeys); objectsMoved.addAll(mergedDiscrepancyResults.alreadySynchronisedKeys); Collections.sort(objectsMoved); Iterator objectsMovedIter = objectsMoved.iterator(); List objectsToDelete = new ArrayList(); while (objectsMovedIter.hasNext()) { String keyPath = objectsMovedIter.next(); StorageObject object = new StorageObject(keyPath); printOutputLine("M " + keyPath, REPORT_LEVEL_ACTIONS); if (doAction) { objectsToDelete.add(object); } } if (objectsToDelete.size() > 0) { StorageObject[] objects = objectsToDelete.toArray( new StorageObject[objectsToDelete.size()]); (new ThreadedStorageService(storageService, serviceEventAdaptor)).deleteObjects( bucket.getName(), objects); serviceEventAdaptor.throwErrorIfPresent(); } } printOutputLine( (doAction ? "" : "[No Action] ") + "New files: " + mergedDiscrepancyResults.onlyOnServerKeys.size() + ", Updated: " + mergedDiscrepancyResults.updatedOnServerKeys.size() + (isKeepFiles? ", Kept: " + (mergedDiscrepancyResults.updatedOnClientKeys.size()) : ", Reverted: " + mergedDiscrepancyResults.updatedOnClientKeys.size() ) + (isNoDelete || isKeepFiles? ", Not Deleted: " + mergedDiscrepancyResults.onlyOnClientKeys.size() : ", Deleted: " + mergedDiscrepancyResults.onlyOnClientKeys.size() ) + (isForce ? ", Forced updates: " + mergedDiscrepancyResults.alreadySynchronisedKeys.size() : ", Unchanged: " + mergedDiscrepancyResults.alreadySynchronisedKeys.size() ) + (isMoveEnabled ? ", Moved: " + objectsMoved.size() : "" ), REPORT_LEVEL_NONE ); } /** * Runs the application, performing the action specified on the given service and local directory paths. * * @param servicePath * the path in service (including the bucket name) to which files are backed-up, or from which files are restored. * @param files * an array of one or more File objects for Uploads, or a single target directory for Downloads. * @param actionCommand * the action to perform, UP(load) or DOWN(load) * @param cryptoPassword * if non-null, an {@link EncryptionUtil} object is created with the provided password to encrypt or decrypt files. * @param aclString * the ACL to apply to the uploaded object * @param providerId * service provider name: "S3" or "GS" * * @throws Exception */ public void run(String servicePath, File[] files, String actionCommand, String cryptoPassword, String aclString, String providerId) throws Exception { String bucketName = null; String objectPath = ""; int slashIndex = servicePath.indexOf(Constants.FILE_PATH_DELIM); if (slashIndex >= 0) { // We have a bucket name and an object path. bucketName = servicePath.substring(0, slashIndex); objectPath = servicePath.substring(slashIndex + 1, servicePath.length()); } else { // We only have a bucket name. bucketName = servicePath; } // Describe the action that will be performed. if ("UP".equals(actionCommand)) { String uploadPathSummary = null; if (files.length > 1) { int dirsCount = 0; int filesCount = 0; for (File file: files) { if (file.isDirectory()) { dirsCount++; } else { filesCount++; } } uploadPathSummary = "[" + dirsCount + (dirsCount == 1 ? " directory" : " directories") + ", " + filesCount + (filesCount == 1 ? " file" : " files") + "]"; } else { uploadPathSummary = Arrays.toString(files); } printOutputLine("UP " + (doAction ? "" : "[No Action] ") + "Local " + uploadPathSummary + " => " + providerId + "[" + servicePath + "]", REPORT_LEVEL_NONE); } else if ("DOWN".equals(actionCommand)) { if (files.length != 1) { throw new SynchronizeException("Only one target directory is allowed for downloads"); } printOutputLine("DOWN " + (doAction ? "" : "[No Action] ") + providerId + "[" + servicePath + "] => Local " + files[0], REPORT_LEVEL_NONE); } else { throw new SynchronizeException("Action string must be 'UP' or 'DOWN'"); } this.cryptoPassword = cryptoPassword; StorageBucket bucket = null; if (storageService.getProviderCredentials() == null) { // Using an anonymous connection, don't check bucket ownership or attempt to create it. bucket = new StorageBucket(bucketName); } else { // Using an authentication connection, so check for bucket ownership and create one if necessary. bucket = storageService.getBucket(bucketName); if (bucket == null) { // Bucket does not exist in this user's account, try creating it. try { bucket = storageService.createBucket(new StorageBucket(bucketName)); } catch (ServiceException e) { // Bucket could not be created, someone else must own it. try { // Let's see if we can at least access the bucket... storageService.listObjectsChunked(bucketName, null, null, 1, null, false); // ... if we get this far we're dealing with a third-party // bucket we can read. That's fine, let's proceed. bucket = new StorageBucket(bucketName); } catch (ServiceException e2) { // We can't create or access this bucket, time to give up. throw new SynchronizeException( "Unable to create or access bucket: " + bucketName, e); } } } } boolean storeEmptyDirectories = properties .getBoolProperty("uploads.storeEmptyDirectories", true); // Generate of object key names to absolute paths of local files printProgressLine("Listing files in local file system"); Map objectKeyToFilepathMap = null; if ("UP".equals(actionCommand)) { // Ensure all files/directories chosen for upload exist and are accessible for (File file: files) { if (!file.exists()) { throw new IOException("File '" + file.getPath() + "' does not exist"); } } objectKeyToFilepathMap = fileComparer.buildObjectKeyToFilepathMap( files, "", storeEmptyDirectories); } else if ("DOWN".equals(actionCommand)) { objectKeyToFilepathMap = fileComparer.buildObjectKeyToFilepathMap( files[0].listFiles(), "", storeEmptyDirectories); } // Watcher to provide feedback during generation of MD5 hash values final long filesSizeTotal[] = new long[] { 0 }; // Don't know how much comparison req'd BytesProgressWatcher md5GenerationProgressWatcher = new BytesProgressWatcher(filesSizeTotal[0]) { @Override public void updateBytesTransferred(long byteCount) { super.updateBytesTransferred(byteCount); printProgressLine("Comparing files: " + byteFormatter.formatByteSize(super.getBytesTransferred())); } }; if ("UP".equals(actionCommand)) { uploadLocalDirectory(objectKeyToFilepathMap, bucket, objectPath, aclString, md5GenerationProgressWatcher); } else if ("DOWN".equals(actionCommand)) { restoreToLocalDirectory(objectKeyToFilepathMap, objectPath, files[0], bucket, md5GenerationProgressWatcher); } } /** * Runs the application, performing the action specified on the given service and local directory paths. * * @param servicePath * the path in service (including the bucket name) to which files are backed-up, or from which files are restored. * @param files * a set of one or more of File objects for Uploads, or a single target directory for Downloads. * @param actionCommand * the action to perform, UP(load) or DOWN(load) * @param cryptoPassword * if non-null, an {@link EncryptionUtil} object is created with the provided password to encrypt or decrypt files. * @param aclString * the ACL to apply to the uploaded object * @param providerId * service provider name: "S3" or "GS" * * @throws Exception */ public void run(String servicePath, List files, String actionCommand, String cryptoPassword, String aclString, String providerId) throws Exception { File[] filesArray = files.toArray(new File[files.size()]); this.run(servicePath, filesArray, actionCommand, cryptoPassword, aclString, providerId); } private void displayProgressStatus(String prefix, ThreadWatcher watcher) { String progressMessage = prefix + watcher.getCompletedThreads() + "/" + watcher.getThreadCount(); // Show percentage of bytes transferred, if this info is available. if (watcher.isBytesTransferredInfoAvailable()) { String bytesTotalStr = byteFormatter.formatByteSize(watcher.getBytesTotal()); long percentage = (int) (((double)watcher.getBytesTransferred() / watcher.getBytesTotal()) * 100); String detailsText = formatTransferDetails(watcher); progressMessage += " - " + percentage + "% of " + bytesTotalStr + (detailsText.length() > 0 ? " (" + detailsText + ")" : ""); } else { long percentage = (int) (((double)watcher.getCompletedThreads() / watcher.getThreadCount()) * 100); progressMessage += " - " + percentage + "%"; } printProgressLine(progressMessage); } S3ServiceEventAdaptor serviceEventAdaptor = new S3ServiceEventAdaptor() { private void displayIgnoredErrors(ServiceEvent event) { if (ServiceEvent.EVENT_IGNORED_ERRORS == event.getEventCode()) { Throwable[] throwables = event.getIgnoredErrors(); for (int i = 0; i < throwables.length; i++) { printOutputLine("Ignoring error: " + throwables[i].getMessage(), REPORT_LEVEL_ALL); } } } @Override public void event(CreateObjectsEvent event) { super.event(event); displayIgnoredErrors(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { displayProgressStatus("Upload: ", event.getThreadWatcher()); } } @Override public void event(MultipartStartsEvent event) { super.event(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { displayProgressStatus("Starting large file uploads: ", event.getThreadWatcher()); } } @Override public void event(MultipartCompletesEvent event) { super.event(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { displayProgressStatus("Completing large file uploads: ", event.getThreadWatcher()); } } @Override public void event(MultipartUploadsEvent event) { super.event(event); displayIgnoredErrors(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { displayProgressStatus("Large upload parts: ", event.getThreadWatcher()); } } @Override public void event(DownloadObjectsEvent event) { super.event(event); displayIgnoredErrors(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { displayProgressStatus("Download: ", event.getThreadWatcher()); } } @Override public void event(GetObjectHeadsEvent event) { super.event(event); displayIgnoredErrors(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { displayProgressStatus("Retrieving object details from service: ", event.getThreadWatcher()); } } @Override public void event(DeleteObjectsEvent event) { super.event(event); displayIgnoredErrors(event); if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { displayProgressStatus("Deleting objects in service: ", event.getThreadWatcher()); } } }; private class ComparisonResult { public String priorLastKey; public FileComparerResults discrepancyResults; public Map objectsMap; } /** * Prints usage/help information and forces the application to exit with errorcode 1. */ private static void printHelpAndExit(boolean fullHelp) { System.out.println(); System.out.println("Usage: Synchronize [options] UP (...)"); System.out.println(" or: Synchronize [options] DOWN "); System.out.println(""); System.out.println("UP : Synchronize the contents of the Local Directory with a service."); System.out.println("DOWN : Synchronize the contents of a service with the Local Directory"); System.out.println("Path : A path to the resource. This must include at least the"); System.out.println(" bucket name, but may also specify a path inside the bucket."); System.out.println(" E.g. /Backups/Documents/20060623"); System.out.println("File/Directory : A file or directory on your computer to upload"); System.out.println("DownloadDirectory : A directory on your computer where downloaded files"); System.out.println(" will be stored"); System.out.println(); System.out.println("Required properties can be provided via: a file named 'synchronize.properties'"); System.out.println("in the classpath, a file specified with the --properties option, or by typing"); System.out.println("them in when prompted on the command line. Required properties are:"); System.out.println(" accesskey : Your Access Key (Required)"); System.out.println(" secretkey : Your Secret Key (Required)"); System.out.println(" password : Encryption password (only required when using crypto)"); System.out.println("Properties specified in this file will override those in jets3t.properties."); if (!fullHelp) { System.out.println(""); System.out.println("For more help : Synchronize --help"); System.exit(1); } System.out.println(""); System.out.println("Options"); System.out.println("-------"); System.out.println("-h | --help"); System.out.println(" Displays this help message."); System.out.println(""); System.out.println("--provider "); System.out.println(" Service provider, either 'S3' for Amazon S3 or 'GS' for Google Storage"); System.out.println(""); System.out.println("-n | --noaction"); System.out.println(" No action taken. No files will be changed locally or on service, instead"); System.out.println(" a report will be generating showing what will happen if the command"); System.out.println(" is run without the -n option."); System.out.println(""); System.out.println("-q | --quiet"); System.out.println(" Runs quietly, without reporting on each action performed or displaying"); System.out.println(" progress messages. The summary is still displayed."); System.out.println(""); System.out.println("-p | --noprogress"); System.out.println(" Runs somewhat quietly, without displaying progress messages."); System.out.println(" The action report and overall summary are still displayed."); System.out.println(""); System.out.println("-f | --force"); System.out.println(" Force tool to perform synchronization even when files are up-to-date."); System.out.println(" This may be useful if you need to update metadata or timestamps online."); System.out.println(""); System.out.println("-k | --keepfiles"); System.out.println(" Keep outdated files on destination instead of reverting/removing them."); System.out.println(" This option cannot be used with --nodelete."); System.out.println(""); System.out.println("-d | --nodelete"); System.out.println(" Keep files on destination that have been removed from the source. This"); System.out.println(" option is similar to --keepfiles except that files may be reverted."); System.out.println(" This option cannot be used with --keepfiles."); System.out.println(""); System.out.println("-m | --move"); System.out.println(" Move items rather than merely copying them. Files on the local computer will"); System.out.println(" be deleted after they have been uploaded to service, or objects will be deleted"); System.out.println(" from service after they have been downloaded. Be *very* careful with this option."); System.out.println(" This option cannot be used with --keepfiles."); System.out.println(""); System.out.println("-b | --batch"); System.out.println(" Download or upload files in batches, rather than all at once. Enabling this"); System.out.println(" option will reduce the memory required to synchronize large buckets, and will"); System.out.println(" ensure file transfers commence as soon as possible. When this option is"); System.out.println(" enabled, the progress status lines refer only to the progress of a single batch."); System.out.println(""); System.out.println("-g | --gzip"); System.out.println(" Compress (GZip) files when backing up and Decompress gzipped files"); System.out.println(" when restoring."); System.out.println(""); System.out.println("-c | --crypto"); System.out.println(" Encrypt files when backing up and decrypt encrypted files when restoring. If"); System.out.println(" this option is specified the properties must contain a password."); System.out.println(""); System.out.println("--properties "); System.out.println(" Load the synchronizer app properties from the given file rather than from"); System.out.println(" a synchronizer.properties file in the classpath."); System.out.println(""); System.out.println("--credentials "); System.out.println(" Load your service credentials from an encrypted file, rather than from the"); System.out.println(" synchronizer.properties file. This encrypted file can be created using"); System.out.println(" the Cockpit application, or the JetS3t API library."); System.out.println(""); System.out.println("--acl "); System.out.println(" Specifies the Access Control List setting to apply. This value must be one"); System.out.println(" of: PRIVATE, PUBLIC_READ, PUBLIC_READ_WRITE. This setting will override any"); System.out.println(" acl property specified in the synchronize.properties file"); System.out.println(""); System.out.println("--reportlevel "); System.out.println(" A number that specifies how much report information will be printed:"); System.out.println(" 0 - no report items will be printed (the summary will still be printed)"); System.out.println(" 1 - only actions are reported [Prefixes N, U, D, R, F, M]"); System.out.println(" 2 - differences & actions are reported [Prefixes N, U, D, R, F, M, d, r]"); System.out.println(" 3 - DEFAULT: all items are reported [Prefixes N, U, D, R, F, M, d, r, -]"); System.out.println(""); System.out.println("Report"); System.out.println("------"); System.out.println("Report items are printed on a single line with an action flag followed by"); System.out.println("the relative path of the file or object. The report legend follows:"); System.out.println(""); System.out.println("N: A new file/object will be created"); System.out.println("U: An existing file/object has changed and will be updated"); System.out.println("D: A file/object existing on the target does not exist on the source and"); System.out.println(" will be deleted."); System.out.println("d: A file/object existing on the target does not exist on the source but"); System.out.println(" because the --keepfiles or --nodelete option was set it was not deleted."); System.out.println("R: An existing file/object has changed more recently on the target than on the"); System.out.println(" source. The target version will be reverted to the older source version"); System.out.println("r: An existing file/object has changed more recently on the target than on the"); System.out.println(" source but because the --keepfiles option was set it was not reverted."); System.out.println("-: A file is identical between the local system and service, no action is necessary."); System.out.println("F: A file identical locally and in service was updated due to the Force option."); System.out.println("M: The file/object will be moved (deleted after it has been copied to/from service)."); System.out.println(); System.exit(1); } /** * Runs this application from the console, accepts and checks command-line parameters and runs an * upload or download operation when all the necessary parameters are provided. * @param args * @throws Exception */ public static void main(String args[]) throws Exception { // Load default JetS3t properties Jets3tProperties myProperties = Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME); String propertiesFileName = "synchronize.properties"; // Read the Synchronize properties file from the classpath Jets3tProperties synchronizeProperties = Jets3tProperties.getInstance(propertiesFileName); if (synchronizeProperties.isLoaded()) { myProperties.loadAndReplaceProperties(synchronizeProperties, propertiesFileName + " in classpath"); } // Required arguments String actionCommand = null; String servicePath = null; int reqArgCount = 0; Set fileSet = new HashSet(); // Options boolean doAction = true; boolean isQuiet = false; boolean isNoProgress = false; boolean isForce = false; boolean isKeepFiles = false; boolean isNoDelete = false; boolean isGzipEnabled = false; boolean isEncryptionEnabled = false; boolean isMoveEnabled = false; boolean isBatchMode = false; String aclString = null; int reportLevel = REPORT_LEVEL_ALL; ProviderCredentials providerCredentials = null; String providerId = "S3"; // Parse arguments. for (int i = 0; i < args.length; i++) { String arg = args[i]; if (arg.startsWith("-")) { // Argument is an option. if (arg.equalsIgnoreCase("-h") || arg.equalsIgnoreCase("--help")) { printHelpAndExit(true); } else if (arg.equalsIgnoreCase("-n") || arg.equalsIgnoreCase("--noaction")) { doAction = false; } else if (arg.equalsIgnoreCase("-q") || arg.equalsIgnoreCase("--quiet")) { isQuiet = true; } else if (arg.equalsIgnoreCase("-p") || arg.equalsIgnoreCase("--noprogress")) { isNoProgress = true; } else if (arg.equalsIgnoreCase("-f") || arg.equalsIgnoreCase("--force")) { isForce = true; } else if (arg.equalsIgnoreCase("-k") || arg.equalsIgnoreCase("--keepfiles")) { isKeepFiles = true; } else if (arg.equalsIgnoreCase("-d") || arg.equalsIgnoreCase("--nodelete")) { isNoDelete = true; } else if (arg.equalsIgnoreCase("-g") || arg.equalsIgnoreCase("--gzip")) { isGzipEnabled = true; } else if (arg.equalsIgnoreCase("-c") || arg.equalsIgnoreCase("--crypto")) { isEncryptionEnabled = true; } else if (arg.equalsIgnoreCase("-m") || arg.equalsIgnoreCase("--move")) { isMoveEnabled = true; } else if (arg.equalsIgnoreCase("-s") || arg.equalsIgnoreCase("--skipmetadata")) { System.err.println("WARNING: --skipmetadata is obsolete since JetS3t 0.8.1, it has no effect"); } else if (arg.equalsIgnoreCase("-b") || arg.equalsIgnoreCase("--batch")) { isBatchMode = true; } else if (arg.equalsIgnoreCase("--provider")) { if (i + 1 < args.length) { // Read custom Synchronize properties file from the specified file i++; providerId = args[i]; if (!"S3".equalsIgnoreCase(providerId) && !"GS".equalsIgnoreCase(providerId)) { System.err.println("ERROR: --provider option must be one of 'S3' or 'GS'"); printHelpAndExit(false); } } else { System.err.println("ERROR: --provider option must be followed by a provider ID 'S3' or 'GS'"); printHelpAndExit(false); } } else if (arg.equalsIgnoreCase("--properties")) { if (i + 1 < args.length) { // Read custom Synchronize properties file from the specified file i++; propertiesFileName = args[i]; File propertiesFile = new File(propertiesFileName); if (!propertiesFile.canRead()) { System.err.println("ERROR: The properties file " + propertiesFileName + " could not be found"); System.exit(2); } myProperties.loadAndReplaceProperties( new FileInputStream(propertiesFileName), propertiesFile.getName()); } else { System.err.println("ERROR: --properties option must be followed by a file path"); printHelpAndExit(false); } } else if (arg.equalsIgnoreCase("--acl")) { if (i + 1 < args.length) { // Read the acl setting string i++; aclString = args[i]; if (!"PUBLIC_READ".equalsIgnoreCase(aclString) && !"PUBLIC_READ_WRITE".equalsIgnoreCase(aclString) && !"PRIVATE".equalsIgnoreCase(aclString)) { System.err.println("ERROR: Acess Control List setting \"acl\" must have one of the values " + "PRIVATE, PUBLIC_READ, PUBLIC_READ_WRITE"); printHelpAndExit(false); } } else { System.err.println("ERROR: --acl option must be followed by an ACL string"); printHelpAndExit(false); } } else if (arg.equalsIgnoreCase("--reportlevel")) { if (i + 1 < args.length) { // Read the report level integer i++; try { reportLevel = Integer.parseInt(args[i]); if (reportLevel < 0 || reportLevel > 3) { System.err.println("ERROR: Report Level setting \"reportlevel\" must have one of the values " + "0 (no reporting), 1 (actions only), 2 (differences only), 3 (DEFAULT - all reporting)"); printHelpAndExit(false); } } catch (NumberFormatException e) { System.err.println("ERROR: --reportlevel option must be followed by 0, 1, 2 or 3"); printHelpAndExit(false); } } else { System.err.println("ERROR: --reportlevel option must be followed by 0, 1, 2 or 3"); printHelpAndExit(false); } } else if (arg.equalsIgnoreCase("--credentials")) { if (i + 1 < args.length) { // Read the credentials file location i++; File credentialsFile = new File(args[i]); if (!credentialsFile.canRead()) { System.err.println("ERROR: Cannot read credentials file '" + credentialsFile + "'"); printHelpAndExit(false); } while (providerCredentials == null) { String credentialsPassword = PasswordInput.getPassword( "Password for credentials file '" + credentialsFile + "'"); try { providerCredentials = ProviderCredentials.load(credentialsPassword, credentialsFile); // Set dummy accesskey and secretkey property values, to avoid prompting for these values later on. myProperties.setProperty("accesskey", ""); myProperties.setProperty("secretkey", ""); } catch (ServiceException e) { System.out.println("Failed to read credentials from the file '" + credentialsFile + "'"); } } } else { System.err.println("ERROR: --credentials option must be followed by a file path"); printHelpAndExit(false); } } else { System.err.println("ERROR: Invalid option: " + arg); printHelpAndExit(false); } } else { // Argument is one of the required parameters. if (reqArgCount == 0) { actionCommand = arg.toUpperCase(Locale.getDefault()); if (!"UP".equals(actionCommand) && !"DOWN".equals(actionCommand)) { System.err.println("ERROR: Invalid action command " + actionCommand + ". Valid values are 'UP' or 'DOWN'"); printHelpAndExit(false); } } else if (reqArgCount == 1) { servicePath = arg; } else if (reqArgCount > 1) { File file = new File(arg); if ("DOWN".equals(actionCommand)) { if (reqArgCount > 2) { System.err.println("ERROR: Only one target directory may be specified" + " for " + actionCommand); printHelpAndExit(false); } if (!file.exists() || !file.isDirectory()) { System.err.println( "ERROR: Target download location is not a directory: " + file); System.exit(1); } if (file.exists() && !file.isDirectory()) { System.err.println( "ERROR: Target download location already exists but is not a directory: " + file); System.exit(1); } } else { if (!file.canRead()) { if (myProperties != null && myProperties.getBoolProperty("upload.ignoreMissingPaths", false)) { System.err.println("WARN: Ignoring missing upload path: " + file); continue; } else { System.err.println( "ERROR: Cannot read upload file/directory: " + file + "\n" + " To ignore missing paths set the property upload.ignoreMissingPaths"); printHelpAndExit(false); } } } fileSet.add(file); } reqArgCount++; } } if (fileSet.size() < 1 && !myProperties.getBoolProperty("upload.ignoreMissingPaths", false)) { // Missing one or more required parameters. System.err.println("ERROR: Missing required file path(s)"); printHelpAndExit(false); } if (isKeepFiles && isNoDelete) { // Incompatible options. System.err.println("ERROR: Options --keepfiles and --nodelete cannot be used at the same time"); printHelpAndExit(false); } if (isKeepFiles && isMoveEnabled) { // Incompatible options. System.err.println("ERROR: Options --keepfiles and --move cannot be used at the same time"); printHelpAndExit(false); } // Ensure the Synchronize properties file contains everything we need, and prompt // for any required information that is missing. if (!myProperties.containsKey("accesskey") || !myProperties.containsKey("secretkey") || (isEncryptionEnabled && !myProperties.containsKey("password"))) { System.out.println("Please enter the required properties that have not been provided in a properties file:"); BufferedReader inputReader = new BufferedReader(new InputStreamReader(System.in)); if (!myProperties.containsKey("accesskey")) { System.out.print("Acccess Key: "); myProperties.setProperty("accesskey", inputReader.readLine()); } if (!myProperties.containsKey("secretkey")) { System.out.print("Secret Key: "); myProperties.setProperty("secretkey", inputReader.readLine()); } if (isEncryptionEnabled && !myProperties.containsKey("password")) { String password1 = "password1"; String password2 = "password2"; while (!password1.equals(password2)) { password1 = PasswordInput.getPassword("Encryption password"); password2 = PasswordInput.getPassword("Confirm password"); if (!password1.equals(password2)) { System.out.println("The original and confirmation passwords do not match, try again."); } } myProperties.setProperty("password", password1); } } // Use property values for the credentials, if we haven't already been // given the credentials through the --credentials argument. if (providerCredentials == null) { if ("S3".equalsIgnoreCase(providerId)) { providerCredentials = new AWSCredentials( myProperties.getStringProperty("accesskey", null), myProperties.getStringProperty("secretkey", null)); } else if ("GS".equalsIgnoreCase(providerId)) { providerCredentials = new GSCredentials( myProperties.getStringProperty("accesskey", null), myProperties.getStringProperty("secretkey", null)); } } // Sanity-check credentials -- if both are null or empty strings, // then nullify the credentials object to get an anonymous connection. if (providerCredentials.getAccessKey() == null || providerCredentials.getAccessKey().length() == 0 || providerCredentials.getSecretKey() == null || providerCredentials.getSecretKey().length() == 0) { providerCredentials = null; } if (aclString == null) { aclString = myProperties.getStringProperty("acl", "PRIVATE"); } if (!"PUBLIC_READ".equalsIgnoreCase(aclString) && !"PUBLIC_READ_WRITE".equalsIgnoreCase(aclString) && !"PRIVATE".equalsIgnoreCase(aclString)) { System.err.println("ERROR: Acess Control List setting \"acl\" must have one of the values " + "PRIVATE, PUBLIC_READ, PUBLIC_READ_WRITE"); System.exit(2); } StorageService service = null; if ("S3".equalsIgnoreCase(providerId)) { service = new RestS3Service( providerCredentials, APPLICATION_DESCRIPTION, new CommandLineCredentialsProvider(), myProperties); } else if ("GS".equalsIgnoreCase(providerId)) { service = new GoogleStorageService( providerCredentials, APPLICATION_DESCRIPTION, new CommandLineCredentialsProvider(), myProperties); } // Perform the UPload/DOWNload. Synchronize client = new Synchronize( service, doAction, isQuiet, isNoProgress, isForce, isKeepFiles, isNoDelete, isMoveEnabled, isBatchMode, isGzipEnabled, isEncryptionEnabled, reportLevel, myProperties); client.run(servicePath, fileSet.toArray(new File[fileSet.size()]), actionCommand, myProperties.getStringProperty("password", null), aclString, providerId.toUpperCase()); } }jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/synchronize/SynchronizeException.java0000644000000000000000000000242111441613550024644 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.synchronize; /** * A standard exception, used for errors specific to the Synchronize application. * * @author James Murty */ public class SynchronizeException extends Exception { private static final long serialVersionUID = -6177810202074757106L; public SynchronizeException() { super(); } public SynchronizeException(String message) { super(message); } public SynchronizeException(String message, Throwable cause) { super(message, cause); } public SynchronizeException(Throwable cause) { super(cause); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/synchronize/PasswordInput.java0000644000000000000000000000750311427702124023302 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2010 Bennett Hiles * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.synchronize; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.lang.reflect.Method; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * A utility class that gives the ability to check which java version * is being used to determine whether the java.io.Console class can be * utitlized to retrieve a password from a user's input. * * @author Bennett Hiles */ public class PasswordInput { private static final Log LOG = LogFactory.getLog(PasswordInput.class); public static String getPassword(String prompt) throws IOException { String password = null; String javaVers = System.getProperty("java.runtime.version"); if (LOG.isDebugEnabled()) { LOG.debug("About to attempt to read password under Java " + "version: "+javaVers); } // Split version string into components. String is of the form // MAJOR_VERSION_NUMBER . MINOR_VERSION_NUMBR . REVISION_STRING // e.g. 1.6.0_17-b04-248-10M3025 String[] versionMajAndMin = javaVers.split("\\."); int majorVersion = Integer.parseInt(versionMajAndMin[0]); int minorVersion = Integer.parseInt(versionMajAndMin[1]); if (majorVersion > 1 || minorVersion >= 6) { password = getPasswordJDK16OrLater(prompt); } else { password = getPasswordBeforeJDK16(prompt); } return password; } private static String getPasswordBeforeJDK16(String prompt) throws IOException { System.out.print(prompt + ": "); BufferedReader inputReader = new BufferedReader(new InputStreamReader(System.in)); String password = inputReader.readLine(); return password; } private static String getPasswordJDK16OrLater(String prompt) throws IOException { String password = null; try { Class consoleClass = Class.forName("java.io.Console"); Method consoleReadPassword = consoleClass.getDeclaredMethod("readPassword", new Class[] {}); Method consoleMethod = System.class.getDeclaredMethod("console", new Class[] {});; Object consoleObject = consoleMethod.invoke(null, new Object[] {}); if (consoleObject == null) { if (LOG.isDebugEnabled()) { LOG.debug("java.io.Console using reflection returned null, " + "so that password will be fetched using the pre-JDK 1.6 version"); } password = getPasswordBeforeJDK16(prompt); } else { System.out.println(prompt + " (typing will be hidden):"); Object passwordObj = consoleReadPassword.invoke(consoleObject, new Object[] {}); char[] passwordChars = (char[]) passwordObj; password = String.valueOf(passwordChars); } } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new IOException("Encountered trouble using relection to generate java.io.Console class"); } return password; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/uploader/0002755000000000000000000000000011537563564017071 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/uploader/Uploader.java0000644000000000000000000023026111550441706021475 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.uploader; import java.awt.CardLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Rectangle; import java.awt.datatransfer.DataFlavor; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.StringTokenizer; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; import javax.swing.BorderFactory; import javax.swing.JApplet; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.LookAndFeel; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.border.Border; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HostConfiguration; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.HttpMethodRetryHandler; import org.apache.commons.httpclient.NTCredentials; import org.apache.commons.httpclient.ProxyHost; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.httpclient.auth.AuthScheme; import org.apache.commons.httpclient.auth.CredentialsNotAvailableException; import org.apache.commons.httpclient.auth.CredentialsProvider; import org.apache.commons.httpclient.auth.NTLMScheme; import org.apache.commons.httpclient.auth.RFC2617Scheme; import org.apache.commons.httpclient.contrib.proxy.PluginProxyUtil; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.params.HttpClientParams; import org.apache.commons.httpclient.params.HttpConnectionManagerParams; import org.apache.commons.httpclient.params.HttpMethodParams; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.gui.AuthenticationDialog; import org.jets3t.gui.ErrorDialog; import org.jets3t.gui.GuiUtils; import org.jets3t.gui.HyperlinkActivatedListener; import org.jets3t.gui.JHtmlLabel; import org.jets3t.gui.UserInputFields; import org.jets3t.gui.skins.SkinsFactory; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.S3ServiceException; import org.jets3t.service.impl.rest.httpclient.RestS3Service; import org.jets3t.service.io.BytesProgressWatcher; import org.jets3t.service.io.ProgressMonitoredInputStream; import org.jets3t.service.model.S3Object; import org.jets3t.service.multithread.CancelEventTrigger; import org.jets3t.service.multithread.CopyObjectsEvent; import org.jets3t.service.multithread.CreateBucketsEvent; import org.jets3t.service.multithread.CreateObjectsEvent; import org.jets3t.service.multithread.DeleteObjectsEvent; import org.jets3t.service.multithread.DeleteVersionedObjectsEvent; import org.jets3t.service.multithread.DownloadObjectsEvent; import org.jets3t.service.multithread.GetObjectHeadsEvent; import org.jets3t.service.multithread.GetObjectsEvent; import org.jets3t.service.multithread.ListObjectsEvent; import org.jets3t.service.multithread.LookupACLEvent; import org.jets3t.service.multithread.S3ServiceEventListener; import org.jets3t.service.multithread.S3ServiceMulti; import org.jets3t.service.multithread.ServiceEvent; import org.jets3t.service.multithread.ThreadWatcher; import org.jets3t.service.multithread.UpdateACLEvent; import org.jets3t.service.security.AWSCredentials; import org.jets3t.service.utils.ByteFormatter; import org.jets3t.service.utils.Mimetypes; import org.jets3t.service.utils.ServiceUtils; import org.jets3t.service.utils.TimeFormatter; import org.jets3t.service.utils.gatekeeper.GatekeeperMessage; import org.jets3t.service.utils.gatekeeper.SignatureRequest; import org.jets3t.service.utils.signedurl.SignedUrlAndObject; import com.centerkey.utils.BareBonesBrowserLaunch; /** * Dual application and applet for uploading files and XML metadata information to the Amazon S3 * service. *

* For more information and help please see the * Uploader Guide. *

*

* The Uploader is highly configurable through properties specified in a file * uploader.properties. This file must be available at the root of the classpath. * * @author James Murty */ public class Uploader extends JApplet implements S3ServiceEventListener, ActionListener, ListSelectionListener, HyperlinkActivatedListener, CredentialsProvider { private static final long serialVersionUID = 2759324769352022783L; private static final Log log = LogFactory.getLog(Uploader.class); public static final String APPLICATION_DESCRIPTION = "Uploader/" + Constants.JETS3T_VERSION; public static final String UPLOADER_PROPERTIES_FILENAME = "uploader.properties"; private static final String UPLOADER_VERSION_ID = "JetS3t Uploader/" + Constants.JETS3T_VERSION; public static final int WIZARD_SCREEN_1 = 1; public static final int WIZARD_SCREEN_2 = 2; public static final int WIZARD_SCREEN_3 = 3; public static final int WIZARD_SCREEN_4 = 4; public static final int WIZARD_SCREEN_5 = 5; /* * Error codes displayed when errors occur. Each possbile error condition has its own code * to aid in resolving user's problems. */ public static final String ERROR_CODE__MISSING_REQUIRED_PARAM = "100"; public static final String ERROR_CODE__S3_UPLOAD_FAILED = "101"; public static final String ERROR_CODE__UPLOAD_REQUEST_DECLINED = "102"; public static final String ERROR_CODE__TRANSACTION_ID_REQUIRED_TO_CREATE_XML_SUMMARY = "103"; /* * HTTP connection settings for communication *with Gatekeeper only*, the * S3 connection parameters are set in the jets3t.properties file. */ public static final int HTTP_CONNECTION_TIMEOUT = 60000; public static final int SOCKET_CONNECTION_TIMEOUT = 60000; public static final int MAX_CONNECTION_RETRIES = 5; private Frame ownerFrame = null; private UserInputFields userInputFields = null; private Properties userInputProperties = null; private HttpClient httpClientGatekeeper = null; private S3ServiceMulti s3ServiceMulti = null; /** * The files to upload to S3. */ private File[] filesToUpload = null; /** * The list of file extensions accepted by the Uploader. */ private ArrayList validFileExtensions = new ArrayList(); /** * Uploader's properties. */ private Jets3tProperties uploaderProperties = null; /** * Properties set in stand-alone application from the command line arguments. */ private Properties standAloneArgumentProperties = null; private final ByteFormatter byteFormatter = new ByteFormatter(); private final TimeFormatter timeFormatter = new TimeFormatter(); /* * Upload file constraints. */ private int fileMaxCount = 0; private long fileMaxSizeMB = 0; private long fileMinSizeMB = 0; /* * Insets used throughout the application. */ private final Insets insetsDefault = new Insets(3, 5, 3, 5); private final Insets insetsNone = new Insets(0, 0, 0, 0); private final GuiUtils guiUtils = new GuiUtils(); private int currentState = 0; private boolean isRunningAsApplet = false; private HashMap parametersMap = new HashMap(); private SkinsFactory skinsFactory = null; private final GridBagLayout GRID_BAG_LAYOUT = new GridBagLayout(); /* * GUI elements that need to be referenced outside initGui method. */ private JHtmlLabel userGuidanceLabel = null; private JPanel appContentPanel = null; private JPanel buttonsPanel = null; private JPanel primaryPanel = null; private CardLayout primaryPanelCardLayout = null; private CardLayout buttonsPanelCardLayout = null; private JButton backButton = null; private JButton nextButton = null; private JButton cancelUploadButton = null; private JHtmlLabel dragDropTargetLabel = null; private JHtmlLabel fileToUploadLabel = null; private JHtmlLabel fileInformationLabel = null; private JHtmlLabel progressTransferDetailsLabel = null; private JProgressBar progressBar = null; private JHtmlLabel progressStatusTextLabel = null; private JHtmlLabel finalMessageLabel = null; private CancelEventTrigger uploadCancelEventTrigger = null; /** * Set to true when the object/file being uploaded is the final in a set, eg when * the XML metadata is being uploaded after a movie file. */ private volatile boolean uploadingFinalObject = false; /** * If set to true via the "xmlSummary" configuration property, the Uploader will * generate an XML summary document describing the files uploaded by the user and * will upload this summary document to S3. */ private volatile boolean includeXmlSummaryDoc = false; /** * Set to true when a file upload has been cancelled, to prevent the Uploader from * uploading an XML summary file when the prior file upload was cancelled. */ private volatile boolean uploadCancelled = false; /** * Set to true if an upload failed due to a key name clash in S3, in which case an error * message is displayed in the final 'thankyou' screen. */ private boolean fatalErrorOccurred = false; /** * Variable to store application exceptions, so that client failure information can be * included in the information provided to the Gatekeeper when uploads are retried. */ private Exception priorFailureException = null; /** * Constructor to run this application as an Applet. */ public Uploader() { isRunningAsApplet = true; } /** * Constructor to run this application in a stand-alone window. * * @param ownerFrame the frame the application will be displayed in * @throws S3ServiceException */ public Uploader(JFrame ownerFrame, Properties standAloneArgumentProperties) throws S3ServiceException { this.ownerFrame = ownerFrame; this.standAloneArgumentProperties = standAloneArgumentProperties; isRunningAsApplet = false; init(); ownerFrame.getContentPane().add(this); ownerFrame.setBounds(this.getBounds()); ownerFrame.setVisible(true); } /** * Prepares application to run as a GUI by finding/creating a root owner JFrame, and * (if necessary) creating a directory for storing remembered logins. */ @Override public void init() { super.init(); boolean isMissingRequiredInitProperty = false; // Find or create a Frame to own modal dialog boxes. if (this.ownerFrame == null) { Component c = this; while (!(c instanceof Frame) && c.getParent() != null) { c = c.getParent(); } if (!(c instanceof Frame)) { this.ownerFrame = new JFrame(); } else { this.ownerFrame = (Frame) c; } } // Read properties from uploader.properties in classpath. uploaderProperties = Jets3tProperties.getInstance(UPLOADER_PROPERTIES_FILENAME); if (isRunningAsApplet) { // Read parameters for Applet, based on names specified in the uploader properties. String appletParamNames = uploaderProperties.getStringProperty("applet.params", ""); StringTokenizer st = new StringTokenizer(appletParamNames, ","); while (st.hasMoreTokens()) { String paramName = st.nextToken(); String paramValue = this.getParameter(paramName); // Fatal error if a parameter is missing. if (null == paramValue) { log.error("Missing required applet parameter: " + paramName); isMissingRequiredInitProperty = true; } else { log.debug("Found applet parameter: " + paramName + "='" + paramValue + "'"); // Set params as properties in the central properties source for this application. // Note that parameter values will over-write properties with the same name. uploaderProperties.setProperty(paramName, paramValue); // Store params in a separate map, which is used to build XML document. parametersMap.put(paramName, paramValue); } } } else { // Add application parameters properties. if (standAloneArgumentProperties != null) { Enumeration e = standAloneArgumentProperties.keys(); while (e.hasMoreElements()) { String propName = (String) e.nextElement(); String propValue = standAloneArgumentProperties.getProperty(propName); // Fatal error if a parameter is missing. if (null == propValue) { log.error("Missing required command-line property: " + propName); isMissingRequiredInitProperty = true; } else { log.debug("Using command-line property: " + propName + "='" + propValue + "'"); // Set arguments as properties in the central properties source for this application. // Note that argument values will over-write properties with the same name. uploaderProperties.setProperty(propName, propValue); // Store arguments in a separate map, which is used to build XML document. parametersMap.put(propName, propValue); } } } } // Determine the file constraints. fileMaxCount = uploaderProperties.getIntProperty("file.maxCount", 1); fileMaxSizeMB = uploaderProperties.getLongProperty("file.maxSizeMB", 200); fileMinSizeMB = uploaderProperties.getLongProperty("file.minSizeMB", 0); // Initialise the GUI. initGui(); // Jump to error page if there was an exception raised during initialisation. if (isMissingRequiredInitProperty) { failWithFatalError(ERROR_CODE__MISSING_REQUIRED_PARAM); return; } // Determine valid file extensions. String validFileExtensionsStr = uploaderProperties.getStringProperty("file.extensions", ""); if (validFileExtensionsStr != null) { StringTokenizer st = new StringTokenizer(validFileExtensionsStr, ","); while (st.hasMoreTokens()) { validFileExtensions.add(st.nextToken().toLowerCase(Locale.getDefault())); } } } /** * Initialises the application's GUI elements. */ private void initGui() { // Initialise skins factory. skinsFactory = SkinsFactory.getInstance(uploaderProperties.getProperties()); // Set Skinned Look and Feel. LookAndFeel lookAndFeel = skinsFactory.createSkinnedMetalTheme("SkinnedLookAndFeel"); try { UIManager.setLookAndFeel(lookAndFeel); } catch (UnsupportedLookAndFeelException e) { log.error("Unable to set skinned LookAndFeel", e); } // Apply branding String applicationTitle = replaceMessageVariables( uploaderProperties.getStringProperty("gui.applicationTitle", null)); if (applicationTitle != null) { ownerFrame.setTitle(applicationTitle); } String applicationIconPath = uploaderProperties.getStringProperty("gui.applicationIcon", null); if (!isRunningAsApplet && applicationIconPath != null) { guiUtils.applyIcon(ownerFrame, applicationIconPath); } String footerHtml = uploaderProperties.getStringProperty("gui.footerHtml", null); String footerIconPath = uploaderProperties.getStringProperty("gui.footerIcon", null); // Footer for branding boolean includeFooter = false; JHtmlLabel footerLabel = skinsFactory.createSkinnedJHtmlLabel("FooterLabel"); footerLabel.setHyperlinkeActivatedListener(this); footerLabel.setHorizontalAlignment(JLabel.CENTER); if (footerHtml != null) { footerLabel.setText(replaceMessageVariables(footerHtml)); includeFooter = true; } if (footerIconPath != null) { guiUtils.applyIcon(footerLabel, footerIconPath); } userInputFields = new UserInputFields(insetsDefault, this, skinsFactory); // Screeen 1 : User input fields. JPanel screen1Panel = skinsFactory.createSkinnedJPanel("Screen1Panel"); screen1Panel.setLayout(GRID_BAG_LAYOUT); userInputFields.buildFieldsPanel(screen1Panel, uploaderProperties); // Screen 2 : Drag/drop panel. JPanel screen2Panel = skinsFactory.createSkinnedJPanel("Screen2Panel"); screen2Panel.setLayout(GRID_BAG_LAYOUT); dragDropTargetLabel = skinsFactory.createSkinnedJHtmlLabel("DragDropTargetLabel"); dragDropTargetLabel.setHyperlinkeActivatedListener(this); dragDropTargetLabel.setHorizontalAlignment(JLabel.CENTER); dragDropTargetLabel.setVerticalAlignment(JLabel.CENTER); JButton chooseFileButton = skinsFactory.createSkinnedJButton("ChooseFileButton"); chooseFileButton.setActionCommand("ChooseFile"); chooseFileButton.addActionListener(this); configureButton(chooseFileButton, "screen.2.browseButton"); screen2Panel.add(dragDropTargetLabel, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); screen2Panel.add(chooseFileButton, new GridBagConstraints(0, 1, 1, 1, 1, 1, GridBagConstraints.NORTH, GridBagConstraints.NONE, insetsDefault, 0, 0)); // Screen 3 : Information about the file to be uploaded. JPanel screen3Panel = skinsFactory.createSkinnedJPanel("Screen3Panel"); screen3Panel.setLayout(GRID_BAG_LAYOUT); fileToUploadLabel = skinsFactory.createSkinnedJHtmlLabel("FileToUploadLabel"); fileToUploadLabel.setHyperlinkeActivatedListener(this); fileToUploadLabel.setHorizontalAlignment(JLabel.CENTER); fileToUploadLabel.setVerticalAlignment(JLabel.CENTER); screen3Panel.add(fileToUploadLabel, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); // Screen 4 : Upload progress. JPanel screen4Panel = skinsFactory.createSkinnedJPanel("Screen4Panel"); screen4Panel.setLayout(GRID_BAG_LAYOUT); fileInformationLabel = skinsFactory.createSkinnedJHtmlLabel("FileInformationLabel"); fileInformationLabel.setHyperlinkeActivatedListener(this); fileInformationLabel.setHorizontalAlignment(JLabel.CENTER); progressBar = skinsFactory.createSkinnedJProgressBar("ProgressBar", 0, 100); progressBar.setStringPainted(true); progressStatusTextLabel = skinsFactory.createSkinnedJHtmlLabel("ProgressStatusTextLabel"); progressStatusTextLabel.setHyperlinkeActivatedListener(this); progressStatusTextLabel.setText(" "); progressStatusTextLabel.setHorizontalAlignment(JLabel.CENTER); progressTransferDetailsLabel = skinsFactory.createSkinnedJHtmlLabel("ProgressTransferDetailsLabel"); progressTransferDetailsLabel.setHyperlinkeActivatedListener(this); progressTransferDetailsLabel.setText(" "); progressTransferDetailsLabel.setHorizontalAlignment(JLabel.CENTER); cancelUploadButton = skinsFactory.createSkinnedJButton("CancelUploadButton"); cancelUploadButton.setActionCommand("CancelUpload"); cancelUploadButton.addActionListener(this); configureButton(cancelUploadButton, "screen.4.cancelButton"); screen4Panel.add(fileInformationLabel, new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); screen4Panel.add(progressBar, new GridBagConstraints(0, 1, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); screen4Panel.add(progressStatusTextLabel, new GridBagConstraints(0, 2, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); screen4Panel.add(progressTransferDetailsLabel, new GridBagConstraints(0, 3, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); screen4Panel.add(cancelUploadButton, new GridBagConstraints(0, 4, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsDefault, 0, 0)); // Screen 5 : Thankyou message. JPanel screen5Panel = skinsFactory.createSkinnedJPanel("Screen5Panel"); screen5Panel.setLayout(GRID_BAG_LAYOUT); finalMessageLabel = skinsFactory.createSkinnedJHtmlLabel("FinalMessageLabel"); finalMessageLabel.setHyperlinkeActivatedListener(this); finalMessageLabel.setHorizontalAlignment(JLabel.CENTER); screen5Panel.add(finalMessageLabel, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); // Wizard Button panel. backButton = skinsFactory.createSkinnedJButton("backButton"); backButton.setActionCommand("Back"); backButton.addActionListener(this); nextButton = skinsFactory.createSkinnedJButton("nextButton"); nextButton.setActionCommand("Next"); nextButton.addActionListener(this); buttonsPanel = skinsFactory.createSkinnedJPanel("ButtonsPanel"); buttonsPanelCardLayout = new CardLayout(); buttonsPanel.setLayout(buttonsPanelCardLayout); JPanel buttonsInvisiblePanel = skinsFactory.createSkinnedJPanel("ButtonsInvisiblePanel"); JPanel buttonsVisiblePanel = skinsFactory.createSkinnedJPanel("ButtonsVisiblePanel"); buttonsVisiblePanel.setLayout(GRID_BAG_LAYOUT); buttonsVisiblePanel.add(backButton, new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); buttonsVisiblePanel.add(nextButton, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); buttonsPanel.add(buttonsInvisiblePanel, "invisible"); buttonsPanel.add(buttonsVisiblePanel, "visible"); // Overall content panel. appContentPanel = skinsFactory.createSkinnedJPanel("ApplicationContentPanel"); appContentPanel.setLayout(GRID_BAG_LAYOUT); JPanel userGuidancePanel = skinsFactory.createSkinnedJPanel("UserGuidancePanel"); userGuidancePanel.setLayout(GRID_BAG_LAYOUT); primaryPanel = skinsFactory.createSkinnedJPanel("PrimaryPanel"); primaryPanelCardLayout = new CardLayout(); primaryPanel.setLayout(primaryPanelCardLayout); JPanel navigationPanel = skinsFactory.createSkinnedJPanel("NavigationPanel"); navigationPanel.setLayout(GRID_BAG_LAYOUT); appContentPanel.add(userGuidancePanel, new GridBagConstraints(0, 0, 1, 1, 1, 0.2, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); appContentPanel.add(primaryPanel, new GridBagConstraints(0, 1, 1, 1, 1, 0.6, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); appContentPanel.add(navigationPanel, new GridBagConstraints(0, 2, 1, 1, 1, 0.2, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); if (includeFooter) { log.debug("Adding footer for branding"); appContentPanel.add(footerLabel, new GridBagConstraints(0, 3, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); } this.getContentPane().add(appContentPanel); userGuidanceLabel = skinsFactory.createSkinnedJHtmlLabel("UserGuidanceLabel"); userGuidanceLabel.setHyperlinkeActivatedListener(this); userGuidanceLabel.setHorizontalAlignment(JLabel.CENTER); userGuidancePanel.add(userGuidanceLabel, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsNone, 0, 0)); navigationPanel.add(buttonsPanel, new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsNone, 0, 0)); primaryPanel.add(screen1Panel, "screen1"); primaryPanel.add(screen2Panel, "screen2"); primaryPanel.add(screen3Panel, "screen3"); primaryPanel.add(screen4Panel, "screen4"); primaryPanel.add(screen5Panel, "screen5"); // Set preferred sizes int preferredWidth = uploaderProperties.getIntProperty("gui.minSizeWidth", 400); int preferredHeight = uploaderProperties.getIntProperty("gui.minSizeHeight", 500); this.setBounds(new Rectangle(new Dimension(preferredWidth, preferredHeight))); // Initialize drop target. initDropTarget(new Component[] {this} ); // Revert to default Look and Feel for all future GUI elements (eg Dialog boxes). try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { log.error("Unable to set default system LookAndFeel", e); } wizardStepForward(); } /** * Initialise the application's File drop targets for drag and drop copying of local files * to S3. * * @param dropTargetComponents * the components files can be dropped on to transfer them to S3 */ private void initDropTarget(Component[] dropTargetComponents) { DropTargetListener dropTargetListener = new DropTargetListener() { private Border originalBorder = appContentPanel.getBorder(); private Border dragOverBorder = BorderFactory.createBevelBorder(1); private boolean checkValidDrag(DropTargetDragEvent dtde) { if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor) && (DnDConstants.ACTION_COPY == dtde.getDropAction() || DnDConstants.ACTION_MOVE == dtde.getDropAction())) { dtde.acceptDrag(dtde.getDropAction()); return true; } else { dtde.rejectDrag(); return false; } } public void dragEnter(DropTargetDragEvent dtde) { if (checkValidDrag(dtde)) { SwingUtilities.invokeLater(new Runnable() { public void run() { appContentPanel.setBorder(dragOverBorder); }; }); } } public void dragOver(DropTargetDragEvent dtde) { checkValidDrag(dtde); } public void dropActionChanged(DropTargetDragEvent dtde) { checkValidDrag(dtde); } public void dragExit(DropTargetEvent dte) { SwingUtilities.invokeLater(new Runnable() { public void run() { appContentPanel.setBorder(originalBorder); }; }); } public void drop(DropTargetDropEvent dtde) { if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor) && (DnDConstants.ACTION_COPY == dtde.getDropAction() || DnDConstants.ACTION_MOVE == dtde.getDropAction())) { dtde.acceptDrop(dtde.getDropAction()); SwingUtilities.invokeLater(new Runnable() { public void run() { appContentPanel.setBorder(originalBorder); }; }); try { final List fileList = (List) dtde.getTransferable().getTransferData( DataFlavor.javaFileListFlavor); if (fileList != null && fileList.size() > 0) { if (checkProposedUploadFiles(fileList)) { wizardStepForward(); } } } catch (Exception e) { String errorMessage = "Unable to accept dropped item"; log.error(errorMessage, e); ErrorDialog.showDialog(ownerFrame, null, uploaderProperties.getProperties(), errorMessage, e); } } else { dtde.rejectDrop(); } } }; // Attach drop target listener to each target component. for (int i = 0; i < dropTargetComponents.length; i++) { new DropTarget(dropTargetComponents[i], DnDConstants.ACTION_COPY, dropTargetListener, true); } } /** * Checks that all the files in a list are acceptable for uploading. * Files are checked against the following criteria: *

    *
  • There are not too many
  • *
  • The size is greater than the minimum size, and less that the maximum size.
  • *
  • The file has a file extension matching one of those explicitly allowed
  • *
* Any deviations from the rules result in an error message, and the method returns false. * A side-effect of this method is that the wizard is moved forward one screen if the * files are all valid. * * @param fileList * A list of {@link File}s to check. * * @return * true if the files in the list are all acceptable, false otherwise. */ private boolean checkProposedUploadFiles(List fileList) { // Check number of files for upload is within constraints. if (fileMaxCount > 0 && fileList.size() > fileMaxCount) { String errorMessage = "You may only upload " + fileMaxCount + (fileMaxCount == 1? " file" : " files") + " at a time"; ErrorDialog.showDialog(ownerFrame, this, uploaderProperties.getProperties(), errorMessage, null); return false; } // Check file size within constraints. Iterator iter = fileList.iterator(); while (iter.hasNext()) { File file = (File) iter.next(); long fileSizeMB = file.length() / (1024 * 1024); if (fileMinSizeMB > 0 && fileSizeMB < fileMinSizeMB) { ErrorDialog.showDialog(ownerFrame, this, uploaderProperties.getProperties(), "File size must be greater than " + fileMinSizeMB + " MB", null); return false; } if (fileMaxSizeMB > 0 && fileSizeMB > fileMaxSizeMB) { ErrorDialog.showDialog(ownerFrame, this, uploaderProperties.getProperties(), "File size must be less than " + fileMaxSizeMB + " MB", null); return false; } } // Check file extension is acceptable. if (validFileExtensions.size() > 0) { iter = fileList.iterator(); while (iter.hasNext()) { File file = (File) iter.next(); String fileName = file.getName(); String fileExtension = fileName.substring(fileName.lastIndexOf(".") + 1); if (!validFileExtensions.contains(fileExtension.toLowerCase(Locale.getDefault()))) { String extList = validFileExtensions.toString(); extList = extList.substring(1, extList.length() -1); extList = extList.replaceAll(",", " "); ErrorDialog.showDialog(ownerFrame, this, uploaderProperties.getProperties(), "File name must end with one of the following extensions:
" + extList + "", null); return false; } } } filesToUpload = (File[]) fileList.toArray(new File[fileList.size()]); return true; } /** * Builds a Gatekeeper response based on AWS credential information available in the Uploader * properties. The response signs URLs to be valid for 1 day. *

* The required properties are: *

    *
  • AwsAccessKey
  • *
  • AwsSecretKey
  • *
  • S3BucketName
  • *
* * @param objects * @return */ private GatekeeperMessage buildGatekeeperResponse(S3Object[] objects) throws Exception { String awsAccessKey = userInputProperties.getProperty("AwsAccessKey"); String awsSecretKey = userInputProperties.getProperty("AwsSecretKey"); String s3BucketName = userInputProperties.getProperty("S3BucketName"); Calendar cal = Calendar.getInstance(); cal.add(Calendar.DATE, 1); Date expiryDate = cal.getTime(); AWSCredentials awsCredentials = new AWSCredentials(awsAccessKey, awsSecretKey); RestS3Service s3Service = new RestS3Service(awsCredentials); try { /* * Build Gatekeeper request. */ GatekeeperMessage gatekeeperMessage = new GatekeeperMessage(); gatekeeperMessage.addApplicationProperties(userInputProperties); // Add User inputs as application properties. gatekeeperMessage.addApplicationProperties(parametersMap); // Add any Applet/Application parameters as application properties. for (int i = 0; i < objects.length; i++) { String signedPutUrl = s3Service.createSignedPutUrl( s3BucketName, objects[i].getKey(), objects[i].getMetadataMap(), expiryDate, false); SignatureRequest signatureRequest = new SignatureRequest( SignatureRequest.SIGNATURE_TYPE_PUT, objects[i].getKey()); signatureRequest.setBucketName(s3BucketName); signatureRequest.setObjectMetadata(objects[i].getMetadataMap()); signatureRequest.signRequest(signedPutUrl); gatekeeperMessage.addSignatureRequest(signatureRequest); } return gatekeeperMessage; } catch (Exception e) { throw new Exception("Unable to generate locally-signed PUT URLs for testing", e); } } /** * Retrieves a signed PUT URL from the given URL address. * The URL must point at a server-side script or service that accepts POST messages. * The POST message will include parameters for all the items in uploaderProperties, * that is everything in the file uploader.properties plus all the applet's parameters. * Based on this input, the server-side script decides whether to allow access and return * a signed PUT URL. * * @param credsProviderParamName * the name of the parameter containing the server URL target for the PUT request. * @return * the AWS credentials provided by the server-side script if access was allowed, null otherwise. * * @throws HttpException * @throws Exception */ private GatekeeperMessage contactGatewayServer(S3Object[] objects) throws HttpException, Exception { // Retrieve credentials from URL location value by the property 'credentialsServiceUrl'. String gatekeeperUrl = uploaderProperties.getStringProperty( "gatekeeperUrl", "Missing required property gatekeeperUrl"); /* * Build Gatekeeper request. */ GatekeeperMessage gatekeeperMessage = new GatekeeperMessage(); gatekeeperMessage.addApplicationProperties(userInputProperties); // Add User inputs as application properties. gatekeeperMessage.addApplicationProperties(parametersMap); // Add any Applet/Application parameters as application properties. // Make the Uploader's identifier available to Gatekeeper for version compatibility checking (if necessary) gatekeeperMessage.addApplicationProperty( GatekeeperMessage.PROPERTY_CLIENT_VERSION_ID, UPLOADER_VERSION_ID); // If a prior failure has occurred, add information about this failure. if (priorFailureException != null) { gatekeeperMessage.addApplicationProperty(GatekeeperMessage.PROPERTY_PRIOR_FAILURE_MESSAGE, priorFailureException.getMessage()); // Now reset the prior failure variable. priorFailureException = null; } // Add all S3 objects as candiates for PUT signing. for (int i = 0; i < objects.length; i++) { SignatureRequest signatureRequest = new SignatureRequest( SignatureRequest.SIGNATURE_TYPE_PUT, objects[i].getKey()); signatureRequest.setObjectMetadata(objects[i].getMetadataMap()); gatekeeperMessage.addSignatureRequest(signatureRequest); } /* * Build HttpClient POST message. */ // Add all properties/parameters to credentials POST request. PostMethod postMethod = new PostMethod(gatekeeperUrl); Properties properties = gatekeeperMessage.encodeToProperties(); Iterator propsIter = properties.entrySet().iterator(); while (propsIter.hasNext()) { Map.Entry entry = (Map.Entry) propsIter.next(); String fieldName = (String) entry.getKey(); String fieldValue = (String) entry.getValue(); postMethod.setParameter(fieldName, fieldValue); } // Create Http Client if necessary, and include User Agent information. if (httpClientGatekeeper == null) { httpClientGatekeeper = initHttpConnection(); } // Try to detect any necessary proxy configurations. try { ProxyHost proxyHost = PluginProxyUtil.detectProxy(new URL(gatekeeperUrl)); if (proxyHost != null) { HostConfiguration hostConfig = new HostConfiguration(); hostConfig.setProxyHost(proxyHost); httpClientGatekeeper.setHostConfiguration(hostConfig); httpClientGatekeeper.getParams().setAuthenticationPreemptive(true); httpClientGatekeeper.getParams().setParameter(CredentialsProvider.PROVIDER, this); } } catch (Throwable t) { log.debug("No proxy detected"); } // Perform Gateway request. log.debug("Contacting Gatekeeper at: " + gatekeeperUrl); try { int responseCode = httpClientGatekeeper.executeMethod(postMethod); String contentType = postMethod.getResponseHeader("Content-Type").getValue(); if (responseCode == 200) { InputStream responseInputStream = null; Header encodingHeader = postMethod.getResponseHeader("Content-Encoding"); if (encodingHeader != null && "gzip".equalsIgnoreCase(encodingHeader.getValue())) { log.debug("Inflating gzip-encoded response"); responseInputStream = new GZIPInputStream(postMethod.getResponseBodyAsStream()); } else { responseInputStream = postMethod.getResponseBodyAsStream(); } if (responseInputStream == null) { throw new IOException("No response input stream available from Gatekeeper"); } Properties responseProperties = new Properties(); try { responseProperties.load(responseInputStream); } finally { responseInputStream.close(); } GatekeeperMessage gatekeeperResponseMessage = GatekeeperMessage.decodeFromProperties(responseProperties); // Check for Gatekeeper Error Code in response. String gatekeeperErrorCode = gatekeeperResponseMessage.getApplicationProperties() .getProperty(GatekeeperMessage.APP_PROPERTY_GATEKEEPER_ERROR_CODE); if (gatekeeperErrorCode != null) { log.warn("Received Gatekeeper error code: " + gatekeeperErrorCode); failWithFatalError(gatekeeperErrorCode); return null; } if (gatekeeperResponseMessage.getSignatureRequests().length != objects.length) { throw new Exception("The Gatekeeper service did not provide the necessary " + objects.length + " response items"); } return gatekeeperResponseMessage; } else { log.debug("The Gatekeeper did not permit a request. Response code: " + responseCode + ", Response content type: " + contentType); throw new Exception("The Gatekeeper did not permit your request"); } } catch (Exception e) { throw new Exception("Gatekeeper did not respond", e); } finally { postMethod.releaseConnection(); } } private GatekeeperMessage retrieveGatekeeperResponse(S3Object[] objects) throws Exception { // Check whether Uploader has all necessary credentials from user inputs. boolean s3CredentialsProvided = userInputProperties.getProperty("AwsAccessKey") != null && userInputProperties.getProperty("AwsSecretKey") != null && userInputProperties.getProperty("S3BucketName") != null; GatekeeperMessage gatekeeperMessage = null; if (s3CredentialsProvided) { log.debug("S3 login credentials and bucket name are available, the Uploader " + "will generate its own Gatekeeper response"); gatekeeperMessage = buildGatekeeperResponse(objects); } else { gatekeeperMessage = contactGatewayServer(objects); } return gatekeeperMessage; } /** * Uploads to S3 the file referenced by the variable fileToUpload, providing * progress feedback to the user all the while. * */ private void uploadFilesToS3() { try { SwingUtilities.invokeLater(new Runnable() { public void run() { // Creating file hash message progressStatusTextLabel.setText(replaceMessageVariables( uploaderProperties.getStringProperty("screen.4.hashingMessage", "Missing property 'screen.4.hashingMessage'"))); }; }); // Calculate total files size. final long filesSizeTotal[] = new long[1]; for (int i = 0; i < filesToUpload.length; i++) { filesSizeTotal[0] += filesToUpload[i].length(); } // Monitor generation of MD5 hash, and provide feedback via the progress bar. BytesProgressWatcher progressWatcher = new BytesProgressWatcher(filesSizeTotal[0]) { @Override public void updateBytesTransferred(long byteCount) { super.updateBytesTransferred(byteCount); final int percentage = (int)((double)getBytesTransferred() * 100 / getBytesToTransfer()); SwingUtilities.invokeLater(new Runnable() { public void run() { progressBar.setValue(percentage); } }); } }; // Create objects for upload from file listing. S3Object[] objectsForUpload = new S3Object[filesToUpload.length]; for (int i = 0; i < filesToUpload.length; i++) { File file = filesToUpload[i]; log.debug("Computing MD5 hash for file: " + file); byte[] fileHash = ServiceUtils.computeMD5Hash( new ProgressMonitoredInputStream( // Report on MD5 hash progress. new FileInputStream(file), progressWatcher)); S3Object object = new S3Object(null, file); object.setMd5Hash(fileHash); objectsForUpload[i] = object; } // Obtain Gatekeeper response. SwingUtilities.invokeLater(new Runnable() { public void run() { progressStatusTextLabel.setText( replaceMessageVariables(uploaderProperties.getStringProperty("screen.4.connectingMessage", "Missing property 'screen.4.connectingMessage'"))); progressBar.setValue(0); }; }); GatekeeperMessage gatekeeperMessage = null; try { gatekeeperMessage = retrieveGatekeeperResponse(objectsForUpload); } catch (Exception e) { log.info("Upload request was denied", e); failWithFatalError(ERROR_CODE__UPLOAD_REQUEST_DECLINED); return; } // If we get a null response, presume the error has already been handled. if (gatekeeperMessage == null) { return; } log.debug("Gatekeeper response properties: " + gatekeeperMessage.encodeToProperties()); XmlGenerator xmlGenerator = new XmlGenerator(); xmlGenerator.addApplicationProperties(gatekeeperMessage.getApplicationProperties()); xmlGenerator.addMessageProperties(gatekeeperMessage.getMessageProperties()); SignedUrlAndObject[] uploadItems = prepareSignedObjects( objectsForUpload, gatekeeperMessage.getSignatureRequests(), xmlGenerator); if (s3ServiceMulti == null) { s3ServiceMulti = new S3ServiceMulti( new RestS3Service(null, APPLICATION_DESCRIPTION, this), this); } /* * Prepare XML Summary document for upload, if the summary option is set. */ includeXmlSummaryDoc = uploaderProperties.getBoolProperty("xmlSummary", false); S3Object summaryXmlObject = null; if (includeXmlSummaryDoc) { String priorTransactionId = gatekeeperMessage.getMessageProperties().getProperty( GatekeeperMessage.PROPERTY_TRANSACTION_ID); if (priorTransactionId == null) { failWithFatalError(ERROR_CODE__TRANSACTION_ID_REQUIRED_TO_CREATE_XML_SUMMARY); return; } summaryXmlObject = new S3Object( null, priorTransactionId + ".xml", xmlGenerator.generateXml()); summaryXmlObject.setContentType(Mimetypes.MIMETYPE_XML); summaryXmlObject.addMetadata(GatekeeperMessage.PROPERTY_TRANSACTION_ID, priorTransactionId); summaryXmlObject.addMetadata(GatekeeperMessage.SUMMARY_DOCUMENT_METADATA_FLAG, "true"); } // PUT the user's selected files in S3. uploadCancelled = false; uploadingFinalObject = (!includeXmlSummaryDoc); s3ServiceMulti.putObjects(uploadItems); // If an XML summary document is required, PUT this in S3 as well. if (includeXmlSummaryDoc && !uploadCancelled && !fatalErrorOccurred) { SwingUtilities.invokeLater(new Runnable() { public void run() { fileInformationLabel.setText( replaceMessageVariables(uploaderProperties.getStringProperty("screen.4.summaryFileInformation", "Missing property 'screen.4.summaryFileInformation'"))); progressStatusTextLabel.setText( replaceMessageVariables(uploaderProperties.getStringProperty("screen.4.connectingMessage", "Missing property 'screen.4.connectingMessage'"))); }; }); // Retrieve signed URL to PUT the XML summary document. gatekeeperMessage = retrieveGatekeeperResponse(new S3Object[] {summaryXmlObject}); SignedUrlAndObject[] xmlSummaryItem = prepareSignedObjects(new S3Object[] {summaryXmlObject}, gatekeeperMessage.getSignatureRequests(), null); // PUT the XML summary document. uploadingFinalObject = true; s3ServiceMulti.putObjects(xmlSummaryItem); } } catch (final Exception e) { priorFailureException = e; SwingUtilities.invokeLater(new Runnable() { public void run() { wizardStepBackward(); log.error("File upload failed", e); ErrorDialog.showDialog(ownerFrame, null, uploaderProperties.getProperties(), "File upload failed", e); }; }); } } private SignedUrlAndObject[] prepareSignedObjects(S3Object[] objects, SignatureRequest[] signatureRequests, XmlGenerator xmlGenerator) throws Exception { List signedObjects = new ArrayList(); String firstDeclineReason = null; for (int i = 0; i < signatureRequests.length; i++) { SignatureRequest request = signatureRequests[i]; S3Object object = objects[i]; // Store summary information in XML document generator. if (xmlGenerator != null) { Map clonedMetadata = new HashMap(); clonedMetadata.putAll(object.getMetadataMap()); xmlGenerator.addSignatureRequest(object.getKey(), object.getBucketName(), clonedMetadata, request); } if (request.isSigned()) { // Update object with any changes dictated by Gatekeeper. if (request.getObjectKey() != null) { object.setKey(request.getObjectKey()); } if (request.getBucketName() != null) { object.setBucketName(request.getBucketName()); } if (request.getObjectMetadata() != null && request.getObjectMetadata().size() > 0) { object.replaceAllMetadata(request.getObjectMetadata()); } SignedUrlAndObject urlAndObject = new SignedUrlAndObject(request.getSignedUrl(), object); signedObjects.add(urlAndObject); } else { // If ANY requests are declined, we will fail with a fatal error message. String declineReason = (request.getDeclineReason() == null ? "Unknown" : request.getDeclineReason()); log.warn("Upload of '" + objects[i].getKey() + "' was declined for reason: " + declineReason); if (firstDeclineReason == null) { firstDeclineReason = declineReason; } } } if (firstDeclineReason != null) { throw new Exception("Your upload" + (objects.length > 1 ? "s were" : " was") + " declined by the Gatekeeper. Reason: " + firstDeclineReason); } return (SignedUrlAndObject[]) signedObjects.toArray(new SignedUrlAndObject[signedObjects.size()]); } /** * Listener method that responds to events from the jets3t toolkit when objects are * created in S3 - ie when files are uploaded. */ public void s3ServiceEventPerformed(final CreateObjectsEvent event) { if (ServiceEvent.EVENT_STARTED == event.getEventCode()) { SwingUtilities.invokeLater(new Runnable() { public void run() { // Cancel button is enabled unless this upload is for the XML summary doc. boolean isXmlSummaryUpload = includeXmlSummaryDoc && uploadingFinalObject; cancelUploadButton.setEnabled(!isXmlSummaryUpload); } }); ThreadWatcher watcher = event.getThreadWatcher(); uploadCancelEventTrigger = watcher.getCancelEventListener(); // Show percentage of bytes transferred. String bytesTotalStr = byteFormatter.formatByteSize(watcher.getBytesTotal()); final String statusText = "Uploaded 0 of " + bytesTotalStr; SwingUtilities.invokeLater(new Runnable() { public void run() { progressStatusTextLabel.setText(replaceMessageVariables(statusText)); progressBar.setValue(0); } }); } else if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { ThreadWatcher watcher = event.getThreadWatcher(); if (watcher.getBytesTransferred() >= watcher.getBytesTotal()) { // Upload is completed, just waiting on resonse from S3. String statusText = "Upload completed, awaiting confirmation"; progressBar.setValue(100); progressStatusTextLabel.setText(replaceMessageVariables(statusText)); progressTransferDetailsLabel.setText(""); } else { String bytesCompletedStr = byteFormatter.formatByteSize(watcher.getBytesTransferred()); String bytesTotalStr = byteFormatter.formatByteSize(watcher.getBytesTotal()); String statusText = "Uploaded " + bytesCompletedStr + " of " + bytesTotalStr; int percentage = (int) (((double)watcher.getBytesTransferred() / watcher.getBytesTotal()) * 100); long bytesPerSecond = watcher.getBytesPerSecond(); String transferDetailsText = "Speed: " + byteFormatter.formatByteSize(bytesPerSecond) + "/s"; if (watcher.isTimeRemainingAvailable()) { long secondsRemaining = watcher.getTimeRemaining(); if (transferDetailsText.trim().length() > 0) { transferDetailsText += " - "; } transferDetailsText += "Time remaining: " + timeFormatter.formatTime(secondsRemaining); } progressBar.setValue(percentage); progressStatusTextLabel.setText(replaceMessageVariables(statusText)); progressTransferDetailsLabel.setText(replaceMessageVariables(transferDetailsText)); } } else if (ServiceEvent.EVENT_COMPLETED == event.getEventCode()) { if (uploadingFinalObject) { drawWizardScreen(WIZARD_SCREEN_5); } progressBar.setValue(0); progressStatusTextLabel.setText(""); progressTransferDetailsLabel.setText(""); SwingUtilities.invokeLater(new Runnable() { public void run() { cancelUploadButton.setEnabled(false); } }); } else if (ServiceEvent.EVENT_CANCELLED == event.getEventCode()) { progressBar.setValue(0); progressStatusTextLabel.setText(""); progressTransferDetailsLabel.setText(""); uploadCancelled = true; drawWizardScreen(WIZARD_SCREEN_3); SwingUtilities.invokeLater(new Runnable() { public void run() { cancelUploadButton.setEnabled(false); } }); } else if (ServiceEvent.EVENT_ERROR == event.getEventCode()) { progressBar.setValue(0); progressStatusTextLabel.setText(""); progressTransferDetailsLabel.setText(""); failWithFatalError(ERROR_CODE__S3_UPLOAD_FAILED); SwingUtilities.invokeLater(new Runnable() { public void run() { cancelUploadButton.setEnabled(false); } }); } } /** * Configures a button's text, tooltip and image using uploader properties prefixed * with the given properties prefix. * * @param button * @param propertiesPrefix */ private void configureButton(JButton button, String propertiesPrefix) { button.setHorizontalAlignment(JLabel.CENTER); String buttonImagePath = uploaderProperties .getStringProperty(propertiesPrefix + ".image", null); String buttonText = replaceMessageVariables(uploaderProperties .getStringProperty(propertiesPrefix + ".text", null)); String buttonTooltip = replaceMessageVariables(uploaderProperties .getStringProperty(propertiesPrefix + ".tooltip", null)); boolean hasImage = false; boolean hasText = false; if (buttonImagePath != null && buttonImagePath.length() > 0) { if (!guiUtils.applyIcon(button, buttonImagePath)) { log.error("Unable to load image URL for a button with property prefix '" + propertiesPrefix + "'. Image path: " + buttonImagePath); } else { hasImage = true; } } if (buttonText != null && buttonText.length() > 0) { String text = replaceMessageVariables(buttonText); button.setText(text); button.setMnemonic(text.charAt(0)); hasText = true; } if (buttonTooltip != null && buttonTooltip.length() > 0) { button.setToolTipText(buttonTooltip); } if (!hasImage && !hasText) { button.setVisible(false); } else { button.setVisible(true); } } /** * Draws the wizard screen appropriate to the stage in the wizard process the user has * reached. * * @param nextState * an integer detailing the screen the user is moving to. */ private void drawWizardScreen(int nextState) { // Configure screen based on properties. String title = uploaderProperties.getStringProperty( "screen." + nextState + ".title", ""); userGuidanceLabel.setText(replaceMessageVariables(title)); configureButton(nextButton, "screen." + nextState + ".nextButton"); configureButton(backButton, "screen." + nextState + ".backButton"); this.getDropTarget().setActive(false); if (nextState == WIZARD_SCREEN_1) { primaryPanelCardLayout.show(primaryPanel, "screen1"); buttonsPanelCardLayout.show(buttonsPanel, "visible"); } else if (nextState == WIZARD_SCREEN_2) { userInputProperties = userInputFields.getUserInputsAsProperties(false); primaryPanelCardLayout.show(primaryPanel, "screen2"); dragDropTargetLabel.setText( replaceMessageVariables(uploaderProperties.getStringProperty("screen.2.dragDropPrompt", "Missing property 'screen.2.dragDropPrompt'"))); this.getDropTarget().setActive(true); } else if (nextState == WIZARD_SCREEN_3) { primaryPanelCardLayout.show(primaryPanel, "screen3"); String fileInformation = uploaderProperties.getStringProperty("screen.3.fileInformation", "Missing property 'screen.3.fileInformation'"); fileToUploadLabel.setText(replaceMessageVariables(fileInformation)); } else if (nextState == WIZARD_SCREEN_4) { primaryPanelCardLayout.show(primaryPanel, "screen4"); String fileInformation = uploaderProperties.getStringProperty("screen.4.fileInformation", "Missing property 'screen.4.fileInformation'"); fileInformationLabel.setText(replaceMessageVariables(fileInformation)); cancelUploadButton.setEnabled(false); new Thread() { @Override public void run() { uploadFilesToS3(); } }.start(); } else if (nextState == WIZARD_SCREEN_5) { primaryPanelCardLayout.show(primaryPanel, "screen5"); String finalMessage = null; if (fatalErrorOccurred) { finalMessage = uploaderProperties.getStringProperty("screen.5.errorMessage", "Missing property 'screen.5.errorMessage'"); } else { finalMessage = uploaderProperties.getStringProperty("screen.5.thankyouMessage", "Missing property 'screen.5.thankyouMessage'"); } finalMessageLabel.setText(replaceMessageVariables(finalMessage)); } else { log.error("Ignoring unexpected wizard screen number: " + nextState); return; } currentState = nextState; } /** * Move the wizard forward one step/screen. */ private void wizardStepForward() { drawWizardScreen(currentState + 1); } /** * Move the wizard backward one step/screen. */ private void wizardStepBackward() { drawWizardScreen(currentState - 1); } /** * When a fatal error occurs, go straight to last screen to display the error message * and make the error code available as a variable (${errorCode}) to be used * in the error message displayed to the user. *

* If there is an Uploader property errorCodeMessage.<code> corresponding * to this error code, the value of this property is made available as a variable * (${errorMessage}). If there is no such property available the * ${errorMessage} variable will be an empty string. * * * @param errorCode * the error code, which may correspond with an error message in uploader.properties. */ private void failWithFatalError(String errorCode) { uploaderProperties.setProperty("errorCode", errorCode); String errorCodeMessagePropertyName = "errorCodeMessage." + errorCode; String errorCodeMessage = uploaderProperties.getStringProperty(errorCodeMessagePropertyName, ""); uploaderProperties.setProperty("errorMessage", errorCodeMessage); fatalErrorOccurred = true; drawWizardScreen(WIZARD_SCREEN_5); } /** * Replaces variables of the form ${variableName} in the input string with the value of that * variable name in the local uploaderProperties properties object, or with one of the * following special variables: *

    *
  • fileName : Name of file being uploaded
  • *
  • fileSize : Size of the file being uploaded, eg 1.04 MB
  • *
  • filePath : Absolute path of the file being uploaded
  • *
  • maxFileSize : The maxiumum allowed file size in MB
  • *
  • maxFileCount : The maximum number of files that may be uploaded
  • *
  • validFileExtensions : A list of the file extensions allowed
  • *
* If the variable named in the input string is not available, or has no value, the variable * reference is left in the result. * * @param message * string that may have variables to replace * @return * the input string with any variable referenced replaced with the variable's value. */ private String replaceMessageVariables(String message) { if (message == null) { return ""; } String result = message; // Replace upload file variables, if an upload file has been chosen. if (filesToUpload != null) { long filesSize = 0; StringBuffer fileNameList = new StringBuffer(); for (int i = 0; i < filesToUpload.length; i++) { filesSize += filesToUpload[i].length(); fileNameList.append(filesToUpload[i].getName()).append(" "); } result = result.replaceAll("\\$\\{fileNameList\\}", fileNameList.toString()); result = result.replaceAll("\\$\\{filesSize\\}", byteFormatter.formatByteSize(filesSize)); } result = result.replaceAll("\\$\\{maxFileSize\\}", String.valueOf(fileMaxSizeMB)); result = result.replaceAll("\\$\\{maxFileCount\\}", String.valueOf(fileMaxCount)); String extList = validFileExtensions.toString(); extList = extList.substring(1, extList.length() -1); extList = extList.replaceAll(",", " "); result = result.replaceAll("\\$\\{validFileExtensions\\}", extList); Pattern pattern = Pattern.compile("\\$\\{.+?\\}"); Matcher matcher = pattern.matcher(result); int offset = 0; while (matcher.find(offset)) { String variable = matcher.group(); String variableName = variable.substring(2, variable.length() - 1); String replacement = null; if (userInputProperties != null && userInputProperties.containsKey(variableName)) { log.debug("Replacing variable '" + variableName + "' with value from a user input field"); replacement = userInputProperties.getProperty(variableName, null); } else if (parametersMap != null && parametersMap.containsKey(variableName)) { log.debug("Replacing variable '" + variableName + "' with value from Uploader's parameters"); replacement = (String) parametersMap.get(variableName); } else if (uploaderProperties != null && uploaderProperties.containsKey(variableName)) { log.debug("Replacing variable '" + variableName + "' with value from uploader.properties file"); replacement = uploaderProperties.getStringProperty(variableName, null); } if (replacement != null) { result = result.substring(0, matcher.start()) + replacement + result.substring(matcher.end()); offset = matcher.start() + 1; matcher.reset(result); } else { offset = matcher.start() + 1; } } if (!result.equals(message)) { log.debug("Replaced variables in text: " + message + " => " + result); } return result; } /** * Handles GUI actions. */ public void actionPerformed(ActionEvent actionEvent) { if ("Next".equals(actionEvent.getActionCommand())) { wizardStepForward(); } else if ("Back".equals(actionEvent.getActionCommand())) { wizardStepBackward(); } else if ("ChooseFile".equals(actionEvent.getActionCommand())) { JFileChooser fileChooser = new JFileChooser(); if (validFileExtensions.size() > 0) { UploaderFileExtensionFilter filter = new UploaderFileExtensionFilter( "Allowed files", validFileExtensions); fileChooser.setFileFilter(filter); } fileChooser.setMultiSelectionEnabled(fileMaxCount > 1); fileChooser.setDialogTitle("Choose file" + (fileMaxCount > 1 ? "s" : "") + " to upload"); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); fileChooser.setApproveButtonText("Choose file" + (fileMaxCount > 1 ? "s" : "")); int returnVal = fileChooser.showOpenDialog(ownerFrame); if (returnVal != JFileChooser.APPROVE_OPTION) { return; } List fileList = new ArrayList(); if (fileChooser.getSelectedFiles().length > 0) { fileList.addAll(Arrays.asList(fileChooser.getSelectedFiles())); } else { fileList.add(fileChooser.getSelectedFile()); } if (checkProposedUploadFiles(fileList)) { wizardStepForward(); } } else if ("CancelUpload".equals(actionEvent.getActionCommand())) { if (uploadCancelEventTrigger != null) { uploadCancelEventTrigger.cancelTask(this); progressBar.setValue(0); } else { log.warn("Ignoring attempt to cancel file upload when cancel trigger is not available"); } } else { log.warn("Unrecognised action command, ignoring: " + actionEvent.getActionCommand()); } } private HttpClient initHttpConnection() { // Set client parameters. HttpClientParams clientParams = new HttpClientParams(); clientParams.setParameter(HttpMethodParams.USER_AGENT, ServiceUtils.getUserAgentDescription(APPLICATION_DESCRIPTION)); // Replace default error retry handler. clientParams.setParameter(HttpClientParams.RETRY_HANDLER, new HttpMethodRetryHandler() { public boolean retryMethod(HttpMethod httpMethod, IOException ioe, int executionCount) { if (executionCount > MAX_CONNECTION_RETRIES) { log.error("Retried connection " + executionCount + " times, which exceeds the maximum retry count of " + MAX_CONNECTION_RETRIES); return false; } log.warn("Retrying request - attempt " + executionCount + " of " + MAX_CONNECTION_RETRIES); return true; } }); // Set connection parameters. HttpConnectionManagerParams connectionParams = new HttpConnectionManagerParams(); connectionParams.setConnectionTimeout(HTTP_CONNECTION_TIMEOUT); connectionParams.setSoTimeout(SOCKET_CONNECTION_TIMEOUT); connectionParams.setStaleCheckingEnabled(false); HttpClient httpClient = new HttpClient(clientParams); httpClient.getHttpConnectionManager().setParams(connectionParams); return httpClient; } /** * Follows hyperlinks clicked on by a user. This is achieved differently depending on whether * Cockpit is running as an applet or as a stand-alone application: *
    *
  • Application: Detects the default browser application for the user's system (using * BareBonesBrowserLaunch) and opens the link as a new window in that browser
  • *
  • Applet: Opens the link in the current browser using the applet's context
  • *
* * @param url * the url to open * @param target * the target pane to open the url in, eg "_blank". This may be null. */ public void followHyperlink(URL url, String target) { if (isRunningAsApplet) { if (target == null) { getAppletContext().showDocument(url); } else { getAppletContext().showDocument(url, target); } } else { BareBonesBrowserLaunch.openURL(url.toString()); } } /** * Implementation method for the CredentialsProvider interface. *

* Based on sample code: * InteractiveAuthenticationExample * */ public Credentials getCredentials(AuthScheme authscheme, String host, int port, boolean proxy) throws CredentialsNotAvailableException { if (authscheme == null) { return null; } try { Credentials credentials = null; if (authscheme instanceof NTLMScheme) { AuthenticationDialog pwDialog = new AuthenticationDialog( ownerFrame, "Authentication Required", "Host " + host + ":" + port + " requires Windows authentication", true); pwDialog.setVisible(true); if (pwDialog.getUser().length() > 0) { credentials = new NTCredentials(pwDialog.getUser(), pwDialog.getPassword(), host, pwDialog.getDomain()); } pwDialog.dispose(); } else if (authscheme instanceof RFC2617Scheme) { AuthenticationDialog pwDialog = new AuthenticationDialog( ownerFrame, "Authentication Required", "

Host " + host + ":" + port + "" + " requires authentication for the realm:
" + authscheme.getRealm() + "
", false); pwDialog.setVisible(true); if (pwDialog.getUser().length() > 0) { credentials = new UsernamePasswordCredentials(pwDialog.getUser(), pwDialog.getPassword()); } pwDialog.dispose(); } else { throw new CredentialsNotAvailableException("Unsupported authentication scheme: " + authscheme.getSchemeName()); } return credentials; } catch (IOException e) { throw new CredentialsNotAvailableException(e.getMessage(), e); } } // S3 Service events that are not used in this Uploader application. public void s3ServiceEventPerformed(ListObjectsEvent event) {} public void s3ServiceEventPerformed(CreateBucketsEvent event) {} public void s3ServiceEventPerformed(DeleteObjectsEvent event) {} public void s3ServiceEventPerformed(GetObjectsEvent event) {} public void s3ServiceEventPerformed(GetObjectHeadsEvent event) {} public void s3ServiceEventPerformed(LookupACLEvent event) {} public void s3ServiceEventPerformed(UpdateACLEvent event) {} public void s3ServiceEventPerformed(DownloadObjectsEvent event) {} public void s3ServiceEventPerformed(CopyObjectsEvent event) {} public void s3ServiceEventPerformed(DeleteVersionedObjectsEvent event) {} public void valueChanged(ListSelectionEvent arg0) {} /** * Run the Uploader as a stand-alone application. * * @param args * @throws Exception */ public static void main(String args[]) throws Exception { JFrame ownerFrame = new JFrame("JetS3t Uploader"); ownerFrame.addWindowListener(new WindowListener() { public void windowOpened(WindowEvent e) { } public void windowClosing(WindowEvent e) { e.getWindow().dispose(); } public void windowClosed(WindowEvent e) { } public void windowIconified(WindowEvent e) { } public void windowDeiconified(WindowEvent e) { } public void windowActivated(WindowEvent e) { } public void windowDeactivated(WindowEvent e) { } }); // Read arguments as properties of the form: '=' Properties argumentProperties = new Properties(); if (args.length > 0) { for (int i = 0; i < args.length; i++) { String arg = args[i]; int delimIndex = arg.indexOf("="); if (delimIndex >= 0) { String name = arg.substring(0, delimIndex); String value = arg.substring(delimIndex + 1); argumentProperties.put(name, value); } else { System.out.println("Ignoring property argument with incorrect format: " + arg); } } } new Uploader(ownerFrame, argumentProperties); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/uploader/XmlGenerator.java0000644000000000000000000002341211427702124022324 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.uploader; import java.io.StringWriter; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.jets3t.service.utils.ServiceUtils; import org.jets3t.service.utils.gatekeeper.SignatureRequest; import org.w3c.dom.CDATASection; import org.w3c.dom.Document; import org.w3c.dom.Element; /** * Generates XML documents containing metadata about files uploaded to Amazon S3 * by the Uploader. The XML document includes metadata for user inputs, * inputs sourced from applet parameter tags, and additional information * available from the uploader such as filenames and generated UUID. * * @author James Murty */ public class XmlGenerator { public static final String xmlVersionNumber = "1.0"; private List objectRequestList = new ArrayList(); private Map applicationProperties = new HashMap(); private Map messageProperties = new HashMap(); /** * Add a signature request item to the XML document to store the request, and details about * the object the request was related to. * * @param key * the key name of the object the signature request applies to. * @param bucketName * the bucket containing the object. * @param metadata * the object's metadata * @param signatureRequest * the signature request for the object. */ public void addSignatureRequest(String key, String bucketName, Map metadata, SignatureRequest signatureRequest) { objectRequestList.add(new ObjectAndSignatureRequestDetails(key, bucketName, metadata, signatureRequest)); } /** * Add application-specific properties to the XML document. * * @param properties */ public void addApplicationProperties(Map properties) { applicationProperties.putAll(properties); } /** * Add message-specific properties to the XML document. * * @param properties */ public void addMessageProperties(Map properties) { messageProperties.putAll(properties); } private class ObjectAndSignatureRequestDetails { public String key = null; public String bucketName = null; public Map metadata = null; public SignatureRequest signatureRequest = null; public ObjectAndSignatureRequestDetails(String key, String bucketName, Map metadata, SignatureRequest signatureRequest) { this.key = key; this.bucketName = bucketName; this.metadata = metadata; this.signatureRequest = signatureRequest; } } /** * Generates an XML document containing metadata information as Property elements. * The root of the document is the element Uploader. * * @return * an XML document string containing Property elements. * * @throws Exception */ public String generateXml() throws Exception { DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document document = builder.newDocument(); Element rootElem = document.createElement("Uploader"); document.appendChild(rootElem); rootElem.setAttribute("version", xmlVersionNumber); rootElem.setAttribute("uploadDate", ServiceUtils.formatIso8601Date(new Date())); // Add application properties (user inputs and application parameters) to XML document. for (Iterator iter = applicationProperties.entrySet().iterator(); iter.hasNext();) { Map.Entry entry = (Map.Entry) iter.next(); String propertyName = (String) entry.getKey(); String propertyValue = (String) entry.getValue(); rootElem.appendChild(createPropertyElement(document, propertyName, propertyValue, "ApplicationProperty")); } // Add message properties (user inputs and application parameters) to XML document. for (Iterator iter = messageProperties.entrySet().iterator(); iter.hasNext();) { Map.Entry entry = (Map.Entry) iter.next(); String propertyName = (String) entry.getKey(); String propertyValue = (String) entry.getValue(); rootElem.appendChild(createPropertyElement(document, propertyName, propertyValue, "MessageProperty")); } // Add Object request details to XML document. ObjectAndSignatureRequestDetails[] details = (ObjectAndSignatureRequestDetails[]) objectRequestList .toArray(new ObjectAndSignatureRequestDetails[objectRequestList.size()]); for (int i = 0; i < details.length; i++) { ObjectAndSignatureRequestDetails objectDetails = details[i]; rootElem.appendChild(createSignatureRequestElement(document, objectDetails)); } // Serialize XML document to String. StringWriter writer = new StringWriter(); StreamResult streamResult = new StreamResult(writer); DOMSource domSource = new DOMSource(document); TransformerFactory tf = TransformerFactory.newInstance(); Transformer serializer = tf.newTransformer(); serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); serializer.setOutputProperty(OutputKeys.INDENT, "yes"); serializer.transform(domSource, streamResult); return writer.toString(); } /** * Creates a Property XML element for a document. * * @param document * the document the property is being created for. * @param propertyName * the property's name, becomes a name attribute of the element. * @param propertyValue * the property's value, becomes the CDATA text value of the element. If this value * is null, the Property element is empty. * @param source * text to describe the source of the information, such as userinput or parameter. * Becomes a source attribute of the element. * * @return * a Property element. */ private Element createPropertyElement( Document document, String propertyName, String propertyValue, String source) { Element propertyElem = document.createElement(source); if (propertyName != null) { propertyElem.setAttribute("name", propertyName); } if (propertyValue != null) { CDATASection cdataSection = document.createCDATASection(propertyValue); propertyElem.appendChild(cdataSection); } return propertyElem; } /** * Creates a SignatureRequest document element. * * @param document * @param details * @return */ private Element createSignatureRequestElement(Document document, ObjectAndSignatureRequestDetails details) { SignatureRequest request = details.signatureRequest; Element requestElem = document.createElement("SignatureRequest"); requestElem.setAttribute("type", request.getSignatureType()); requestElem.setAttribute("signed", String.valueOf(request.isSigned())); requestElem.appendChild( createObjectElement(document, details.key, details.bucketName, details.metadata, "RequestObject")); if (request.isSigned()) { requestElem.appendChild( createObjectElement(document, request.getObjectKey(), request.getBucketName(), request.getObjectMetadata(), "SignedObject")); requestElem.appendChild( createPropertyElement(document, null, request.getSignedUrl(), "SignedURL")); } else if (request.getDeclineReason() != null) { requestElem.appendChild( createPropertyElement(document, null, request.getDeclineReason(), "DeclineReason")); } return requestElem; } /** * Creates and element to contain information about an object. * * @param document * @param key * @param bucketName * @param metadata * @param elementName * @return */ private Element createObjectElement(Document document, String key, String bucketName, Map metadata, String elementName) { if (key == null) { key = ""; } if (bucketName == null) { bucketName = ""; } Element objectElement = document.createElement(elementName); objectElement.setAttribute("key", key); objectElement.setAttribute("bucketName", bucketName); Iterator iter = metadata.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); String metadataName = (String) entry.getKey(); String metadataValue = (String) entry.getValue(); if (metadataValue == null) { metadataValue = ""; } objectElement.appendChild( createPropertyElement(document, metadataName, metadataValue, "Metadata")); } return objectElement; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/uploader/UploaderFileExtensionFilter.java0000644000000000000000000000545311427702124025340 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.uploader; import java.io.File; import javax.swing.filechooser.FileFilter; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Locale; /** * Defines which files can be selected within the Uploader's file chooser * for upload to S3. Files are filtered based on their filename extension. * * @author James Murty */ public class UploaderFileExtensionFilter extends FileFilter { private String description = null; private List acceptableFileExtensionsList = null; /** * Construct an extension-based file filter * * @param description * the name for this filter, such as "Movie files" * @param fileExtensionsList * a list of file extensions that the filter will accept, eg "avi", "mpg". */ public UploaderFileExtensionFilter(String description, List fileExtensionsList) { this.description = description; acceptableFileExtensionsList = new ArrayList(); for (Iterator iter = fileExtensionsList.iterator(); iter.hasNext();) { String extension = iter.next().toString(); // Convert to lower case for case-insensitive matches. extension = extension.toLowerCase(Locale.getDefault()); acceptableFileExtensionsList.add(extension); } } /** * @return * True if the file is a Directory, or the file has an extension that matches one of the * allowed extensions provided to this class's constructor. False otherwise. */ public boolean accept(File file) { if (file.isDirectory()) { return true; } String fileName = file.getName(); if (fileName.indexOf(".") >= 0 && fileName.lastIndexOf(".") < fileName.length()) { String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1); // Conver to lower case for case-insensitive matching. fileExt = fileExt.toLowerCase(Locale.getDefault()); return (acceptableFileExtensionsList.contains(fileExt)); } return false; } public String getDescription() { return description; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/cockpit/0002755000000000000000000000000011537563564016712 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/cockpit/gui/0002755000000000000000000000000011441613550017457 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/cockpit/gui/LoginCredentialsPanel.java0000644000000000000000000002323711441613550024535 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty, 2008 Zmanda Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.cockpit.gui; import java.awt.Component; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.ItemSelectable; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.ArrayList; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JTextField; import org.jets3t.gui.HyperlinkActivatedListener; import org.jets3t.gui.JHtmlLabel; /** * A panel for obtaining a user's credentials. The panel prompts for an Access Key and * an Secret Key, and optionally for a Friendly name for an account. * * @author James Murty * @author Nikolas Coukouma */ public class LoginCredentialsPanel extends JPanel implements ItemListener { private static final long serialVersionUID = 5819631423081597078L; private final Insets insetsDefault = new Insets(3, 5, 3, 5); private final Insets insetsZero = new Insets(0, 0, 0, 0); private HyperlinkActivatedListener hyperlinkListener = null; private JTextField accessKeyTextField = null; private JPasswordField secretKeyPasswordField = null; private JCheckBox useDevPayCheckBox = null; private JTextField awsUserTokenTextField = null; private AWSDevPayProductPanel awsProductPanel = null; private JTextField friendlyNameTextField = null; private boolean askForFriendlyName = false; private Component[] awsDevPayComponents = null; public LoginCredentialsPanel(boolean askForFriendlyName, HyperlinkActivatedListener hyperlinkListener) { super(new GridBagLayout()); this.hyperlinkListener = hyperlinkListener; this.askForFriendlyName = askForFriendlyName; initGui(); } private void initGui() { // Textual information. String descriptionText = "
View your " + "AWS Access Identifiers on Amazon's web site.
"; String friendlyNameLabelText = "Nickname"; String friendlyNameTooltipText = "A nickname for your stored account"; String accessKeyLabelText = "Access Key"; String accessKeyTooltipText = "Your access key"; String secretKeyLabelText = "Secret Key"; String secretKeyTooltipText = "Your secret key"; String useDevPayButtonText = "Use AWS DevPay"; String awsUserTokenLabelText = "DevPay User Token"; String awsUserTokenTooltipText = "Your DevPay user token"; // Components. JHtmlLabel descriptionLabel = new JHtmlLabel(descriptionText, hyperlinkListener); descriptionLabel.setHorizontalAlignment(JLabel.CENTER); JHtmlLabel friendlyNameLabel = new JHtmlLabel(friendlyNameLabelText, hyperlinkListener); friendlyNameTextField = new JTextField(); friendlyNameTextField.setToolTipText(friendlyNameTooltipText); JHtmlLabel accessKeyLabel = new JHtmlLabel(accessKeyLabelText, hyperlinkListener); accessKeyTextField = new JTextField(); accessKeyTextField.setToolTipText(accessKeyTooltipText); JHtmlLabel secretKeyLabel = new JHtmlLabel(secretKeyLabelText, hyperlinkListener); secretKeyPasswordField = new JPasswordField(); secretKeyPasswordField.setToolTipText(secretKeyTooltipText); useDevPayCheckBox = new JCheckBox(useDevPayButtonText); useDevPayCheckBox.setSelected(false); useDevPayCheckBox.addItemListener(this); JHtmlLabel awsUserTokenLabel = new JHtmlLabel(awsUserTokenLabelText, hyperlinkListener); awsUserTokenTextField = new JTextField(); awsUserTokenTextField.setToolTipText(awsUserTokenTooltipText); awsProductPanel = new AWSDevPayProductPanel(); int row = 0; add(descriptionLabel, new GridBagConstraints(0, row++, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); if (askForFriendlyName) { friendlyNameTextField.setText("My Credentials"); add(friendlyNameLabel, new GridBagConstraints(0, row++, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); add(friendlyNameTextField, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); } add(accessKeyLabel, new GridBagConstraints(0, row++, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); add(accessKeyTextField, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); add(secretKeyLabel, new GridBagConstraints(0, row++, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); add(secretKeyPasswordField, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); add(useDevPayCheckBox, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); // These items are displayed conditionally when useDevPayCheckBox is checked add(awsUserTokenLabel, new GridBagConstraints(0, row++, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); add(awsUserTokenTextField, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); add(awsProductPanel, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsZero, 0, 0)); // Padder. add(new JLabel(), new GridBagConstraints(0, row++, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); awsDevPayComponents = new Component[] {awsUserTokenLabel, awsUserTokenTextField, awsProductPanel}; // Make DevPay GUI elements inivisible initially. for (int i = 0; i < awsDevPayComponents.length; i++) { awsDevPayComponents[i].setVisible(useDevPayCheckBox.isSelected()); } this.setPreferredSize(new Dimension(400, 350)); } public void itemStateChanged(ItemEvent e) { ItemSelectable source = e.getItemSelectable(); if (source == useDevPayCheckBox) { for (int i = 0; i < awsDevPayComponents.length; i++) { awsDevPayComponents[i].setVisible(useDevPayCheckBox.isSelected()); } } } /** * @return * the Access Key provided by the user. */ public String getAccessKey() { return accessKeyTextField.getText().trim(); } /** * @return * the Secret Key provided by the user. */ public String getSecretKey() { return new String(secretKeyPasswordField.getPassword()).trim(); } /** * @return * whether or not DevPay authentication should be used */ public boolean getUsingDevPay() { return useDevPayCheckBox.isSelected(); } /** * @return * the user token provided by the user. */ public String getAWSUserToken() { return awsUserTokenTextField.getText().trim(); } /** * @return * the product token provided by the user. */ public String getAWSProductToken() { return awsProductPanel.getAWSProductToken(); } /** * @return * the Friendly Name (nickname) provided by the user, or an empty string if the user was not * prompted to provide one (the askForFriendlyName option was false). */ public String getFriendlyName() { return friendlyNameTextField.getText(); } /** * Verifies that the user has provided the correct inputs, and returns a list * of error messages if not. * * @return * an empty array if there a no input errors, otherwise the array will contain * a list of error messages. */ public String[] checkForInputErrors() { ArrayList errors = new ArrayList(); if (getAccessKey().trim().length() == 0) { errors.add("Access Key must be provided"); } if (getSecretKey().trim().length() == 0) { errors.add("Secret Key must be provided"); } if (getUsingDevPay()) { if (getAWSUserToken().trim().length() == 0) { errors.add("DevPay User Token must be provided"); } if (getAWSProductToken().trim().length() == 0) { errors.add("DevPay Product Token must be provided"); } } return (String[]) errors.toArray(new String[errors.size()]); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/cockpit/gui/LoginLocalFolderPanel.java0000644000000000000000000002646311441613550024472 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.cockpit.gui; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.ListSelectionModel; import javax.swing.table.DefaultTableModel; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.gui.ErrorDialog; import org.jets3t.gui.HyperlinkActivatedListener; import org.jets3t.gui.JHtmlLabel; import org.jets3t.service.Constants; import org.jets3t.service.security.ProviderCredentials; /** * A panel for displaying a user's login credentials where those credentials are stored * in files available on the user's computer. * * @author James Murty */ public class LoginLocalFolderPanel extends JPanel implements ActionListener { private static final long serialVersionUID = 1500994545263522051L; private static final Log log = LogFactory.getLog(LoginLocalFolderPanel.class); private final Insets insetsDefault = new Insets(3, 5, 3, 5); private Frame ownerFrame = null; private HyperlinkActivatedListener hyperlinkListener = null; private File cockpitHomeFolder = null; private JTextField folderPathTextField = null; private JTable accountNicknameTable = null; private ProviderCredentialsFileTableModel nicknamesTableModel = null; private JPasswordField passwordPasswordField = null; public LoginLocalFolderPanel(Frame ownerFrame, HyperlinkActivatedListener hyperlinkListener) { super(new GridBagLayout()); this.ownerFrame = ownerFrame; if (Constants.DEFAULT_PREFERENCES_DIRECTORY.exists()) { this.cockpitHomeFolder = Constants.DEFAULT_PREFERENCES_DIRECTORY; } else { this.cockpitHomeFolder = new File(System.getProperty("user.home")); } this.hyperlinkListener = hyperlinkListener; initGui(); refreshStoredCredentialsTable(); } private void initGui() { // Textual information. String descriptionText = "
" + "Your credentials are stored in encrypted files in a folder on " + "your computer. Each stored login has a nickname." + "
You need to store your credentials before you can use this login method." + "
"; String folderTooltipText = "The folder containing your credentials"; String browseButtonText = "Change Folder"; String accountNicknameText = "Stored logins"; String accountNicknameTooltipText = "Nicknames of the login credentials you have stored"; String passwordLabelText = "Password"; String passwordTooltipText = "The password that protects your encrypted file. " + "This password may be left empty if you are sure your computer cannot be compromised"; // Components. JHtmlLabel descriptionLabel = new JHtmlLabel(descriptionText, hyperlinkListener); descriptionLabel.setHorizontalAlignment(JLabel.CENTER); folderPathTextField = new JTextField(this.cockpitHomeFolder.getAbsolutePath()); folderPathTextField.setEnabled(false); folderPathTextField.setToolTipText(folderTooltipText); JButton browseButton = new JButton(browseButtonText); browseButton.addActionListener(this); JHtmlLabel accountNicknamesLabel = new JHtmlLabel(accountNicknameText, hyperlinkListener); nicknamesTableModel = new ProviderCredentialsFileTableModel(); accountNicknameTable = new JTable(nicknamesTableModel); accountNicknameTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); accountNicknameTable.setShowHorizontalLines(true); accountNicknameTable.getTableHeader().setVisible(false); JScrollPane accountNicknamesScrollPane = new JScrollPane(accountNicknameTable); accountNicknamesScrollPane.setToolTipText(accountNicknameTooltipText); JHtmlLabel passwordLabel = new JHtmlLabel(passwordLabelText, hyperlinkListener); passwordPasswordField = new JPasswordField(); passwordPasswordField.setToolTipText(passwordTooltipText); int row = 0; add(descriptionLabel, new GridBagConstraints(0, row++, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); add(folderPathTextField, new GridBagConstraints(0, row, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); add(browseButton, new GridBagConstraints(1, row++, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); add(accountNicknamesLabel, new GridBagConstraints(0, row++, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); add(accountNicknamesScrollPane, new GridBagConstraints(0, row++, 2, 1, 0, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); add(passwordLabel, new GridBagConstraints(0, row++, 2, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); add(passwordPasswordField, new GridBagConstraints(0, row++, 2, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); } /** * Refreshes the table of stored credentials by finding *.enc files in the * directory specified as the Cockpit home folder. * */ public void refreshStoredCredentialsTable() { nicknamesTableModel.removeAll(); try { File[] files = cockpitHomeFolder.listFiles(); for (int i = 0; files != null && i < files.length; i++) { File candidateFile = files[i]; if (candidateFile.getName().endsWith(".enc")) { // Load partial details from credentials file. ProviderCredentials credentials = ProviderCredentials.load(null, candidateFile); nicknamesTableModel.addCredentialsFile( credentials, candidateFile); } } } catch (Exception e) { String message = "Unable to find credential files in the folder " + cockpitHomeFolder.getAbsolutePath(); log.error(message, e); ErrorDialog.showDialog(ownerFrame, hyperlinkListener, message, e); } } private void chooseFolder() { // Prompt user to choose their Cockpit home directory. JFileChooser fileChooser = new JFileChooser(); fileChooser.setAcceptAllFileFilterUsed(true); fileChooser.setDialogTitle("Choose Cockpit Home Folder"); fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); fileChooser.setApproveButtonText("Choose Folder"); fileChooser.setCurrentDirectory(cockpitHomeFolder); int returnVal = fileChooser.showOpenDialog(ownerFrame); if (returnVal != JFileChooser.APPROVE_OPTION) { return; } else { this.cockpitHomeFolder = fileChooser.getSelectedFile(); this.folderPathTextField.setText(this.cockpitHomeFolder.getAbsolutePath()); refreshStoredCredentialsTable(); } } public void actionPerformed(ActionEvent arg0) { chooseFolder(); } /** * @return * the folder chosen by the user as their Cockpit home. */ public File getHomeFolder() { return this.cockpitHomeFolder; } /** * @return * the credentials encrypted file chosen by the user. */ public File getCredentialsFile() { int selectedNicknameIndex = accountNicknameTable.getSelectedRow(); if (selectedNicknameIndex < 0) { return null; } return nicknamesTableModel.getCredentialsFile(selectedNicknameIndex); } /** * @return * the password the user provided to unlock their encrypted credentials file. */ public String getPassword() { return new String(passwordPasswordField.getPassword()); } /** * Clears the user-provided password field. */ public void clearPassword() { passwordPasswordField.setText(""); } private class ProviderCredentialsFileTableModel extends DefaultTableModel { private static final long serialVersionUID = 8560515388653630790L; ArrayList credentialsList = new ArrayList(); ArrayList credentialFileList = new ArrayList(); public ProviderCredentialsFileTableModel() { super(new String[] {""}, 0); } public int addCredentialsFile(ProviderCredentials credentials, File credentialsFile) { int insertRow = Collections.binarySearch(credentialsList, credentials, new Comparator() { public int compare(Object o1, Object o2) { String name1 = ((ProviderCredentials)o1).getFriendlyName(); String name2 = ((ProviderCredentials)o2).getFriendlyName(); int result = name1.compareToIgnoreCase(name2); return result; } }); if (insertRow >= 0) { // We already have an item with this key, replace it. credentialsList.remove(insertRow); credentialFileList.remove(insertRow); this.removeRow(insertRow); } else { insertRow = (-insertRow) - 1; } // New object to insert. credentialsList.add(insertRow, credentials); credentialFileList.add(insertRow, credentialsFile); this.insertRow(insertRow, new Object[] {credentials.getFriendlyName()}); return insertRow; } public void removeAll() { int rowCount = this.getRowCount(); for (int i = 0; i < rowCount; i++) { this.removeRow(0); } credentialFileList.clear(); credentialsList.clear(); } public File getCredentialsFile(int row) { return (File) credentialFileList.get(row); } @Override public boolean isCellEditable(int row, int column) { return false; } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/cockpit/gui/BucketLoggingDialog.java0000644000000000000000000003754311427702124024200 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.cockpit.gui; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.HashMap; import javax.swing.AbstractAction; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import org.jets3t.gui.ErrorDialog; import org.jets3t.gui.HyperlinkActivatedListener; import org.jets3t.gui.JHtmlLabel; import org.jets3t.gui.ProgressDialog; import org.jets3t.service.S3Service; import org.jets3t.service.model.S3Bucket; import org.jets3t.service.model.S3BucketLoggingStatus; /** * Dialog box for displaying and modifying the logging status of buckets. *

* The first time a bucket is selected its logging status is retrieved from S3 and the details are * displayed, as well as being cached so further lookups aren't necessary. The logging status is * modified by choosing/changing the target log bucket. * * @author James Murty * */ public class BucketLoggingDialog extends JDialog implements ActionListener { private static final long serialVersionUID = 7251165117085406917L; private Frame ownerFrame = null; private S3Service s3Service = null; private HashMap loggingStatusMap = new HashMap(); private JComboBox loggedBucketComboBox = null; private JComboBox loggedToBucketComboBox = null; private JTextField prefixTextField = null; private JButton finishedButton = null; private final Insets insetsDefault = new Insets(3, 5, 3, 5); public BucketLoggingDialog(Frame ownerFrame, S3Service s3Service, String[] bucketNames, HyperlinkActivatedListener hyperlinkListener) { super(ownerFrame, "Bucket Logging Status", true); this.ownerFrame = ownerFrame; this.s3Service = s3Service; String introductionText = "

View and modify your bucket logging settings
" + "Select a bucket in the Log to list to apply changes
Note: The target " + "bucket's ACL permissions are updated if necessary to allow logging

 

"; JHtmlLabel introductionLabel = new JHtmlLabel(introductionText, hyperlinkListener); introductionLabel.setHorizontalAlignment(JLabel.CENTER); JHtmlLabel loggingStatusLabel = new JHtmlLabel("Logging status", hyperlinkListener); loggingStatusLabel.setHorizontalAlignment(JLabel.CENTER); JHtmlLabel loggedBucketLabel = new JHtmlLabel("Bucket:", hyperlinkListener); loggedBucketComboBox = new JComboBox(bucketNames); loggedBucketComboBox.insertItemAt("-- Choose a bucket --", 0); loggedBucketComboBox.addActionListener(this); JHtmlLabel prefixLabel = new JHtmlLabel("Log file prefix:", hyperlinkListener); prefixTextField = new JTextField(); prefixTextField.setToolTipText("Log files for the bucket start with this prefix. The prefix cannot be empty"); JHtmlLabel loggedToBucketLabel = new JHtmlLabel("Log to:", hyperlinkListener); loggedToBucketComboBox = new JComboBox(bucketNames); loggedToBucketComboBox.setToolTipText("Where the bucket's log files will be stored"); loggedToBucketComboBox.insertItemAt("-- Not Logged --", 0); loggedToBucketComboBox.addActionListener(this); finishedButton = new JButton("Finished"); finishedButton.setActionCommand("Finished"); finishedButton.addActionListener(this); // Set default ENTER and ESCAPE buttons. this.getRootPane().setDefaultButton(finishedButton); this.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke("ESCAPE"), "ESCAPE"); this.getRootPane().getActionMap().put("ESCAPE", new AbstractAction() { private static final long serialVersionUID = -6225706489569112809L; public void actionPerformed(ActionEvent actionEvent) { setVisible(false); } }); loggedBucketComboBox.setSelectedIndex(0); loggedToBucketComboBox.setSelectedIndex(0); JPanel panel = new JPanel(new GridBagLayout()); int row = 0; panel.add(introductionLabel, new GridBagConstraints(0, row++, 2, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); panel.add(loggedBucketLabel, new GridBagConstraints(0, row, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); panel.add(loggedBucketComboBox, new GridBagConstraints(1, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); panel.add(loggingStatusLabel, new GridBagConstraints(0, row++, 2, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); panel.add(prefixLabel, new GridBagConstraints(0, row, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); panel.add(prefixTextField, new GridBagConstraints(1, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); panel.add(loggedToBucketLabel, new GridBagConstraints(0, row, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); panel.add(loggedToBucketComboBox, new GridBagConstraints(1, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); panel.add(finishedButton, new GridBagConstraints(0, row, 2, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsDefault, 0, 0)); this.getContentPane().setLayout(new GridBagLayout()); this.getContentPane().add(panel, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); this.pack(); this.setResizable(false); this.setLocationRelativeTo(ownerFrame); } private int findBucketIndexByName(String bucketName) { for (int i = 0; i < loggedToBucketComboBox.getItemCount(); i++) { String testBucketName = (String) loggedToBucketComboBox.getItemAt(i); if (testBucketName.equals(bucketName)) { return i; } } return 0; } private void displayBucketLoggingStatus(S3BucketLoggingStatus loggingStatus) { if (loggingStatus.isLoggingEnabled()) { loggedToBucketComboBox.setSelectedIndex( findBucketIndexByName(loggingStatus.getTargetBucketName())); prefixTextField.setText(loggingStatus.getLogfilePrefix()); } else { loggedToBucketComboBox.setSelectedIndex(0); if (loggedBucketComboBox.getSelectedIndex() != 0) { prefixTextField.setText(loggedBucketComboBox.getSelectedItem() + "."); } else { prefixTextField.setText(""); } } prefixTextField.setEnabled(true); loggedToBucketComboBox.setEnabled(true); } public void actionPerformed(ActionEvent event) { if (event.getSource().equals(finishedButton)) { // Hack to update the logging status of a bucket before exiting the dialog // if the prefix string has changed String bucketName = (String) loggedBucketComboBox.getSelectedItem(); if (loggingStatusMap.containsKey(bucketName)) { S3BucketLoggingStatus loggingStatus = (S3BucketLoggingStatus) loggingStatusMap.get(bucketName); if (!prefixTextField.getText().equals(loggingStatus.getLogfilePrefix()) && loggedToBucketComboBox.getSelectedIndex() != 0) { loggedToBucketComboBox.setSelectedIndex(loggedToBucketComboBox.getSelectedIndex()); } } this.setVisible(false); } else if (event.getSource().equals(loggedBucketComboBox)) { prefixTextField.setEnabled(false); loggedToBucketComboBox.setEnabled(false); if (loggedBucketComboBox.getSelectedIndex() == 0) { prefixTextField.setText(""); loggedToBucketComboBox.setSelectedIndex(0); } else { final String bucketName = (String) loggedBucketComboBox.getSelectedItem(); if (loggingStatusMap.containsKey(bucketName)) { S3BucketLoggingStatus loggingStatus = (S3BucketLoggingStatus) loggingStatusMap.get(bucketName); displayBucketLoggingStatus(loggingStatus); } else { (new Thread() { public void run() { final ProgressDialog progressDialog = new ProgressDialog(ownerFrame, "Bucket Logging", null); SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.startDialog("Retrieving bucket logging status", null, 0, 0, null, null); } }); try { S3BucketLoggingStatus loggingStatus = s3Service.getBucketLoggingStatus(bucketName); loggingStatusMap.put(bucketName, loggingStatus); displayBucketLoggingStatus(loggingStatus); } catch (Exception e) { SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.stopDialog(); } }); ErrorDialog.showDialog(ownerFrame, null, "Unable to retrieve bucket logging status for " + bucketName, e); } SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.stopDialog(); } }); } }).start(); } } } else if (event.getSource().equals(loggedToBucketComboBox)) { if (!loggedToBucketComboBox.isEnabled()) { // Ignore this event, it is internally generated. return; } final String loggedBucketName = (String) loggedBucketComboBox.getSelectedItem(); final String[] loggedToBucketName = new String[1]; final String[] loggingFilePrefix = new String[1]; if (loggedToBucketComboBox.getSelectedIndex() == 0) { // Logging is being disabled, leave values as null. } else { if (prefixTextField.getText().length() == 0) { ErrorDialog.showDialog(ownerFrame, null, "A log file name prefix must be provided to log buckets", null); loggedToBucketComboBox.setSelectedIndex(0); return; } loggedToBucketName[0] = (String) loggedToBucketComboBox.getSelectedItem(); loggingFilePrefix[0] = prefixTextField.getText(); } (new Thread(new Runnable() { public void run() { final ProgressDialog progressDialog = new ProgressDialog(ownerFrame, "Bucket Logging", null); SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.startDialog("Setting bucket logging status", null, 0, 0, null, null); } }); try { S3BucketLoggingStatus loggingStatus = new S3BucketLoggingStatus(loggedToBucketName[0], loggingFilePrefix[0]); s3Service.setBucketLoggingStatus(loggedBucketName, loggingStatus, true); loggingStatusMap.put(loggedBucketName, loggingStatus); } catch (Exception e) { SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.stopDialog(); } }); ErrorDialog.showDialog(ownerFrame, null, "Unable to set bucket logging status for " + loggedBucketName, e); } SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.stopDialog(); } }); }; })).start(); } } /** * Dialog box for displaying and modifying the logging status of buckets. * * @param ownerFrame * the frame that will own the dialog. * @param s3Service * an S3 Service that will be used to query and update the logging status of buckets. This * service must be initialised with the necessary AWS credentials to perform the logging status * change operations. * @param buckets * the buckets in the user's S3 account. * @param hyperlinkListener * the listener that will act on any hyperlink events triggered by the user clicking on HTTP links. */ public static void showDialog(Frame ownerFrame, S3Service s3Service, S3Bucket[] buckets, HyperlinkActivatedListener hyperlinkListener) { String[] bucketNames = new String[buckets.length]; for (int i = 0; i < buckets.length; i++) { bucketNames[i] = buckets[i].getName(); } showDialog(ownerFrame, s3Service, bucketNames, hyperlinkListener); } /** * Dialog box for displaying and modifying the logging status of buckets. * * @param ownerFrame * the frame that will own the dialog. * @param s3Service * an S3 Service that will be used to query and update the logging status of buckets. This * service must be initialised with the necessary AWS credentials to perform the logging status * change operations. * @param bucketNames * the names of buckets in the user's S3 account. * @param hyperlinkListener * the listener that will act on any hyperlink events triggered by the user clicking on HTTP links. */ public static void showDialog(Frame ownerFrame, S3Service s3Service, String[] bucketNames, HyperlinkActivatedListener hyperlinkListener) { BucketLoggingDialog dialog = new BucketLoggingDialog( ownerFrame, s3Service, bucketNames, hyperlinkListener); dialog.setVisible(true); dialog.dispose(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/cockpit/gui/CredentialsDialog.java0000644000000000000000000002176411441613550023707 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty, 2008 Zmanda Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.cockpit.gui; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.AbstractAction; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JPanel; import javax.swing.KeyStroke; import org.jets3t.gui.ErrorDialog; import org.jets3t.gui.HyperlinkActivatedListener; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.security.AWSCredentials; import org.jets3t.service.security.AWSDevPayCredentials; import org.jets3t.service.security.GSCredentials; import org.jets3t.service.security.ProviderCredentials; /** * Dialog box for obtaining a user's credentials, where the dialog is simply * a wrapping for a {@link LoginCredentialsPanel}. * * @author James Murty * @author Nikolas Coukouma */ public class CredentialsDialog extends JDialog implements ActionListener { private static final long serialVersionUID = -8201015667689728582L; private LoginCredentialsPanel loginCredentialsPanel = null; private JButton okButton = null; private boolean isConfirmed = false; private Jets3tProperties jets3tProperties = null; private final Insets insetsZero = new Insets(0, 0, 0, 0); private final Insets insetsDefault = new Insets(3, 5, 3, 5); /** * Displays a dialog box prompting for a user's credentials * * @param ownerFrame * the frame that will own the dialog * @param askForFriendlyName * if true, the dialog will prompt the user for a "friendly" name they want to give to their * credentials - such as a nickname they can use to distinguish between multiple accounts. * @param hyperlinkListener * the listener that will act on any hyperlink events triggered by the user clicking on HTTP links. */ public CredentialsDialog(Frame ownerFrame, boolean askForFriendlyName, Jets3tProperties jets3tProperties, HyperlinkActivatedListener hyperlinkListener) { super(ownerFrame, "Service Credentials", true); this.jets3tProperties = jets3tProperties; this.loginCredentialsPanel = new LoginCredentialsPanel(askForFriendlyName, hyperlinkListener); JButton cancelButton = new JButton("Cancel"); cancelButton.setActionCommand("Cancel"); cancelButton.addActionListener(this); okButton = new JButton("OK"); okButton.setActionCommand("OK"); okButton.addActionListener(this); JPanel buttonsPanel = new JPanel(new GridBagLayout()); buttonsPanel.add(cancelButton, new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsZero, 0, 0)); buttonsPanel.add(okButton, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsZero, 0, 0)); this.getContentPane().setLayout(new GridBagLayout()); this.getContentPane().add(loginCredentialsPanel, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); this.getContentPane().add(buttonsPanel, new GridBagConstraints(0, 1, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); // Set default ENTER and ESCAPE buttons. this.getRootPane().setDefaultButton(okButton); this.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke("ESCAPE"), "ESCAPE"); this.getRootPane().getActionMap().put("ESCAPE", new AbstractAction() { private static final long serialVersionUID = -6225706489569112809L; public void actionPerformed(ActionEvent actionEvent) { isConfirmed = false; setVisible(false); } }); this.pack(); this.setResizable(false); this.setLocationRelativeTo(ownerFrame); } public void actionPerformed(ActionEvent e) { if (e.getSource().equals(okButton)) { String[] inputErrors = loginCredentialsPanel.checkForInputErrors(); if (inputErrors.length == 0) { isConfirmed = true; this.setVisible(false); } else { // Sanity-check provided information String errorMessages = "Please correct the following errors:
    "; for (int i = 0; i < inputErrors.length; i++) { errorMessages += "
  • " + inputErrors[i] + "
  • "; } errorMessages += "
"; ErrorDialog.showDialog(this, null, errorMessages, null); } } else if ("Cancel".equals(e.getActionCommand())) { isConfirmed = false; this.setVisible(false); } } /** * @return * true if the OK button was pressed, false otherwise (ie if the dialog was cancelled) */ public boolean isConfirmed() { return isConfirmed; } /** * @return * the Access Key provided by the user. */ public String getAccessKey() { return loginCredentialsPanel.getAccessKey().trim(); } /** * @return * the Secret Key provided by the user. */ public String getSecretKey() { return loginCredentialsPanel.getSecretKey().trim(); } /** * @return * whether or not DevPay authentication should be used */ public boolean getUsingDevPay() { return loginCredentialsPanel.getUsingDevPay(); } /** * @return * the AWS User Token provided by the user. */ public String getAWSUserToken() { return loginCredentialsPanel.getAWSUserToken().trim(); } /** * @return * the AWS Product Token provided by the user. */ public String getAWSProductToken() { return loginCredentialsPanel.getAWSProductToken().trim(); } /** * @return * the Friendly Name (nickname) provided by the user, or an empty string if the user was not * prompted to provide one (the askForFriendlyName option was false). */ public String getFriendlyName() { return loginCredentialsPanel.getFriendlyName().trim(); } /** * Displays a dialog box prompting for a user's AWS credentials. * * @param ownerFrame * the frame that will own the dialog * @param askForFriendlyName * if true, the dialog will prompt the user for a "friendly" name they want to give to their * AWS credentials - such as a nickname they can use to distinguish between multiple AWS accounts. * @param hyperlinkListener * the listener that will act on any hyperlink events triggered by the user clicking on HTTP links. */ public static ProviderCredentials showDialog(Frame ownerFrame, boolean askForFriendlyName, boolean isTargetS3, Jets3tProperties jets3tProperties, HyperlinkActivatedListener hyperlinkListener) { CredentialsDialog dialog = new CredentialsDialog( ownerFrame, askForFriendlyName, jets3tProperties, hyperlinkListener); dialog.setVisible(true); ProviderCredentials credentials = null; if (dialog.isConfirmed()) { // Handle Google Storage endpoint if (!isTargetS3) { credentials = new GSCredentials( dialog.getAccessKey(), dialog.getSecretKey(), dialog.getFriendlyName()); } // Handle Amazon endpoint else { if (dialog.getUsingDevPay()) { credentials = new AWSDevPayCredentials( dialog.getAccessKey(), dialog.getSecretKey(), dialog.getAWSUserToken(), dialog.getAWSProductToken(), dialog.getFriendlyName()); } else { credentials = new AWSCredentials( dialog.getAccessKey(), dialog.getSecretKey(), dialog.getFriendlyName()); } } } else { credentials = null; } dialog.dispose(); return credentials; } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/cockpit/gui/PreferencesDialog.java0000644000000000000000000004666111441613550023716 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.cockpit.gui; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.AbstractAction; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JRadioButton; import javax.swing.JTabbedPane; import javax.swing.KeyStroke; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.jets3t.apps.cockpit.CockpitPreferences; import org.jets3t.gui.ErrorDialog; import org.jets3t.gui.HyperlinkActivatedListener; import org.jets3t.gui.JHtmlLabel; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.model.S3Object; import org.jets3t.service.security.EncryptionUtil; /** * Dialog box for managing Cockpit Preferences. * * @author James Murty */ public class PreferencesDialog extends JDialog implements ActionListener, ChangeListener { private static final long serialVersionUID = 4017680813954709789L; private static PreferencesDialog preferencesDialog = null; private CockpitPreferences cockpitPreferences = null; private Frame ownerFrame = null; private HyperlinkActivatedListener hyperlinkListener = null; private ButtonGroup aclButtonGroup = null; private ButtonGroup compressButtonGroup = null; private ButtonGroup encryptButtonGroup = null; private JPasswordField encryptPasswordField = null; private JPasswordField confirmPasswordField = null; private JComboBox encryptAlgorithmComboBox = null; private JComboBox storageClassComboBox = null; private JButton okButton = null; private JButton cancelButton = null; private JCheckBox rememberPreferencesCheckBox = null; private JTabbedPane tabbedPane = null; private final Insets insetsDefault = new Insets(3, 5, 3, 5); /** * Creates a modal dialog box with a title. * * @param owner * the frame within which this dialog will be displayed and centred. * @param jets3tHomeDirectory */ private PreferencesDialog(CockpitPreferences cockpitPreferences, Frame owner, HyperlinkActivatedListener hyperlinkListener) { super(owner, "Cockpit Preferences", true); this.cockpitPreferences = cockpitPreferences; this.ownerFrame = owner; this.hyperlinkListener = hyperlinkListener; this.initGui(); } /** * Initialises all GUI elements. */ private void initGui() { this.setResizable(false); this.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE); String introductionText = "
Configure Cockpit's preferences
"; JHtmlLabel introductionLabel = new JHtmlLabel(introductionText, hyperlinkListener); introductionLabel.setHorizontalAlignment(JLabel.CENTER); cancelButton = new JButton("Cancel"); cancelButton.setActionCommand("Cancel"); cancelButton.addActionListener(this); okButton = new JButton("Apply preferences"); okButton.setActionCommand("ApplyPreferences"); okButton.addActionListener(this); // Set default ENTER and ESCAPE buttons. this.getRootPane().setDefaultButton(okButton); this.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke("ESCAPE"), "ESCAPE"); this.getRootPane().getActionMap().put("ESCAPE", new AbstractAction() { private static final long serialVersionUID = 1478626539912658292L; public void actionPerformed(ActionEvent actionEvent) { setVisible(false); } }); JPanel buttonsPanel = new JPanel(new GridBagLayout()); buttonsPanel.add(cancelButton, new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); buttonsPanel.add(okButton, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); // Uploads preferences pane. JPanel uploadPrefsPanel = new JPanel(new GridBagLayout()); int row = 0; JHtmlLabel storageClassLabel = new JHtmlLabel( "Storage Class
Choose a storage class " + "to balance cost and redundancy", hyperlinkListener); uploadPrefsPanel.add(storageClassLabel, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); String[] storageClasses = new String[] { S3Object.STORAGE_CLASS_STANDARD, S3Object.STORAGE_CLASS_REDUCED_REDUNDANCY }; storageClassComboBox = new JComboBox(storageClasses); storageClassComboBox.addActionListener(this); uploadPrefsPanel.add(storageClassComboBox, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); JHtmlLabel aclPrefsLabel = new JHtmlLabel( "ACL Permissions", hyperlinkListener); uploadPrefsPanel.add(aclPrefsLabel, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); aclButtonGroup = new ButtonGroup(); JRadioButton aclPrivateButton = new JRadioButton("Private", true); aclPrivateButton.setActionCommand(CockpitPreferences.UPLOAD_ACL_PERMISSION_PRIVATE); JRadioButton aclPublicReadButton = new JRadioButton("Public read"); aclPublicReadButton.setActionCommand(CockpitPreferences.UPLOAD_ACL_PERMISSION_PUBLIC_READ); JRadioButton aclPublicReadWriteButton = new JRadioButton("Public read and write"); aclPublicReadWriteButton.setActionCommand(CockpitPreferences.UPLOAD_ACL_PERMISSION_PUBLIC_READ_WRITE); aclButtonGroup.add(aclPrivateButton); aclButtonGroup.add(aclPublicReadButton); aclButtonGroup.add(aclPublicReadWriteButton); JPanel aclPrefsRadioPanel = new JPanel(new GridBagLayout()); aclPrefsRadioPanel.add(aclPrivateButton, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); aclPrefsRadioPanel.add(aclPublicReadButton, new GridBagConstraints(1, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); aclPrefsRadioPanel.add(aclPublicReadWriteButton, new GridBagConstraints(2, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); uploadPrefsPanel.add(aclPrefsRadioPanel, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); JHtmlLabel compressionPrefsLabel = new JHtmlLabel( "Compress files with GZip?", hyperlinkListener); uploadPrefsPanel.add(compressionPrefsLabel, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); compressButtonGroup = new ButtonGroup(); JRadioButton compressNoButton = new JRadioButton("Don't compress", true); compressNoButton.setActionCommand("INACTIVE"); JRadioButton compressYesButton = new JRadioButton("Compress"); compressYesButton.setActionCommand("ACTIVE"); compressButtonGroup.add(compressNoButton); compressButtonGroup.add(compressYesButton); JPanel compressPrefsRadioPanel = new JPanel(new GridBagLayout()); compressPrefsRadioPanel.add(compressNoButton, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); compressPrefsRadioPanel.add(compressYesButton, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); uploadPrefsPanel.add(compressPrefsRadioPanel, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); JHtmlLabel encryptionPrefsLabel = new JHtmlLabel( "Encrypt Uploaded Files?
If encryption is turned on you must " + "also set the Encryption password", hyperlinkListener); uploadPrefsPanel.add(encryptionPrefsLabel, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); encryptButtonGroup = new ButtonGroup(); JRadioButton encryptNoButton = new JRadioButton("Don't encrypt", true); encryptNoButton.setActionCommand("INACTIVE"); JRadioButton encryptYesButton = new JRadioButton("Encrypt"); encryptYesButton.setActionCommand("ACTIVE"); encryptButtonGroup.add(encryptNoButton); encryptButtonGroup.add(encryptYesButton); encryptPasswordField = new JPasswordField(); confirmPasswordField = new JPasswordField(); JPanel encryptPrefsRadioPanel = new JPanel(new GridBagLayout()); encryptPrefsRadioPanel.add(encryptNoButton, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); encryptPrefsRadioPanel.add(encryptYesButton, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); uploadPrefsPanel.add(encryptPrefsRadioPanel, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); // Determine the default crypto algorithm from jets3t.properties. String encryptAlgorithm = Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME) .getStringProperty("crypto.algorithm", "PBEWithMD5AndDES"); // Determine the available PBE algorithms. String[] algorithms = EncryptionUtil.listAvailablePbeCiphers(true); JPanel encryptionPrefsPanel = new JPanel(new GridBagLayout()); encryptionPrefsPanel.add(new JHtmlLabel("Password", hyperlinkListener), new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); encryptionPrefsPanel.add(encryptPasswordField, new GridBagConstraints(0, 1, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); encryptionPrefsPanel.add(new JHtmlLabel("Confirm Password", hyperlinkListener), new GridBagConstraints(0, 2, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); encryptionPrefsPanel.add(confirmPasswordField, new GridBagConstraints(0, 3, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); encryptionPrefsPanel.add(new JHtmlLabel("Algorithm for Encrypting Uploads", hyperlinkListener), new GridBagConstraints(0, 4, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); encryptAlgorithmComboBox = new JComboBox(algorithms); encryptAlgorithmComboBox.addActionListener(this); encryptAlgorithmComboBox.setSelectedItem(encryptAlgorithm.toUpperCase()); encryptionPrefsPanel.add(encryptAlgorithmComboBox, new GridBagConstraints(0, 5, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); String algorithmExplanation = "This algorithm need not be set correctly to download
" + "encrypted objects, as Cockpit will detect and apply the
" + "appropriate algorithm.

" + "" + "The algorithm list only includes the Password-Based (PBE) algorithms
" + "available to Java programs on your system.
"; encryptionPrefsPanel.add(new JHtmlLabel(algorithmExplanation, hyperlinkListener), new GridBagConstraints(0, 6, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); // Padding encryptionPrefsPanel.add(new JLabel(), new GridBagConstraints(0, 7, 1, 1, 1, 1, GridBagConstraints.WEST, GridBagConstraints.BOTH, insetsDefault, 0, 0)); // Tabbed Pane. tabbedPane = new JTabbedPane(); tabbedPane.addChangeListener(this); tabbedPane.add(uploadPrefsPanel, "Uploads"); tabbedPane.add(encryptionPrefsPanel, "Encryption"); // Remember preferences option rememberPreferencesCheckBox = new JCheckBox("Remember my preferences on this computer?"); rememberPreferencesCheckBox.setHorizontalAlignment(JCheckBox.CENTER); String rememberPreferencesExplanation = "" + "Your encryption password will never be remembered." + ""; JHtmlLabel rememberPreferencesLabel = new JHtmlLabel(rememberPreferencesExplanation, hyperlinkListener); rememberPreferencesLabel.setHorizontalAlignment(JLabel.CENTER); row = 0; this.getContentPane().setLayout(new GridBagLayout()); this.getContentPane().add(introductionLabel, new GridBagConstraints(0, row++, 2, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); this.getContentPane().add(tabbedPane, new GridBagConstraints(0, row++, 2, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); this.getContentPane().add(rememberPreferencesCheckBox, new GridBagConstraints(0, row++, 2, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 10, 0, 10), 0, 0)); this.getContentPane().add(rememberPreferencesLabel, new GridBagConstraints(0, row++, 2, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 10, 0, 10), 0, 0)); this.getContentPane().add(buttonsPanel, new GridBagConstraints(0, row++, 2, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); // Load preferences from CockpitPreferences object. rememberPreferencesCheckBox.setSelected(cockpitPreferences.isRememberPreferences()); String aclPermission = cockpitPreferences.getUploadACLPermission(); if (CockpitPreferences.UPLOAD_ACL_PERMISSION_PRIVATE.equals(aclPermission)) { aclPrivateButton.setSelected(true); } else if (CockpitPreferences.UPLOAD_ACL_PERMISSION_PUBLIC_READ.equals(aclPermission)) { aclPublicReadButton.setSelected(true); } else if (CockpitPreferences.UPLOAD_ACL_PERMISSION_PUBLIC_READ_WRITE.equals(aclPermission)) { aclPublicReadWriteButton.setSelected(true); } if (cockpitPreferences.isUploadCompressionActive()) { compressYesButton.setSelected(true); } else { compressNoButton.setSelected(true); } if (cockpitPreferences.isUploadEncryptionActive()) { encryptYesButton.setSelected(true); } else { encryptNoButton.setSelected(true); } encryptAlgorithmComboBox.setSelectedItem(cockpitPreferences.getEncryptionAlgorithm()); storageClassComboBox.setSelectedItem(cockpitPreferences.getUploadStorageClass()); this.pack(); this.setLocationRelativeTo(this.getOwner()); } /** * Event handler for this dialog. */ public void actionPerformed(ActionEvent e) { if (e.getSource().equals(okButton)) { if ("ACTIVE".equals(encryptButtonGroup.getSelection().getActionCommand()) && encryptPasswordField.getPassword().length == 0) { ErrorDialog.showDialog(ownerFrame, hyperlinkListener, "If encryption is set for Uploads the Encryption password cannot be empty", null); return; } if (encryptPasswordField.getPassword().length > 0 || confirmPasswordField.getPassword().length > 0) { String password = new String(encryptPasswordField.getPassword()); String confirmedPassword = new String(confirmPasswordField.getPassword()); if (!password.equals(confirmedPassword)) { ErrorDialog.showDialog(ownerFrame, hyperlinkListener, "You entered an encryption password that does not match the password in the Confirm Password field", null); return; } } // Save preferences to CockpitPreferences object. cockpitPreferences.setRememberPreferences( rememberPreferencesCheckBox.isSelected()); cockpitPreferences.setUploadACLPermission( aclButtonGroup.getSelection().getActionCommand()); cockpitPreferences.setUploadCompressionActive( "ACTIVE".equals(compressButtonGroup.getSelection().getActionCommand())); cockpitPreferences.setUploadEncryptionActive( "ACTIVE".equals(encryptButtonGroup.getSelection().getActionCommand())); cockpitPreferences.setUploadStorageClass( (String) storageClassComboBox.getSelectedItem()); cockpitPreferences.setEncryptionPassword( new String(encryptPasswordField.getPassword())); cockpitPreferences.setEncryptionAlgorithm( (String) encryptAlgorithmComboBox.getSelectedItem()); this.setVisible(false); } else if (e.getSource().equals(cancelButton)) { this.setVisible(false); } } public void stateChanged(ChangeEvent e) { // Ignore these events. } /** * Displays the Preferences dialog box and waits until the user selects to cancel the dialog or * to save the properties. * * @param cockpitPreferences * an object with the current cockpit preferences, which will be updated to reflect any changes * the user makes to their preferences. * @param owner * the frame that will own this dialog. * @param hyperlinkListener * the listener that will act on any hyperlink events triggered by the user clicking on HTTP links. */ public static void showDialog(CockpitPreferences cockpitPreferences, Frame owner, HyperlinkActivatedListener hyperlinkListener) { if (preferencesDialog == null) { preferencesDialog = new PreferencesDialog(cockpitPreferences, owner, hyperlinkListener); } preferencesDialog.setVisible(true); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/cockpit/gui/BucketTableModel.java0000644000000000000000000001352611427702124023475 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.cockpit.gui; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.table.DefaultTableModel; import org.jets3t.gui.GuiUtils; import org.jets3t.service.model.S3Bucket; /** * A table model to store {@link S3Bucket}s. * * @author James Murty */ public class BucketTableModel extends DefaultTableModel { private static final long serialVersionUID = 7957867859342194534L; private GuiUtils guiUtils = new GuiUtils(); private ArrayList bucketList = new ArrayList(); private boolean includeDistributions = false; private Icon distributionActiveIcon = null; public BucketTableModel(boolean includeDistributions) { super(includeDistributions ? new String[] {"Bucket Name", ""} : new String[] {"Bucket Name"}, 0); this.includeDistributions = includeDistributions; JLabel dummyLabel = new JLabel(); if (guiUtils.applyIcon(dummyLabel, "/images/nuvola/16x16/actions/irkick.png")) { distributionActiveIcon = dummyLabel.getIcon(); } } protected int findBucketsIndex(S3Bucket bucket) { return Collections.binarySearch( bucketList, new S3BucketAndDistributionFlag(bucket, false), new Comparator() { public int compare(Object o1, Object o2) { String b1Name = ((S3BucketAndDistributionFlag)o1).getS3Bucket().getName(); String b2Name = ((S3BucketAndDistributionFlag)o2).getS3Bucket().getName(); int result = b1Name.compareTo(b2Name); return result; } } ); } public int addBucket(S3Bucket bucket, boolean hasDistributions) { int insertRow = findBucketsIndex(bucket); if (insertRow >= 0) { // We already have an item with this key, replace it. bucketList.remove(insertRow); this.removeRow(insertRow); } else { insertRow = (-insertRow) - 1; } // New object to insert. bucketList.add(insertRow, new S3BucketAndDistributionFlag(bucket, hasDistributions)); if (this.includeDistributions) { Boolean flag = hasDistributions ? Boolean.TRUE : Boolean.FALSE; this.insertRow(insertRow, new Object[] {bucket.getName(), flag}); } else { this.insertRow(insertRow, new Object[] {bucket.getName()}); } return insertRow; } public void removeBucket(S3Bucket bucket) { int index = findBucketsIndex(bucket); this.removeRow(index); bucketList.remove(index); } public void removeAllBuckets() { int rowCount = this.getRowCount(); for (int i = 0; i < rowCount; i++) { this.removeRow(0); } bucketList.clear(); } public S3Bucket getBucket(int row) { return ((S3BucketAndDistributionFlag)bucketList.get(row)).getS3Bucket(); } public S3Bucket[] getBuckets() { S3Bucket[] buckets = new S3Bucket[bucketList.size()]; for (int i = 0; i < bucketList.size(); i++) { buckets[i] = getBucket(i); } return buckets; } public int getBucketIndexByName(String name) { synchronized (bucketList) { for (int index=0; index < bucketList.size(); index++) { S3Bucket bucket = getBucket(index); if (bucket.getName().equals(name)) { return index; } } return -1; } } /** * @return * true if the distributions flag is true for at least one bucket. */ public boolean hasDistributions() { for (int i = 0; i < bucketList.size(); i++) { if ( ((S3BucketAndDistributionFlag)bucketList.get(i)).distributionFlag ) { return true; } } return false; } public boolean isCellEditable(int row, int column) { return false; } public Class getColumnClass(int columnIndex) { if (columnIndex == 1) { if (distributionActiveIcon != null) { return ImageIcon.class; } else { return Boolean.class; } } else { return String.class; } } public Object getValueAt(int rowIndex, int columnIndex) { if (columnIndex == 1 && distributionActiveIcon != null) { if (((S3BucketAndDistributionFlag)bucketList.get(rowIndex)).hasDistribution()) { return distributionActiveIcon; } } return super.getValueAt(rowIndex, columnIndex); } private class S3BucketAndDistributionFlag { private S3Bucket bucket = null; private boolean distributionFlag = false; public S3BucketAndDistributionFlag(S3Bucket bucket, boolean distributionFlag) { this.bucket = bucket; this.distributionFlag = distributionFlag; } public S3Bucket getS3Bucket() { return bucket; } public boolean hasDistribution() { return distributionFlag; } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/cockpit/gui/LoginPassphrasePanel.java0000644000000000000000000001124611441613550024406 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.cockpit.gui; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JTextField; import org.jets3t.gui.HyperlinkActivatedListener; import org.jets3t.gui.JHtmlLabel; /** * A panel for prompting a user to provide a passphrase and password used to store * or access their credentials in a storage service. * * @author James Murty */ public class LoginPassphrasePanel extends JPanel { private static final long serialVersionUID = -5554177389537270280L; private final Insets insetsDefault = new Insets(3, 5, 3, 5); private HyperlinkActivatedListener hyperlinkListener = null; private JTextField passphraseTextField = null; private JPasswordField passwordPasswordField = null; public LoginPassphrasePanel(HyperlinkActivatedListener hyperlinkListener) { super(new GridBagLayout()); this.hyperlinkListener = hyperlinkListener; initGui(); } private void initGui() { // Textual information. String descriptionText = "
" + "Your credentials are stored in an encrypted object in your online storage account. " + "To access your credentials you must provide your unique passphrase and password." + "

" + "You need to store your credentials before you can use this login method." + "
"; String passphraseLabelText = "Passphrase"; String passphraseTooltipText = "An easy to remember phrase of 6 characters or more that is unlikely to be used by anyone else"; String passwordLabelText = "Password"; String passwordTooltipText = "A password of at least 6 characters"; // Components. JHtmlLabel descriptionLabel = new JHtmlLabel(descriptionText, hyperlinkListener); descriptionLabel.setHorizontalAlignment(JLabel.CENTER); JHtmlLabel passphraseLabel = new JHtmlLabel(passphraseLabelText, hyperlinkListener); passphraseTextField = new JTextField(); passphraseTextField.setName("LoginPassphrasePanel.Passphrase"); passphraseTextField.setToolTipText(passphraseTooltipText); JHtmlLabel passwordLabel = new JHtmlLabel(passwordLabelText, hyperlinkListener); passwordPasswordField = new JPasswordField(); passwordPasswordField.setName("LoginPassphrasePanel.Password"); passwordPasswordField.setToolTipText(passwordTooltipText); int row = 0; add(descriptionLabel, new GridBagConstraints(0, row++, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); add(passphraseLabel, new GridBagConstraints(0, row++, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); add(passphraseTextField, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); add(passwordLabel, new GridBagConstraints(0, row++, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); add(passwordPasswordField, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); // Padder. add(new JLabel(), new GridBagConstraints(0, row++, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); } /** * @return * the passphrase provided by the user (may be an empty string) */ public String getPassphrase() { return passphraseTextField.getText(); } /** * @return * the password provided by the user (may be an empty string) */ public String getPassword() { return new String(passwordPasswordField.getPassword()); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/cockpit/gui/ObjectTableModel.java0000644000000000000000000000731411427702124023464 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.cockpit.gui; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.Iterator; import javax.swing.table.DefaultTableModel; import org.jets3t.service.model.S3Object; /** * A table model to store {@link S3Object}s. * * @author James Murty */ public class ObjectTableModel extends DefaultTableModel { private static final long serialVersionUID = 8570725021470237261L; private ArrayList objectList = new ArrayList(); public ObjectTableModel() { super(new String[] {"Object Key","Size","Last Modified"}, 0); } public int addObject(S3Object object) { int insertRow = Collections.binarySearch(objectList, object, new Comparator() { public int compare(Object o1, Object o2) { return ((S3Object)o1).getKey().compareToIgnoreCase(((S3Object)o2).getKey()); } }); if (insertRow >= 0) { // We already have an item with this key, replace it. objectList.remove(insertRow); this.removeRow(insertRow); } else { insertRow = (-insertRow) - 1; } // New object to insert. objectList.add(insertRow, object); this.insertRow(insertRow, new Object[] {object.getKey(), new Long(object.getContentLength()), object.getLastModifiedDate()}); return insertRow; } public void addObjects(S3Object[] objects) { for (int i = 0; i < objects.length; i++) { addObject(objects[i]); } } public void removeObject(S3Object object) { int index = objectList.indexOf(object); if (index >= 0) { this.removeRow(index); objectList.remove(object); } } public void removeAllObjects() { int rowCount = this.getRowCount(); for (int i = 0; i < rowCount; i++) { this.removeRow(0); } objectList.clear(); } public S3Object getObject(int row) { synchronized (objectList) { return (S3Object) objectList.get(row); } } public S3Object getObjectByKey(String key) { synchronized (objectList) { Iterator objectIter = objectList.iterator(); while (objectIter.hasNext()) { S3Object object = (S3Object) objectIter.next(); if (object.getKey().equals(key)) { return object; } } return null; } } public S3Object[] getObjects() { synchronized (objectList) { return (S3Object[]) objectList.toArray(new S3Object[objectList.size()]); } } public boolean isCellEditable(int row, int column) { return false; } public Class getColumnClass(int columnIndex) { if (columnIndex == 0) { return String.class; } else if (columnIndex == 1) { return Long.class; } else { return Date.class; } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/cockpit/gui/CreateBucketDialog.java0000644000000000000000000002555111441613550024011 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2007 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.cockpit.gui; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.HashMap; import java.util.Map; import javax.swing.AbstractAction; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import org.jets3t.gui.HyperlinkActivatedListener; import org.jets3t.gui.JHtmlLabel; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.model.S3Bucket; import org.jets3t.service.utils.ServiceUtils; /** * Dialog box to prompt for the name and location of an S3 bucket. This dialog * should be created and displayed with {@link #setVisible(boolean)}, and once * control returns the user's responses are available via {@link #getOkClicked()}, * {@link #getBucketName()} and {@link #getBucketLocation()}. *

* The caller is responsible for disposing of this dialog. * * @author James Murty * */ public class CreateBucketDialog extends JDialog implements ActionListener { private static final long serialVersionUID = -8085778146542157010L; private static String[] locationNames = new String[] {}; private static Map locationValueMap = new HashMap(); private boolean okClicked = false; private JTextField bucketNameTextField = null; private JLabel bucketNameIsValidDNSResultLabel = null; private JComboBox bucketLocationComboBox = null; private JButton okButton = null; private JButton cancelButton = null; private final Insets insetsDefault = new Insets(3, 5, 3, 5); static { locationNames = new String[] { "US Standard", "US West (N. California)", "EU West (Ireland)", "Asia Pacific (Singapore)" }; locationValueMap.put(locationNames[0], S3Bucket.LOCATION_US); locationValueMap.put(locationNames[1], S3Bucket.LOCATION_US_WEST); locationValueMap.put(locationNames[2], S3Bucket.LOCATION_EUROPE); locationValueMap.put(locationNames[3], S3Bucket.LOCATION_ASIA_PACIFIC); } public CreateBucketDialog(String suggestedBucketName, Frame ownerFrame, HyperlinkActivatedListener hyperlinkListener) { super(ownerFrame, "Create a new bucket", true); boolean disableDnsBuckets = Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME) .getBoolProperty("s3service.disable-dns-buckets", false); cancelButton = new JButton("Cancel"); cancelButton.setActionCommand("Cancel"); cancelButton.addActionListener(this); okButton = new JButton("Create Bucket"); okButton.setActionCommand("OK"); okButton.addActionListener(this); JHtmlLabel bucketNameLabel = new JHtmlLabel("Bucket name", hyperlinkListener); bucketNameLabel.setHorizontalAlignment(JLabel.CENTER); JHtmlLabel bucketLocationLabel = new JHtmlLabel("Bucket location", hyperlinkListener); bucketLocationLabel.setHorizontalAlignment(JLabel.CENTER); JHtmlLabel bucketNameIsValidDNSLabel = new JHtmlLabel("DNS compatible?", hyperlinkListener); bucketLocationLabel.setHorizontalAlignment(JLabel.CENTER); bucketNameIsValidDNSResultLabel = new JLabel("No"); bucketLocationComboBox = new JComboBox(locationNames); bucketLocationComboBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { okButton.setEnabled( bucketLocationComboBox.getSelectedIndex() == 0 || "Yes".equals(bucketNameIsValidDNSResultLabel.getText())); } }); bucketLocationComboBox.setToolTipText("The geographical location where the bucket's contents will be stored"); JHtmlLabel bucketNameIsValidDNSExplanationLabel = null; if (disableDnsBuckets) { bucketNameIsValidDNSExplanationLabel = new JHtmlLabel( "Because the 's3service.disable-dns-buckets' property is set, you
" + "may only create buckets in the U.S. location.
", hyperlinkListener); bucketLocationComboBox.setEnabled(false); } else { bucketNameIsValidDNSExplanationLabel = new JHtmlLabel( "If your bucket name is DNS-compatible, you can choose a storage location
" + "other than US Standard and may potentially use the bucket as a virtual host.
", hyperlinkListener); bucketLocationComboBox.setEnabled(true); } bucketNameIsValidDNSExplanationLabel.setHorizontalAlignment(JLabel.CENTER); bucketNameTextField = new JTextField(); bucketNameTextField.setToolTipText("A unique bucket name in S3"); bucketNameTextField.getDocument().addDocumentListener(new DocumentListener() { public void insertUpdate(DocumentEvent e) { checkBucketName(e.getDocument()); } public void removeUpdate(DocumentEvent e) { checkBucketName(e.getDocument()); } public void changedUpdate(DocumentEvent e) { checkBucketName(e.getDocument()); } private void checkBucketName(Document doc) { String bucketName = ""; try { bucketName = doc.getText(0, doc.getLength()); } catch (BadLocationException e) { } if (ServiceUtils.isBucketNameValidDNSName(bucketName)) { bucketNameIsValidDNSResultLabel.setText("Yes"); okButton.setEnabled(true); } else { bucketNameIsValidDNSResultLabel.setText("No"); // OK button should not be enabled for non-US locations okButton.setEnabled(bucketLocationComboBox.getSelectedIndex() == 0); } } }); bucketNameTextField.setText(suggestedBucketName); bucketNameTextField.setSelectionStart(0); bucketNameTextField.setSelectionEnd(suggestedBucketName.length()); // Set default ENTER and ESCAPE buttons. this.getRootPane().setDefaultButton(okButton); this.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke("ESCAPE"), "ESCAPE"); this.getRootPane().getActionMap().put("ESCAPE", new AbstractAction() { private static final long serialVersionUID = -6225706489569112809L; public void actionPerformed(ActionEvent actionEvent) { setVisible(false); okClicked = false; } }); JPanel buttonsPanel = new JPanel(new GridBagLayout()); buttonsPanel.add(cancelButton, new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsDefault, 0, 0)); buttonsPanel.add(okButton, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsDefault, 0, 0)); JPanel panel = new JPanel(new GridBagLayout()); int row = 0; panel.add(bucketNameLabel, new GridBagConstraints(0, row, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); panel.add(bucketNameTextField, new GridBagConstraints(1, row, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); panel.add(bucketNameIsValidDNSExplanationLabel, new GridBagConstraints(0, ++row, 2, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); if (!disableDnsBuckets) { panel.add(bucketNameIsValidDNSLabel, new GridBagConstraints(0, ++row, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); panel.add(bucketNameIsValidDNSResultLabel, new GridBagConstraints(1, row, 2, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); } panel.add(bucketLocationLabel, new GridBagConstraints(0, ++row, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); panel.add(bucketLocationComboBox, new GridBagConstraints(1, row, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); panel.add(new JHtmlLabel("Choosing a location other than US Standard may incur additional S3 usage fees.", hyperlinkListener), new GridBagConstraints(0, ++row, 2, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); panel.add(buttonsPanel, new GridBagConstraints(0, ++row, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); this.getContentPane().setLayout(new GridBagLayout()); this.getContentPane().add(panel, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); this.pack(); this.setResizable(false); this.setLocationRelativeTo(ownerFrame); } public void actionPerformed(ActionEvent event) { if (event.getSource().equals(okButton)) { this.setVisible(false); okClicked = true; } else if (event.getSource().equals(cancelButton)) { this.setVisible(false); okClicked = false; } } public boolean getOkClicked() { return okClicked; } public String getBucketLocation() { Object locationSelected = bucketLocationComboBox.getSelectedItem(); return (String) locationValueMap.get(locationSelected); } public String getBucketName() { return bucketNameTextField.getText(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/cockpit/gui/AWSDevPayProductPanel.java0000644000000000000000000001065011427702124024406 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 Zmanda Inc, 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.cockpit.gui; import java.awt.Component; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import javax.swing.ButtonGroup; import javax.swing.JComboBox; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JTextField; import org.jets3t.service.model.AWSDevPayProduct; /** * Class to store information about a AWS DevPay product. * * @author Nikolas Coukouma * @author James Murty */ public class AWSDevPayProductPanel extends JPanel { private static final long serialVersionUID = -5192203961525549067L; private final Insets insetsDefault = new Insets(3, 5, 3, 5); private JRadioButton awsProductRadioButton = null; private JComboBox awsProductListComboBox = null; private JRadioButton awsProductTokenRadioButton = null; private JTextField awsProductTokenTextField = null; private Component[] internalComponents = null; public AWSDevPayProductPanel() { super(new GridBagLayout()); initGui(); } private void initGui() { String awsProductRadioButtonText = "DevPay Product"; String awsProductTokenRadioButtonText = "DevPay Product Token"; String awsProductTokenTooltipText = "DevPay product token"; awsProductRadioButton = new JRadioButton(awsProductRadioButtonText); try { awsProductListComboBox = new JComboBox(AWSDevPayProduct.load()); } catch(Exception e) { awsProductListComboBox = new JComboBox(); } awsProductTokenRadioButton = new JRadioButton(awsProductTokenRadioButtonText); awsProductTokenTextField = new JTextField(); awsProductTokenTextField.setToolTipText(awsProductTokenTooltipText); ButtonGroup productTokenGroup = new ButtonGroup(); productTokenGroup.add(awsProductRadioButton); productTokenGroup.add(awsProductTokenRadioButton); Component[] tmp = {awsProductRadioButton, awsProductTokenRadioButton, awsProductListComboBox}; internalComponents = tmp; if (awsProductListComboBox.getItemCount() == 0) { awsProductTokenRadioButton.setSelected(true); awsProductRadioButton.setVisible(false); awsProductListComboBox.setVisible(false); } else { awsProductRadioButton.setSelected(true); } int row = 0; add(awsProductRadioButton, new GridBagConstraints(0, row, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); add(awsProductListComboBox, new GridBagConstraints(1, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); add(awsProductTokenRadioButton, new GridBagConstraints(0, row, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); add(awsProductTokenTextField, new GridBagConstraints(1, row++, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); } public void setEnabled(boolean enabled) { super.setEnabled(enabled); if (awsProductListComboBox.getItemCount() == 0) { enabled = false; } for (int i = 0; i < internalComponents.length; i++) { internalComponents[i].setEnabled(enabled); } } /** * @return * the product token provided, or selected, by the user. */ public String getAWSProductToken() { if (awsProductTokenRadioButton.isSelected()) { return awsProductTokenTextField.getText().trim(); } else { return ((AWSDevPayProduct) awsProductListComboBox.getSelectedItem()).getProductToken().trim(); } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/cockpit/gui/StartupDialog.java0000644000000000000000000006426511447770416023132 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty, 2008 Zmanda Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.cockpit.gui; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.net.URL; import javax.swing.AbstractAction; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JTabbedPane; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.gui.ErrorDialog; import org.jets3t.gui.HyperlinkActivatedListener; import org.jets3t.gui.ProgressDialog; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.S3ServiceException; import org.jets3t.service.ServiceException; import org.jets3t.service.StorageService; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.impl.rest.httpclient.RestS3Service; import org.jets3t.service.model.StorageObject; import org.jets3t.service.security.AWSCredentials; import org.jets3t.service.security.AWSDevPayCredentials; import org.jets3t.service.security.GSCredentials; import org.jets3t.service.security.ProviderCredentials; import org.jets3t.service.utils.ServiceUtils; import com.centerkey.utils.BareBonesBrowserLaunch; /** * Dialog box for obtaining a user's service credentials, and performing other startup * tasks such as loading properties files. *

* * @author James Murty * @author Nikolas Coukouma */ public class StartupDialog extends JDialog implements ActionListener, ChangeListener { private static final long serialVersionUID = -2520889480615456474L; private static final Log log = LogFactory.getLog(StartupDialog.class); public static final String EMPTY_PASSWORD_SURROGATE = "NONE"; private Frame ownerFrame = null; private HyperlinkActivatedListener hyperlinkListener = null; private Jets3tProperties myProperties = null; private ProviderCredentials credentials = null; private JRadioButton targetS3 = null; private JRadioButton targetGS = null; private JButton okButton = null; private JButton cancelButton = null; private JButton storeCredentialsButton = null; private JTabbedPane tabbedPane = null; private LoginPassphrasePanel loginPassphrasePanel = null; private LoginLocalFolderPanel loginLocalFolderPanel = null; private LoginCredentialsPanel loginCredentialsPanel = null; private final Insets insetsZero = new Insets(0, 0, 0, 0); private final Insets insetsDefault = new Insets(3, 5, 3, 5); private static final int LOGIN_MODE_PASSPHRASE = 0; private static final int LOGIN_MODE_LOCAL_FOLDER = 1; private static final int LOGIN_MODE_DIRECT = 2; private int loginMode = LOGIN_MODE_PASSPHRASE; /** * Creates a modal dialog box with a title. * * @param owner * the frame within which this dialog will be displayed and centred. * @param hyperlinkListener */ public StartupDialog(Frame owner, Jets3tProperties properties, HyperlinkActivatedListener hyperlinkListener) { super(owner, "Cockpit Login", true); this.ownerFrame = owner; this.hyperlinkListener = hyperlinkListener; this.myProperties = properties; this.initGui(); } /** * Initialises all GUI elements. */ private void initGui() { this.setResizable(false); this.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE); cancelButton = new JButton("Don't log in"); cancelButton.setActionCommand("Cancel"); cancelButton.addActionListener(this); storeCredentialsButton = new JButton("Store Credentials"); storeCredentialsButton.setActionCommand("StoreCredentials"); storeCredentialsButton.addActionListener(this); okButton = new JButton("Log in"); okButton.setActionCommand("LogIn"); okButton.addActionListener(this); // Set default ENTER and ESCAPE buttons. this.getRootPane().setDefaultButton(okButton); this.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke("ESCAPE"), "ESCAPE"); this.getRootPane().getActionMap().put("ESCAPE", new AbstractAction() { private static final long serialVersionUID = -1742280851624947873L; public void actionPerformed(ActionEvent actionEvent) { setVisible(false); } }); JPanel buttonsPanel = new JPanel(new GridBagLayout()); buttonsPanel.add(cancelButton, new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsZero, 0, 0)); buttonsPanel.add(storeCredentialsButton, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsZero, 0, 0)); buttonsPanel.add(okButton, new GridBagConstraints(2, 0, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsZero, 0, 0)); loginPassphrasePanel = new LoginPassphrasePanel(hyperlinkListener); loginLocalFolderPanel = new LoginLocalFolderPanel(ownerFrame, hyperlinkListener); loginCredentialsPanel = new LoginCredentialsPanel(false, hyperlinkListener); // Target storage service selection targetS3 = new JRadioButton("Amazon S3"); targetS3.setSelected(true); targetGS = new JRadioButton("Google Storage"); ButtonGroup targetButtonGroup = new ButtonGroup(); targetButtonGroup.add(targetS3); targetButtonGroup.add(targetGS); JPanel targetServicePanel = new JPanel(new GridBagLayout()); targetServicePanel.add(targetS3, new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsZero, 0, 0)); targetServicePanel.add(targetGS, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsZero, 0, 0)); // Tabbed Pane. tabbedPane = new JTabbedPane(); tabbedPane.addChangeListener(this); tabbedPane.add(loginPassphrasePanel, "Online"); tabbedPane.add(loginLocalFolderPanel, "Local Folder"); tabbedPane.add(loginCredentialsPanel, "Direct Login"); int row = 0; this.getContentPane().setLayout(new GridBagLayout()); this.getContentPane().add(targetServicePanel, new GridBagConstraints(0, row++, 2, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); this.getContentPane().add(tabbedPane, new GridBagConstraints(0, row++, 2, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsZero, 0, 0)); this.getContentPane().add(buttonsPanel, new GridBagConstraints(0, row++, 2, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); this.pack(); this.setSize(500, 430); this.setLocationRelativeTo(this.getOwner()); } public boolean isTargetS3() { return targetS3.isSelected(); } protected StorageService getStorageService() throws S3ServiceException { if (targetS3.isSelected()) { return new RestS3Service(credentials); } else { // Override endpoint property in JetS3t properties Jets3tProperties gsProperties = Jets3tProperties.getInstance( Constants.JETS3T_PROPERTIES_FILENAME); gsProperties.setProperty( "s3service.s3-endpoint", Constants.GS_DEFAULT_HOSTNAME); return new RestS3Service(credentials, null, null, gsProperties); } } /** * Event handler for this dialog. */ public void actionPerformed(ActionEvent e) { if (e.getSource().equals(okButton)) { if (loginMode == LOGIN_MODE_PASSPHRASE) { retrieveCredentialsFromStorageService( loginPassphrasePanel.getPassphrase(), loginPassphrasePanel.getPassword()); } else if (loginMode == LOGIN_MODE_LOCAL_FOLDER) { retrieveCredentialsFromDirectory(loginLocalFolderPanel.getHomeFolder(), loginLocalFolderPanel.getCredentialsFile(), loginLocalFolderPanel.getPassword()); } else if (loginMode == LOGIN_MODE_DIRECT) { String[] inputErrors = loginCredentialsPanel.checkForInputErrors(); if (inputErrors.length > 0) { String errorMessages = "Please correct the following errors:

    "; for (int i = 0; i < inputErrors.length; i++) { errorMessages += "
  • " + inputErrors[i] + "
  • "; } errorMessages += "
"; ErrorDialog.showDialog(this, null, errorMessages, null); } else { if (loginCredentialsPanel.getUsingDevPay()) { this.credentials = new AWSDevPayCredentials( loginCredentialsPanel.getAccessKey(), loginCredentialsPanel.getSecretKey(), loginCredentialsPanel.getAWSUserToken(), loginCredentialsPanel.getAWSProductToken(), loginCredentialsPanel.getFriendlyName()); } else { if (targetS3.isSelected()) { this.credentials = new AWSCredentials( loginCredentialsPanel.getAccessKey(), loginCredentialsPanel.getSecretKey(), loginCredentialsPanel.getFriendlyName()); } else { this.credentials = new GSCredentials( loginCredentialsPanel.getAccessKey(), loginCredentialsPanel.getSecretKey(), loginCredentialsPanel.getFriendlyName()); } } this.setVisible(false); } } } else if (e.getSource().equals(storeCredentialsButton)) { if (loginMode == LOGIN_MODE_PASSPHRASE) { storeCredentialsInStorageService( loginPassphrasePanel.getPassphrase(), loginPassphrasePanel.getPassword()); } else if (loginMode == LOGIN_MODE_LOCAL_FOLDER) { storeCredentialsInDirectory( loginLocalFolderPanel.getHomeFolder(), loginLocalFolderPanel.getPassword()); } else if (loginMode == LOGIN_MODE_DIRECT) { throw new IllegalStateException("Cannot store credentials from Direct Login panel"); } } else if (e.getSource().equals(cancelButton)) { this.credentials = null; this.setVisible(false); } } public void stateChanged(ChangeEvent e) { if (e.getSource().equals(tabbedPane)) { loginMode = tabbedPane.getSelectedIndex(); changedLoginMode(); } } private void changedLoginMode() { if (loginMode == LOGIN_MODE_PASSPHRASE) { storeCredentialsButton.setEnabled(true); } else if (loginMode == LOGIN_MODE_LOCAL_FOLDER) { storeCredentialsButton.setEnabled(true); } else if (loginMode == LOGIN_MODE_DIRECT) { storeCredentialsButton.setEnabled(false); } else { throw new IllegalStateException("Invalid value for loginMode: " + loginMode); } } private String generateBucketNameFromPassphrase(String passphrase) throws Exception { return "jets3t-" + ServiceUtils.toHex( ServiceUtils.computeMD5Hash(passphrase.getBytes(Constants.DEFAULT_ENCODING))); } private String generateObjectKeyFromPassphrase(String passphrase, String password) throws Exception { String combinedString = passphrase + password; return ServiceUtils.toHex( ServiceUtils.computeMD5Hash(combinedString.getBytes(Constants.DEFAULT_ENCODING))) + "/jets3t.credentials"; } private boolean validPassphraseInputs(String passphrase, String password) { String invalidInputsMessage = ""; if (passphrase.length() < 6) { invalidInputsMessage += "Passphrase must be at least 6 characters."; } if (password.length() < 6) { invalidInputsMessage += (invalidInputsMessage.length() > 0 ? " and password" : "Password") + " must be at least 6 characters"; } if (invalidInputsMessage.length() > 0) { ErrorDialog.showDialog(this, hyperlinkListener, invalidInputsMessage, null); return false; } else { return true; } } private boolean validFolderInputs(boolean isStoreAction, File directory, File credentialsFile, String password, boolean allowLegacyPassword) { if (password.length() < 6) { if (allowLegacyPassword) { // Legacy password allowed for login, an error will be displayed later if it's incorrect. } else if (EMPTY_PASSWORD_SURROGATE.equals(password)) { // Surrogate empty password was used, not an error. } else { ErrorDialog.showDialog(this, hyperlinkListener, "Password must be at least 6 characters. " + "If you do not wish to set a password, use the password " + EMPTY_PASSWORD_SURROGATE + ".", null); return false; } } if (!directory.exists() || !directory.canWrite()) { String invalidInputsMessage = "Directory '" + directory.getAbsolutePath() + "' does not exist or cannot be written to."; ErrorDialog.showDialog(this, hyperlinkListener, invalidInputsMessage, null); return false; } if (credentialsFile == null && !isStoreAction) { String invalidInputsMessage = "You must choose which stored login to use"; ErrorDialog.showDialog(this, hyperlinkListener, invalidInputsMessage, null); return false; } return true; } private void retrieveCredentialsFromStorageService(String passphrase, final String password) { if (!validPassphraseInputs(passphrase, password)) { return; } final String[] bucketName = new String[1]; final String[] credentialObjectKey = new String[1]; try { bucketName[0] = generateBucketNameFromPassphrase(passphrase); credentialObjectKey[0] = generateObjectKeyFromPassphrase(passphrase, password); } catch (Exception e) { String message = "Unable to generate bucket name or object key"; log.error(message, e); ErrorDialog.showDialog(this, hyperlinkListener, message, e); return; } final ProgressDialog progressDialog = new ProgressDialog( ownerFrame, "Retrieving credentials", null); final StartupDialog myself = this; (new Thread(new Runnable() { public void run() { SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.startDialog("Downloading your credentials", "", 0, 0, null, null); } }); StorageObject encryptedCredentialsObject = null; try { credentials = null; StorageService service = getStorageService(); encryptedCredentialsObject = service.getObject( bucketName[0], credentialObjectKey[0]); } catch (ServiceException e) { SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.stopDialog(); } }); String errorMessage = "
Unable to find your credentials online" + "

Please check your passphrase and password
"; log.error(errorMessage, e); ErrorDialog.showDialog(myself, hyperlinkListener, errorMessage, null); return; } SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.updateDialog("Decrypting your credentials", null, 0); } }); try { if (targetS3.isSelected()) { myself.credentials = AWSCredentials.load(password, new BufferedInputStream(encryptedCredentialsObject.getDataInputStream())); } else { myself.credentials = GSCredentials.load(password, new BufferedInputStream(encryptedCredentialsObject.getDataInputStream())); } SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.stopDialog(); } }); myself.setVisible(false); } catch (ServiceException e) { SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.stopDialog(); } }); String errorMessage = "
Unable to load your online credentials" + "

Please check your password
"; log.error(errorMessage, e); ErrorDialog.showDialog(myself, hyperlinkListener, errorMessage, null); } } })).start(); } private void storeCredentialsInStorageService(String passphrase, String password) { if (!validPassphraseInputs(passphrase, password)) { return; } final ProviderCredentials credentials = CredentialsDialog.showDialog(ownerFrame, (loginMode == LOGIN_MODE_LOCAL_FOLDER), this.isTargetS3(), myProperties, hyperlinkListener); if (credentials == null) { return; } final String[] bucketName = new String[1]; final String[] credentialObjectKey = new String[1]; try { bucketName[0] = generateBucketNameFromPassphrase(passphrase); credentialObjectKey[0] = generateObjectKeyFromPassphrase(passphrase, password); } catch (Exception e) { String message = "Unable to generate bucket name or object key"; log.error(message, e); ErrorDialog.showDialog(this, hyperlinkListener, message, e); return; } final ByteArrayInputStream[] bais = new ByteArrayInputStream[1]; try { // Convert credentials into a readable input stream. String algorithm = myProperties.getStringProperty("crypto.algorithm", "PBEWithMD5AndDES"); ByteArrayOutputStream baos = new ByteArrayOutputStream(); credentials.save(password, baos, algorithm); bais[0] = new ByteArrayInputStream(baos.toByteArray()); } catch (RuntimeException e) { throw e; } catch (Exception e) { String message = "Unable to encrypt your credentials"; log.error(message, e); ErrorDialog.showDialog(this, hyperlinkListener, message, e); return; } final ProgressDialog progressDialog = new ProgressDialog( ownerFrame, "Storing credentials", null); final StartupDialog myself = this; (new Thread(new Runnable() { public void run() { SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.startDialog("Uploading your credentials", null, 0, 0, null, null); } }); try { StorageObject encryptedCredentialsObject = new StorageObject(credentialObjectKey[0]); encryptedCredentialsObject.setDataInputStream(bais[0]); encryptedCredentialsObject.setAcl(AccessControlList.REST_CANNED_PUBLIC_READ); // Store credentials StorageService service = getStorageService(); service.createBucket(bucketName[0]); service.putObject(bucketName[0], encryptedCredentialsObject); SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.stopDialog(); } }); JOptionPane.showMessageDialog(ownerFrame, "Your credentials have been stored online" + "\n\nBucket name: " + bucketName[0] + "\nObject key: " + credentialObjectKey[0]); } catch (ServiceException e) { SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.stopDialog(); } }); String message = "Unable to store your credentials online"; log.error(message, e); ErrorDialog.showDialog(myself, hyperlinkListener, message, e); } } })).start(); } private void retrieveCredentialsFromDirectory(File directory, File credentialsFile, String password) { if (!validFolderInputs(false, directory, credentialsFile, password, true)) { return; } try { this.credentials = ProviderCredentials.load(password, credentialsFile); this.setVisible(false); } catch (Exception e) { String message = "
Unable to load your credentials from the file: " + credentialsFile + "

Please check your password
"; log.error(message, e); ErrorDialog.showDialog(this, hyperlinkListener, message, null); } } private void storeCredentialsInDirectory(File directory, String password) { if (!validFolderInputs(true, directory, null, password, false)) { return; } if (EMPTY_PASSWORD_SURROGATE.equals(password.trim())) { password = ""; } ProviderCredentials myCredentials = CredentialsDialog.showDialog(ownerFrame, true, this.isTargetS3(), myProperties, hyperlinkListener); if (myCredentials == null) { return; } if (myCredentials.getFriendlyName() == null || myCredentials.getFriendlyName().length() == 0) { String message = "You must enter a nickname when storing your credentials"; log.error(message); ErrorDialog.showDialog(this, hyperlinkListener, message, null); return; } File credentialsFile = new File(directory, myCredentials.getFriendlyName() + ".enc"); try { String algorithm = myProperties.getStringProperty("crypto.algorithm", "PBEWithMD5AndDES"); myCredentials.save(password, credentialsFile, algorithm); loginLocalFolderPanel.clearPassword(); loginLocalFolderPanel.refreshStoredCredentialsTable(); JOptionPane.showMessageDialog(ownerFrame, "Your credentials have been stored in the file:\n" + credentialsFile.getAbsolutePath()); } catch (RuntimeException e) { throw e; } catch (Exception e) { String message = "Unable to encrypt your credentials to a folder"; log.error(message, e); ErrorDialog.showDialog(this, hyperlinkListener, message, e); } } public ProviderCredentials getProviderCredentials() { return this.credentials; } /** * Creates stand-alone dialog box for testing only. * * @param args * @throws Exception */ public static void main(String args[]) throws Exception { JFrame f = new JFrame(); HyperlinkActivatedListener listener = new HyperlinkActivatedListener() { private static final long serialVersionUID = -225585129296632961L; public void followHyperlink(URL url, String target) { BareBonesBrowserLaunch.openURL(url.toString()); } }; StartupDialog startupDialog = new StartupDialog(f, Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME), listener); startupDialog.setVisible(true); ProviderCredentials credentials = startupDialog.getProviderCredentials(); startupDialog.dispose(); if (credentials != null) { System.out.println("Credentials: " + credentials.getLogString()); } else { System.out.println("Credentials: null"); } f.dispose(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/cockpit/gui/AccessControlDialog.java0000644000000000000000000006570411441613550024216 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.cockpit.gui; import java.awt.Component; import java.awt.Dimension; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import javax.swing.AbstractAction; import javax.swing.DefaultCellEditor; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; import org.jets3t.gui.GuiUtils; import org.jets3t.gui.HyperlinkActivatedListener; import org.jets3t.gui.JHtmlLabel; import org.jets3t.gui.TableSorter; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.acl.CanonicalGrantee; import org.jets3t.service.acl.EmailAddressGrantee; import org.jets3t.service.acl.GrantAndPermission; import org.jets3t.service.acl.GranteeInterface; import org.jets3t.service.acl.GroupGrantee; import org.jets3t.service.acl.Permission; import org.jets3t.service.model.BaseStorageItem; import org.jets3t.service.model.S3Bucket; import org.jets3t.service.model.S3Object; import org.jets3t.service.model.S3Owner; /** * Dialog for managing S3 access control settings for buckets and objects. *

* All S3 group types are supported: *

    *
  • Canonical Users
  • *
  • Groups: All Users, Authenticated Users, and Amazon S3 Log Writers
  • *
  • Users identified by Email address
  • *
*

* The following access permissions are supported: *

    *
  • READ
  • *
  • WRITE
  • *
  • READ_ACP
  • *
  • WRITE_ACP
  • *
  • FULL_CONTROL
  • *
* * @author James Murty */ public class AccessControlDialog extends JDialog implements ActionListener { private static final long serialVersionUID = -6621927508514378546L; private final GuiUtils guiUtils = new GuiUtils(); private static AccessControlDialog accessControlDialog = null; private HyperlinkActivatedListener hyperlinkListener = null; private AccessControlList originalAccessControlList = null; private AccessControlList updatedAccessControlList = null; private JHtmlLabel itemsDescription = null; private JTable canonicalGranteeTable = null; private GranteeTableModel canonicalGranteeTableModel = null; private JTable emailGranteeTable = null; private GranteeTableModel emailGranteeTableModel = null; private JTable groupGranteeTable = null; private GranteeTableModel groupGranteeTableModel = null; private static final String[] canonicalUserTableColumnNames = new String[] { "Canonical ID", "Display Name", "Permission" }; private static final String[] groupTableColumnNames = new String[] { "Group URI", "Permission" }; private static final String[] emailTableColumnNames = new String[] { "Email Address", "Permission" }; /** * The set of access permission values. */ private final JComboBox permissionComboBox = new JComboBox(new Permission[] { Permission.PERMISSION_READ, Permission.PERMISSION_WRITE, Permission.PERMISSION_FULL_CONTROL, Permission.PERMISSION_READ_ACP, Permission.PERMISSION_WRITE_ACP }); /** * The set of groups. */ private final JComboBox groupGranteeComboBox = new JComboBox(new GroupGrantee[] { GroupGrantee.ALL_USERS, GroupGrantee.AUTHENTICATED_USERS, GroupGrantee.LOG_DELIVERY }); private final Insets insetsZero = new Insets(0, 0, 0, 0); private final Insets insetsDefault = new Insets(5, 7, 5, 7); private final Insets insetsZeroAtBottom = new Insets(5, 7, 0, 7); private final Insets insetsZeroAtTop = new Insets(0, 7, 5, 7); /** * Creates a modal dialog box with a title. * * @param owner the frame within which this dialog will be displayed and centred. */ protected AccessControlDialog(Frame owner, HyperlinkActivatedListener hyperlinkListener) { super(owner, "Update Access Control List Permissions", true); this.hyperlinkListener = hyperlinkListener; initGui(); } /** * Initialises the dialog with access control information for the given S3 items (bucket or objects) * * @param s3Items May be a single S3Bucket, or one or more S3Objects * @param accessControlList the initial ACL settings to represent in the dialog. */ protected void initData(BaseStorageItem[] s3Items, AccessControlList accessControlList) { this.originalAccessControlList = accessControlList; // Item(s) description. if (s3Items.length > 1) { // Only objects can be updated in multiples, buckets are always single. itemsDescription.setText("Object count: " + s3Items.length + " objects"); } else { if (s3Items[0] instanceof S3Bucket) { itemsDescription.setText("Bucket
" + ((S3Bucket)s3Items[0]).getName()); } else { itemsDescription.setText("Object
" + ((S3Object)s3Items[0]).getKey()); } } // Populate grantees tables. canonicalGranteeTableModel.removeAllGrantAndPermissions(); emailGranteeTableModel.removeAllGrantAndPermissions(); groupGranteeTableModel.removeAllGrantAndPermissions(); for (GrantAndPermission gap: originalAccessControlList.getGrantAndPermissions()) { GranteeInterface grantee = gap.getGrantee(); Permission permission = gap.getPermission(); if (grantee instanceof CanonicalGrantee) { canonicalGranteeTableModel.addGrantee(grantee, permission); } else if (grantee instanceof EmailAddressGrantee) { emailGranteeTableModel.addGrantee(grantee, permission); } else if (grantee instanceof GroupGrantee) { groupGranteeTableModel.addGrantee(grantee, permission); } } } /** * Initialises all GUI elements. */ protected void initGui() { this.setResizable(true); this.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE); // Canonical Grantee Table and add/remove buttons. canonicalGranteeTableModel = new GranteeTableModel(CanonicalGrantee.class); canonicalGranteeTable = new GranteeTable(canonicalGranteeTableModel); JButton removeCanonical = new JButton(); removeCanonical.setToolTipText("Remove the selected Canonical User grantee"); guiUtils.applyIcon(removeCanonical, "/images/nuvola/16x16/actions/viewmag-.png"); removeCanonical.addActionListener(this); removeCanonical.setActionCommand("removeCanonicalGrantee"); JButton addCanonical = new JButton(); addCanonical.setToolTipText("Add a new Canonical User grantee"); guiUtils.applyIcon(addCanonical, "/images/nuvola/16x16/actions/viewmag+.png"); addCanonical.setActionCommand("addCanonicalGrantee"); addCanonical.addActionListener(this); // Email Address Grantee Table and add/remove buttons. emailGranteeTableModel = new GranteeTableModel(EmailAddressGrantee.class); emailGranteeTable = new GranteeTable(emailGranteeTableModel); JButton removeEmail = new JButton(); removeEmail.setToolTipText("Remove the selected Email Address grantee"); guiUtils.applyIcon(removeEmail, "/images/nuvola/16x16/actions/viewmag-.png"); removeEmail.setActionCommand("removeEmailGrantee"); removeEmail.addActionListener(this); JButton addEmail = new JButton(); addEmail.setToolTipText("Add a new Email Address grantee"); guiUtils.applyIcon(addEmail, "/images/nuvola/16x16/actions/viewmag+.png"); addEmail.setActionCommand("addEmailGrantee"); addEmail.addActionListener(this); // Group grantee table and add/remove buttons. groupGranteeTableModel = new GranteeTableModel(GroupGrantee.class); groupGranteeTable = new GranteeTable(groupGranteeTableModel); JButton removeGroup = new JButton(); removeGroup.setToolTipText("Remove the selected Group grantee"); guiUtils.applyIcon(removeGroup, "/images/nuvola/16x16/actions/viewmag-.png"); removeGroup.setActionCommand("removeGroupGrantee"); removeGroup.addActionListener(this); JButton addGroup = new JButton(); addGroup.setToolTipText("Add a new Group grantee"); guiUtils.applyIcon(addGroup, "/images/nuvola/16x16/actions/viewmag+.png"); addGroup.setActionCommand("addGroupGrantee"); addGroup.addActionListener(this); // Action buttons. JPanel buttonsContainer = new JPanel(new GridBagLayout()); final JButton cancelButton = new JButton("Cancel Permission Changes"); cancelButton.setDefaultCapable(true); cancelButton.addActionListener(this); cancelButton.setActionCommand("Cancel"); JButton okButton = new JButton("Save Permission Changes"); okButton.setActionCommand("OK"); okButton.addActionListener(this); // Set default ENTER and ESCAPE buttons. this.getRootPane().setDefaultButton(okButton); this.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke("ESCAPE"), "ESCAPE"); this.getRootPane().getActionMap().put("ESCAPE", new AbstractAction() { private static final long serialVersionUID = 4173433313456104263L; public void actionPerformed(ActionEvent actionEvent) { cancelButton.doClick(); } }); // Overall container. JPanel container = new JPanel(new GridBagLayout()); int row = 0; itemsDescription = new JHtmlLabel("", hyperlinkListener); container.add(itemsDescription, new GridBagConstraints(0, row, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); JPanel canonicalAddRemovePanel = new JPanel(); canonicalAddRemovePanel.add(removeCanonical); canonicalAddRemovePanel.add(addCanonical); container.add(new JHtmlLabel("Canonical User Grantees", hyperlinkListener), new GridBagConstraints(0, ++row, 2, 1, 0, 0, GridBagConstraints.SOUTHWEST, GridBagConstraints.HORIZONTAL, insetsZeroAtBottom, 0, 0)); container.add(new JScrollPane(canonicalGranteeTable), new GridBagConstraints(0, ++row, 2, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsZeroAtBottom, 0, 0)); container.add(new JHtmlLabel("Group Grantees", hyperlinkListener), new GridBagConstraints(0, ++row, 1, 1, 1, 0, GridBagConstraints.SOUTHWEST, GridBagConstraints.HORIZONTAL, insetsZeroAtBottom, 0, 0)); container.add(canonicalAddRemovePanel, new GridBagConstraints(1, row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsZeroAtTop, 0, 0)); JPanel groupAddRemovePanel = new JPanel(); groupAddRemovePanel.add(removeGroup); groupAddRemovePanel.add(addGroup); container.add(new JScrollPane(groupGranteeTable), new GridBagConstraints(0, ++row, 2, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsZeroAtBottom, 0, 0)); container.add(new JHtmlLabel("Email Address Grantees", hyperlinkListener), new GridBagConstraints(0, ++row, 1, 1, 1, 0, GridBagConstraints.SOUTHWEST, GridBagConstraints.HORIZONTAL, insetsZeroAtBottom, 0, 0)); container.add(groupAddRemovePanel, new GridBagConstraints(1, row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsZeroAtTop, 0, 0)); JPanel emailAddRemovePanel = new JPanel(); emailAddRemovePanel.add(removeEmail); emailAddRemovePanel.add(addEmail); container.add(new JScrollPane(emailGranteeTable), new GridBagConstraints(0, ++row, 2, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsZeroAtBottom, 0, 0)); container.add(emailAddRemovePanel, new GridBagConstraints(1, ++row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsZeroAtTop, 0, 0)); buttonsContainer.add(cancelButton, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsZero, 0, 0)); buttonsContainer.add(okButton, new GridBagConstraints(1, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsZero, 0, 0)); container.add(buttonsContainer, new GridBagConstraints(0, ++row, 2, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); this.getContentPane().add(container); this.pack(); this.setSize(new Dimension(700, 450)); this.setLocationRelativeTo(this.getOwner()); // Resize columns. canonicalGranteeTable.getColumnModel().getColumn(0).setPreferredWidth((int) (canonicalGranteeTable.getParent().getBounds().getWidth() * 0.9)); emailGranteeTable.getColumnModel().getColumn(0).setPreferredWidth((int) (emailGranteeTable.getParent().getBounds().getWidth() * 0.9)); groupGranteeTable.getColumnModel().getColumn(0).setPreferredWidth((int) (groupGranteeTable.getParent().getBounds().getWidth() * 0.9)); } /** * @return the ACL settings as set by the user in the dialog. */ public AccessControlList getUpdatedAccessControlList() { return updatedAccessControlList; } /** * Populates the local {@link #updatedAccessControlList} variable with ACL * details set by the user in the GUI elements. */ private void updateAccessControlList() { updatedAccessControlList = new AccessControlList(); updatedAccessControlList.setOwner(originalAccessControlList.getOwner()); for (int i = 0; i < canonicalGranteeTable.getRowCount(); i++) { GranteeInterface grantee = canonicalGranteeTableModel.getGrantee(i); Permission permission = canonicalGranteeTableModel.getPermission(i); updatedAccessControlList.grantPermission(grantee, permission); } for (int i = 0; i < emailGranteeTable.getRowCount(); i++) { GranteeInterface grantee = emailGranteeTableModel.getGrantee(i); Permission permission = emailGranteeTableModel.getPermission(i); updatedAccessControlList.grantPermission(grantee, permission); } for (int i = 0; i < groupGranteeTable.getRowCount(); i++) { GranteeInterface grantee = groupGranteeTableModel.getGrantee(i); Permission permission = groupGranteeTableModel.getPermission(i); updatedAccessControlList.grantPermission(grantee, permission); } } /** * Event handler for this dialog. */ public void actionPerformed(ActionEvent e) { if ("OK".equals(e.getActionCommand())) { updateAccessControlList(); this.setVisible(false); } else if ("Cancel".equals(e.getActionCommand())) { updatedAccessControlList = null; this.setVisible(false); } else if ("addCanonicalGrantee".equals(e.getActionCommand())) { int rowIndex = canonicalGranteeTableModel.addGrantee( new CanonicalGrantee("NewCanonicalId"), Permission.PERMISSION_READ); canonicalGranteeTable.setRowSelectionInterval(rowIndex, rowIndex); } else if ("removeCanonicalGrantee".equals(e.getActionCommand())) { if (canonicalGranteeTable.getSelectedRow() >= 0) { canonicalGranteeTableModel.removeGrantAndPermission(canonicalGranteeTable.getSelectedRow()); } } else if ("addEmailGrantee".equals(e.getActionCommand())) { int rowIndex = emailGranteeTableModel.addGrantee( new EmailAddressGrantee("new.email@address.here"), Permission.PERMISSION_READ); emailGranteeTable.setRowSelectionInterval(rowIndex, rowIndex); } else if ("removeEmailGrantee".equals(e.getActionCommand())) { if (emailGranteeTable.getSelectedRow() >= 0) { emailGranteeTableModel.removeGrantAndPermission(emailGranteeTable.getSelectedRow()); } } else if ("addGroupGrantee".equals(e.getActionCommand())) { int rowIndex = groupGranteeTableModel.addGrantee( GroupGrantee.AUTHENTICATED_USERS, Permission.PERMISSION_READ); groupGranteeTable.setRowSelectionInterval(rowIndex, rowIndex); } else if ("removeGroupGrantee".equals(e.getActionCommand())) { if (groupGranteeTable.getSelectedRow() >= 0) { groupGranteeTableModel.removeGrantAndPermission(groupGranteeTable.getSelectedRow()); } } else { System.err.println("UNRECOGNISED ACTION COMMAND: " + e.getActionCommand()); } } /** * Displays the dialog box and waits until the user applies their changes or cancels the dialog. *

* If the user elects to apply their changes, this method returns the updated ACL information. * If the user cancels the dialog, this method returns null. * * @param owner the Frame within which this dialog will be displayed and centered * @param s3Items an array of {@link S3Bucket} or {@link S3Object}s to which ACL change will be applied * @param accessControlList the original ACL settings for the S3Bucket or S3Objects provided * @return the update ACL settings if the user applies changes, null if the dialog is cancelled. */ public static AccessControlList showDialog(Frame owner, BaseStorageItem[] s3Items, AccessControlList accessControlList, HyperlinkActivatedListener hyperlinkListener) { if (accessControlDialog == null) { accessControlDialog = new AccessControlDialog(owner, hyperlinkListener); } accessControlDialog.initData(s3Items, accessControlList); accessControlDialog.setVisible(true); return accessControlDialog.getUpdatedAccessControlList(); } /** * Table to represent ACL grantees. * * @author James Murty */ private class GranteeTable extends JTable { private static final long serialVersionUID = -5339684196750695854L; private TableSorter sorter = null; public GranteeTable(GranteeTableModel granteeTableModel) { super(); sorter = new TableSorter(granteeTableModel); this.setModel(sorter); sorter.setTableHeader(this.getTableHeader()); getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); getSelectionModel().addListSelectionListener(this); DefaultCellEditor groupCellEditor = new DefaultCellEditor(groupGranteeComboBox); groupCellEditor.setClickCountToStart(2); setDefaultEditor(GroupGrantee.class, groupCellEditor); setDefaultRenderer(GroupGrantee.class, new DefaultTableCellRenderer() { private static final long serialVersionUID = 4938391147702620699L; @Override public Component getTableCellRendererComponent(JTable arg0, Object value, boolean arg2, boolean arg3, int arg4, int arg5) { GroupGrantee groupGrantee = (GroupGrantee) value; return super.getTableCellRendererComponent(arg0, groupGrantee.getIdentifier(), arg2, arg3, arg4, arg5); } }); DefaultCellEditor permissionCellEditor = new DefaultCellEditor(permissionComboBox); permissionCellEditor.setClickCountToStart(2); setDefaultEditor(Permission.class, permissionCellEditor); } @Override public int getSelectedRow() { int tableIndex = super.getSelectedRow(); return sorter.modelIndex(tableIndex); } } /** * Grantee table model that knows what kind of grantees it is displaying and displays * them appropriately. * * @author James Murty */ private class GranteeTableModel extends DefaultTableModel { private static final long serialVersionUID = -5533290183089426571L; private Class granteeClass = null; ArrayList currentGrantees = new ArrayList(); int permissionColumn = 0; public GranteeTableModel(Class granteeClass) { super( (CanonicalGrantee.class.equals(granteeClass) ? canonicalUserTableColumnNames : EmailAddressGrantee.class.equals(granteeClass) ? emailTableColumnNames : GroupGrantee.class.equals(granteeClass) ? groupTableColumnNames : new String[] {} ), 0); this.granteeClass = granteeClass; permissionColumn = (CanonicalGrantee.class.equals(granteeClass) ? 2 : 1); } public int addGrantee(GranteeInterface grantee, Permission permission) { GrantAndPermission gap = new GrantAndPermission(grantee, permission); int insertRow = Collections.binarySearch(currentGrantees, gap, new Comparator() { public int compare(Object o1, Object o2) { GrantAndPermission g1 = (GrantAndPermission) o1; GrantAndPermission g2 = (GrantAndPermission) o2; return g1.getGrantee().getIdentifier().compareToIgnoreCase( g2.getGrantee().getIdentifier()); } }); if (insertRow >= 0) { // We already have an item with this key, but that's OK. } else { insertRow = (-insertRow) - 1; } // New object to insert. currentGrantees.add(insertRow, gap); if (grantee instanceof GroupGrantee) { this.insertRow(insertRow, new Object[] {grantee, permission}); } else if (grantee instanceof CanonicalGrantee) { CanonicalGrantee canonicalGrantee = (CanonicalGrantee) grantee; this.insertRow(insertRow, new Object[] {canonicalGrantee.getIdentifier(), canonicalGrantee.getDisplayName(), permission}); } else { this.insertRow(insertRow, new Object[] {grantee.getIdentifier(), permission}); } return insertRow; } public void removeGrantAndPermission(int index) { Object grantee = this.getGrantee(index); this.removeRow(index); currentGrantees.remove(grantee); } public void removeAllGrantAndPermissions() { int rowCount = this.getRowCount(); for (int i = 0; i < rowCount; i++) { this.removeRow(0); } currentGrantees.clear(); } public Permission getPermission(int index) { return (Permission) this.getValueAt(index, permissionColumn); } public GranteeInterface getGrantee(int index) { GrantAndPermission originalGAP = (GrantAndPermission) currentGrantees.get(index); Object updatedGrantee = super.getValueAt(index, 0); if (updatedGrantee instanceof GroupGrantee) { // We can return this as-is, because GroupGrantees are actually stored in the table. return (GroupGrantee) updatedGrantee; } else { // Non-group Grantees are stored as Strings in the table, so update the original's ID. originalGAP.getGrantee().setIdentifier((String) updatedGrantee); return originalGAP.getGrantee(); } } @Override public boolean isCellEditable(int row, int column) { return (column == 0 || column == permissionColumn); } @Override public Class getColumnClass(int columnIndex) { if (columnIndex == 0) { if (GroupGrantee.class.equals(granteeClass)) { return GroupGrantee.class; } else { return String.class; } } else if (columnIndex == permissionColumn) { return Permission.class; } else { return String.class; } } } /** * Creates stand-alone dialog box for testing only. * * @param args * @throws Exception */ public static void main(String args[]) throws Exception { // TEST DATA AccessControlList acl = new AccessControlList(); S3Owner owner = new S3Owner("1234567890", "Some Name"); acl.setOwner(owner); GranteeInterface grantee = new CanonicalGrantee(); grantee.setIdentifier("zzz"); acl.grantPermission(grantee, Permission.PERMISSION_WRITE); grantee = new CanonicalGrantee(); grantee.setIdentifier("abc"); ((CanonicalGrantee)grantee).setDisplayName("jamesmurty"); acl.grantPermission(grantee, Permission.PERMISSION_FULL_CONTROL); grantee = new CanonicalGrantee(); grantee.setIdentifier("aaa"); acl.grantPermission(grantee, Permission.PERMISSION_READ); grantee = GroupGrantee.ALL_USERS; acl.grantPermission(grantee, Permission.PERMISSION_READ); grantee = GroupGrantee.AUTHENTICATED_USERS; acl.grantPermission(grantee, Permission.PERMISSION_WRITE); grantee = new EmailAddressGrantee(); grantee.setIdentifier("james@test.com"); acl.grantPermission(grantee, Permission.PERMISSION_READ); grantee = new EmailAddressGrantee(); grantee.setIdentifier("james@test2.com"); acl.grantPermission(grantee, Permission.PERMISSION_FULL_CONTROL); JFrame f = new JFrame("Cockpit"); S3Bucket bucket = new S3Bucket(); bucket.setName("SomeReallyLongAndWackyBucketNamePath.HereItIs"); AccessControlList updatedACL = acl; while ((updatedACL = AccessControlDialog.showDialog(f, new S3Bucket[] {bucket}, updatedACL, null)) != null) { System.out.println(updatedACL.toXml()); } f.dispose(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/cockpit/gui/RequesterPaysDialog.java0000644000000000000000000001270611427702124024262 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.cockpit.gui; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.AbstractAction; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.KeyStroke; import org.jets3t.gui.HyperlinkActivatedListener; import org.jets3t.gui.JHtmlLabel; import org.jets3t.service.model.S3Bucket; /** * Dialog box show the Request Payment Configuration setting for a bucket, * and to allow this setting to be changed. * * @author James Murty */ public class RequesterPaysDialog extends JDialog implements ActionListener { private static final long serialVersionUID = 2406896456675486928L; private boolean okClicked = false; private JTextField bucketNameTextField = null; private JCheckBox requesterPaysCheckBox = null; private JButton okButton = null; private JButton cancelButton = null; private final Insets insetsDefault = new Insets(3, 5, 3, 5); public RequesterPaysDialog(S3Bucket bucket, Frame ownerFrame, HyperlinkActivatedListener hyperlinkListener) { super(ownerFrame, "Requester Pays", true); cancelButton = new JButton("Cancel"); cancelButton.setActionCommand("Cancel"); cancelButton.addActionListener(this); okButton = new JButton("Update Status"); okButton.setActionCommand("OK"); okButton.addActionListener(this); JHtmlLabel bucketNameLabel = new JHtmlLabel("Bucket name", hyperlinkListener); bucketNameLabel.setHorizontalAlignment(JLabel.CENTER); bucketNameTextField = new JTextField(bucket.getName()); bucketNameTextField.setEditable(false); JHtmlLabel requesterPaysLabel = new JHtmlLabel("Requester Pays?", hyperlinkListener); requesterPaysCheckBox = new JCheckBox(); requesterPaysCheckBox.setSelected(bucket.isRequesterPays()); // Set default ENTER and ESCAPE buttons. this.getRootPane().setDefaultButton(okButton); this.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke("ESCAPE"), "ESCAPE"); this.getRootPane().getActionMap().put("ESCAPE", new AbstractAction() { private static final long serialVersionUID = -6225706489569112809L; public void actionPerformed(ActionEvent actionEvent) { setVisible(false); okClicked = false; } }); JPanel buttonsPanel = new JPanel(new GridBagLayout()); buttonsPanel.add(cancelButton, new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsDefault, 0, 0)); buttonsPanel.add(okButton, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsDefault, 0, 0)); JPanel panel = new JPanel(new GridBagLayout()); int row = 0; panel.add(bucketNameLabel, new GridBagConstraints(0, row, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); panel.add(bucketNameTextField, new GridBagConstraints(1, row, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); panel.add(requesterPaysLabel, new GridBagConstraints(0, ++row, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); panel.add(requesterPaysCheckBox, new GridBagConstraints(1, row, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); panel.add(buttonsPanel, new GridBagConstraints(0, ++row, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); this.getContentPane().setLayout(new GridBagLayout()); this.getContentPane().add(panel, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); this.pack(); this.setResizable(false); this.setLocationRelativeTo(ownerFrame); } public void actionPerformed(ActionEvent event) { if (event.getSource().equals(okButton)) { this.setVisible(false); okClicked = true; } else if (event.getSource().equals(cancelButton)) { this.setVisible(false); okClicked = false; } } public boolean getOkClicked() { return okClicked; } public boolean isRequesterPaysSelected() { return requesterPaysCheckBox.isSelected(); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/cockpit/gui/SignedGetUrlDialog.java0000644000000000000000000002544211427702124024003 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.cockpit.gui; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Calendar; import javax.swing.AbstractAction; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.gui.ErrorDialog; import org.jets3t.gui.HyperlinkActivatedListener; import org.jets3t.gui.JHtmlLabel; import org.jets3t.service.Constants; import org.jets3t.service.S3Service; import org.jets3t.service.S3ServiceException; import org.jets3t.service.model.S3Object; /** * Dialog box to query to generate Signed URLs for a given set of objects, based * on URL signing configuration options selected by the user. This dialog does * all the work, prompting for user inputs then generating and displaying the * resultant Signed URLs. *

* The caller is responsible for disposing of this dialog. * * @author James Murty * */ public class SignedGetUrlDialog extends JDialog implements ActionListener, DocumentListener { private static final long serialVersionUID = -3243824805519630114L; private static final Log log = LogFactory.getLog(SignedGetUrlDialog.class); private Frame ownerFrame = null; private HyperlinkActivatedListener hyperlinkListener = null; private S3Service s3Service = null; private S3Object[] objects = null; private JCheckBox virtualHostCheckBox = null; private JCheckBox requesterPaysCheckBox = null; private JCheckBox httpsUrlsCheckBox = null; private JTextField expiryTimeTextField = null; private JTextArea signedUrlsTextArea = null; private JButton finishedButton = null; private final Insets insetsDefault = new Insets(3, 5, 3, 5); public SignedGetUrlDialog(Frame ownerFrame, HyperlinkActivatedListener hyperlinkListener, S3Service s3Service, S3Object[] objects) { super(ownerFrame, "Generate Signed GET URLs", true); this.ownerFrame = ownerFrame; this.hyperlinkListener = hyperlinkListener; this.s3Service = s3Service; this.objects = objects; String introductionText = "

Generate signed GET URLs that you can provide to anyone
" + "who needs to access objects in your bucket for a limited time.
"; JHtmlLabel introductionLabel = new JHtmlLabel(introductionText, hyperlinkListener); introductionLabel.setHorizontalAlignment(JLabel.CENTER); JHtmlLabel expiryTimeLabel = new JHtmlLabel("Expiry Time (Hours)", hyperlinkListener); expiryTimeLabel.setHorizontalAlignment(JLabel.RIGHT); JHtmlLabel httpsUrlsLabel = new JHtmlLabel("Secure HTTPS URLs?", hyperlinkListener); httpsUrlsLabel.setHorizontalAlignment(JLabel.RIGHT); JHtmlLabel virtualHostLabel = new JHtmlLabel("Bucket is a Virtual Host?", hyperlinkListener); virtualHostLabel.setHorizontalAlignment(JLabel.RIGHT); JHtmlLabel requesterPaysLabel = new JHtmlLabel("Bucket is Requester Pays?", hyperlinkListener); requesterPaysLabel.setHorizontalAlignment(JLabel.RIGHT); expiryTimeTextField = new JTextField("1.0"); expiryTimeTextField.setToolTipText("How long in hours until the URL will expire"); expiryTimeTextField.getDocument().addDocumentListener(this); httpsUrlsCheckBox = new JCheckBox(); httpsUrlsCheckBox.setSelected(false); httpsUrlsCheckBox.setToolTipText("Check this box to generate secure HTTPS URLs."); httpsUrlsCheckBox.addActionListener(this); virtualHostCheckBox = new JCheckBox(); virtualHostCheckBox.setSelected(false); virtualHostCheckBox.setToolTipText("Check this box if your bucket is configured as a virtual host."); virtualHostCheckBox.addActionListener(this); requesterPaysCheckBox = new JCheckBox(); requesterPaysCheckBox.setSelected(false); requesterPaysCheckBox.setToolTipText("Check this box if the bucket has Requester Pays enabled."); requesterPaysCheckBox.addActionListener(this); finishedButton = new JButton("Finished"); finishedButton.setActionCommand("Finished"); finishedButton.addActionListener(this); signedUrlsTextArea = new JTextArea(); signedUrlsTextArea.setEditable(false); // Set default ENTER and ESCAPE buttons. this.getRootPane().setDefaultButton(finishedButton); this.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke("ESCAPE"), "ESCAPE"); this.getRootPane().getActionMap().put("ESCAPE", new AbstractAction() { private static final long serialVersionUID = -6225706489569112809L; public void actionPerformed(ActionEvent actionEvent) { setVisible(false); } }); JPanel panel = new JPanel(new GridBagLayout()); int row = 0; panel.add(introductionLabel, new GridBagConstraints(0, row, 6, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); panel.add(expiryTimeLabel, new GridBagConstraints(0, ++row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); panel.add(expiryTimeTextField, new GridBagConstraints(1, row, 5, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); panel.add(httpsUrlsLabel, new GridBagConstraints(0, ++row, 1, 1, 0.3, 0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); panel.add(httpsUrlsCheckBox, new GridBagConstraints(1, row, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); panel.add(virtualHostLabel, new GridBagConstraints(2, row, 1, 1, 0.3, 0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); panel.add(virtualHostCheckBox, new GridBagConstraints(3, row, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); panel.add(requesterPaysLabel, new GridBagConstraints(4, row, 1, 1, 0.3, 0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); panel.add(requesterPaysCheckBox, new GridBagConstraints(5, row, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); panel.add(new JScrollPane(signedUrlsTextArea), new GridBagConstraints(0, ++row, 6, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); panel.add(finishedButton, new GridBagConstraints(0, ++row, 6, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsDefault, 0, 0)); this.getContentPane().setLayout(new GridBagLayout()); this.getContentPane().add(panel, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); this.setSize(700, 450); this.setResizable(true); this.setLocationRelativeTo(ownerFrame); generateSignedUrls(); } public void actionPerformed(ActionEvent event) { if (event.getSource().equals(finishedButton)) { this.setVisible(false); } else { generateSignedUrls(); } } public void changedUpdate(DocumentEvent e) { generateSignedUrls(); } public void insertUpdate(DocumentEvent e) { generateSignedUrls(); } public void removeUpdate(DocumentEvent e) { generateSignedUrls(); } protected void generateSignedUrls() { try { signedUrlsTextArea.setText(""); if (expiryTimeTextField.getText().length() == 0) { return; } // Determine expiry time for URL double hoursFromNow = Double.parseDouble(expiryTimeTextField.getText()); int secondsFromNow = (int) (hoursFromNow * 60 * 60); Calendar cal = Calendar.getInstance(); cal.add(Calendar.SECOND, secondsFromNow); long secondsSinceEpoch = cal.getTimeInMillis() / 1000; // Include Requester Pays flag if our service has these buckets enabled. String specialParamName = null; if (requesterPaysCheckBox.isSelected()) { specialParamName = Constants.REQUESTER_PAYS_BUCKET_FLAG; } boolean disableDnsBuckets = s3Service.getJetS3tProperties() .getBoolProperty("s3service.disable-dns-buckets", false); // Generate URLs StringBuffer signedUrlsBuffer = new StringBuffer(); for (int i = 0; i < objects.length; i++) { S3Object currentObject = objects[i]; String signedUrl = this.s3Service.createSignedUrl("GET", currentObject.getBucketName(), currentObject.getKey(), specialParamName, null, secondsSinceEpoch, virtualHostCheckBox.isSelected(), httpsUrlsCheckBox.isSelected(), disableDnsBuckets); signedUrlsBuffer.append(signedUrl + "\n"); } signedUrlsTextArea.setText(signedUrlsBuffer.toString()); } catch (NumberFormatException e) { String message = "Hours must be a valid decimal value; eg 3, 0.1"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, hyperlinkListener, message, e); } catch (S3ServiceException e) { String message = "Unable to generate public GET URL"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, hyperlinkListener, message, e); } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/cockpit/Cockpit.java0000644000000000000000000041747111550441664021154 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.cockpit; import java.awt.Component; import java.awt.Dimension; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Rectangle; import java.awt.datatransfer.DataFlavor; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.net.MalformedURLException; import java.net.URL; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import javax.swing.JApplet; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.JSplitPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableColumn; import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.NTCredentials; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.httpclient.auth.AuthScheme; import org.apache.commons.httpclient.auth.CredentialsNotAvailableException; import org.apache.commons.httpclient.auth.CredentialsProvider; import org.apache.commons.httpclient.auth.NTLMScheme; import org.apache.commons.httpclient.auth.RFC2617Scheme; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.apps.cockpit.gui.AccessControlDialog; import org.jets3t.apps.cockpit.gui.BucketLoggingDialog; import org.jets3t.apps.cockpit.gui.BucketTableModel; import org.jets3t.apps.cockpit.gui.CreateBucketDialog; import org.jets3t.apps.cockpit.gui.ObjectTableModel; import org.jets3t.apps.cockpit.gui.PreferencesDialog; import org.jets3t.apps.cockpit.gui.RequesterPaysDialog; import org.jets3t.apps.cockpit.gui.SignedGetUrlDialog; import org.jets3t.apps.cockpit.gui.StartupDialog; import org.jets3t.gui.AuthenticationDialog; import org.jets3t.gui.CopyObjectsDialog; import org.jets3t.gui.ErrorDialog; import org.jets3t.gui.GuiUtils; import org.jets3t.gui.HyperlinkActivatedListener; import org.jets3t.gui.ItemPropertiesDialog; import org.jets3t.gui.JHtmlLabel; import org.jets3t.gui.ManageDistributionsDialog; import org.jets3t.gui.ObjectsAttributesDialog; import org.jets3t.gui.ProgressDialog; import org.jets3t.gui.TableSorter; import org.jets3t.gui.skins.SkinsFactory; import org.jets3t.service.CloudFrontService; import org.jets3t.service.CloudFrontServiceException; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.S3ServiceException; import org.jets3t.service.StorageObjectsChunk; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.impl.rest.httpclient.RestS3Service; import org.jets3t.service.io.BytesProgressWatcher; import org.jets3t.service.model.S3Bucket; import org.jets3t.service.model.S3Object; import org.jets3t.service.model.cloudfront.Distribution; import org.jets3t.service.multithread.CancelEventTrigger; import org.jets3t.service.multithread.CopyObjectsEvent; import org.jets3t.service.multithread.CreateBucketsEvent; import org.jets3t.service.multithread.CreateObjectsEvent; import org.jets3t.service.multithread.DeleteObjectsEvent; import org.jets3t.service.multithread.DeleteVersionedObjectsEvent; import org.jets3t.service.multithread.DownloadObjectsEvent; import org.jets3t.service.multithread.DownloadPackage; import org.jets3t.service.multithread.GetObjectHeadsEvent; import org.jets3t.service.multithread.GetObjectsEvent; import org.jets3t.service.multithread.ListObjectsEvent; import org.jets3t.service.multithread.LookupACLEvent; import org.jets3t.service.multithread.S3ServiceEventListener; import org.jets3t.service.multithread.S3ServiceMulti; import org.jets3t.service.multithread.ServiceEvent; import org.jets3t.service.multithread.ThreadWatcher; import org.jets3t.service.multithread.UpdateACLEvent; import org.jets3t.service.security.EncryptionUtil; import org.jets3t.service.security.ProviderCredentials; import org.jets3t.service.utils.ByteFormatter; import org.jets3t.service.utils.FileComparer; import org.jets3t.service.utils.FileComparerResults; import org.jets3t.service.utils.Mimetypes; import org.jets3t.service.utils.ObjectUtils; import org.jets3t.service.utils.TimeFormatter; import com.centerkey.utils.BareBonesBrowserLaunch; /** * Cockpit is a graphical Java application for viewing and managing the contents of an Amazon S3 account. * For more information and help please see the * Cockpit Guide. *

* This is the Cockpit application class; it may be run as a stand-alone application or as an Applet. * * @author jmurty */ public class Cockpit extends JApplet implements S3ServiceEventListener, ActionListener, ListSelectionListener, HyperlinkActivatedListener, CredentialsProvider { private static final long serialVersionUID = -3193198830234682011L; private static final Log log = LogFactory.getLog(Cockpit.class); public static final String JETS3T_COCKPIT_HELP_PAGE = "http://www.jets3t.org/applications/cockpit.html"; public static final String AMAZON_S3_PAGE = "http://www.amazon.com/s3"; public static final String OS_NAME_MAC = "Mac OS X"; public static final String APPLICATION_DESCRIPTION = "Cockpit/" + Constants.JETS3T_VERSION; public static final String APPLICATION_TITLE = "JetS3t Cockpit"; private static final int BUCKET_LIST_CHUNKING_SIZE = 1000; private final File cockpitHomeDirectory = Constants.DEFAULT_PREFERENCES_DIRECTORY; private CockpitPreferences cockpitPreferences = null; private final Insets insetsZero = new Insets(0, 0, 0, 0); private final Insets insetsDefault = new Insets(5, 7, 5, 7); private final ByteFormatter byteFormatter = new ByteFormatter(); private final TimeFormatter timeFormatter = new TimeFormatter(); private final SimpleDateFormat yearAndTimeSDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); private final SimpleDateFormat timeSDF = new SimpleDateFormat("HH:mm:ss"); private final GuiUtils guiUtils = new GuiUtils(); /** * Multi-threaded S3 service used by the application. */ private boolean isTargetS3 = true; private String originalTargetEndpoint = null; private S3ServiceMulti s3ServiceMulti = null; private CloudFrontService cloudFrontService = null; private boolean cloudFrontMembershipChecked = false; private JFrame ownerFrame = null; private boolean isStandAloneApplication = false; // Service main menu items private JMenuItem loginMenuItem = null; private JMenuItem logoutMenuItem = null; private JMenu loginSwitchMenu = null; // Bucket main menu items private JPopupMenu bucketActionMenu = null; private JMenuItem viewBucketPropertiesMenuItem = null; private JMenuItem refreshBucketMenuItem = null; private JMenuItem createBucketMenuItem = null; private JMenuItem manageDistributionsMenuItem = null; private JMenuItem updateBucketACLMenuItem = null; private JMenuItem updateBucketRequesterPaysStatusMenuItem = null; private JMenuItem deleteBucketMenuItem = null; // Object main menu items private JPopupMenu objectActionMenu = null; private JMenuItem refreshObjectMenuItem = null; private JMenuItem viewOrModifyObjectAttributesMenuItem = null; private JMenuItem copyObjectsMenuItem = null; private JMenuItem updateObjectACLMenuItem = null; private JMenuItem downloadObjectMenuItem = null; private JMenuItem uploadFilesMenuItem = null; private JMenuItem generatePublicGetUrls = null; private JMenuItem generateTorrentUrl = null; private JMenuItem deleteObjectMenuItem = null; // Tools menu items. private JMenuItem bucketLoggingMenuItem = null; // Preference menu items. private JMenuItem preferencesDialogMenuItem = null; // Help menu items. private JMenuItem cockpitHelpMenuItem = null; private JMenuItem amazonS3HelpMenuItem = null; // Tables private JTable bucketsTable = null; private JTable objectsTable = null; private JScrollPane objectsTableSP = null; private BucketTableModel bucketTableModel = null; private TableSorter bucketTableModelSorter = null; private ObjectTableModel objectTableModel = null; private TableSorter objectTableModelSorter = null; private JLabel objectsSummaryLabel = null; private final HashMap cachedBuckets = new HashMap(); private ProgressDialog progressDialog = null; private ObjectsAttributesDialog objectsAttributesDialog = null; private File downloadDirectory = null; private File fileChoosersLastUploadDirectory = null; private JPanel filterObjectsPanel = null; private JCheckBox filterObjectsCheckBox = null; private JTextField filterObjectsPrefix = null; private JComboBox filterObjectsDelimiter = null; // File comparison options private static final String UPLOAD_NEW_FILES_ONLY = "Only upload new files"; private static final String UPLOAD_NEW_AND_CHANGED_FILES = "Upload new and changed files"; private static final String UPLOAD_ALL_FILES = "Upload all files"; private static final String DOWNLOAD_NEW_FILES_ONLY = "Only download new files"; private static final String DOWNLOAD_NEW_AND_CHANGED_FILES = "Download new and changed files"; private static final String DOWNLOAD_ALL_FILES = "Download all files"; private EncryptionUtil encryptionUtil = null; private Jets3tProperties cockpitProperties = null; private SkinsFactory skinsFactory = null; private S3Bucket currentSelectedBucket = null; private final HashMap loginAwsCredentialsMap = new HashMap(); /** * Constructor to run this application as an Applet. */ public Cockpit() { } /** * Constructor to run this application in a stand-alone window. * * @param ownerFrame the frame the application will be displayed in * @throws S3ServiceException */ public Cockpit(JFrame ownerFrame) throws S3ServiceException { this.ownerFrame = ownerFrame; isStandAloneApplication = true; init(); ownerFrame.getContentPane().add(this); ownerFrame.setBounds(this.getBounds()); ownerFrame.setVisible(true); } protected RestS3Service getRestS3Service(ProviderCredentials credentials) throws S3ServiceException { if (!this.isTargetS3) { // Override endpoint property in JetS3t properties originalTargetEndpoint = cockpitProperties.getStringProperty( "s3service.s3-endpoint", Constants.S3_DEFAULT_HOSTNAME); cockpitProperties.setProperty( "s3service.s3-endpoint", Constants.GS_DEFAULT_HOSTNAME); } else if (originalTargetEndpoint != null) { cockpitProperties.setProperty( "s3service.s3-endpoint", originalTargetEndpoint); } return new RestS3Service(credentials, APPLICATION_DESCRIPTION, this, cockpitProperties); } /** * Prepares application to run as a GUI by finding/creating a root owner JFrame, creating an * un-authenticated {@link RestS3Service} and loading properties files. */ @Override public void init() { super.init(); // Find or create a Frame to own modal dialog boxes. if (this.ownerFrame == null) { Component c = this; while (!(c instanceof Frame) && c.getParent() != null) { c = c.getParent(); } if (!(c instanceof JFrame)) { this.ownerFrame = new JFrame(); } else { this.ownerFrame = (JFrame) c; } } // Initialise the GUI. initGui(); // Load Cockpit configuration files from cockpit's home directory. File mimeTypesFile = new File(cockpitHomeDirectory, "mime.types"); if (mimeTypesFile.exists()) { try { Mimetypes.getInstance().loadAndReplaceMimetypes( new FileInputStream(mimeTypesFile)); } catch (IOException e) { String message = "Unable to load mime.types file: " + mimeTypesFile; log.error(message, e); ErrorDialog.showDialog(ownerFrame, this, message, e); } } File jets3tPropertiesFile = new File(cockpitHomeDirectory, "jets3t.properties"); if (jets3tPropertiesFile.exists()) { try { Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME) .loadAndReplaceProperties(new FileInputStream(jets3tPropertiesFile), "jets3t.properties in Cockpit's home folder " + cockpitHomeDirectory); } catch (IOException e) { String message = "Unable to load jets3t.properties file: " + jets3tPropertiesFile; log.error(message, e); ErrorDialog.showDialog(ownerFrame, this, message, e); } } // Initialise the user's preferences. this.cockpitPreferences = new CockpitPreferences(); File cockpitPreferencesPropertiesFile = new File(cockpitHomeDirectory, Constants.COCKPIT_PROPERTIES_FILENAME); if (cockpitPreferencesPropertiesFile.exists()) { try { Properties properties = new Properties(); properties.load(new FileInputStream(cockpitPreferencesPropertiesFile)); this.cockpitPreferences.fromProperties(properties); } catch (IOException e) { String message = "Unable to load your preferences"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, this, message, e); } } cockpitProperties = Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME); skinsFactory = SkinsFactory.getInstance(cockpitProperties.getProperties()); SwingUtilities.invokeLater(new Runnable() { public void run() { loginEvent(null); } }); } /** * Initialises the application's GUI elements. */ private void initGui() { initMenus(); JPanel appContent = new JPanel(new GridBagLayout()); this.getContentPane().add(appContent); // Buckets panel. JPanel bucketsPanel = new JPanel(new GridBagLayout()); JButton bucketActionButton = new JButton(); bucketActionButton.setToolTipText("Bucket actions menu"); guiUtils.applyIcon(bucketActionButton, "/images/nuvola/16x16/actions/misc.png"); bucketActionButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JButton sourceButton = (JButton) e.getSource(); bucketActionMenu.show(sourceButton, 0, sourceButton.getHeight()); } }); bucketsPanel.add(new JHtmlLabel("Buckets", this), new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsZero, 0, 0)); bucketsPanel.add(bucketActionButton, new GridBagConstraints(1, 0, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, insetsZero, 0, 0)); bucketTableModel = new BucketTableModel(false); bucketTableModelSorter = new TableSorter(bucketTableModel); bucketsTable = new JTable(bucketTableModelSorter); bucketTableModelSorter.setTableHeader(bucketsTable.getTableHeader()); bucketsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); bucketsTable.getSelectionModel().addListSelectionListener(this); bucketsTable.setShowHorizontalLines(true); bucketsTable.setShowVerticalLines(false); bucketsTable.addMouseListener(new ContextMenuListener()); bucketsPanel.add(new JScrollPane(bucketsTable), new GridBagConstraints(0, 1, 2, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsZero, 0, 0)); bucketsPanel.add(new JLabel(" "), new GridBagConstraints(0, 2, 2, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); // Filter panel. filterObjectsPanel = new JPanel(new GridBagLayout()); filterObjectsPrefix = new JTextField(); filterObjectsPrefix.setToolTipText("Only show objects with this prefix"); filterObjectsPrefix.addActionListener(this); filterObjectsPrefix.setActionCommand("RefreshObjects"); filterObjectsDelimiter = new JComboBox(new String[] {"", "/", "?", "\\"}); filterObjectsDelimiter.setEditable(true); filterObjectsDelimiter.setToolTipText("Object name delimiter"); filterObjectsDelimiter.addActionListener(this); filterObjectsDelimiter.setActionCommand("RefreshObjects"); filterObjectsPanel.add(new JHtmlLabel("Prefix:", this), new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsZero, 0, 0)); filterObjectsPanel.add(filterObjectsPrefix, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); filterObjectsPanel.add(new JHtmlLabel("Delimiter:", this), new GridBagConstraints(2, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); filterObjectsPanel.add(filterObjectsDelimiter, new GridBagConstraints(3, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsZero, 0, 0)); filterObjectsPanel.setVisible(false); // Objects panel. JPanel objectsPanel = new JPanel(new GridBagLayout()); int row = 0; filterObjectsCheckBox = new JCheckBox("Filter objects"); filterObjectsCheckBox.addActionListener(this); filterObjectsCheckBox.setToolTipText("Check this option to filter the objects listed"); objectsPanel.add(new JHtmlLabel("Objects", this), new GridBagConstraints(0, row, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsZero, 0, 0)); objectsPanel.add(filterObjectsCheckBox, new GridBagConstraints(1, row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, insetsZero, 0, 0)); JButton objectActionButton = new JButton(); objectActionButton.setToolTipText("Object actions menu"); guiUtils.applyIcon(objectActionButton, "/images/nuvola/16x16/actions/misc.png"); objectActionButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JButton sourceButton = (JButton) e.getSource(); objectActionMenu.show(sourceButton, 0, sourceButton.getHeight()); } }); objectsPanel.add(objectActionButton, new GridBagConstraints(2, row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, insetsZero, 0, 0)); objectsPanel.add(filterObjectsPanel, new GridBagConstraints(0, ++row, 3, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsZero, 0, 0)); objectsTable = new JTable(); objectTableModel = new ObjectTableModel(); objectTableModelSorter = new TableSorter(objectTableModel); objectTableModelSorter.setTableHeader(objectsTable.getTableHeader()); objectsTable.setModel(objectTableModelSorter); objectsTable.setDefaultRenderer(Long.class, new DefaultTableCellRenderer() { private static final long serialVersionUID = 301092191828910402L; @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { String formattedSize = byteFormatter.formatByteSize(((Long)value).longValue()); return super.getTableCellRendererComponent(table, formattedSize, isSelected, hasFocus, row, column); } }); objectsTable.setDefaultRenderer(Date.class, new DefaultTableCellRenderer() { private static final long serialVersionUID = 7285511556343895652L; @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Date date = (Date) value; return super.getTableCellRendererComponent(table, yearAndTimeSDF.format(date), isSelected, hasFocus, row, column); } }); objectsTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); objectsTable.getSelectionModel().addListSelectionListener(this); objectsTable.setShowHorizontalLines(true); objectsTable.setShowVerticalLines(true); objectsTable.addMouseListener(new ContextMenuListener()); objectsTableSP = new JScrollPane(objectsTable); objectsPanel.add(objectsTableSP, new GridBagConstraints(0, ++row, 3, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsZero, 0, 0)); objectsSummaryLabel = new JHtmlLabel("Please select a bucket", this); objectsSummaryLabel.setHorizontalAlignment(JLabel.CENTER); objectsSummaryLabel.setFocusable(false); objectsPanel.add(objectsSummaryLabel, new GridBagConstraints(0, ++row, 3, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); // Combine sections. JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, bucketsPanel, objectsPanel); splitPane.setOneTouchExpandable(true); splitPane.setContinuousLayout(true); appContent.add(splitPane, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); // Set preferred sizes int preferredWidth = 800; int preferredHeight = 600; this.setBounds(new Rectangle(new Dimension(preferredWidth, preferredHeight))); splitPane.setResizeWeight(0.30); // Initialize drop target. initDropTarget(new JComponent[] {objectsTableSP, objectsTable} ); objectsTable.getDropTarget().setActive(false); objectsTableSP.getDropTarget().setActive(false); } /** * Initialise the application's menu bar. */ private void initMenus() { JMenuBar appMenuBar = new JMenuBar(); if (this.isStandAloneApplication && OS_NAME_MAC.equals(System.getProperty("os.name"))) { /* * We need to check we're running on a Mac before adding the menu to the * owner frame, otherwise the menus will be displayed *behind* the main * GUI panel on Windows Vista and later [sigh] */ ownerFrame.setJMenuBar(appMenuBar); } else { this.setJMenuBar(appMenuBar); } // Service menu JMenu serviceMenu = new JMenu("Service"); loginMenuItem = new JMenuItem("Log in..."); loginMenuItem.setActionCommand("LoginEvent"); loginMenuItem.addActionListener(this); guiUtils.applyIcon(loginMenuItem, "/images/nuvola/16x16/actions/connect_creating.png"); serviceMenu.add(loginMenuItem); logoutMenuItem = new JMenuItem("Log out"); logoutMenuItem.setActionCommand("LogoutEvent"); logoutMenuItem.addActionListener(this); guiUtils.applyIcon(logoutMenuItem, "/images/nuvola/16x16/actions/connect_no.png"); serviceMenu.add(logoutMenuItem); loginSwitchMenu = new JMenu("Switch login"); loginSwitchMenu.addActionListener(this); serviceMenu.add(new JSeparator()); guiUtils.applyIcon(loginSwitchMenu, "/images/nuvola/16x16/actions/connect_established.png"); serviceMenu.add(loginSwitchMenu); loginSwitchMenu.setEnabled(false); if (isStandAloneApplication) { serviceMenu.add(new JSeparator()); JMenuItem quitMenuItem = new JMenuItem("Quit"); quitMenuItem.setActionCommand("QuitEvent"); quitMenuItem.addActionListener(this); guiUtils.applyIcon(quitMenuItem, "/images/nuvola/16x16/actions/exit.png"); serviceMenu.add(quitMenuItem); } logoutMenuItem.setEnabled(false); // Bucket action menu. bucketActionMenu = new JPopupMenu(); refreshBucketMenuItem = new JMenuItem("Refresh bucket listing"); refreshBucketMenuItem.setActionCommand("RefreshBuckets"); refreshBucketMenuItem.addActionListener(this); guiUtils.applyIcon(refreshBucketMenuItem, "/images/nuvola/16x16/actions/reload.png"); bucketActionMenu.add(refreshBucketMenuItem); viewBucketPropertiesMenuItem = new JMenuItem("View bucket properties..."); viewBucketPropertiesMenuItem.setActionCommand("ViewBucketProperties"); viewBucketPropertiesMenuItem.addActionListener(this); guiUtils.applyIcon(viewBucketPropertiesMenuItem, "/images/nuvola/16x16/actions/viewmag.png"); bucketActionMenu.add(viewBucketPropertiesMenuItem); updateBucketACLMenuItem = new JMenuItem("Update bucket's Access Control List..."); updateBucketACLMenuItem.setActionCommand("UpdateBucketACL"); updateBucketACLMenuItem.addActionListener(this); guiUtils.applyIcon(updateBucketACLMenuItem, "/images/nuvola/16x16/actions/encrypted.png"); bucketActionMenu.add(updateBucketACLMenuItem); updateBucketRequesterPaysStatusMenuItem = new JMenuItem("Update bucket's Requester Pays status..."); updateBucketRequesterPaysStatusMenuItem.setActionCommand("UpdateBucketRequesterPaysStatus"); updateBucketRequesterPaysStatusMenuItem.addActionListener(this); guiUtils.applyIcon(updateBucketRequesterPaysStatusMenuItem, "/images/nuvola/16x16/actions/identity.png"); bucketActionMenu.add(updateBucketRequesterPaysStatusMenuItem); bucketActionMenu.add(new JSeparator()); createBucketMenuItem = new JMenuItem("Create new bucket..."); createBucketMenuItem.setActionCommand("CreateBucket"); createBucketMenuItem.addActionListener(this); guiUtils.applyIcon(createBucketMenuItem, "/images/nuvola/16x16/actions/viewmag+.png"); bucketActionMenu.add(createBucketMenuItem); JMenuItem thirdPartyBucketMenuItem = new JMenuItem("Add third-party bucket..."); thirdPartyBucketMenuItem.setActionCommand("AddThirdPartyBucket"); thirdPartyBucketMenuItem.addActionListener(this); guiUtils.applyIcon(thirdPartyBucketMenuItem, "/images/nuvola/16x16/actions/viewmagfit.png"); bucketActionMenu.add(thirdPartyBucketMenuItem); bucketActionMenu.add(new JSeparator()); deleteBucketMenuItem = new JMenuItem("Delete bucket..."); deleteBucketMenuItem.setActionCommand("DeleteBucket"); deleteBucketMenuItem.addActionListener(this); guiUtils.applyIcon(deleteBucketMenuItem, "/images/nuvola/16x16/actions/cancel.png"); bucketActionMenu.add(deleteBucketMenuItem); viewBucketPropertiesMenuItem.setEnabled(false); refreshBucketMenuItem.setEnabled(false); createBucketMenuItem.setEnabled(false); updateBucketACLMenuItem.setEnabled(false); updateBucketRequesterPaysStatusMenuItem.setEnabled(false); deleteBucketMenuItem.setEnabled(false); // Object action menu. objectActionMenu = new JPopupMenu(); refreshObjectMenuItem = new JMenuItem("Refresh object listing"); refreshObjectMenuItem.setActionCommand("RefreshObjects"); refreshObjectMenuItem.addActionListener(this); guiUtils.applyIcon(refreshObjectMenuItem, "/images/nuvola/16x16/actions/reload.png"); objectActionMenu.add(refreshObjectMenuItem); viewOrModifyObjectAttributesMenuItem = new JMenuItem("View or Modify object attributes..."); viewOrModifyObjectAttributesMenuItem.setActionCommand("ViewOrModifyObjectAttributes"); viewOrModifyObjectAttributesMenuItem.addActionListener(this); guiUtils.applyIcon(viewOrModifyObjectAttributesMenuItem, "/images/nuvola/16x16/actions/viewmag.png"); objectActionMenu.add(viewOrModifyObjectAttributesMenuItem); copyObjectsMenuItem = new JMenuItem("Copy or Move objects..."); copyObjectsMenuItem.setActionCommand("CopyObjects"); copyObjectsMenuItem.addActionListener(this); guiUtils.applyIcon(copyObjectsMenuItem, "/images/nuvola/16x16/actions/filenew.png"); objectActionMenu.add(copyObjectsMenuItem); updateObjectACLMenuItem = new JMenuItem("View or Modify Access Control Lists..."); updateObjectACLMenuItem.setActionCommand("UpdateObjectACL"); updateObjectACLMenuItem.addActionListener(this); guiUtils.applyIcon(updateObjectACLMenuItem, "/images/nuvola/16x16/actions/encrypted.png"); objectActionMenu.add(updateObjectACLMenuItem); downloadObjectMenuItem = new JMenuItem("Download objects..."); downloadObjectMenuItem.setActionCommand("DownloadObjects"); downloadObjectMenuItem.addActionListener(this); guiUtils.applyIcon(downloadObjectMenuItem, "/images/nuvola/16x16/actions/1downarrow.png"); objectActionMenu.add(downloadObjectMenuItem); uploadFilesMenuItem = new JMenuItem("Upload files..."); uploadFilesMenuItem.setActionCommand("UploadFiles"); uploadFilesMenuItem.addActionListener(this); guiUtils.applyIcon(uploadFilesMenuItem, "/images/nuvola/16x16/actions/1uparrow.png"); objectActionMenu.add(uploadFilesMenuItem); objectActionMenu.add(new JSeparator()); generatePublicGetUrls = new JMenuItem("Generate Public GET URLs..."); generatePublicGetUrls.setActionCommand("GeneratePublicGetURLs"); generatePublicGetUrls.addActionListener(this); guiUtils.applyIcon(generatePublicGetUrls, "/images/nuvola/16x16/actions/wizard.png"); objectActionMenu.add(generatePublicGetUrls); generateTorrentUrl = new JMenuItem("Generate Torrent URL..."); generateTorrentUrl.setActionCommand("GenerateTorrentURL"); generateTorrentUrl.addActionListener(this); guiUtils.applyIcon(generateTorrentUrl, "/images/nuvola/16x16/actions/wizard.png"); objectActionMenu.add(generateTorrentUrl); objectActionMenu.add(new JSeparator()); deleteObjectMenuItem = new JMenuItem("Delete objects..."); deleteObjectMenuItem.setActionCommand("DeleteObjects"); deleteObjectMenuItem.addActionListener(this); guiUtils.applyIcon(deleteObjectMenuItem, "/images/nuvola/16x16/actions/cancel.png"); objectActionMenu.add(deleteObjectMenuItem); viewOrModifyObjectAttributesMenuItem.setEnabled(false); copyObjectsMenuItem.setEnabled(false); refreshObjectMenuItem.setEnabled(false); updateObjectACLMenuItem.setEnabled(false); downloadObjectMenuItem.setEnabled(false); uploadFilesMenuItem.setEnabled(false); generatePublicGetUrls.setEnabled(false); generateTorrentUrl.setEnabled(false); deleteObjectMenuItem.setEnabled(false); // Tools menu. JMenu toolsMenu = new JMenu("Tools"); bucketLoggingMenuItem = new JMenuItem("Configure Bucket logging..."); bucketLoggingMenuItem.setActionCommand("BucketLogging"); bucketLoggingMenuItem.addActionListener(this); bucketLoggingMenuItem.setEnabled(false); guiUtils.applyIcon(bucketLoggingMenuItem, "/images/nuvola/16x16/actions/toggle_log.png"); toolsMenu.add(bucketLoggingMenuItem); manageDistributionsMenuItem = new JMenuItem("CloudFront Distributions..."); manageDistributionsMenuItem.setActionCommand("ManageDistributions"); manageDistributionsMenuItem.addActionListener(this); guiUtils.applyIcon(manageDistributionsMenuItem, "/images/nuvola/16x16/actions/irkick.png"); manageDistributionsMenuItem.setEnabled(false); toolsMenu.add(manageDistributionsMenuItem); toolsMenu.add(new JSeparator()); preferencesDialogMenuItem = new JMenuItem("Preferences..."); preferencesDialogMenuItem.setActionCommand("PreferencesDialog"); preferencesDialogMenuItem.addActionListener(this); guiUtils.applyIcon(preferencesDialogMenuItem, "/images/nuvola/16x16/actions/configure.png"); toolsMenu.add(preferencesDialogMenuItem); // Help menu. JMenu helpMenu = new JMenu("Help"); cockpitHelpMenuItem = new JMenuItem("Cockpit Guide"); guiUtils.applyIcon(cockpitHelpMenuItem, "/images/nuvola/16x16/actions/help.png"); cockpitHelpMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { followHyperlink(new URL(JETS3T_COCKPIT_HELP_PAGE), "_blank"); } catch (MalformedURLException ex) { throw new IllegalStateException("Invalid URL embedded in program: " + JETS3T_COCKPIT_HELP_PAGE); } } }); helpMenu.add(cockpitHelpMenuItem); amazonS3HelpMenuItem = new JMenuItem("Amazon S3"); guiUtils.applyIcon(amazonS3HelpMenuItem, "/images/nuvola/16x16/actions/gohome.png"); amazonS3HelpMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { followHyperlink(new URL(AMAZON_S3_PAGE), "_blank"); } catch (MalformedURLException ex) { throw new IllegalStateException("Invalid URL embedded in program: " + AMAZON_S3_PAGE); } } }); helpMenu.add(amazonS3HelpMenuItem); // Build application menu bar. appMenuBar.add(serviceMenu); appMenuBar.add(toolsMenu); appMenuBar.add(helpMenu); } /** * Initialise the application's File drop targets for drag and drop copying of local files * to S3. * * @param dropTargetComponents * the components files can be dropped on to transfer them to S3 */ private void initDropTarget(JComponent[] dropTargetComponents) { DropTargetListener dropTargetListener = new DropTargetListener() { private boolean checkValidDrag(DropTargetDragEvent dtde) { if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor) && (DnDConstants.ACTION_COPY == dtde.getDropAction() || DnDConstants.ACTION_MOVE == dtde.getDropAction())) { dtde.acceptDrag(dtde.getDropAction()); return true; } else { dtde.rejectDrag(); return false; } } public void dragEnter(DropTargetDragEvent dtde) { if (checkValidDrag(dtde)) { SwingUtilities.invokeLater(new Runnable() { public void run() { objectsTable.requestFocusInWindow(); }; }); } } public void dragOver(DropTargetDragEvent dtde) { checkValidDrag(dtde); } public void dropActionChanged(DropTargetDragEvent dtde) { if (checkValidDrag(dtde)) { SwingUtilities.invokeLater(new Runnable() { public void run() { objectsTable.requestFocusInWindow(); }; }); } else { SwingUtilities.invokeLater(new Runnable() { public void run() { ownerFrame.requestFocusInWindow(); }; }); } } public void dragExit(DropTargetEvent dte) { SwingUtilities.invokeLater(new Runnable() { public void run() { ownerFrame.requestFocusInWindow(); }; }); } public void drop(DropTargetDropEvent dtde) { if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor) && (DnDConstants.ACTION_COPY == dtde.getDropAction() || DnDConstants.ACTION_MOVE == dtde.getDropAction())) { dtde.acceptDrop(dtde.getDropAction()); try { final List fileList = (List) dtde.getTransferable().getTransferData( DataFlavor.javaFileListFlavor); if (fileList != null && fileList.size() > 0) { uploadFiles((File[]) fileList.toArray(new File[fileList.size()])); } } catch (Exception e) { String message = "Unable to start accept dropped items"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, null, message, e); } } else { dtde.rejectDrop(); } } }; // Attach drop target listener to each target component. for (int i = 0; i < dropTargetComponents.length; i++) { new DropTarget(dropTargetComponents[i], DnDConstants.ACTION_COPY, dropTargetListener, true); } } /** * Run the provided Runnable object in a background thread. This method will * return as soon as the background thread is started, it does not wait for * the thread to complete. */ private synchronized void runInBackgroundThread(Runnable runnable) { Thread t = new Thread(runnable); t.start(); } /** * Run the provided runnable in the application's event dispatcher thread, * and wait for the action to complete before returning. * * @param runnable * @return */ private synchronized boolean runInDispatcherThreadImmediately(Runnable runnable) { try { SwingUtilities.invokeAndWait(runnable); return true; } catch (Exception e) { log.error("Error displaying graphical elements", e); return false; } } /** * Starts a progress display dialog that cannot be cancelled. While the dialog is running the user * cannot interact with the application. * * @param statusText * describes the status of a task in text meaningful to the user */ private void startProgressDialog(String statusText) { startProgressDialog(statusText, null, 0, 0, null, null); } /** * Starts a progress display dialog. While the dialog is running the user cannot interact * with the application, except to cancel the task. * * @param statusMessage * describes the status of a task text meaningful to the user, such as "3 files of 7 uploaded" * @param detailsText * describes the status of a task in more detail, such as the current transfer rate and Time remaining. * @param minTaskValue the minimum progress value for a task, generally 0 * @param maxTaskValue * the maximum progress value for a task, such as the total number of threads or 100 if * using percentage-complete as a metric. * @param cancelEventListener * listener that is responsible for cancelling a long-lived task when the user clicks * the cancel button. If a task cannot be cancelled this must be null. * @param cancelButtonText * text displayed in the cancel button if a task can be cancelled. This is only used if * a cancel event listener is provided. */ private void startProgressDialog(final String statusMessage, final String detailsText, final int minTaskValue, final int maxTaskValue, final String cancelButtonText, final CancelEventTrigger cancelEventListener) { if (this.progressDialog == null) { this.progressDialog = new ProgressDialog(this.ownerFrame, "Please wait...", null); } SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.startDialog(statusMessage, detailsText, minTaskValue, maxTaskValue, cancelEventListener, cancelButtonText); } }); } /** * Updates the status text and value of the progress display dialog. * @param statusMessage * describes the status of a task text meaningful to the user, such as "3 files of 7 uploaded" * @param detailsText * describes the status of a task in more detail, such as the current transfer rate and time remaining. * @param progressValue * value representing how far through the task we are (relative to min and max values) */ private void updateProgressDialog(final String statusMessage, final String detailsText, final int progressValue) { SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.updateDialog(statusMessage, detailsText, progressValue); } }); } /** * Stops/halts the progress display dialog and allows the user to interact with the application. */ private void stopProgressDialog() { runInDispatcherThreadImmediately(new Runnable() { public void run() { progressDialog.stopDialog(); } }); } /** * Event handler for this application, handles all menu items. */ public void actionPerformed(ActionEvent event) { // Service Menu Events if ("LoginEvent".equals(event.getActionCommand())) { loginEvent(null); } else if ("LogoutEvent".equals(event.getActionCommand())) { logoutEvent(); } else if (event.getActionCommand() != null && event.getActionCommand().startsWith("LoginSwitch")) { String loginName = event.getActionCommand().substring("LoginSwitch:".length()); ProviderCredentials credentials = (ProviderCredentials) loginAwsCredentialsMap.get(loginName); loginEvent(credentials); } else if ("QuitEvent".equals(event.getActionCommand())) { System.exit(0); } // Bucket Events. else if ("ViewBucketProperties".equals(event.getActionCommand())) { listBucketProperties(); } else if ("RefreshBuckets".equals(event.getActionCommand())) { listAllBuckets(); } else if ("CreateBucket".equals(event.getActionCommand())) { createBucketAction(); } else if ("DeleteBucket".equals(event.getActionCommand())) { deleteSelectedBucket(); } else if ("ManageDistributions".equals(event.getActionCommand())) { S3Bucket[] buckets = bucketTableModel.getBuckets(); String[] bucketNames = new String[buckets.length]; for (int i = 0; i < buckets.length; i++) { bucketNames[i] = buckets[i].getName(); } ManageDistributionsDialog.showDialog(ownerFrame, cloudFrontService, bucketNames, this); } else if ("AddThirdPartyBucket".equals(event.getActionCommand())) { addThirdPartyBucket(); } else if ("UpdateBucketACL".equals(event.getActionCommand())) { updateBucketAccessControlList(); } else if ("UpdateBucketRequesterPaysStatus".equals(event.getActionCommand())) { updateBucketRequesterPaysSetting(); } // Object Events else if ("ViewOrModifyObjectAttributes".equals(event.getActionCommand())) { displayObjectsAttributesDialog(); } else if ("CopyObjects".equals(event.getActionCommand())) { copyObjects(); } else if ("RefreshObjects".equals(event.getActionCommand())) { listObjects(); } else if ("UpdateObjectACL".equals(event.getActionCommand())) { displayAclModificationDialog(); } else if ("GeneratePublicGetURLs".equals(event.getActionCommand())) { generatePublicGetUrls(); } else if ("GenerateTorrentURL".equals(event.getActionCommand())) { generateTorrentUrl(); } else if ("DeleteObjects".equals(event.getActionCommand())) { deleteSelectedObjects(); } else if ("DownloadObjects".equals(event.getActionCommand())) { downloadSelectedObjects(); } else if ("UploadFiles".equals(event.getActionCommand())) { JFileChooser fileChooser = new JFileChooser(); fileChooser.setMultiSelectionEnabled(true); fileChooser.setDialogTitle("Choose files to upload"); fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); fileChooser.setApproveButtonText("Upload files"); fileChooser.setCurrentDirectory(fileChoosersLastUploadDirectory); int returnVal = fileChooser.showOpenDialog(ownerFrame); if (returnVal != JFileChooser.APPROVE_OPTION) { return; } final File[] uploadFiles = fileChooser.getSelectedFiles(); if (uploadFiles.length == 0) { return; } // Save the chosen directory location for next time. fileChoosersLastUploadDirectory = uploadFiles[0].getParentFile(); uploadFiles(uploadFiles); } else if (event.getSource().equals(filterObjectsCheckBox)) { if (filterObjectsCheckBox.isSelected()) { filterObjectsPanel.setVisible(true); } else { filterObjectsPanel.setVisible(false); filterObjectsPrefix.setText(""); if (filterObjectsDelimiter.getSelectedIndex() != 0) { filterObjectsDelimiter.setSelectedIndex(0); } } } // Tools events else if ("BucketLogging".equals(event.getActionCommand())) { S3Bucket[] buckets = bucketTableModel.getBuckets(); BucketLoggingDialog.showDialog(ownerFrame, s3ServiceMulti.getS3Service(), buckets, this); } // Preference Events else if ("PreferencesDialog".equals(event.getActionCommand())) { PreferencesDialog.showDialog(cockpitPreferences, ownerFrame, this); // Save a user's preferences if requested, otherwise wipe any existing preferences file. File cockpitPreferencesPropertiesFile = new File(cockpitHomeDirectory, Constants.COCKPIT_PROPERTIES_FILENAME); if (cockpitPreferences.isRememberPreferences()) { try { Properties properties = cockpitPreferences.toProperties(); if (!cockpitHomeDirectory.exists()) { cockpitHomeDirectory.mkdir(); } properties.list(new PrintStream( new FileOutputStream(cockpitPreferencesPropertiesFile))); } catch (IOException e) { String message = "Unable to save your preferences"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, this, message, e); } } else if (cockpitPreferencesPropertiesFile.exists()) { // User elected not to store preferences, delete the existing preferences file. cockpitPreferencesPropertiesFile.delete(); } if (cockpitPreferences.isEncryptionPasswordSet()) { try { encryptionUtil = new EncryptionUtil( cockpitPreferences.getEncryptionPassword(), cockpitPreferences.getEncryptionAlgorithm(), EncryptionUtil.DEFAULT_VERSION); } catch (Exception e) { String message = "Unable to start encryption utility"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, this, message, e); } } else { encryptionUtil = null; } } // Ooops... else { log.debug("Unrecognised ActionEvent command '" + event.getActionCommand() + "' in " + event); } } /** * Handles list selection events for this application. */ public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting()) { return; } if (e.getSource().equals(bucketsTable.getSelectionModel())) { bucketSelectedAction(); } else if (e.getSource().equals(objectsTable.getSelectionModel())) { objectSelectedAction(); } } /** * Displays the {@link StartupDialog} dialog and, if the user provides login credentials, * logs into the S3 service using those credentials. * * This method should always be run within the event dispatcher thread. */ private void loginEvent(ProviderCredentials credentials) { try { if (credentials == null) { StartupDialog startupDialog = new StartupDialog(ownerFrame, cockpitProperties, this); startupDialog.setVisible(true); credentials = startupDialog.getProviderCredentials(); this.isTargetS3 = startupDialog.isTargetS3(); startupDialog.dispose(); if (credentials == null) { log.debug("Log in cancelled by user"); return; } } s3ServiceMulti = new S3ServiceMulti( getRestS3Service(credentials), this); cloudFrontMembershipChecked = false; listAllBuckets(); objectsSummaryLabel.setText(" "); logoutMenuItem.setEnabled(true); refreshBucketMenuItem.setEnabled(true); createBucketMenuItem.setEnabled(true); bucketLoggingMenuItem.setEnabled(true); String loginName = (credentials.hasFriendlyName() ? credentials.getFriendlyName() : credentials.getAccessKey()); if (!loginAwsCredentialsMap.containsKey(loginName)) { loginAwsCredentialsMap.put(loginName, credentials); JMenuItem menuItem = new JMenuItem(loginName); menuItem.setActionCommand("LoginSwitch:" + loginName); menuItem.addActionListener(this); loginSwitchMenu.add(menuItem); loginSwitchMenu.setEnabled(true); } } catch (Exception e) { String message = "Unable to log in to storage service"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, this, message, e); logoutEvent(); } } /** * Logs out of the S3 service by clearing all listed objects and buckets and resetting * the s3ServiceMulti member variable. * * This method should always be invoked within the event dispatching thread. */ private void logoutEvent() { log.debug("Logging out"); try { ProviderCredentials credentials = s3ServiceMulti.getAWSCredentials(); String loginName = (credentials.hasFriendlyName() ? credentials.getFriendlyName() : credentials.getAccessKey()); if (loginAwsCredentialsMap.containsKey(loginName)) { Component[] components = loginSwitchMenu.getMenuComponents(); for (int i = 0; i < components.length; i++) { JMenuItem menuItem = (JMenuItem)components[i]; if (loginName.equals(menuItem.getText())) { loginSwitchMenu.remove(components[i]); break; } } loginAwsCredentialsMap.remove(loginName); loginSwitchMenu.setEnabled(loginAwsCredentialsMap.size() > 0); } // Revert to anonymous service. s3ServiceMulti = new S3ServiceMulti( getRestS3Service(null), this); cloudFrontService = null; bucketsTable.clearSelection(); bucketTableModel.removeAllBuckets(); objectTableModel.removeAllObjects(); objectsSummaryLabel.setText(" "); ownerFrame.setTitle(APPLICATION_TITLE); logoutMenuItem.setEnabled(false); refreshBucketMenuItem.setEnabled(false); createBucketMenuItem.setEnabled(false); bucketLoggingMenuItem.setEnabled(false); manageDistributionsMenuItem.setEnabled(false); } catch (Exception e) { String message = "Unable to log out from S3"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, this, message, e); } } /** * Displays the currently selected bucket's properties in the dialog {@link ItemPropertiesDialog}. */ private void listBucketProperties() { final S3Bucket selectedBucket = currentSelectedBucket; if (selectedBucket.getAcl() == null || !selectedBucket.isLocationKnown()) { // Retrieve all a bucket's details before displaying the summary. runInBackgroundThread(new Runnable() { public void run() { startProgressDialog("Retrieving details for bucket " + selectedBucket.getName()); try { try { if (selectedBucket.getAcl() == null) { selectedBucket.setAcl( s3ServiceMulti.getS3Service().getBucketAcl( selectedBucket)); } if (!selectedBucket.isLocationKnown()) { selectedBucket.setLocation( s3ServiceMulti.getS3Service().getBucketLocation( selectedBucket.getName())); } if (!selectedBucket.isRequesterPaysKnown()) { selectedBucket.setRequesterPays( s3ServiceMulti.getS3Service().isRequesterPaysBucket( selectedBucket.getName())); } } catch (S3ServiceException e) { // Retrieving details for a third-party bucket will // often fail when ACL or Location is retrieved, // ignore these failures. } stopProgressDialog(); runInDispatcherThreadImmediately(new Runnable() { public void run() { ItemPropertiesDialog.showDialog(ownerFrame, selectedBucket, null); } }); } catch (final Exception e) { stopProgressDialog(); String message = "Unable to retrieve details for bucket"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, null, message, e); } }; }); } else { ItemPropertiesDialog.showDialog(ownerFrame, selectedBucket, null); } } /** * Displays the currently selected object's properties in the dialog {@link ObjectsAttributesDialog}. *

* As detailed information about the object may not yet be available, this method works * indirectly via the {@link #retrieveObjectsDetails} method. The retrieveObjectsDetails * method retrieves all the details for the currently selected objects, and once they are available * knows to display the dialog as the {@link #isViewingOrModifyingObjectProperties} flag is set. */ private void displayObjectsAttributesDialog() { final S3Bucket selectedBucket = currentSelectedBucket; runInBackgroundThread(new Runnable() { public void run() { if (!retrieveObjectsDetails(getSelectedObjects())) { return; } if (objectsAttributesDialog == null) { objectsAttributesDialog = new ObjectsAttributesDialog( ownerFrame, "Object Attributes", skinsFactory); } final S3Object[] sourceObjects = getSelectedObjects(); boolean ok = runInDispatcherThreadImmediately(new Runnable() { public void run() { objectsAttributesDialog.displayDialog(sourceObjects, true); } }); if (!ok) { return; } final String[] sourceObjectKeys = objectsAttributesDialog.getSourceObjectKeys(); final S3Object[] destinationObjects = objectsAttributesDialog.getDestinationObjects(); if (!objectsAttributesDialog.isModifyActionApproved()) { // Do nothing. return; } // Retain ACL settings from original objects. if (!s3ServiceMulti.getObjectACLs(selectedBucket, sourceObjects)) { return; } for (int i = 0; i < sourceObjects.length; i++) { destinationObjects[i].setAcl( sourceObjects[i].getAcl()); } // Copy objects in-place, to REPLACE their metadata attributes. ok = s3ServiceMulti.copyObjects( selectedBucket.getName(), selectedBucket.getName(), sourceObjectKeys, destinationObjects, true); // Refresh details for modified objects if (ok) { s3ServiceMulti.getObjectsHeads( selectedBucket, destinationObjects); } } }); } /** * Lists the buckets in the user's S3 account and refreshes the GUI to display * these buckets. Any buckets or objects already listed in the GUI are cleared first. */ private void listAllBuckets() { // Remove current bucket and object data from models. cachedBuckets.clear(); bucketsTable.clearSelection(); bucketTableModel.removeAllBuckets(); objectTableModel.removeAllObjects(); final Cockpit myself = this; // This is all very convoluted. This was necessary so we can display the status dialog box. runInBackgroundThread(new Runnable() { public void run() { if (!cloudFrontMembershipChecked) { // Check whether the user is signed-up for CloudFront. startProgressDialog("Checking for CloudFront account membership"); try { cloudFrontService = new CloudFrontService( s3ServiceMulti.getAWSCredentials(), APPLICATION_DESCRIPTION, myself, null, null); cloudFrontService.listDistributions(); } catch (CloudFrontServiceException e) { stopProgressDialog(); if ("OptInRequired".equals(e.getErrorCode())) { log.debug("Your AWS account is not subscribed to the Amazon CloudFront service, " + "you will not be able to manage distributions"); } cloudFrontService = null; } finally { stopProgressDialog(); cloudFrontMembershipChecked = true; // Update the bucket table to show, or not show, distributions bucketTableModel = new BucketTableModel(cloudFrontService != null); bucketTableModelSorter = new TableSorter(bucketTableModel); bucketsTable.setModel(bucketTableModelSorter); bucketTableModelSorter.setTableHeader(bucketsTable.getTableHeader()); if (cloudFrontService != null) { // Set column width for Cloud Front distributions indicator. TableColumn distributionFlagColumn = bucketsTable.getColumnModel().getColumn(1); int distributionFlagColumnWidth = 18; distributionFlagColumn.setPreferredWidth(distributionFlagColumnWidth); distributionFlagColumn.setMaxWidth(distributionFlagColumnWidth); distributionFlagColumn.setMinWidth(0); } manageDistributionsMenuItem.setEnabled(cloudFrontService != null); } } startProgressDialog("Listing buckets for " + s3ServiceMulti.getAWSCredentials().getAccessKey()); try { final S3Bucket[] buckets = s3ServiceMulti.getS3Service().listAllBuckets(); // Lookup user's CloudFront distributions. Distribution[] distributions = new Distribution[] {}; if (cloudFrontService != null) { updateProgressDialog("Listing distributions for " + cloudFrontService.getAWSCredentials().getAccessKey(), "", 0); distributions = cloudFrontService.listDistributions(); } final Distribution[] finalDistributions = distributions; runInDispatcherThreadImmediately(new Runnable() { public void run() { for (int i = 0; i < buckets.length; i++) { // Determine whether each bucket has one or more CloudFront distributions. boolean bucketHasDistribution = false; for (int j = 0; j < finalDistributions.length; j++) { if (finalDistributions[j].getOrigin().equals(buckets[i].getName() + ".s3.amazonaws.com")) { bucketHasDistribution = true; } } bucketTableModel.addBucket(buckets[i], bucketHasDistribution); if (i == 0) { ownerFrame.setTitle(APPLICATION_TITLE + " : " + buckets[i].getOwner().getDisplayName()); } } } }); } catch (final Exception e) { stopProgressDialog(); SwingUtilities.invokeLater(new Runnable() { public void run() { logoutEvent(); String message = "Unable to list your buckets in S3, please log in again"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, null, message, e); loginEvent(null); } }); } finally { stopProgressDialog(); } }; }); } /** * This method is an {@link S3ServiceEventListener} action method that is invoked when this * application's S3ServiceMulti triggers a GetObjectsEvent. *

* This never happens in this application as downloads are performed by * {@link S3ServiceMulti#downloadObjects(S3Bucket, DownloadPackage[])} instead. * * @param event */ public void s3ServiceEventPerformed(GetObjectsEvent event) { // Not used. } /** * This method is an {@link S3ServiceEventListener} action method that is invoked when this * application's S3ServiceMulti triggers a ListObjectsEvent. *

* This never happens in this application as it does not perform multi-threaded object * listings. * * @param event */ public void s3ServiceEventPerformed(ListObjectsEvent event) { // Not used. } public void s3ServiceEventPerformed(DeleteVersionedObjectsEvent event) { // Not used. } /** * Actions performed when a bucket is selected in the bucket list table. */ private void bucketSelectedAction() { this.currentSelectedBucket = null; // Find the selected bucket in the buckets table, if any. if (bucketsTable.getSelectedRows().length != 0) { this.currentSelectedBucket = bucketTableModel.getBucket( bucketTableModelSorter.modelIndex( bucketsTable.getSelectedRows()[0])); } if (currentSelectedBucket == null) { viewBucketPropertiesMenuItem.setEnabled(false); refreshBucketMenuItem.setEnabled(true); updateBucketACLMenuItem.setEnabled(false); updateBucketRequesterPaysStatusMenuItem.setEnabled(false); deleteBucketMenuItem.setEnabled(false); refreshObjectMenuItem.setEnabled(false); uploadFilesMenuItem.setEnabled(false); objectTableModel.removeAllObjects(); objectsTable.getDropTarget().setActive(false); objectsTableSP.getDropTarget().setActive(false); } else { viewBucketPropertiesMenuItem.setEnabled(true); refreshBucketMenuItem.setEnabled(true); updateBucketACLMenuItem.setEnabled(true); updateBucketRequesterPaysStatusMenuItem.setEnabled(true); deleteBucketMenuItem.setEnabled(true); refreshObjectMenuItem.setEnabled(true); uploadFilesMenuItem.setEnabled(true); objectsTable.getDropTarget().setActive(true); objectsTableSP.getDropTarget().setActive(true); if (cachedBuckets.containsKey(currentSelectedBucket.getName())) { S3Object[] objects = (S3Object[]) cachedBuckets.get(currentSelectedBucket.getName()); objectTableModel.removeAllObjects(); objectTableModel.addObjects(objects); updateObjectsSummary(false); } else { listObjects(); } } } /** * Actions performed when an object is selected in the objects list table. */ private void objectSelectedAction() { int count = getSelectedObjects().length; updateObjectACLMenuItem.setEnabled(count > 0); downloadObjectMenuItem.setEnabled(count > 0); deleteObjectMenuItem.setEnabled(count > 0); viewOrModifyObjectAttributesMenuItem.setEnabled(count > 0); copyObjectsMenuItem.setEnabled(count > 0); generatePublicGetUrls.setEnabled(count >= 1 && s3ServiceMulti.getAWSCredentials() != null); generateTorrentUrl.setEnabled(count == 1); } /** * Starts a thread to run {@link S3ServiceMulti#listObjects}. */ private void listObjects() { if (currentSelectedBucket == null) { // Oops, better do nothing. return; } final boolean listingCancelled[] = new boolean[1]; // Default to false. final CancelEventTrigger cancelListener = new CancelEventTrigger() { private static final long serialVersionUID = 6939193243303189876L; public void cancelTask(Object eventSource) { listingCancelled[0] = true; } }; objectTableModel.removeAllObjects(); objectsSummaryLabel.setText(" "); // This is all very convoluted, it was done this way to ensure we can display the dialog box. runInBackgroundThread(new Runnable() { public void run() { try { startProgressDialog( "Listing objects in " + currentSelectedBucket.getName(), "", 0, 0, "Cancel bucket listing", cancelListener); final String prefix = filterObjectsPrefix.getText(); final String delimiter = (String) filterObjectsDelimiter.getSelectedItem(); final ArrayList allObjects = new ArrayList(); String priorLastKey = null; do { StorageObjectsChunk chunk = s3ServiceMulti.getS3Service().listObjectsChunked( currentSelectedBucket.getName(), prefix, delimiter, BUCKET_LIST_CHUNKING_SIZE, priorLastKey); final S3Object[] objects = S3Object.cast(chunk.getObjects()); for (int i = 0; i < objects.length; i++) { objects[i].setOwner(currentSelectedBucket.getOwner()); } priorLastKey = chunk.getPriorLastKey(); allObjects.addAll(Arrays.asList(objects)); updateProgressDialog( "Listed " + allObjects.size() + " objects in " + currentSelectedBucket.getName(), "", 0); runInDispatcherThreadImmediately(new Runnable() { public void run() { objectTableModel.addObjects(objects); updateObjectsSummary(true); } }); } while (!listingCancelled[0] && priorLastKey != null); runInDispatcherThreadImmediately(new Runnable() { public void run() { updateObjectsSummary(listingCancelled[0]); S3Object[] allObjects = objectTableModel.getObjects(); cachedBuckets.put(currentSelectedBucket.getName(), allObjects); } }); } catch (final Exception e) { stopProgressDialog(); String message = "Unable to list objects"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, null, message, e); } finally { stopProgressDialog(); } }; }); } /** * Updates the summary text shown below the listing of objects, which details the * number and total size of the objects. * */ private void updateObjectsSummary(boolean isIncompleteListing) { S3Object[] objects = objectTableModel.getObjects(); try { String summary = "Please select a bucket"; long totalBytes = 0; if (objects != null) { summary = "" + objects.length + " item" + (objects.length != 1? "s" : ""); for (int i = 0; i < objects.length; i++) { totalBytes += objects[i].getContentLength(); } if (totalBytes > 0) { summary += ", " + byteFormatter.formatByteSize(totalBytes); } summary += " @ " + timeSDF.format(new Date()); if (isObjectFilteringActive()) { summary += " - Filtered"; } if (isIncompleteListing) { summary += " - Incomplete"; } summary += ""; } objectsSummaryLabel.setText(summary); } catch (Throwable t) { String message = "Unable to update object list summary"; log.error(message, t); ErrorDialog.showDialog(ownerFrame, this, message, t); } } /** * Displays bucket-specific actions in a popup menu. * @param invoker the component near which the popup menu will be displayed * @param xPos the mouse's horizontal co-ordinate when the popup menu was invoked * @param yPos the mouse's vertical co-ordinate when the popup menu was invoked */ private void showBucketPopupMenu(JComponent invoker, int xPos, int yPos) { if (s3ServiceMulti == null) { return; } bucketActionMenu.show(invoker, xPos, yPos); } /** * Displays object-specific actions in a popup menu. * @param invoker the component near which the popup menu will be displayed * @param xPos the mouse's horizontal co-ordinate when the popup menu was invoked * @param yPos the mouse's vertical co-ordinate when the popup menu was invoked */ private void showObjectPopupMenu(JComponent invoker, int xPos, int yPos) { if (currentSelectedBucket == null || getSelectedObjects().length == 0) { return; } objectActionMenu.show(invoker, xPos, yPos); } /** * Action to create a new bucket in S3 after prompting the user for a bucket name. * */ private void createBucketAction() { String proposedNewName = s3ServiceMulti.getAWSCredentials().getAccessKey().toLowerCase() + "." + "bucket-name"; CreateBucketDialog dialog = new CreateBucketDialog(proposedNewName, ownerFrame, this); dialog.setVisible(true); if (!dialog.getOkClicked()) { return; } final S3Bucket newBucket = new S3Bucket(dialog.getBucketName(), dialog.getBucketLocation()); dialog.dispose(); runInBackgroundThread(new Runnable() { public void run() { if (s3ServiceMulti.createBuckets(new S3Bucket[] { newBucket })) { int modelIndex = bucketTableModel.getBucketIndexByName(newBucket.getName()); int viewIndex = bucketTableModelSorter.viewIndex(modelIndex); bucketsTable.setRowSelectionInterval(viewIndex, viewIndex); } } }); } /** * This method is an {@link S3ServiceEventListener} action method that is invoked when this * application's S3ServiceMulti triggers a CreateBucketsEvent. *

* When a bucket is successfully created it is added to the listing of buckets. * * @param event */ public void s3ServiceEventPerformed(final CreateBucketsEvent event) { if (ServiceEvent.EVENT_STARTED == event.getEventCode()) { startProgressDialog( "Creating " + event.getThreadWatcher().getThreadCount() + " buckets", "", 0, (int) event.getThreadWatcher().getThreadCount(), "Cancel bucket creation", event.getThreadWatcher().getCancelEventListener()); } else if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { runInDispatcherThreadImmediately(new Runnable() { public void run() { for (int i = 0; i < event.getCreatedBuckets().length; i++) { bucketTableModel.addBucket(event.getCreatedBuckets()[i], false); } } }); ThreadWatcher progressStatus = event.getThreadWatcher(); String statusText = "Created " + progressStatus.getCompletedThreads() + " buckets of " + progressStatus.getThreadCount(); updateProgressDialog(statusText, "", (int) progressStatus.getCompletedThreads()); } else if (ServiceEvent.EVENT_COMPLETED == event.getEventCode()) { stopProgressDialog(); } else if (ServiceEvent.EVENT_CANCELLED == event.getEventCode()) { stopProgressDialog(); } else if (ServiceEvent.EVENT_ERROR == event.getEventCode()) { stopProgressDialog(); String message = "Unable to create a bucket"; log.error(message, event.getErrorCause()); ErrorDialog.showDialog(ownerFrame, this, message, event.getErrorCause()); } } /** * Deletes the bucket currently selected in the gui. * */ private void deleteSelectedBucket() { if (currentSelectedBucket == null) { log.warn("Ignoring delete bucket command, no currently selected bucket"); return; } int response = JOptionPane.showConfirmDialog(ownerFrame, "Are you sure you want to delete '" + currentSelectedBucket.getName() + "'?", "Delete Bucket?", JOptionPane.YES_NO_OPTION); if (response == JOptionPane.NO_OPTION) { return; } try { s3ServiceMulti.getS3Service().deleteBucket(currentSelectedBucket.getName()); bucketTableModel.removeBucket(currentSelectedBucket); currentSelectedBucket = null; } catch (Exception e) { String message = "Unable to delete bucket"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, this, message, e); } } /** * Adds a bucket not owned by the current S3 user to the bucket listing, after * prompting the user for the name of the bucket to add. * To be added in this way, the third-party bucket must be publicly available. * */ private void addThirdPartyBucket() { try { String bucketName = JOptionPane.showInputDialog(ownerFrame, "Name for third-party bucket:", "Add a third-party bucket", JOptionPane.QUESTION_MESSAGE); if (bucketName != null) { if (s3ServiceMulti.getS3Service().isBucketAccessible(bucketName)) { S3Bucket thirdPartyBucket = new S3Bucket(bucketName); bucketTableModel.addBucket(thirdPartyBucket, false); } else { String message = "Unable to access third-party bucket: " + bucketName; log.error(message); ErrorDialog.showDialog(ownerFrame, this, message, null); } } } catch (RuntimeException e) { throw e; } catch (Exception e) { String message = "Unable to access third-party bucket"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, this, message, e); } } /** * Updates the ACL settings for the currently selected bucket. */ private void updateBucketAccessControlList() { try { AccessControlList bucketACL = s3ServiceMulti.getS3Service().getBucketAcl(currentSelectedBucket); AccessControlList updatedBucketACL = AccessControlDialog.showDialog( ownerFrame, new S3Bucket[] {currentSelectedBucket}, bucketACL, this); if (updatedBucketACL != null) { currentSelectedBucket.setAcl(updatedBucketACL); s3ServiceMulti.getS3Service().putBucketAcl(currentSelectedBucket); } } catch (Exception e) { String message = "Unable to update bucket's Access Control List"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, this, message, e); } } /** * Updates the ACL settings for the currently selected bucket. */ private void updateBucketRequesterPaysSetting() { try { final S3Bucket selectedBucket = currentSelectedBucket; if (!selectedBucket.isRequesterPaysKnown()) { selectedBucket.setRequesterPays( s3ServiceMulti.getS3Service().isRequesterPaysBucket( selectedBucket.getName())); } boolean originalRequesterPaysFlag = selectedBucket.isRequesterPays(); RequesterPaysDialog dialog = new RequesterPaysDialog(selectedBucket, ownerFrame, this); dialog.setVisible(true); if (!dialog.getOkClicked()) { return; } final boolean newRequesterPaysFlag = dialog.isRequesterPaysSelected(); dialog.dispose(); if (newRequesterPaysFlag != originalRequesterPaysFlag) { runInBackgroundThread(new Runnable() { public void run() { try { s3ServiceMulti.getS3Service().setRequesterPaysBucket( selectedBucket.getName(), newRequesterPaysFlag); selectedBucket.setRequesterPays(newRequesterPaysFlag); } catch (final Exception e) { String message = "Unable to update Requester Pays status"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, null, message, e); } } }); } } catch (Exception e) { String message = "Unable to update bucket's Access Control List"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, this, message, e); } } /** * @return the set of objects currently selected in the gui, or an empty array if none are selected. */ private S3Object[] getSelectedObjects() { int viewRows[] = objectsTable.getSelectedRows(); if (viewRows.length == 0) { return new S3Object[] {}; } else { S3Object objects[] = new S3Object[viewRows.length]; for (int i = 0; i < viewRows.length; i++) { int modelRow = objectTableModelSorter.modelIndex(viewRows[i]); objects[i] = objectTableModel.getObject(modelRow); } return objects; } } private void displayAclModificationDialog() { final HyperlinkActivatedListener hyperlinkListener = this; final S3Bucket selectedBucket = currentSelectedBucket; runInBackgroundThread(new Runnable() { public void run() { final S3Object[] selectedObjects = getSelectedObjects(); boolean aclLookupSucceeded = s3ServiceMulti.getObjectACLs( selectedBucket, selectedObjects); if (!aclLookupSucceeded) { return; } final AccessControlList[] updatedObjectACL = new AccessControlList[] {null}; runInDispatcherThreadImmediately(new Runnable() { public void run() { // Build merged ACL containing ALL relevant permissions AccessControlList mergedACL = new AccessControlList(); for (int i = 0; i < selectedObjects.length; i++) { AccessControlList objectACL = selectedObjects[i].getAcl(); mergedACL.grantAllPermissions(objectACL.getGrantAndPermissions()); // BEWARE! Here we assume that all the objects have the same owner... if (mergedACL.getOwner() == null) { mergedACL.setOwner(objectACL.getOwner()); } } // Show ACL dialog box for user to change ACL settings for all objects. updatedObjectACL[0] = AccessControlDialog.showDialog( ownerFrame, selectedObjects, mergedACL, hyperlinkListener); } }); if (updatedObjectACL[0] != null) { // Update ACLs for each object. for (int i = 0; i < selectedObjects.length; i++) { selectedObjects[i].setAcl(updatedObjectACL[0]); } // Perform ACL updates. s3ServiceMulti.putACLs(selectedBucket, selectedObjects); } } }); } /** * This method is an {@link S3ServiceEventListener} action method that is invoked when this * application's S3ServiceMulti triggers a LookupACLEvent. *

* The ACL details are retrieved for the currently selected objects in the gui, then the * {@link AccessControlDialog} is displayed to allow the user to update the ACL settings * for these objects. * * @param event */ public void s3ServiceEventPerformed(LookupACLEvent event) { if (ServiceEvent.EVENT_STARTED == event.getEventCode()) { startProgressDialog( "Retrieved 0 of " + event.getThreadWatcher().getThreadCount() + " ACLs", "", 0, (int) event.getThreadWatcher().getThreadCount(), "Cancel Lookup", event.getThreadWatcher().getCancelEventListener()); } else if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { ThreadWatcher progressStatus = event.getThreadWatcher(); String statusText = "Retrieved " + progressStatus.getCompletedThreads() + " of " + progressStatus.getThreadCount() + " ACLs"; updateProgressDialog(statusText, "", (int) progressStatus.getCompletedThreads()); } else if (ServiceEvent.EVENT_COMPLETED == event.getEventCode()) { stopProgressDialog(); } else if (ServiceEvent.EVENT_CANCELLED == event.getEventCode()) { stopProgressDialog(); } else if (ServiceEvent.EVENT_ERROR == event.getEventCode()) { stopProgressDialog(); String message = "Unable to lookup Access Control list for objects"; log.error(message, event.getErrorCause()); ErrorDialog.showDialog(ownerFrame, this, message, event.getErrorCause()); } } /** * This method is an {@link S3ServiceEventListener} action method that is invoked when this * application's S3ServiceMulti triggers a UpdateACLEvent. *

* This method merely updates the progress dialog as ACLs are updated. * * @param event */ public void s3ServiceEventPerformed(UpdateACLEvent event) { if (ServiceEvent.EVENT_STARTED == event.getEventCode()) { startProgressDialog( "Updated 0 of " + event.getThreadWatcher().getThreadCount() + " ACLs", "", 0, (int) event.getThreadWatcher().getThreadCount(), "Cancel Update", event.getThreadWatcher().getCancelEventListener()); } else if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { ThreadWatcher progressStatus = event.getThreadWatcher(); String statusText = "Updated " + progressStatus.getCompletedThreads() + " of " + progressStatus.getThreadCount() + " ACLs"; updateProgressDialog(statusText, "", (int) progressStatus.getCompletedThreads()); } else if (ServiceEvent.EVENT_COMPLETED == event.getEventCode()) { stopProgressDialog(); } else if (ServiceEvent.EVENT_CANCELLED == event.getEventCode()) { stopProgressDialog(); } else if (ServiceEvent.EVENT_ERROR == event.getEventCode()) { stopProgressDialog(); String message = "Unable to update Access Control Lists"; log.error(message, event.getErrorCause()); ErrorDialog.showDialog(ownerFrame, this, message, event.getErrorCause()); } } /** * Downloads the objects currently selected in the objects table. The user is * prompted * Prepares to perform a download of objects from S3 by prompting the user for a directory * to store the files in, then performing the download. * * @throws IOException */ private void downloadSelectedObjects() { // Prompt user to choose directory location for downloaded files (or cancel download altogether) JFileChooser fileChooser = new JFileChooser(); fileChooser.setDialogTitle("Choose directory to save S3 files in"); fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); fileChooser.setMultiSelectionEnabled(false); fileChooser.setSelectedFile(downloadDirectory); int returnVal = fileChooser.showDialog(ownerFrame, "Choose Directory"); if (returnVal != JFileChooser.APPROVE_OPTION) { return; } downloadDirectory = fileChooser.getSelectedFile(); boolean storeEmptyDirectories = Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME) .getBoolProperty("uploads.storeEmptyDirectories", true); final Map objectKeyToFilepathMap = FileComparer.getInstance() .buildObjectKeyToFilepathMap(downloadDirectory.listFiles(), "", storeEmptyDirectories); // Build map of S3 Objects being downloaded. final Map s3DownloadObjectsMap = FileComparer.getInstance() .populateObjectMap("", getSelectedObjects()); final HyperlinkActivatedListener hyperlinkListener = this; runInBackgroundThread(new Runnable() { public void run() { // Retrieve details of objects for download if (!retrieveObjectsDetails(getSelectedObjects())) { return; } try { final FileComparerResults comparisonResults = compareRemoteAndLocalFiles( objectKeyToFilepathMap, s3DownloadObjectsMap); DownloadPackage[] downloadPackages = buildDownloadPackageList(comparisonResults, s3DownloadObjectsMap); if (downloadPackages == null) { return; } s3ServiceMulti.downloadObjects(currentSelectedBucket, downloadPackages); } catch (final Exception e) { runInDispatcherThreadImmediately(new Runnable() { public void run() { String message = "Unable to download objects"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, hyperlinkListener, message, e); } }); } } }); } private void uploadFiles(File[] uploadFiles) { // Fail if encryption is turned on but no password is available. if (cockpitPreferences.isUploadEncryptionActive() && !cockpitPreferences.isEncryptionPasswordSet()) { ErrorDialog.showDialog(ownerFrame, this, "Upload encryption is enabled but you have not yet set a password in the Encryption Preferences.", null); return; } try { // Build map of files proposed for upload. boolean storeEmptyDirectories = Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME) .getBoolProperty("uploads.storeEmptyDirectories", true); final Map objectKeyToFilepathMap = FileComparer.getInstance() .buildObjectKeyToFilepathMap(uploadFiles, "", storeEmptyDirectories); // Build map of objects already existing in target S3 bucket with keys // matching the proposed upload keys. List objectsWithExistingKeys = new ArrayList(); S3Object[] existingObjects = objectTableModel.getObjects(); for (int i = 0; i < existingObjects.length; i++) { if (objectKeyToFilepathMap.containsKey(existingObjects[i].getKey())) { objectsWithExistingKeys.add(existingObjects[i]); } } existingObjects = (S3Object[]) objectsWithExistingKeys .toArray(new S3Object[objectsWithExistingKeys.size()]); final Map s3ExistingObjectsMap = FileComparer.getInstance() .populateObjectMap("", existingObjects); final HyperlinkActivatedListener hyperlinkListener = this; final S3Object[] clashingObjects = existingObjects; runInBackgroundThread(new Runnable() { public void run() { if (clashingObjects.length > 0) { // Retrieve details of potential clashes if (!retrieveObjectsDetails(clashingObjects)) { return; } } try { FileComparerResults comparisonResults = compareRemoteAndLocalFiles(objectKeyToFilepathMap, s3ExistingObjectsMap); S3Object[] uploadObjects = buildUploadObjectsList( comparisonResults, objectKeyToFilepathMap); if (uploadObjects == null) { return; } // Upload the files. s3ServiceMulti.putObjects(currentSelectedBucket, uploadObjects); } catch (final Exception e) { runInDispatcherThreadImmediately(new Runnable() { public void run() { String message = "Unable to upload objects"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, hyperlinkListener, message, e); } }); } } }); } catch (Exception e) { String message = "Unable to upload objects"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, this, message, e); } } private FileComparerResults compareRemoteAndLocalFiles( final Map objectKeyToFilepathMap, final Map s3ObjectsMap) throws Exception { try { // Compare objects being downloaded and existing local files. final String statusText = "Comparing " + s3ObjectsMap.size() + " object" + (s3ObjectsMap.size() > 1 ? "s" : "") + " in S3 with " + objectKeyToFilepathMap.size() + " local file" + (objectKeyToFilepathMap.size() > 1 ? "s" : ""); startProgressDialog(statusText, "", 0, 100, null, null); // Calculate total files size. final long filesSizeTotal[] = new long[1]; for (String filepath: objectKeyToFilepathMap.values()) { filesSizeTotal[0] += (new File(filepath)).length(); } // Monitor generation of MD5 hash, and provide feedback via the progress bar. BytesProgressWatcher progressWatcher = new BytesProgressWatcher(filesSizeTotal[0]) { @Override public void updateBytesTransferred(long byteCount) { super.updateBytesTransferred(byteCount); String detailsText = formatBytesProgressWatcherDetails(this, true); int progressValue = (int)((double)getBytesTransferred() * 100 / getBytesToTransfer()); updateProgressDialog(statusText, detailsText, progressValue); } }; FileComparerResults comparisonResults = FileComparer.getInstance() .buildDiscrepancyLists(objectKeyToFilepathMap, s3ObjectsMap, progressWatcher); stopProgressDialog(); return comparisonResults; } finally { stopProgressDialog(); } } /** * Performs the real work of downloading files by comparing the download candidates against * existing files, prompting the user whether to overwrite any pre-existing file versions, * and starting {@link S3ServiceMulti#downloadObjects} where the real work is done. * */ private DownloadPackage[] buildDownloadPackageList(FileComparerResults comparisonResults, Map s3DownloadObjectsMap) throws Exception { // Determine which files to download, prompting user whether to over-write existing files List objectKeysForDownload = new ArrayList(); objectKeysForDownload.addAll(comparisonResults.onlyOnServerKeys); int newFiles = comparisonResults.onlyOnServerKeys.size(); int unchangedFiles = comparisonResults.alreadySynchronisedKeys.size(); int changedFiles = comparisonResults.updatedOnClientKeys.size() + comparisonResults.updatedOnServerKeys.size(); if (unchangedFiles > 0 || changedFiles > 0) { // Ask user whether to replace existing unchanged and/or existing changed files. log.debug("Files for download clash with existing local files, prompting user to choose which files to replace"); List options = new ArrayList(); String message = "Of the " + (newFiles + unchangedFiles + changedFiles) + " objects being downloaded:\n\n"; if (newFiles > 0) { message += newFiles + " files are new.\n\n"; options.add(DOWNLOAD_NEW_FILES_ONLY); } if (changedFiles > 0) { message += changedFiles + " files have changed.\n\n"; options.add(DOWNLOAD_NEW_AND_CHANGED_FILES); } if (unchangedFiles > 0) { message += unchangedFiles + " files already exist and are unchanged.\n\n"; options.add(DOWNLOAD_ALL_FILES); } message += "Please choose which files you wish to download:"; Object response = JOptionPane.showInputDialog( ownerFrame, message, "Replace files?", JOptionPane.QUESTION_MESSAGE, null, options.toArray(), DOWNLOAD_NEW_AND_CHANGED_FILES); if (response == null) { return null; } if (DOWNLOAD_NEW_FILES_ONLY.equals(response)) { // No change required to default objectKeysForDownload list. } else if (DOWNLOAD_ALL_FILES.equals(response)) { objectKeysForDownload.addAll(comparisonResults.updatedOnClientKeys); objectKeysForDownload.addAll(comparisonResults.updatedOnServerKeys); objectKeysForDownload.addAll(comparisonResults.alreadySynchronisedKeys); } else if (DOWNLOAD_NEW_AND_CHANGED_FILES.equals(response)) { objectKeysForDownload.addAll(comparisonResults.updatedOnClientKeys); objectKeysForDownload.addAll(comparisonResults.updatedOnServerKeys); } else { // Download cancelled. return null; } } log.debug("Downloading " + objectKeysForDownload.size() + " objects"); if (objectKeysForDownload.size() == 0) { return null; } // Create array of objects for download. S3Object[] objects = new S3Object[objectKeysForDownload.size()]; int objectIndex = 0; for (Iterator iter = objectKeysForDownload.iterator(); iter.hasNext();) { objects[objectIndex++] = (S3Object) s3DownloadObjectsMap.get(iter.next()); } Map downloadObjectsToFileMap = new HashMap(); ArrayList downloadPackageList = new ArrayList(); // Setup files to write to, creating parent directories when necessary. for (int i = 0; i < objects.length; i++) { File file = new File(downloadDirectory, objects[i].getKey()); // Encryption password must be null if no password is set. String encryptionPassword = null; if (cockpitPreferences.isEncryptionPasswordSet()) { encryptionPassword = cockpitPreferences.getEncryptionPassword(); } // Create local directories corresponding to objects flagged as dirs. if (objects[i].isDirectoryPlaceholder()) { file = new File(downloadDirectory, ObjectUtils.convertDirPlaceholderKeyNameToDirName( objects[i].getKey())); file.mkdirs(); } DownloadPackage downloadPackage = ObjectUtils .createPackageForDownload(objects[i], file, true, true, encryptionPassword); if (downloadPackage != null) { downloadObjectsToFileMap.put(objects[i].getKey(), file); downloadPackageList.add(downloadPackage); } } return (DownloadPackage[]) downloadPackageList .toArray(new DownloadPackage[downloadPackageList.size()]); } /** * This method is an {@link S3ServiceEventListener} action method that is invoked when this * application's S3ServiceMulti triggers a DownloadObjectsEvent. *

* This method merely updates the progress dialog as objects are downloaded. * * @param event */ public void s3ServiceEventPerformed(DownloadObjectsEvent event) { if (ServiceEvent.EVENT_STARTED == event.getEventCode()) { ThreadWatcher watcher = event.getThreadWatcher(); // Show percentage of bytes transferred, if this info is available. if (watcher.isBytesTransferredInfoAvailable()) { startProgressDialog("Downloaded " + watcher.getCompletedThreads() + "/" + watcher.getThreadCount() + " - " + byteFormatter.formatByteSize(watcher.getBytesTransferred()) + " of " + byteFormatter.formatByteSize(watcher.getBytesTotal()), "", 0, 100, "Cancel Download", watcher.getCancelEventListener()); // ... otherwise just show the number of completed threads. } else { startProgressDialog("Downloaded " + watcher.getCompletedThreads() + " of " + watcher.getThreadCount() + " objects", "", 0, (int) watcher.getThreadCount(), "Cancel Download", watcher.getCancelEventListener()); } } else if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { ThreadWatcher watcher = event.getThreadWatcher(); // Show percentage of bytes transferred, if this info is available. if (watcher.isBytesTransferredInfoAvailable()) { String bytesCompletedStr = byteFormatter.formatByteSize(watcher.getBytesTransferred()); String bytesTotalStr = byteFormatter.formatByteSize(watcher.getBytesTotal()); String statusText = "Downloaded " + watcher.getCompletedThreads() + "/" + watcher.getThreadCount() + " - " + bytesCompletedStr + " of " + bytesTotalStr; String detailsText = formatTransferDetails(watcher); int percentage = (int) (((double)watcher.getBytesTransferred() / watcher.getBytesTotal()) * 100); updateProgressDialog(statusText, detailsText, percentage); } // ... otherwise just show the number of completed threads. else { ThreadWatcher progressStatus = event.getThreadWatcher(); String statusText = "Downloaded " + progressStatus.getCompletedThreads() + " of " + progressStatus.getThreadCount() + " objects"; updateProgressDialog(statusText, "", (int) progressStatus.getCompletedThreads()); } } else if (ServiceEvent.EVENT_COMPLETED == event.getEventCode()) { stopProgressDialog(); } else if (ServiceEvent.EVENT_CANCELLED == event.getEventCode()) { stopProgressDialog(); } else if (ServiceEvent.EVENT_ERROR == event.getEventCode()) { stopProgressDialog(); String message = "Unable to download objects"; log.error(message, event.getErrorCause()); ErrorDialog.showDialog(ownerFrame, this, message, event.getErrorCause()); } } private S3Object[] buildUploadObjectsList(FileComparerResults comparisonResults, Map objectKeyToFilepathMap) throws Exception { // Determine which files to upload, prompting user whether to over-write existing files List fileKeysForUpload = new ArrayList(); fileKeysForUpload.addAll(comparisonResults.onlyOnClientKeys); int newFiles = comparisonResults.onlyOnClientKeys.size(); int unchangedFiles = comparisonResults.alreadySynchronisedKeys.size(); int changedFiles = comparisonResults.updatedOnClientKeys.size() + comparisonResults.updatedOnServerKeys.size(); if (unchangedFiles > 0 || changedFiles > 0) { // Ask user whether to replace existing unchanged and/or existing changed files. log.debug("Files for upload clash with existing S3 objects, prompting user to choose which files to replace"); List options = new ArrayList(); String message = "Of the " + objectKeyToFilepathMap.size() + " files being uploaded:\n\n"; if (newFiles > 0) { message += newFiles + " files are new.\n\n"; options.add(UPLOAD_NEW_FILES_ONLY); } if (changedFiles > 0) { message += changedFiles + " files have changed.\n\n"; options.add(UPLOAD_NEW_AND_CHANGED_FILES); } if (unchangedFiles > 0) { message += unchangedFiles + " files already exist and are unchanged.\n\n"; options.add(UPLOAD_ALL_FILES); } message += "Please choose which files you wish to upload:"; Object response = JOptionPane.showInputDialog( ownerFrame, message, "Replace files?", JOptionPane.QUESTION_MESSAGE, null, options.toArray(), UPLOAD_NEW_AND_CHANGED_FILES); if (response == null) { return null; } if (UPLOAD_NEW_FILES_ONLY.equals(response)) { // No change required to default fileKeysForUpload list. } else if (UPLOAD_ALL_FILES.equals(response)) { fileKeysForUpload.addAll(comparisonResults.updatedOnClientKeys); fileKeysForUpload.addAll(comparisonResults.updatedOnServerKeys); fileKeysForUpload.addAll(comparisonResults.alreadySynchronisedKeys); } else if (UPLOAD_NEW_AND_CHANGED_FILES.equals(response)) { fileKeysForUpload.addAll(comparisonResults.updatedOnClientKeys); fileKeysForUpload.addAll(comparisonResults.updatedOnServerKeys); } else { // Upload cancelled. stopProgressDialog(); return null; } } if (fileKeysForUpload.size() == 0) { return null; } final String[] statusText = new String[1]; statusText[0] = "Prepared 0 of " + fileKeysForUpload.size() + " files for upload"; startProgressDialog(statusText[0], "", 0, 100, null, null); long bytesToProcess = 0; for (Iterator iter = fileKeysForUpload.iterator(); iter.hasNext();) { File file = new File(objectKeyToFilepathMap.get(iter.next().toString())); bytesToProcess += file.length() * (cockpitPreferences.isUploadEncryptionActive() || cockpitPreferences.isUploadCompressionActive() ? 3 : 1); } BytesProgressWatcher progressWatcher = new BytesProgressWatcher(bytesToProcess) { @Override public void updateBytesTransferred(long byteCount) { super.updateBytesTransferred(byteCount); String detailsText = formatBytesProgressWatcherDetails(this, false); int progressValue = (int)((double)getBytesTransferred() * 100 / getBytesToTransfer()); updateProgressDialog(statusText[0], detailsText, progressValue); } }; // Populate S3Objects representing upload files with metadata etc. final S3Object[] objects = new S3Object[fileKeysForUpload.size()]; int objectIndex = 0; for (Iterator iter = fileKeysForUpload.iterator(); iter.hasNext();) { String fileKey = iter.next().toString(); File file = new File(objectKeyToFilepathMap.get(fileKey)); S3Object newObject = ObjectUtils .createObjectForUpload(fileKey, file, (cockpitPreferences.isUploadEncryptionActive() ? encryptionUtil : null), cockpitPreferences.isUploadCompressionActive(), progressWatcher); String aclPreferenceString = cockpitPreferences.getUploadACLPermission(); if (CockpitPreferences.UPLOAD_ACL_PERMISSION_PRIVATE.equals(aclPreferenceString)) { // Objects are private by default, nothing more to do. } else if (CockpitPreferences.UPLOAD_ACL_PERMISSION_PUBLIC_READ.equals(aclPreferenceString)) { newObject.setAcl(AccessControlList.REST_CANNED_PUBLIC_READ); } else if (CockpitPreferences.UPLOAD_ACL_PERMISSION_PUBLIC_READ_WRITE.equals(aclPreferenceString)) { newObject.setAcl(AccessControlList.REST_CANNED_PUBLIC_READ_WRITE); } else { log.warn("Ignoring unrecognised upload ACL permission setting: " + aclPreferenceString); } newObject.setStorageClass(cockpitPreferences.getUploadStorageClass()); statusText[0] = "Prepared " + (objectIndex + 1) + " of " + fileKeysForUpload.size() + " files for upload"; objects[objectIndex++] = newObject; } stopProgressDialog(); return objects; } /** * This method is an {@link S3ServiceEventListener} action method that is invoked when this * application's S3ServiceMulti triggers a CreateObjectsEvent. *

* This method merely updates the progress dialog as files are uploaded. * * @param event */ public void s3ServiceEventPerformed(final CreateObjectsEvent event) { if (ServiceEvent.EVENT_STARTED == event.getEventCode()) { ThreadWatcher watcher = event.getThreadWatcher(); // Show percentage of bytes transferred, if this info is available. if (watcher.isBytesTransferredInfoAvailable()) { String bytesTotalStr = byteFormatter.formatByteSize(watcher.getBytesTotal()); String statusText = "Uploaded " + watcher.getCompletedThreads() + "/" + watcher.getThreadCount() + " - " + "0 of " + bytesTotalStr; startProgressDialog(statusText, " ", 0, 100, "Cancel Upload", event.getThreadWatcher().getCancelEventListener()); } // ... otherwise show the number of completed threads. else { startProgressDialog( "Uploaded 0 of " + watcher.getThreadCount() + " objects", "", (int) watcher.getCompletedThreads(), (int) watcher.getThreadCount(), "Cancel upload", event.getThreadWatcher().getCancelEventListener()); } } else if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { SwingUtilities.invokeLater(new Runnable() { public void run() { for (int i = 0; i < event.getCreatedObjects().length; i++) { S3Object object = event.getCreatedObjects()[i]; object.setBucketName(currentSelectedBucket.getName()); objectTableModel.addObject(object); } if (event.getCreatedObjects().length > 0) { updateObjectsSummary(true); } } }); ThreadWatcher watcher = event.getThreadWatcher(); // Show percentage of bytes transferred, if this info is available. if (watcher.isBytesTransferredInfoAvailable()) { if (watcher.getBytesTransferred() >= watcher.getBytesTotal()) { // Upload is completed, just waiting on resonse from S3. String statusText = "Upload completed, awaiting confirmation"; updateProgressDialog(statusText, "", 100); } else { String bytesCompletedStr = byteFormatter.formatByteSize(watcher.getBytesTransferred()); String bytesTotalStr = byteFormatter.formatByteSize(watcher.getBytesTotal()); String statusText = "Uploaded " + watcher.getCompletedThreads() + "/" + watcher.getThreadCount() + " - " + bytesCompletedStr + " of " + bytesTotalStr; int percentage = (int) (((double)watcher.getBytesTransferred() / watcher.getBytesTotal()) * 100); String detailsText = formatTransferDetails(watcher); updateProgressDialog(statusText, detailsText, percentage); } } // ... otherwise show the number of completed threads. else { ThreadWatcher progressStatus = event.getThreadWatcher(); String statusText = "Uploaded " + progressStatus.getCompletedThreads() + " of " + progressStatus.getThreadCount() + " objects"; updateProgressDialog(statusText, "", (int) progressStatus.getCompletedThreads()); } } else if (ServiceEvent.EVENT_COMPLETED == event.getEventCode()) { stopProgressDialog(); SwingUtilities.invokeLater(new Runnable() { public void run() { updateObjectsSummary(false); S3Object[] allObjects = objectTableModel.getObjects(); cachedBuckets.put(currentSelectedBucket.getName(), allObjects); } }); } else if (ServiceEvent.EVENT_CANCELLED == event.getEventCode()) { SwingUtilities.invokeLater(new Runnable() { public void run() { updateObjectsSummary(false); } }); stopProgressDialog(); } else if (ServiceEvent.EVENT_ERROR == event.getEventCode()) { stopProgressDialog(); String message = "Unable to upload objects"; log.error(message, event.getErrorCause()); ErrorDialog.showDialog(ownerFrame, this, message, event.getErrorCause()); } } private void copyObjects() { try { final S3Object[] sourceObjects = getSelectedObjects(); CopyObjectsDialog dialog = new CopyObjectsDialog(ownerFrame, "Copy or Move Objects", skinsFactory, sourceObjects, bucketTableModel.getBuckets()); dialog.setVisible(true); if (dialog.isCopyActionApproved()) { final String currentBucketName = currentSelectedBucket.getName(); final String destinationBucketName = dialog.getDestinationBucketName(); final String[] sourceObjectKeys = dialog.getSourceObjectKeys(); final S3Object[] destinationObjects = dialog.getDestinationObjects(); final boolean isDeleteAfterCopy = dialog.isMoveOptionSelected(); final boolean retainAcls = dialog.isCopyOriginalAccessControlLists(); dialog.dispose(); if (!destinationBucketName.equals(currentBucketName)) { cachedBuckets.remove(destinationBucketName); } runInBackgroundThread(new Runnable() { public void run() { if (retainAcls) { // Retain ACL settings from original objects. if (!s3ServiceMulti.getObjectACLs( currentSelectedBucket, sourceObjects)) { return; } for (int i = 0; i < sourceObjects.length; i++) { destinationObjects[i].setAcl( sourceObjects[i].getAcl()); } } // Copy objects. Metadata is retained, not replaced. s3ServiceMulti.copyObjects(currentBucketName, destinationBucketName, sourceObjectKeys, destinationObjects, false); if (isDeleteAfterCopy) { final S3Object[] sourceObjects = new S3Object[sourceObjectKeys.length]; for (int i = 0; i < sourceObjectKeys.length; i++) { sourceObjects[i] = new S3Object(sourceObjectKeys[i]); } s3ServiceMulti.deleteObjects(currentSelectedBucket, sourceObjects); } if (destinationBucketName.equals(currentBucketName) || isDeleteAfterCopy) { // Refesh object listing for current bucket if the bucket's contents // have changed. listObjects(); } } }); } else { dialog.dispose(); } } catch (RuntimeException e) { throw e; } catch (Exception e) { stopProgressDialog(); String message = "Unable to modify objects"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, this, message, e); } } /** * This method is an {@link S3ServiceEventListener} action method that is invoked when this * application's S3ServiceMulti triggers a CopyObjectsEvent. *

* This method merely updates the progress dialog as objects are copied. * * @param event */ public void s3ServiceEventPerformed(final CopyObjectsEvent event) { if (ServiceEvent.EVENT_STARTED == event.getEventCode()) { ThreadWatcher watcher = event.getThreadWatcher(); startProgressDialog("Copied 0 of " + watcher.getThreadCount() + " objects", "", 0, (int) watcher.getThreadCount(), "Cancel Copy", event.getThreadWatcher().getCancelEventListener()); } else if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { ThreadWatcher watcher = event.getThreadWatcher(); String statusText = "Copied " + watcher.getCompletedThreads() + " of " + watcher.getThreadCount() + " objects"; updateProgressDialog(statusText, "", (int) watcher.getCompletedThreads()); } else if (ServiceEvent.EVENT_COMPLETED == event.getEventCode() || ServiceEvent.EVENT_CANCELLED == event.getEventCode()) { stopProgressDialog(); } else if (ServiceEvent.EVENT_ERROR == event.getEventCode()) { stopProgressDialog(); String message = "Unable to copy objects"; log.error(message, event.getErrorCause()); ErrorDialog.showDialog(ownerFrame, this, message, event.getErrorCause()); } } private void generatePublicGetUrls() { final S3Object[] objects = getSelectedObjects(); if (objects.length < 1) { log.warn("Ignoring Generate Public URLs object command because no objects are selected"); return; } SignedGetUrlDialog dialog = new SignedGetUrlDialog(ownerFrame, this, s3ServiceMulti.getS3Service(), objects); dialog.setVisible(true); } private void generateTorrentUrl() { final S3Object[] objects = getSelectedObjects(); if (objects.length != 1) { log.warn("Ignoring Generate Public URL object command, can only operate on a single object"); return; } S3Object currentObject = objects[0]; // Generate URL String torrentUrl = s3ServiceMulti.getS3Service().createTorrentUrl( currentSelectedBucket.getName(), currentObject.getKey()); // Display signed URL JOptionPane.showInputDialog(ownerFrame, "Torrent URL for '" + currentObject.getKey() + "'.", "Torrent URL", JOptionPane.INFORMATION_MESSAGE, null, null, torrentUrl); } private void deleteSelectedObjects() { final S3Object[] objects = getSelectedObjects(); if (objects.length == 0) { log.warn("Ignoring delete objects command, no currently selected objects"); return; } int response = JOptionPane.showConfirmDialog(ownerFrame, (objects.length == 1 ? "Are you sure you want to delete '" + objects[0].getKey() + "'?" : "Are you sure you want to delete " + objects.length + " objects" ), "Delete Objects?", JOptionPane.YES_NO_OPTION); if (response == JOptionPane.NO_OPTION) { return; } runInBackgroundThread(new Runnable() { public void run() { s3ServiceMulti.deleteObjects(currentSelectedBucket, objects); runInDispatcherThreadImmediately(new Runnable() { public void run() { updateObjectsSummary(false); S3Object[] allObjects = objectTableModel.getObjects(); cachedBuckets.put(currentSelectedBucket.getName(), allObjects); } }); } }); } /** * This method is an {@link S3ServiceEventListener} action method that is invoked when this * application's S3ServiceMulti triggers a DeleteObjectsEvent. *

* This method merely updates the progress dialog as objects are deleted. * * @param event */ public void s3ServiceEventPerformed(final DeleteObjectsEvent event) { if (ServiceEvent.EVENT_STARTED == event.getEventCode()) { startProgressDialog( "Deleted 0 of " + event.getThreadWatcher().getThreadCount() + " objects", "", 0, (int) event.getThreadWatcher().getThreadCount(), "Cancel Delete Objects", event.getThreadWatcher().getCancelEventListener()); } else if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { SwingUtilities.invokeLater(new Runnable() { public void run() { for (int i = 0; i < event.getDeletedObjects().length; i++) { objectTableModel.removeObject( event.getDeletedObjects()[i]); } if (event.getDeletedObjects().length > 0) { updateObjectsSummary(true); } } }); ThreadWatcher progressStatus = event.getThreadWatcher(); String statusText = "Deleted " + progressStatus.getCompletedThreads() + " of " + progressStatus.getThreadCount() + " objects"; updateProgressDialog(statusText, "", (int) progressStatus.getCompletedThreads()); } else if (ServiceEvent.EVENT_COMPLETED == event.getEventCode()) { stopProgressDialog(); } else if (ServiceEvent.EVENT_CANCELLED == event.getEventCode()) { stopProgressDialog(); } else if (ServiceEvent.EVENT_ERROR == event.getEventCode()) { stopProgressDialog(); String message = "Unable to delete objects"; log.error(message, event.getErrorCause()); ErrorDialog.showDialog(ownerFrame, this, message, event.getErrorCause()); } } /** * Retrieves details about objects including metadata etc by invoking the method * {@link S3ServiceMulti#getObjectsHeads}. * * This is generally done as a prelude to some further action, such as * displaying the objects' details or downloading the objects. * The real action occurs in the method s3ServiceEventPerformed for handling * GetObjectHeadsEvent events. * * @param candidateObjects * * @return * true if objects details were successfully retrieved. */ private boolean retrieveObjectsDetails(final S3Object[] candidateObjects) { // Identify which of the candidate objects have incomplete metadata. ArrayList s3ObjectsIncompleteList = new ArrayList(); for (int i = 0; i < candidateObjects.length; i++) { if (!candidateObjects[i].isMetadataComplete()) { s3ObjectsIncompleteList.add(candidateObjects[i]); } } log.debug("Of " + candidateObjects.length + " object candidates for HEAD requests " + s3ObjectsIncompleteList.size() + " are incomplete, performing requests for these only"); final S3Object[] incompleteObjects = (S3Object[]) s3ObjectsIncompleteList .toArray(new S3Object[s3ObjectsIncompleteList.size()]); return s3ServiceMulti.getObjectsHeads(currentSelectedBucket, incompleteObjects); } /** * This method is an {@link S3ServiceEventListener} action method that is invoked when this * application's S3ServiceMulti triggers a GetObjectHeadsEvent. *

* This method merely updates the progress dialog as object details (heads) are retrieved. * * @param event */ public void s3ServiceEventPerformed(final GetObjectHeadsEvent event) { if (ServiceEvent.EVENT_STARTED == event.getEventCode()) { if (event.getThreadWatcher().getThreadCount() > 0) { startProgressDialog("Retrieved details for 0 of " + event.getThreadWatcher().getThreadCount() + " objects", "", 0, (int) event.getThreadWatcher().getThreadCount(), "Cancel Retrieval", event.getThreadWatcher().getCancelEventListener()); } } else if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { final ThreadWatcher progressStatus = event.getThreadWatcher(); // Store detail-complete objects in table. runInDispatcherThreadImmediately(new Runnable() { public void run() { // Update object in table with the retrieved details. for (int i = 0; i < event.getCompletedObjects().length; i++) { S3Object objectWithDetails = event.getCompletedObjects()[i]; S3Object originalObject = objectTableModel.getObjectByKey( objectWithDetails.getKey()); originalObject.replaceAllMetadata(objectWithDetails.getMetadataMap()); originalObject.setMetadataComplete(true); log.debug("Updated table with " + originalObject.getKey() + ", content-type=" + originalObject.getContentType()); } } }); // Update progress of GetObject requests. String statusText = "Retrieved details for " + progressStatus.getCompletedThreads() + " of " + progressStatus.getThreadCount() + " objects"; updateProgressDialog(statusText, "", (int) progressStatus.getCompletedThreads()); } else if (ServiceEvent.EVENT_COMPLETED == event.getEventCode()) { // Stop GetObjectHead progress display. stopProgressDialog(); } else if (ServiceEvent.EVENT_CANCELLED == event.getEventCode()) { stopProgressDialog(); } else if (ServiceEvent.EVENT_ERROR == event.getEventCode()) { stopProgressDialog(); String message = "Unable to retrieve objects details"; log.error(message, event.getErrorCause()); ErrorDialog.showDialog(ownerFrame, this, message, event.getErrorCause()); } } private String formatTransferDetails(ThreadWatcher watcher) { long bytesPerSecond = watcher.getBytesPerSecond(); String detailsText = byteFormatter.formatByteSize(bytesPerSecond) + "/s"; if (watcher.isTimeRemainingAvailable()) { long secondsRemaining = watcher.getTimeRemaining(); detailsText += " - Time remaining: " + timeFormatter.formatTime(secondsRemaining); } return detailsText; } private String formatBytesProgressWatcherDetails(BytesProgressWatcher watcher, boolean includeBytes) { long secondsRemaining = watcher.getRemainingTime(); String detailsText = (includeBytes ? byteFormatter.formatByteSize(watcher.getBytesTransferred()) + " of " + byteFormatter.formatByteSize(watcher.getBytesToTransfer()) + " - " : "") + "Time remaining: " + timeFormatter.formatTime(secondsRemaining); return detailsText; } /** * Follows hyperlinks clicked on by a user. This is achieved differently depending on whether * Cockpit is running as an applet or as a stand-alone application: *

    *
  • Application: Detects the default browser application for the user's system (using * BareBonesBrowserLaunch) and opens the link as a new window in that browser
  • *
  • Applet: Opens the link in the current browser using the applet's context
  • *
* * @param url * the url to open * @param target * the target pane to open the url in, eg "_blank". This may be null. */ public void followHyperlink(URL url, String target) { if (!isStandAloneApplication) { if (target == null) { getAppletContext().showDocument(url); } else { getAppletContext().showDocument(url, target); } } else { BareBonesBrowserLaunch.openURL(url.toString()); } } /** * Implementation method for the CredentialsProvider interface. *

* Based on sample code: * InteractiveAuthenticationExample * */ public Credentials getCredentials(AuthScheme authscheme, String host, int port, boolean proxy) throws CredentialsNotAvailableException { if (authscheme == null) { return null; } try { Credentials credentials = null; if (authscheme instanceof NTLMScheme) { AuthenticationDialog pwDialog = new AuthenticationDialog( ownerFrame, "Authentication Required", "Host " + host + ":" + port + " requires Windows authentication", true); pwDialog.setVisible(true); if (pwDialog.getUser().length() > 0) { credentials = new NTCredentials(pwDialog.getUser(), pwDialog.getPassword(), host, pwDialog.getDomain()); } pwDialog.dispose(); } else if (authscheme instanceof RFC2617Scheme) { AuthenticationDialog pwDialog = new AuthenticationDialog( ownerFrame, "Authentication Required", "

Host " + host + ":" + port + "" + " requires authentication for the realm:
" + authscheme.getRealm() + "
", false); pwDialog.setVisible(true); if (pwDialog.getUser().length() > 0) { credentials = new UsernamePasswordCredentials(pwDialog.getUser(), pwDialog.getPassword()); } pwDialog.dispose(); } else { throw new CredentialsNotAvailableException("Unsupported authentication scheme: " + authscheme.getSchemeName()); } return credentials; } catch (IOException e) { throw new CredentialsNotAvailableException(e.getMessage(), e); } } private boolean isObjectFilteringActive() { if (!filterObjectsCheckBox.isSelected()) { return false; } else { String delimiter = (String) filterObjectsDelimiter.getSelectedItem(); if (filterObjectsPrefix.getText().length() > 0 || delimiter.length() > 0) { return true; } else { return false; } } } private class ContextMenuListener extends MouseAdapter { @Override public void mousePressed(MouseEvent e) { showContextMenu(e); } @Override public void mouseReleased(MouseEvent e) { showContextMenu(e); } private void showContextMenu(MouseEvent e) { if (e.isPopupTrigger()) { // Select item under context-click. if (e.getSource() instanceof JList) { JList jList = (JList) e.getSource(); int locIndex = jList.locationToIndex(e.getPoint()); if (locIndex >= 0) { jList.setSelectedIndex(locIndex); } } else if (e.getSource() instanceof JTable) { JTable jTable = (JTable) e.getSource(); int rowIndex = jTable.rowAtPoint(e.getPoint()); if (rowIndex >= 0) { jTable.addRowSelectionInterval(rowIndex, rowIndex); } } // Show context popup menu. if (e.getSource().equals(bucketsTable)) { showBucketPopupMenu((JComponent)e.getSource(), e.getX(), e.getY()); } else if (e.getSource().equals(objectsTable)) { showObjectPopupMenu((JComponent)e.getSource(), e.getX(), e.getY()); } } } } /** * Runs Cockpit as a stand-alone application. * @param args * @throws Exception */ public static void main(String args[]) throws Exception { // When running on OS X, display app menu in the right place (i.e. not the app window) System.setProperty("apple.laf.useScreenMenuBar", "true"); JFrame ownerFrame = new JFrame("JetS3t Cockpit"); ownerFrame.addWindowListener(new WindowListener() { public void windowOpened(WindowEvent e) { } public void windowClosing(WindowEvent e) { e.getWindow().dispose(); } public void windowClosed(WindowEvent e) { } public void windowIconified(WindowEvent e) { } public void windowDeiconified(WindowEvent e) { } public void windowActivated(WindowEvent e) { } public void windowDeactivated(WindowEvent e) { } }); new Cockpit(ownerFrame); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/cockpit/CockpitPreferences.java0000644000000000000000000001420211450003512023300 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2006-2010 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.cockpit; import java.io.Serializable; import java.util.Properties; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.model.S3Object; /** *

* Stores Cockpit's preferences as set by the user via the * {@link org.jets3t.apps.cockpit.gui.PreferencesDialog}. *

* * @author James Murty */ public class CockpitPreferences implements Serializable { private static final long serialVersionUID = 6072192057121567975L; /** * Represents ACL permissions to make objects private. */ public static final String UPLOAD_ACL_PERMISSION_PRIVATE = "PRIVATE"; /** * Represents ACL permissions to make objects readable by anyone. */ public static final String UPLOAD_ACL_PERMISSION_PUBLIC_READ = "PUBLIC_READ"; /** * Represents ACL permissions to make objects readable and writable by anyone. */ public static final String UPLOAD_ACL_PERMISSION_PUBLIC_READ_WRITE = "PUBLIC_READ_WRITE"; private boolean rememberPreferences = true; private String uploadACLPermission = UPLOAD_ACL_PERMISSION_PRIVATE; private boolean uploadCompressionActive = false; private boolean uploadEncryptionActive = false; private String uploadStorageClass = Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME) .getStringProperty("s3service.default-storage-class", S3Object.STORAGE_CLASS_STANDARD); private String encryptionPassword = null; private String encryptionAlgorithm = Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME) .getStringProperty("crypto.algorithm", "PBEWithMD5AndDES"); public String getEncryptionPassword() { return encryptionPassword; } public void setEncryptionPassword(String encryptionPasswrod) { this.encryptionPassword = encryptionPasswrod; } public String getEncryptionAlgorithm() { return encryptionAlgorithm; } public void setEncryptionAlgorithm(String encryptionAlgorithm) { this.encryptionAlgorithm = encryptionAlgorithm; } public boolean isEncryptionPasswordSet() { return this.encryptionPassword != null && this.encryptionPassword.length() > 0; } /** * @return * the ACL permission setting, which will match one of the UPLOAD_ACL_PERMISSION_xyz * constants contained in this class. */ public String getUploadACLPermission() { return uploadACLPermission; } /** * Set the ACL permissions string setting. * * @param uploadACLPermission * the ACL permission setting, which must match one of the UPLOAD_ACL_PERMISSION_xyz * constants contained in this class. */ public void setUploadACLPermission(String uploadACLPermission) { if (!UPLOAD_ACL_PERMISSION_PRIVATE.equals(uploadACLPermission) && !UPLOAD_ACL_PERMISSION_PUBLIC_READ.equals(uploadACLPermission) && !UPLOAD_ACL_PERMISSION_PUBLIC_READ_WRITE.equals(uploadACLPermission)) { throw new IllegalArgumentException("ACL Permission string is not a legal value: " + uploadACLPermission); } this.uploadACLPermission = uploadACLPermission; } public boolean isUploadCompressionActive() { return uploadCompressionActive; } public void setUploadCompressionActive(boolean uploadCompressionActive) { this.uploadCompressionActive = uploadCompressionActive; } public boolean isUploadEncryptionActive() { return uploadEncryptionActive; } public void setUploadEncryptionActive(boolean uploadEncryptionActive) { this.uploadEncryptionActive = uploadEncryptionActive; } public String getUploadStorageClass() { return this.uploadStorageClass; } public void setUploadStorageClass(String storageClass) { this.uploadStorageClass = storageClass; } public void setRememberPreferences(boolean rememberPreferences) { this.rememberPreferences = rememberPreferences; } public boolean isRememberPreferences() { return rememberPreferences; } public Properties toProperties() { Properties properties = new Properties(); properties.setProperty("upload-acl-permission", getUploadACLPermission()); properties.setProperty("upload-compression-active", isUploadCompressionActive() ? "true" : "false"); properties.setProperty("upload-encryption-active", isUploadEncryptionActive() ? "true" : "false"); properties.setProperty("upload-storage-class", getUploadStorageClass()); properties.setProperty("upload-encryption-algorithm", getEncryptionAlgorithm()); return properties; } public void fromProperties(Properties properties) { setRememberPreferences(true); setUploadACLPermission( properties.getProperty("upload-acl-permission", getUploadACLPermission())); setUploadCompressionActive( "true".equalsIgnoreCase(properties.getProperty("upload-compression-active"))); setUploadEncryptionActive( "true".equalsIgnoreCase(properties.getProperty("upload-encryption-active"))); setUploadStorageClass( properties.getProperty("upload-storage-class", getUploadStorageClass())); setEncryptionAlgorithm( properties.getProperty("upload-encryption-algorithm", getEncryptionAlgorithm())); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/utils/0002755000000000000000000000000011441613550016377 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/utils/FileCryptoTool.java0000644000000000000000000003577311441613550022175 0ustar package org.jets3t.apps.utils; /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2008 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.Provider; import java.security.Security; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidKeySpecException; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import javax.crypto.Cipher; import javax.crypto.CipherInputStream; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.PBEParameterSpec; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JTextField; /** * A rudimentary GUI and utility for encrypting and decrypting files in a way * that is compatible with JetS3t's cryptographic features. * * @author James Murty */ public class FileCryptoTool { private String algorithm = "PBEWithMD5AndDES"; private SecretKey key = null; private AlgorithmParameterSpec algParamSpec = null; private int iterationCount = 5000; private byte[] salt = { (byte)0xA4, (byte)0x0B, (byte)0xC8, (byte)0x34, (byte)0xD6, (byte)0x95, (byte)0xF3, (byte)0x13 }; static { try { Class bouncyCastleProviderClass = Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider"); if (bouncyCastleProviderClass != null) { Provider bouncyCastleProvider = (Provider) bouncyCastleProviderClass .getConstructor(new Class[] {}).newInstance(new Object[] {}); Security.addProvider(bouncyCastleProvider); } } catch (RuntimeException e) { throw e; } catch (Exception e) { System.err.println("Unable to load security provider BouncyCastleProvider"); } } public FileCryptoTool() { } public void init(String password, String algorithm, byte[] salt, int interationCount) throws NoSuchAlgorithmException, InvalidKeySpecException { this.algorithm = algorithm; this.salt = salt; this.iterationCount = interationCount; PBEKeySpec keyspec = new PBEKeySpec(password.toCharArray(), this.salt, this.iterationCount, 32); SecretKeyFactory skf = SecretKeyFactory.getInstance(algorithm); this.key = skf.generateSecret(keyspec); this.algParamSpec = new PBEParameterSpec(this.salt, this.iterationCount); } public void init(String password, String algorithm) throws NoSuchAlgorithmException, InvalidKeySpecException { init(password, algorithm, this.salt, this.iterationCount); } public void decryptFile(File inputFile, File outputFile) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IOException { Cipher cipher = Cipher.getInstance(this.algorithm); cipher.init(Cipher.DECRYPT_MODE, this.key, this.algParamSpec); transferFileData(inputFile, outputFile, cipher); } public void encryptFile(File inputFile, File outputFile) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IOException { Cipher cipher = Cipher.getInstance(this.algorithm); cipher.init(Cipher.ENCRYPT_MODE, this.key, this.algParamSpec); transferFileData(inputFile, outputFile, cipher); } protected void transferFileData(File inputFile, File outputFile, Cipher cipher) throws IOException { InputStream is = null; OutputStream os = null; try { os = new BufferedOutputStream(new FileOutputStream(outputFile)); is = new CipherInputStream(new BufferedInputStream(new FileInputStream(inputFile)), cipher); byte[] buffer = new byte[16384]; int read = -1; while ((read = is.read(buffer)) != -1) { os.write(buffer, 0, read); } } finally { if (os != null) os.close(); if (is != null) is.close(); } } protected void initGui(final JFrame frame) { final FileCryptoTool self = this; final File[] filesArray = new File[2]; JLabel inputFileLabel = new JLabel("Input file:"); final JTextField inputFileTextField = new JTextField(); JButton inputFileBrowseButton = new JButton("Browse"); inputFileBrowseButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { filesArray[0] = fileChooser("Input File", frame, false); if (filesArray[0] != null) { inputFileTextField.setText(filesArray[0].getAbsolutePath()); } else { inputFileTextField.setText(""); } } }); JLabel outputDirectoryLabel = new JLabel("Output directory:"); final JTextField outputDirectoryTextField = new JTextField(); JButton outputDirectoryBrowseButton = new JButton("Browse"); outputDirectoryBrowseButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { filesArray[1] = fileChooser("Output Directory", frame, true); if (filesArray[1] != null) { outputDirectoryTextField.setText(filesArray[1].getAbsolutePath()); } else { outputDirectoryTextField.setText(""); } } }); JLabel passwordLabel = new JLabel("Password:"); final JPasswordField passwordField = new JPasswordField(); JLabel passwordConfirmLabel = new JLabel("Password (confirm):"); final JPasswordField password2Field = new JPasswordField(); JLabel algorithmLabel = new JLabel("Algorithm:"); final JComboBox algorithmComboBox = new JComboBox(listAvailablePbeCiphers()); algorithmComboBox.setSelectedItem(this.algorithm.toUpperCase()); algorithmComboBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { self.algorithm = (String) algorithmComboBox.getSelectedItem(); } }); final JButton encryptButton = new JButton("Encrypt File"); final JButton decryptButton = new JButton("Decrypt File"); ActionListener buttonListener = new ActionListener() { public void actionPerformed(ActionEvent event) { try { if (inputFileTextField.getText().trim().length() == 0) { JOptionPane.showMessageDialog(frame, "Choose an input file"); } else if (outputDirectoryTextField.getText().trim().length() == 0) { JOptionPane.showMessageDialog(frame, "Choose an output directory"); } else if (passwordField.getPassword().length == 0 || password2Field.getPassword().length == 0) { JOptionPane.showMessageDialog(frame, "Enter your password twice"); } else if (!new String(passwordField.getPassword()).equals(new String(password2Field.getPassword()))) { JOptionPane.showMessageDialog(frame, "Password and confirmation password do not match"); } else { File inputFile = new File(inputFileTextField.getText().trim()); File outputDirectory = new File(outputDirectoryTextField.getText().trim()); File outputFile = new File(outputDirectory, inputFile.getName()); if (!outputDirectory.isDirectory()) { JOptionPane.showMessageDialog(frame, "The output directory is not valid"); } else if (inputFile.equals(outputFile)) { JOptionPane.showMessageDialog(frame, "Choose a different output directory from the one that contains the input file"); } else { boolean encrypting = event.getSource().equals(encryptButton); init(new String(passwordField.getPassword()), self.algorithm); if (encrypting) { encryptFile(inputFile, outputFile); } else { decryptFile(inputFile, outputFile); } JOptionPane.showMessageDialog(frame, "'" + inputFile.getName() + "' " + (encrypting ? "encrypted" : "decrypted") + " to: \n'" + outputFile.getAbsolutePath() + "'"); } } } catch (RuntimeException e) { throw e; } catch (Exception e) { JOptionPane.showMessageDialog(frame, "ERROR: " + e.getMessage()); } } }; encryptButton.addActionListener(buttonListener); decryptButton.addActionListener(buttonListener); Insets insetsDefault = new Insets(2, 3, 2, 3); JPanel inputsPanel = new JPanel(new GridBagLayout()); inputsPanel.add(inputFileLabel, new GridBagConstraints(0, 0, 1, 1, 0, 1, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); inputsPanel.add(inputFileTextField, new GridBagConstraints(1, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); inputsPanel.add(inputFileBrowseButton, new GridBagConstraints(2, 0, 1, 1, 0, 1, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsDefault, 0, 0)); inputsPanel.add(outputDirectoryLabel, new GridBagConstraints(0, 1, 1, 1, 0, 1, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); inputsPanel.add(outputDirectoryTextField, new GridBagConstraints(1, 1, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); inputsPanel.add(outputDirectoryBrowseButton, new GridBagConstraints(2, 1, 1, 1, 0, 1, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsDefault, 0, 0)); inputsPanel.add(passwordLabel, new GridBagConstraints(0, 2, 1, 1, 0, 1, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); inputsPanel.add(passwordField, new GridBagConstraints(1, 2, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); inputsPanel.add(passwordConfirmLabel, new GridBagConstraints(0, 3, 1, 1, 0, 1, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); inputsPanel.add(password2Field, new GridBagConstraints(1, 3, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); inputsPanel.add(algorithmLabel, new GridBagConstraints(0, 4, 1, 1, 0, 1, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); inputsPanel.add(algorithmComboBox, new GridBagConstraints(1, 4, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); JPanel buttonsPanel = new JPanel(new GridBagLayout()); buttonsPanel.add(encryptButton, new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsDefault, 0, 0)); buttonsPanel.add(decryptButton, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, insetsDefault, 0, 0)); frame.getContentPane().setLayout(new GridBagLayout()); frame.getContentPane().add(inputsPanel, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); frame.getContentPane().add(buttonsPanel, new GridBagConstraints(0, 1, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsDefault, 0, 0)); frame.pack(); frame.setVisible(true); } private File fileChooser(String title, JFrame frame, boolean dirOnly) { // Prompt user to choose their Cockpit home directory. JFileChooser fileChooser = new JFileChooser(); fileChooser.setAcceptAllFileFilterUsed(true); fileChooser.setDialogTitle(title); fileChooser.setFileSelectionMode( (dirOnly ? JFileChooser.DIRECTORIES_ONLY : JFileChooser.FILES_ONLY)); fileChooser.setApproveButtonText("Select " + (dirOnly ? "Directory" : "File")); int returnVal = fileChooser.showOpenDialog(frame); if (returnVal != JFileChooser.APPROVE_OPTION) { return null; } else { return fileChooser.getSelectedFile(); } } private static String[] listAvailablePbeCiphers() { Set ciphers = Security.getAlgorithms("Cipher"); Set pbeCiphers = new HashSet(); for (Iterator iter = ciphers.iterator(); iter.hasNext(); ) { String cipher = (String) iter.next(); if (cipher.toLowerCase().startsWith("pbe")) { pbeCiphers.add(cipher); } } return (String[]) pbeCiphers.toArray(new String[pbeCiphers.size()]); } public static void main(String[] args) throws Exception { FileCryptoTool fct = new FileCryptoTool(); JFrame frame = new JFrame("File Crypto Tool"); fct.initGui(frame); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/cockpitlite/0002755000000000000000000000000011537563564017570 5ustar jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/cockpitlite/CLObjectTableModel.java0000644000000000000000000001363111441613550023774 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2007 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.cockpitlite; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import javax.swing.table.DefaultTableModel; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.service.model.S3Object; /** * A table model to store {@link S3Object}s. * * @author James Murty */ public class CLObjectTableModel extends DefaultTableModel { private static final long serialVersionUID = 8570725021470237261L; private static final Log log = LogFactory.getLog(CLObjectTableModel.class); private ArrayList objectList = new ArrayList(); private String usersPath = ""; public CLObjectTableModel() { super(new String[] {"File","Size","Last Modified","Public?"}, 0); } public void setUsersPath(String usersPath) { this.usersPath = usersPath; } private void sanitizeObjectKey(S3Object object) { if (object.getKey().startsWith(usersPath)) { object.setKey(object.getKey().substring(usersPath.length())); } } public int addObject(S3Object object) { sanitizeObjectKey(object); int insertRow = Collections.binarySearch(objectList, object, new Comparator() { public int compare(Object o1, Object o2) { return ((S3Object)o1).getKey().compareToIgnoreCase(((S3Object)o2).getKey()); } }); String aclStatus = null; if (insertRow >= 0) { // Retain the object's ACL status if it's available. aclStatus = (String) this.getValueAt(insertRow, 3); // We already have an item with this key, replace it. objectList.remove(insertRow); this.removeRow(insertRow); } else { insertRow = (-insertRow) - 1; } if (object.getAcl() != null || aclStatus == null) { aclStatus = CockpitLite.getAclDescription(object.getAcl()); } // New object to insert. objectList.add(insertRow, object); this.insertRow(insertRow, new Object[] {object.getKey(), new Long(object.getContentLength()), object.getLastModifiedDate(), aclStatus}); return insertRow; } public int updateObjectAclStatus(S3Object objectWithAcl, String aclStatus) { sanitizeObjectKey(objectWithAcl); int updateRow = Collections.binarySearch(objectList, objectWithAcl, new Comparator() { public int compare(Object o1, Object o2) { return ((S3Object)o1).getKey().compareToIgnoreCase(((S3Object)o2).getKey()); } }); if (updateRow >= 0) { this.setValueAt(aclStatus, updateRow, 3); } else { // Object isn't in table! log.warn("Cannot find object named '" + objectWithAcl.getKey() + "' in objects table"); } return updateRow; } public String getObjectAclStatus(S3Object objectWithAcl) { synchronized (objectList) { int updateRow = Collections.binarySearch(objectList, objectWithAcl, new Comparator() { public int compare(Object o1, Object o2) { return ((S3Object)o1).getKey().compareToIgnoreCase(((S3Object)o2).getKey()); } }); if (updateRow >= 0) { return (String) this.getValueAt(updateRow, 3); } else { return null; } } } public void addObjects(S3Object[] objects) { for (int i = 0; i < objects.length; i++) { addObject(objects[i]); } } public void removeObject(S3Object object) { sanitizeObjectKey(object); int row = Collections.binarySearch(objectList, object, new Comparator() { public int compare(Object o1, Object o2) { return ((S3Object)o1).getKey().compareToIgnoreCase(((S3Object)o2).getKey()); } }); if (row >= 0) { this.removeRow(row); objectList.remove(row); } } public void removeAllObjects() { int rowCount = this.getRowCount(); for (int i = 0; i < rowCount; i++) { this.removeRow(0); } objectList.clear(); } public S3Object getObject(int row) { synchronized (objectList) { return (S3Object) objectList.get(row); } } public S3Object[] getObjects() { synchronized (objectList) { return (S3Object[]) objectList.toArray(new S3Object[objectList.size()]); } } public boolean isCellEditable(int row, int column) { return false; } public Class getColumnClass(int columnIndex) { if (columnIndex == 0) { return String.class; } else if (columnIndex == 1) { return Long.class; } else if (columnIndex == 2) { return Date.class; } else { return String.class; } } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/cockpitlite/CockpitLite.java0000644000000000000000000034201411550441700022625 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2007 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.cockpitlite; import java.awt.CardLayout; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Rectangle; import java.awt.datatransfer.DataFlavor; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.io.File; import java.io.IOException; import java.net.URL; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; import javax.swing.JApplet; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.ListSelectionModel; import javax.swing.LookAndFeel; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.DefaultTableCellRenderer; import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.NTCredentials; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.httpclient.auth.AuthScheme; import org.apache.commons.httpclient.auth.CredentialsNotAvailableException; import org.apache.commons.httpclient.auth.CredentialsProvider; import org.apache.commons.httpclient.auth.NTLMScheme; import org.apache.commons.httpclient.auth.RFC2617Scheme; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.gui.AuthenticationDialog; import org.jets3t.gui.ErrorDialog; import org.jets3t.gui.GuiUtils; import org.jets3t.gui.HyperlinkActivatedListener; import org.jets3t.gui.ItemPropertiesDialog; import org.jets3t.gui.ProgressDialog; import org.jets3t.gui.ProgressPanel; import org.jets3t.gui.TableSorter; import org.jets3t.gui.UserInputFields; import org.jets3t.gui.skins.SkinsFactory; import org.jets3t.service.Constants; import org.jets3t.service.Jets3tProperties; import org.jets3t.service.S3ServiceException; import org.jets3t.service.acl.AccessControlList; import org.jets3t.service.acl.GrantAndPermission; import org.jets3t.service.acl.GroupGrantee; import org.jets3t.service.acl.Permission; import org.jets3t.service.impl.rest.httpclient.RestS3Service; import org.jets3t.service.io.BytesProgressWatcher; import org.jets3t.service.model.S3Bucket; import org.jets3t.service.model.S3Object; import org.jets3t.service.multithread.CancelEventTrigger; import org.jets3t.service.multithread.CopyObjectsEvent; import org.jets3t.service.multithread.CreateBucketsEvent; import org.jets3t.service.multithread.CreateObjectsEvent; import org.jets3t.service.multithread.DeleteObjectsEvent; import org.jets3t.service.multithread.DeleteVersionedObjectsEvent; import org.jets3t.service.multithread.DownloadObjectsEvent; import org.jets3t.service.multithread.DownloadPackage; import org.jets3t.service.multithread.GetObjectHeadsEvent; import org.jets3t.service.multithread.GetObjectsEvent; import org.jets3t.service.multithread.ListObjectsEvent; import org.jets3t.service.multithread.LookupACLEvent; import org.jets3t.service.multithread.S3ServiceEventListener; import org.jets3t.service.multithread.S3ServiceMulti; import org.jets3t.service.multithread.ServiceEvent; import org.jets3t.service.multithread.ThreadWatcher; import org.jets3t.service.multithread.UpdateACLEvent; import org.jets3t.service.utils.ByteFormatter; import org.jets3t.service.utils.FileComparer; import org.jets3t.service.utils.FileComparerResults; import org.jets3t.service.utils.ObjectUtils; import org.jets3t.service.utils.ServiceUtils; import org.jets3t.service.utils.TimeFormatter; import org.jets3t.service.utils.gatekeeper.GatekeeperMessage; import org.jets3t.service.utils.gatekeeper.SignatureRequest; import org.jets3t.service.utils.signedurl.GatekeeperClientUtils; import org.jets3t.service.utils.signedurl.SignedUrlAndObject; import com.centerkey.utils.BareBonesBrowserLaunch; /** * CockpitLite is a graphical Java application for viewing and managing the * contents of an Amazon S3 account, where the S3 account is not owned by the * application's user directly but is made available by a service provider. * The service provider uses the Gatekeeper application to mediate the user's * access to the S3 account, authorizing each of the user's interactions before * it can be executed. *

* CockpitLite Guide. *

* This is the CockpitLite application class; it may be run as a stand-alone * application or as an Applet. * * @author jmurty */ public class CockpitLite extends JApplet implements S3ServiceEventListener, ActionListener, ListSelectionListener, HyperlinkActivatedListener, CredentialsProvider { private static final long serialVersionUID = 4969295009540293079L; private static final Log log = LogFactory.getLog(CockpitLite.class); private static final String PROPERTIES_FILENAME = "cockpitlite.properties"; public static final String APPLICATION_DESCRIPTION = "Cockpit Lite/" + Constants.JETS3T_VERSION; public static final String APPLICATION_TITLE = "JetS3t Cockpit Lite"; private final Insets insetsZero = new Insets(0, 0, 0, 0); private final Insets insetsDefault = new Insets(5, 7, 5, 7); private final ByteFormatter byteFormatter = new ByteFormatter(); private final ByteFormatter byteFormatterTerse = new ByteFormatter("G","M","K","B",1); private final TimeFormatter timeFormatterTerse = new TimeFormatter("h","h","m","m","s","s"); private final SimpleDateFormat yearAndTimeSDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); private final SimpleDateFormat timeSDF = new SimpleDateFormat("HH:mm:ss"); private final GuiUtils guiUtils = new GuiUtils(); private Jets3tProperties cockpitLiteProperties = null; private static final String ACL_PRIVATE_DESCRIPTION = "Private"; private static final String ACL_PUBLIC_DESCRIPTION = "Public"; private static final String ACL_UNKNOWN_DESCRIPTION = "?"; /** * Properties set in stand-alone application from the command line arguments. */ private Properties standAloneArgumentProperties = null; /** * Stores the active ProgressPanel objects that track event progress. */ private final Map progressPanelMap = new HashMap(); private final Object lock = new Object(); /** * Multi-threaded S3 service used by the application. */ private S3ServiceMulti s3ServiceMulti = null; private GatekeeperClientUtils gkClient = null; private String userBucketName = null; private String userVanityHost = null; private String userPath = ""; private boolean userCanUpload = false; private boolean userCanDownload = false; private boolean userCanDelete = false; private boolean userCanACL = false; private boolean isRunningAsApplet = false; private Frame ownerFrame = null; private boolean isStandAloneApplication = false; private SkinsFactory skinsFactory = null; /* * HTTP connection settings for communication *with Gatekeeper only*, the * S3 connection parameters are set in the jets3t.properties file. */ public static final int HTTP_CONNECTION_TIMEOUT = 60000; public static final int SOCKET_CONNECTION_TIMEOUT = 60000; public static final int MAX_CONNECTION_RETRIES = 5; private JPanel stackPanel = null; private CardLayout stackPanelCardLayout = null; // Object main menu items private JPopupMenu objectActionMenu = null; private JMenuItem viewObjectPropertiesMenuItem = null; private JMenuItem refreshObjectMenuItem = null; private JMenuItem togglePublicMenuItem = null; private JMenuItem downloadObjectMenuItem = null; private JMenuItem uploadFilesMenuItem = null; private JMenuItem generatePublicGetUrl = null; private JMenuItem deleteObjectMenuItem = null; // Login panel items private JPanel loginPanel = null; private JButton loginButton = null; // Objects table private JLabel objectsHeadingLabel = null; private JTable objectsTable = null; private JScrollPane objectsTableSP = null; private CLObjectTableModel objectTableModel = null; private TableSorter objectTableModelSorter = null; // Progress notification aea private JPanel progressNotificationPanel = null; private JLabel objectsSummaryLabel = null; private ProgressDialog progressDialog = null; private UserInputFields userInputFields = null; // Class variables used for uploading or downloading files. private File downloadDirectory = null; private Map downloadObjectsToFileMap = null; private boolean isDownloadingObjects = false; private boolean isUploadingFiles = false; private Map filesAlreadyInDownloadDirectoryMap = null; private Map s3DownloadObjectsMap = null; private Map objectKeyToFilepathMap = null; private Map s3ExistingObjectsMap = null; private File fileChoosersLastUploadDirectory = null; private JPanel filterObjectsPanel = null; private JCheckBox filterObjectsCheckBox = null; private JTextField filterObjectsPrefix = null; // File comparison options private static final String UPLOAD_NEW_FILES_ONLY = "Only upload new file(s)"; private static final String UPLOAD_NEW_AND_CHANGED_FILES = "Upload new and changed file(s)"; private static final String UPLOAD_ALL_FILES = "Upload all files"; private static final String DOWNLOAD_NEW_FILES_ONLY = "Only download new file(s)"; private static final String DOWNLOAD_NEW_AND_CHANGED_FILES = "Download new and changed file(s)"; private static final String DOWNLOAD_ALL_FILES = "Download all files"; /** * Flag used to indicate the "viewing objects" application state. */ private boolean isViewingObjectProperties = false; /** * Constructor to run this application as an Applet. */ public CockpitLite() { isRunningAsApplet = true; } /** * Constructor to run this application in a stand-alone window. * * @param ownerFrame the frame the application will be displayed in * @throws S3ServiceException */ public CockpitLite(JFrame ownerFrame, Properties standAloneArgumentProperties) throws S3ServiceException { this.ownerFrame = ownerFrame; this.standAloneArgumentProperties = standAloneArgumentProperties; isStandAloneApplication = true; init(); ownerFrame.getContentPane().add(this); ownerFrame.setBounds(this.getBounds()); ownerFrame.setVisible(true); } /** * Prepares application to run as a GUI by finding/creating a root owner JFrame, creating an * un-authenticated {@link RestS3Service} and loading properties files. */ @Override public void init() { super.init(); // Find or create a Frame to own modal dialog boxes. if (this.ownerFrame == null) { Component c = this; while (!(c instanceof Frame) && c.getParent() != null) { c = c.getParent(); } if (!(c instanceof Frame)) { this.ownerFrame = new JFrame(); } else { this.ownerFrame = (Frame) c; } } cockpitLiteProperties = Jets3tProperties.getInstance(PROPERTIES_FILENAME); boolean isMissingRequiredInitProperty = false; if (isRunningAsApplet) { // Read parameters for Applet, based on names specified in the uploader properties. String appletParamNames = cockpitLiteProperties.getStringProperty("applet.params", ""); StringTokenizer st = new StringTokenizer(appletParamNames, ","); while (st.hasMoreTokens()) { String paramName = st.nextToken(); String paramValue = this.getParameter(paramName); // Fatal error if a parameter is missing. if (null == paramValue) { log.error("Missing required applet parameter: " + paramName); isMissingRequiredInitProperty = true; } else { log.debug("Found applet parameter: " + paramName + "='" + paramValue + "'"); // Set params as properties in the central properties source for this application. // Note that parameter values will over-write properties with the same name. cockpitLiteProperties.setProperty(paramName, paramValue); } } } else { // Add application parameters properties. if (standAloneArgumentProperties != null) { Enumeration e = standAloneArgumentProperties.keys(); while (e.hasMoreElements()) { String propName = (String) e.nextElement(); String propValue = standAloneArgumentProperties.getProperty(propName); // Fatal error if a parameter is missing. if (null == propValue) { log.error("Missing required command-line property: " + propName); isMissingRequiredInitProperty = true; } else { log.debug("Using command-line property: " + propName + "='" + propValue + "'"); // Set arguments as properties in the central properties source for this application. // Note that argument values will over-write properties with the same name. cockpitLiteProperties.setProperty(propName, propValue); } } } } // Initialise the GUI. initGui(); if (isMissingRequiredInitProperty) { String message = "Missing one or more required application properties"; log.error(message); ErrorDialog.showDialog(ownerFrame, this, cockpitLiteProperties.getProperties(), message, null); System.exit(1); } String gatekeeperUrl = cockpitLiteProperties.getStringProperty("gatekeeperUrl", null); if (gatekeeperUrl == null) { String message = "Application properties file '" + PROPERTIES_FILENAME + "' is not available"; log.error(message); ErrorDialog.showDialog(ownerFrame, this, cockpitLiteProperties.getProperties(), message, null); System.exit(1); } gkClient = new GatekeeperClientUtils( gatekeeperUrl, APPLICATION_DESCRIPTION, MAX_CONNECTION_RETRIES, HTTP_CONNECTION_TIMEOUT, this); // Initialise a non-authenticated service. try { // Revert to anonymous service. s3ServiceMulti = new S3ServiceMulti( new RestS3Service(null, APPLICATION_DESCRIPTION, this), this); } catch (S3ServiceException e) { String message = "Unable to start anonymous service"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, this, cockpitLiteProperties.getProperties(), message, e); } } /** * Initialises the application's GUI elements. */ private void initGui() { // Initialise skins factory. skinsFactory = SkinsFactory.getInstance(cockpitLiteProperties.getProperties()); // Set Skinned Look and Feel. LookAndFeel lookAndFeel = skinsFactory.createSkinnedMetalTheme("SkinnedLookAndFeel"); try { UIManager.setLookAndFeel(lookAndFeel); } catch (UnsupportedLookAndFeelException e) { log.error("Unable to set skinned LookAndFeel", e); } // Primary panel that contains all other items. JPanel primaryPanel = skinsFactory.createSkinnedJPanel("PrimaryPanel"); primaryPanel.setLayout(new GridBagLayout()); this.getContentPane().add(primaryPanel); // Setup the stack panel, which contains all other panels as a stack. stackPanel = skinsFactory.createSkinnedJPanel("StackPanel"); stackPanelCardLayout = new CardLayout(); stackPanel.setLayout(stackPanelCardLayout); primaryPanel.add(stackPanel, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsZero, 0, 0)); // Progress notification panel progressNotificationPanel = skinsFactory.createSkinnedJPanel("ProgressNotificationPanel"); progressNotificationPanel.setLayout(new GridBagLayout()); primaryPanel.add(progressNotificationPanel, new GridBagConstraints(0, 1, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 0, 5, 0), 0, 0)); int row = 0; // Login panel. row = 0; loginPanel = skinsFactory.createSkinnedJPanel("LoginPanel"); loginPanel.setLayout(new GridBagLayout()); userInputFields = new UserInputFields(insetsDefault, null, skinsFactory); userInputFields.buildFieldsPanel(loginPanel, cockpitLiteProperties); loginButton = skinsFactory.createSkinnedJButton("LoginButton"); loginButton.setText("Log me in"); loginButton.addActionListener(this); loginPanel.add(loginButton, new GridBagConstraints(0, loginPanel.getComponentCount(), 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsDefault, 0, 0)); // Filter panel. filterObjectsPanel = skinsFactory.createSkinnedJPanel("FilterPanel"); filterObjectsPanel.setLayout(new GridBagLayout()); filterObjectsPrefix = skinsFactory.createSkinnedJTextField("FilterPrefix"); filterObjectsPrefix.setToolTipText("Only show files starting with this string"); filterObjectsPrefix.addActionListener(this); filterObjectsPrefix.setActionCommand("RefreshObjects"); JLabel filterPrefixLabel = skinsFactory.createSkinnedJHtmlLabel("FilterPrefixLable", this); filterPrefixLabel.setText("File name starts with: "); filterObjectsPanel.add(filterPrefixLabel, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, insetsZero, 0, 0)); filterObjectsPanel.add(filterObjectsPrefix, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); filterObjectsPanel.setVisible(false); // Objects panel. row = 0; JPanel objectsPanel = skinsFactory.createSkinnedJPanel("ObjectsPanel"); objectsPanel.setLayout(new GridBagLayout()); filterObjectsCheckBox = skinsFactory.createSkinnedJCheckBox("FilterCheckbox"); filterObjectsCheckBox.setText("Search files"); filterObjectsCheckBox.setEnabled(true); filterObjectsCheckBox.addActionListener(this); filterObjectsCheckBox.setToolTipText("Check this option to search your files"); objectsHeadingLabel = skinsFactory.createSkinnedJHtmlLabel("ObjectsHeadingLabel", this); objectsHeadingLabel.setText("Not logged in"); objectsPanel.add(objectsHeadingLabel, new GridBagConstraints(0, row, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsZero, 0, 0)); objectsPanel.add(filterObjectsCheckBox, new GridBagConstraints(1, row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, insetsZero, 0, 0)); JButton objectActionButton = skinsFactory.createSkinnedJButton("ObjectMenuButton"); objectActionButton.setToolTipText("File actions menu"); guiUtils.applyIcon(objectActionButton, "/images/nuvola/16x16/actions/misc.png"); objectActionButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JButton sourceButton = (JButton) e.getSource(); objectActionMenu.show(sourceButton, 0, sourceButton.getHeight()); } }); objectsPanel.add(objectActionButton, new GridBagConstraints(2, row, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, insetsZero, 0, 0)); objectsPanel.add(filterObjectsPanel, new GridBagConstraints(0, ++row, 3, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insetsZero, 0, 0)); objectsTable = skinsFactory.createSkinnedJTable("ObjectsTable"); objectTableModel = new CLObjectTableModel(); objectTableModelSorter = new TableSorter(objectTableModel); objectTableModelSorter.setTableHeader(objectsTable.getTableHeader()); objectsTable.setModel(objectTableModelSorter); objectsTable.setDefaultRenderer(Long.class, new DefaultTableCellRenderer() { private static final long serialVersionUID = 7229656175879985698L; @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { String formattedSize = byteFormatter.formatByteSize(((Long)value).longValue()); return super.getTableCellRendererComponent(table, formattedSize, isSelected, hasFocus, row, column); } }); objectsTable.setDefaultRenderer(Date.class, new DefaultTableCellRenderer() { private static final long serialVersionUID = -4983176028291916397L; @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Date date = (Date) value; return super.getTableCellRendererComponent(table, yearAndTimeSDF.format(date), isSelected, hasFocus, row, column); } }); objectsTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); objectsTable.getSelectionModel().addListSelectionListener(this); objectsTable.setShowHorizontalLines(true); objectsTable.setShowVerticalLines(true); objectsTable.addMouseListener(new ContextMenuListener()); objectsTableSP = skinsFactory.createSkinnedJScrollPane("ObjectsTableSP", objectsTable); objectsPanel.add(objectsTableSP, new GridBagConstraints(0, ++row, 3, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsZero, 0, 0)); objectsSummaryLabel = skinsFactory.createSkinnedJHtmlLabel("ObjectsSummary", this); objectsSummaryLabel.setHorizontalAlignment(JLabel.CENTER); objectsSummaryLabel.setFocusable(false); objectsPanel.add(objectsSummaryLabel, new GridBagConstraints(0, ++row, 3, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); // Object action menu. objectActionMenu = skinsFactory.createSkinnedJPopupMenu("ObjectPopupMenu"); refreshObjectMenuItem = skinsFactory.createSkinnedJMenuItem("RefreshMenuItem"); refreshObjectMenuItem.setText("Refresh file listing"); refreshObjectMenuItem.setActionCommand("RefreshObjects"); refreshObjectMenuItem.addActionListener(this); guiUtils.applyIcon(refreshObjectMenuItem, "/images/nuvola/16x16/actions/reload.png"); objectActionMenu.add(refreshObjectMenuItem); viewObjectPropertiesMenuItem = skinsFactory.createSkinnedJMenuItem("PropertiesMenuItem"); viewObjectPropertiesMenuItem.setText("View file properties..."); viewObjectPropertiesMenuItem.setActionCommand("ViewObjectProperties"); viewObjectPropertiesMenuItem.addActionListener(this); guiUtils.applyIcon(viewObjectPropertiesMenuItem, "/images/nuvola/16x16/actions/viewmag.png"); objectActionMenu.add(viewObjectPropertiesMenuItem); downloadObjectMenuItem = skinsFactory.createSkinnedJMenuItem("DownloadMenuItem"); downloadObjectMenuItem.setText("Download file(s)..."); downloadObjectMenuItem.setActionCommand("DownloadObjects"); downloadObjectMenuItem.addActionListener(this); guiUtils.applyIcon(downloadObjectMenuItem, "/images/nuvola/16x16/actions/1downarrow.png"); objectActionMenu.add(downloadObjectMenuItem); uploadFilesMenuItem = skinsFactory.createSkinnedJMenuItem("UploadMenuItem"); uploadFilesMenuItem.setText("Upload file(s)..."); uploadFilesMenuItem.setActionCommand("UploadFiles"); uploadFilesMenuItem.addActionListener(this); guiUtils.applyIcon(uploadFilesMenuItem, "/images/nuvola/16x16/actions/1uparrow.png"); objectActionMenu.add(uploadFilesMenuItem); objectActionMenu.add(new JSeparator()); togglePublicMenuItem = skinsFactory.createSkinnedJMenuItem("AclToggleMenuItem"); togglePublicMenuItem.setText("Change privacy setting..."); togglePublicMenuItem.setActionCommand("TogglePublicPrivate"); togglePublicMenuItem.addActionListener(this); guiUtils.applyIcon(togglePublicMenuItem, "/images/nuvola/16x16/actions/encrypted.png"); objectActionMenu.add(togglePublicMenuItem); generatePublicGetUrl = skinsFactory.createSkinnedJMenuItem("PublicUrlMenuItem"); generatePublicGetUrl.setText("Public web link..."); generatePublicGetUrl.setActionCommand("GeneratePublicGetURL"); generatePublicGetUrl.addActionListener(this); guiUtils.applyIcon(generatePublicGetUrl, "/images/nuvola/16x16/actions/wizard.png"); objectActionMenu.add(generatePublicGetUrl); objectActionMenu.add(new JSeparator()); deleteObjectMenuItem = skinsFactory.createSkinnedJMenuItem("DeleteMenuItem"); deleteObjectMenuItem.setText("Delete file(s)..."); deleteObjectMenuItem.setActionCommand("DeleteObjects"); deleteObjectMenuItem.addActionListener(this); guiUtils.applyIcon(deleteObjectMenuItem, "/images/nuvola/16x16/actions/cancel.png"); objectActionMenu.add(deleteObjectMenuItem); viewObjectPropertiesMenuItem.setEnabled(false); refreshObjectMenuItem.setEnabled(false); togglePublicMenuItem.setEnabled(false); downloadObjectMenuItem.setEnabled(false); generatePublicGetUrl.setEnabled(false); deleteObjectMenuItem.setEnabled(false); // Card layout in stack panel stackPanel.add(loginPanel, "LoginPanel"); stackPanel.add(objectsPanel, "ObjectsPanel"); // Set preferred sizes int preferredWidth = 800; int preferredHeight = 600; this.setBounds(new Rectangle(new Dimension(preferredWidth, preferredHeight))); // Initialize drop target. initDropTarget(new JComponent[] {objectsPanel} ); objectsPanel.getDropTarget().setActive(true); } /** * Initialise the application's File drop targets for drag and drop copying of local files * to S3. * * @param dropTargetComponents * the components files can be dropped on to transfer them to S3 */ private void initDropTarget(JComponent[] dropTargetComponents) { DropTargetListener dropTargetListener = new DropTargetListener() { private boolean checkValidDrag(DropTargetDragEvent dtde) { if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor) && (DnDConstants.ACTION_COPY == dtde.getDropAction() || DnDConstants.ACTION_MOVE == dtde.getDropAction())) { dtde.acceptDrag(dtde.getDropAction()); return true; } else { dtde.rejectDrag(); return false; } } public void dragEnter(DropTargetDragEvent dtde) { if (checkValidDrag(dtde)) { SwingUtilities.invokeLater(new Runnable() { public void run() { objectsTable.requestFocusInWindow(); }; }); } } public void dragOver(DropTargetDragEvent dtde) { checkValidDrag(dtde); } public void dropActionChanged(DropTargetDragEvent dtde) { if (checkValidDrag(dtde)) { SwingUtilities.invokeLater(new Runnable() { public void run() { objectsTable.requestFocusInWindow(); }; }); } else { SwingUtilities.invokeLater(new Runnable() { public void run() { ownerFrame.requestFocusInWindow(); }; }); } } public void dragExit(DropTargetEvent dte) { SwingUtilities.invokeLater(new Runnable() { public void run() { ownerFrame.requestFocusInWindow(); }; }); } public void drop(DropTargetDropEvent dtde) { if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor) && (DnDConstants.ACTION_COPY == dtde.getDropAction() || DnDConstants.ACTION_MOVE == dtde.getDropAction())) { dtde.acceptDrop(dtde.getDropAction()); try { final List fileList = (List) dtde.getTransferable().getTransferData( DataFlavor.javaFileListFlavor); if (fileList != null && fileList.size() > 0) { new Thread() { @Override public void run() { prepareForFilesUpload((File[]) fileList.toArray(new File[fileList.size()])); } }.start(); } } catch (Exception e) { String message = "Unable to start accept dropped item(s)"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, null, cockpitLiteProperties.getProperties(), message, e); } } else { dtde.rejectDrop(); } } }; // Attach drop target listener to each target component. for (int i = 0; i < dropTargetComponents.length; i++) { new DropTarget(dropTargetComponents[i], DnDConstants.ACTION_COPY, dropTargetListener, true); } } /** * Starts a progress display dialog. While the dialog is running the user cannot interact * with the application, except to cancel the task. * * @param statusMessage * describes the status of a task text meaningful to the user, such as "3 files of 7 uploaded" * @param detailsText * describes the status of a task in more detail, such as the current transfer rate and Time remaining. * @param minTaskValue the minimum progress value for a task, generally 0 * @param maxTaskValue * the maximum progress value for a task, such as the total number of threads or 100 if * using percentage-complete as a metric. * @param cancelEventListener * listener that is responsible for cancelling a long-lived task when the user clicks * the cancel button. If a task cannot be cancelled this must be null. * @param cancelButtonText * text displayed in the cancel button if a task can be cancelled. This is only used if * a cancel event listener is provided. */ private void startProgressDialog(final String statusMessage, final String detailsText, final int minTaskValue, final int maxTaskValue, final String cancelButtonText, final CancelEventTrigger cancelEventListener) { if (this.progressDialog == null) { this.progressDialog = new ProgressDialog( this.ownerFrame, "Please wait...", cockpitLiteProperties.getProperties()); } this.getContentPane().setCursor(new Cursor(Cursor.WAIT_CURSOR)); SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.startDialog(statusMessage, detailsText, minTaskValue, maxTaskValue, cancelEventListener, cancelButtonText); } }); } /** * Updates the status text and value of the progress display dialog. * @param statusMessage * describes the status of a task text meaningful to the user, such as "3 files of 7 uploaded" * @param detailsText * describes the status of a task in more detail, such as the current transfer rate and time remaining. * @param progressValue * value representing how far through the task we are (relative to min and max values) */ private void updateProgressDialog(final String statusMessage, final String detailsText, final int progressValue) { SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.updateDialog(statusMessage, detailsText, progressValue); } }); } /** * Stops/halts the progress display dialog and allows the user to interact with the application. */ private void stopProgressDialog() { this.getContentPane().setCursor(null); SwingUtilities.invokeLater(new Runnable() { public void run() { progressDialog.stopDialog(); } }); } protected void startProgressPanel(Object operationId, String statusMessage, int maxCount, CancelEventTrigger cancelEventTrigger) { // Create new progress panel. final ProgressPanel progressPanel = new ProgressPanel( cockpitLiteProperties.getProperties(), cancelEventTrigger); progressPanel.startProgress(statusMessage, 0, maxCount); // Store this panel against the operation ID it tracks. progressPanelMap.put(operationId, progressPanel); // Display panel in progress notification area. SwingUtilities.invokeLater(new Runnable() { public void run() { progressNotificationPanel.add(progressPanel, new GridBagConstraints(0, progressNotificationPanel.getComponents().length, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsZero, 0, 0)); progressNotificationPanel.revalidate(); } }); } protected void updateProgressPanel(Object operationId, final String statusMessage, final int currentCount) { // Retrieve progress panel. final ProgressPanel progressPanel = (ProgressPanel) progressPanelMap.get(operationId); if (progressPanel != null) { SwingUtilities.invokeLater(new Runnable() { public void run() { progressPanel.updateProgress(statusMessage, currentCount); } }); } } protected void stopProgressPanel(Object operationId) { // Retrieve progress panel. final ProgressPanel progressPanel = (ProgressPanel) progressPanelMap.get(operationId); if (progressPanel != null) { SwingUtilities.invokeLater(new Runnable() { public void run() { progressNotificationPanel.remove(progressPanel); progressNotificationPanel.revalidate(); progressPanelMap.remove(progressPanel); progressPanel.dispose(); } }); } } /** * Event handler for this application, handles all menu items. */ public void actionPerformed(ActionEvent event) { if (event.getSource().equals(loginButton)) { new Thread() { @Override public void run() { listObjects(); } }.start(); } // Object Events else if ("ViewObjectProperties".equals(event.getActionCommand())) { listObjectProperties(); } else if ("RefreshObjects".equals(event.getActionCommand())) { new Thread() { @Override public void run() { listObjects(); } }.start(); } else if ("TogglePublicPrivate".equals(event.getActionCommand())) { new Thread() { @Override public void run() { S3Object object = getSelectedObjects()[0]; String aclStatus = objectTableModel.getObjectAclStatus(object); boolean originalAclWasPublic = ACL_PUBLIC_DESCRIPTION.equals(aclStatus); ToggleAclDialog dialog = new ToggleAclDialog(ownerFrame, originalAclWasPublic, null, cockpitLiteProperties.getProperties()); dialog.setVisible(true); // Update ACL setting. S3Object minimalObject = new S3Object(object.getKey()); AccessControlList newAcl = (dialog.isPublicAclSet() ? AccessControlList.REST_CANNED_PUBLIC_READ : AccessControlList.REST_CANNED_PRIVATE); if (newAcl != null) { if (AccessControlList.REST_CANNED_PRIVATE.equals(newAcl)) { minimalObject.addMetadata(Constants.REST_HEADER_PREFIX + "acl", "private"); } else if (AccessControlList.REST_CANNED_PUBLIC_READ.equals(newAcl)) { minimalObject.addMetadata(Constants.REST_HEADER_PREFIX + "acl", "public-read"); } } updateObjectsAccessControlLists( new S3Object[] {minimalObject}, newAcl); dialog.dispose(); } }.start(); } else if ("GeneratePublicGetURL".equals(event.getActionCommand())) { generatePublicGetUrl(); } else if ("DeleteObjects".equals(event.getActionCommand())) { deleteSelectedObjects(); } else if ("DownloadObjects".equals(event.getActionCommand())) { try { downloadSelectedObjects(); } catch (Exception ex) { String message = "Unable to download objects from S3"; log.error(message, ex); ErrorDialog.showDialog(ownerFrame, this, cockpitLiteProperties.getProperties(), message, ex); } } else if ("UploadFiles".equals(event.getActionCommand())) { JFileChooser fileChooser = new JFileChooser(); fileChooser.setMultiSelectionEnabled(true); fileChooser.setDialogTitle("Choose file(s) to upload"); fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); fileChooser.setApproveButtonText("Upload files"); fileChooser.setCurrentDirectory(fileChoosersLastUploadDirectory); int returnVal = fileChooser.showOpenDialog(ownerFrame); if (returnVal != JFileChooser.APPROVE_OPTION) { return; } final File[] uploadFiles = fileChooser.getSelectedFiles(); if (uploadFiles.length == 0) { return; } // Save the chosen directory location for next time. fileChoosersLastUploadDirectory = uploadFiles[0].getParentFile(); new Thread() { @Override public void run() { prepareForFilesUpload(uploadFiles); } }.start(); } else if (event.getSource().equals(filterObjectsCheckBox)) { if (filterObjectsCheckBox.isSelected()) { filterObjectsPanel.setVisible(true); } else { filterObjectsPanel.setVisible(false); filterObjectsPrefix.setText(""); } } // Ooops... else { log.warn("Unrecognised ActionEvent command '" + event.getActionCommand() + "' in " + event); } } /** * Handles list selection events for this application. */ public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting()) { return; } if (e.getSource().equals(objectsTable.getSelectionModel())) { objectSelectedAction(); } } private void listObjects() { try { // Obtain login details from application's login screen and store them in // the application properties so the details will be forwarded to the Gatekeeper // with each request. Properties loginProperties = userInputFields.getUserInputsAsProperties(true); Iterator iter = loginProperties.keySet().iterator(); while (iter.hasNext()) { String propertyName = (String) iter.next(); String propertyValue = loginProperties.getProperty(propertyName); cockpitLiteProperties.setProperty(propertyName, propertyValue); } startProgressPanel(this, "Finding files", 0, null); // Perform object listing operation via Gatekeeper. Map requestProperties = new HashMap(); requestProperties.put(GatekeeperMessage.LIST_OBJECTS_IN_BUCKET_FLAG, ""); requestProperties.putAll(cockpitLiteProperties.getProperties()); if (filterObjectsCheckBox.isSelected() && filterObjectsPrefix.getText().length() > 0) { requestProperties.put("Prefix", filterObjectsPrefix.getText()); } GatekeeperMessage responseMessage = gkClient.requestActionThroughGatekeeper( null, null, new S3Object[] {}, requestProperties); stopProgressPanel(this); String gatekeeperErrorCode = responseMessage.getApplicationProperties() .getProperty(GatekeeperMessage.APP_PROPERTY_GATEKEEPER_ERROR_CODE); if (gatekeeperErrorCode == null) { // Listing succeeded final S3Object[] objects = gkClient.buildS3ObjectsFromSignatureRequests( responseMessage.getSignatureRequests()); // User account description provided by Gatekeeper final String accountDescription = responseMessage.getApplicationProperties().getProperty("AccountDescription"); // User's settings userCanUpload = "true".equalsIgnoreCase( responseMessage.getApplicationProperties().getProperty("UserCanUpload")); userCanDownload = "true".equalsIgnoreCase( responseMessage.getApplicationProperties().getProperty("UserCanDownload")); userCanDelete = "true".equalsIgnoreCase( responseMessage.getApplicationProperties().getProperty("UserCanDelete")); userCanACL = "true".equalsIgnoreCase( responseMessage.getApplicationProperties().getProperty("UserCanACL")); userBucketName = responseMessage.getApplicationProperties().getProperty("S3BucketName"); userPath = responseMessage.getApplicationProperties().getProperty("UserPath", ""); userVanityHost = responseMessage.getApplicationProperties().getProperty("UserVanityHost"); objectTableModel.setUsersPath(userPath); uploadFilesMenuItem.setEnabled(userCanUpload); SwingUtilities.invokeLater(new Runnable() { public void run() { objectsHeadingLabel.setText( (accountDescription != null ? accountDescription : "Logged in")); objectTableModel.removeAllObjects(); objectTableModel.addObjects(objects); updateObjectsSummary(); refreshObjectMenuItem.setEnabled(true); lookupObjectsAccessControlLists(objects); } }); stackPanelCardLayout.show(stackPanel, "ObjectsPanel"); } else { // Listing failed ErrorDialog.showDialog(ownerFrame, this, cockpitLiteProperties.getProperties(), "Your log-in information was not correct, please try again", null); } } catch (Exception e) { stopProgressPanel(this); log.error("Gatekeeper login failed for URL: " + gkClient.getGatekeeperUrl(), e); ErrorDialog.showDialog(ownerFrame, this, cockpitLiteProperties.getProperties(), "Log-in failed, please try again", e); } } /** * Displays the currently selected object's properties in the dialog {@link ItemPropertiesDialog}. *

* As detailed information about the object may not yet be available, this method works * indirectly via the {@link #retrieveObjectsDetails} method. The retrieveObjectsDetails * method retrieves all the details for the currently selected objects, and once they are available * knows to display the PropertiesDialog as the {@link #isViewingObjectProperties} flag * is set. */ private void listObjectProperties() { isViewingObjectProperties = true; retrieveObjectsDetails(getSelectedObjects()); } /** * This method is an {@link S3ServiceEventListener} action method that is invoked when this * application's S3ServiceMulti triggers a GetObjectsEvent. *

* This never happens in this application as downloads are performed by * {@link S3ServiceMulti#downloadObjects(S3Bucket, DownloadPackage[])} instead. * * @param event */ public void s3ServiceEventPerformed(GetObjectsEvent event) { // Not used. } /** * This method is an {@link S3ServiceEventListener} action method that is invoked when this * application's S3ServiceMulti triggers a ListObjectsEvent. *

* This never happens in this application as it does not perform multi-threaded object * listings. * * @param event */ public void s3ServiceEventPerformed(ListObjectsEvent event) { // Not used. } public void s3ServiceEventPerformed(DeleteVersionedObjectsEvent event) { // Not used. } /** * Actions performed when an object is selected in the objects list table. */ private void objectSelectedAction() { S3Object[] selectedObjects = getSelectedObjects(); int count = selectedObjects.length; togglePublicMenuItem.setEnabled( userCanACL && count == 1); downloadObjectMenuItem.setEnabled( userCanDownload && count > 0); deleteObjectMenuItem.setEnabled( userCanDelete && count > 0); viewObjectPropertiesMenuItem.setEnabled(count > 0); generatePublicGetUrl.setEnabled( count == 1 && ACL_PUBLIC_DESCRIPTION.equals( objectTableModel.getObjectAclStatus(selectedObjects[0]))); } /** * Updates the summary text shown below the listing of objects, which details the * number and total size of the objects. * */ private void updateObjectsSummary() { S3Object[] objects = objectTableModel.getObjects(); try { String summary = "Please select a bucket"; long totalBytes = 0; if (objects != null) { summary = "" + objects.length + " item" + (objects.length != 1? "s" : ""); for (int i = 0; i < objects.length; i++) { totalBytes += objects[i].getContentLength(); } if (totalBytes > 0) { summary += ", " + byteFormatter.formatByteSize(totalBytes); } summary += " @ " + timeSDF.format(new Date()); if (isObjectFilteringActive()) { summary += " - Search results"; } summary += ""; } objectsSummaryLabel.setText(summary); } catch (Throwable t) { String message = "Unable to update object list summary"; log.error(message, t); ErrorDialog.showDialog(ownerFrame, this, cockpitLiteProperties.getProperties(), message, t); } } /** * Displays object-specific actions in a popup menu. * @param invoker the component near which the popup menu will be displayed * @param xPos the mouse's horizontal co-ordinate when the popup menu was invoked * @param yPos the mouse's vertical co-ordinate when the popup menu was invoked */ private void showObjectPopupMenu(JComponent invoker, int xPos, int yPos) { if (getSelectedObjects().length == 0) { return; } objectActionMenu.show(invoker, xPos, yPos); } /** * @return the set of objects currently selected in the gui, or an empty array if none are selected. */ private S3Object[] getSelectedObjects() { int viewRows[] = objectsTable.getSelectedRows(); if (viewRows.length == 0) { return new S3Object[] {}; } else { S3Object objects[] = new S3Object[viewRows.length]; for (int i = 0; i < viewRows.length; i++) { int modelRow = objectTableModelSorter.modelIndex(viewRows[i]); objects[i] = objectTableModel.getObject(modelRow); } return objects; } } /** * Retrieves ACL settings for the currently selected objects. The actual action is performed * in the s3ServiceEventPerformed method specific to LookupACLEvents. * */ private void lookupObjectsAccessControlLists(final S3Object[] objects) { (new Thread() { @Override public void run() { try { SignatureRequest[] signatureRequests = requestSignedRequests( SignatureRequest.SIGNATURE_TYPE_ACL_LOOKUP, objects); if (signatureRequests != null) { String[] signedRequests = new String[signatureRequests.length]; for (int i = 0; i < signedRequests.length; i++) { signedRequests[i] = signatureRequests[i].getSignedUrl(); } s3ServiceMulti.getObjectsACLs(signedRequests); } else { // Signature request failed ErrorDialog.showDialog(ownerFrame, null, cockpitLiteProperties.getProperties(), "Sorry, you do not have the permission to view object privacy settings", null); } } catch (Exception e) { log.error("Gatekeeper permissions check failed", e); ErrorDialog.showDialog(ownerFrame, null, cockpitLiteProperties.getProperties(), "Permissions check failed, please try again", e); } } }).start(); } /** * This method is an {@link S3ServiceEventListener} action method that is invoked when this * application's S3ServiceMulti triggers a LookupACLEvent. * * @param event */ public void s3ServiceEventPerformed(final LookupACLEvent event) { if (ServiceEvent.EVENT_STARTED == event.getEventCode()) { int threadCount = (int) event.getThreadWatcher().getThreadCount(); startProgressPanel(event.getUniqueOperationId(), "Privacy lookup 0/" + threadCount, threadCount, event.getThreadWatcher().getCancelEventListener()); } else if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { int threadCount = (int) event.getThreadWatcher().getThreadCount(); int threadsCompleted = (int) event.getThreadWatcher().getCompletedThreads(); updateProgressPanel(event.getUniqueOperationId(), "Privacy lookup " + threadsCompleted + "/" + threadCount, threadsCompleted); SwingUtilities.invokeLater(new Runnable() { public void run() { S3Object[] objectsWithAcl = event.getObjectsWithACL(); for (int i = 0; i < objectsWithAcl.length; i++) { String aclStatus = getAclDescription(objectsWithAcl[i].getAcl()); objectTableModel.updateObjectAclStatus(objectsWithAcl[i], aclStatus); } } }); } else if (ServiceEvent.EVENT_COMPLETED == event.getEventCode()) { stopProgressPanel(event.getUniqueOperationId()); } else if (ServiceEvent.EVENT_CANCELLED == event.getEventCode()) { stopProgressPanel(event.getUniqueOperationId()); } else if (ServiceEvent.EVENT_ERROR == event.getEventCode()) { stopProgressPanel(event.getUniqueOperationId()); String message = "Unable to lookup Access Control list for object(s)"; log.error(message, event.getErrorCause()); } } /** * Updates ACL settings for the currently selected objects. The actual action is performed * in the s3ServiceEventPerformed method specific to UpdateACLEvents. * */ private void updateObjectsAccessControlLists(final S3Object[] objectsToUpdate, final AccessControlList acl) { (new Thread() { @Override public void run() { try { SignatureRequest[] signatureRequests = requestSignedRequests( SignatureRequest.SIGNATURE_TYPE_ACL_UPDATE, objectsToUpdate); if (signatureRequests != null) { String[] signedRequests = new String[signatureRequests.length]; for (int i = 0; i < signedRequests.length; i++) { signedRequests[i] = signatureRequests[i].getSignedUrl(); } s3ServiceMulti.putObjectsACLs(signedRequests, acl); } else { // Listing failed ErrorDialog.showDialog(ownerFrame, null, cockpitLiteProperties.getProperties(), "Sorry, you do not have the permission to change object privacy settings", null); } } catch (Exception e) { log.error("Gatekeeper permissions check failed", e); ErrorDialog.showDialog(ownerFrame, null, cockpitLiteProperties.getProperties(), "Permissions check failed, please try again", e); } } }).start(); } /** * This method is an {@link S3ServiceEventListener} action method that is invoked when this * application's S3ServiceMulti triggers a UpdateACLEvent. *

* This method merely updates the progress dialog as ACLs are updated. * * @param event */ public void s3ServiceEventPerformed(final UpdateACLEvent event) { if (ServiceEvent.EVENT_STARTED == event.getEventCode()) { startProgressPanel(event.getUniqueOperationId(), "Privacy update 0/" + event.getThreadWatcher().getThreadCount(), (int) event.getThreadWatcher().getThreadCount(), event.getThreadWatcher().getCancelEventListener()); } else if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { ThreadWatcher progressStatus = event.getThreadWatcher(); String statusText = "Privacy update " + progressStatus.getCompletedThreads() + "/" + progressStatus.getThreadCount(); updateProgressPanel(event.getUniqueOperationId(), statusText, (int) progressStatus.getCompletedThreads()); SwingUtilities.invokeLater(new Runnable() { public void run() { S3Object[] objects = event.getObjectsWithUpdatedACL(); for (int i = 0; i < objects.length; i++) { String aclStatus = getAclDescription(objects[i].getAcl()); objectTableModel.updateObjectAclStatus(objects[i], aclStatus); objectSelectedAction(); } } }); } else if (ServiceEvent.EVENT_COMPLETED == event.getEventCode()) { stopProgressPanel(event.getUniqueOperationId()); } else if (ServiceEvent.EVENT_CANCELLED == event.getEventCode()) { stopProgressPanel(event.getUniqueOperationId()); } else if (ServiceEvent.EVENT_ERROR == event.getEventCode()) { stopProgressPanel(event.getUniqueOperationId()); String message = "Unable to update Access Control List(s)"; log.error(message, event.getErrorCause()); ErrorDialog.showDialog(ownerFrame, this, cockpitLiteProperties.getProperties(), message, event.getErrorCause()); } } /** * Prepares to perform a download of objects from S3 by prompting the user for a directory * to store the files in, then performing the download. * * @throws IOException */ private void downloadSelectedObjects() throws IOException { // Prompt user to choose directory location for downloaded files (or cancel download altogether) JFileChooser fileChooser = new JFileChooser(); fileChooser.setDialogTitle("Choose directory to save S3 files in"); fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); fileChooser.setMultiSelectionEnabled(false); fileChooser.setSelectedFile(downloadDirectory); int returnVal = fileChooser.showDialog(ownerFrame, "Choose Directory"); if (returnVal != JFileChooser.APPROVE_OPTION) { return; } downloadDirectory = fileChooser.getSelectedFile(); prepareForObjectsDownload(); } private void prepareForObjectsDownload() { // Build map of existing local files. Map objectKeyToFilepathMap = null; try { boolean storeEmptyDirectories = Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME) .getBoolProperty("uploads.storeEmptyDirectories", true); objectKeyToFilepathMap = FileComparer.getInstance() .buildObjectKeyToFilepathMap(downloadDirectory.listFiles(), "", storeEmptyDirectories); } catch (Exception e) { String message = "Unable to review files in targetted download directory"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, this, cockpitLiteProperties.getProperties(), message, e); return; } filesAlreadyInDownloadDirectoryMap = new HashMap(); // Build map of S3 Objects being downloaded. s3DownloadObjectsMap = FileComparer.getInstance() .populateObjectMap("", getSelectedObjects()); // Identify objects that may clash with existing files, or may be directories, // and retrieve details for these. ArrayList potentialClashingObjects = new ArrayList(); Set existingFilesObjectKeys = objectKeyToFilepathMap.keySet(); Iterator objectsIter = s3DownloadObjectsMap.entrySet().iterator(); while (objectsIter.hasNext()) { Map.Entry entry = (Map.Entry) objectsIter.next(); String objectKey = (String) entry.getKey(); S3Object object = (S3Object) entry.getValue(); if (object.getContentLength() == 0 || existingFilesObjectKeys.contains(objectKey)) { potentialClashingObjects.add(object); } if (existingFilesObjectKeys.contains(objectKey)) { filesAlreadyInDownloadDirectoryMap.put( objectKey, objectKeyToFilepathMap.get(objectKey)); } } if (potentialClashingObjects.size() > 0) { // Retrieve details of potential clashes. final S3Object[] clashingObjects = (S3Object[]) potentialClashingObjects.toArray(new S3Object[potentialClashingObjects.size()]); (new Thread() { @Override public void run() { isDownloadingObjects = true; retrieveObjectsDetails(clashingObjects); } }).start(); } else { compareRemoteAndLocalFiles(filesAlreadyInDownloadDirectoryMap, s3DownloadObjectsMap, false); } } private void prepareForFilesUpload(File[] uploadFiles) { try { // Build map of files proposed for upload. boolean storeEmptyDirectories = Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME) .getBoolProperty("uploads.storeEmptyDirectories", true); objectKeyToFilepathMap = FileComparer.getInstance() .buildObjectKeyToFilepathMap(uploadFiles, "", storeEmptyDirectories); // Build map of objects already existing in target S3 bucket with keys // matching the proposed upload keys. List objectsWithExistingKeys = new ArrayList(); S3Object[] existingObjects = objectTableModel.getObjects(); for (int i = 0; i < existingObjects.length; i++) { if (objectKeyToFilepathMap.containsKey(existingObjects[i].getKey())) { objectsWithExistingKeys.add(existingObjects[i]); } } existingObjects = (S3Object[]) objectsWithExistingKeys .toArray(new S3Object[objectsWithExistingKeys.size()]); s3ExistingObjectsMap = FileComparer.getInstance() .populateObjectMap("", existingObjects); if (existingObjects.length > 0) { // Retrieve details of potential clashes. final S3Object[] clashingObjects = existingObjects; (new Thread() { @Override public void run() { isUploadingFiles = true; retrieveObjectsDetails(clashingObjects); } }).start(); } else { compareRemoteAndLocalFiles(objectKeyToFilepathMap, s3ExistingObjectsMap, true); } } catch (Exception e) { String message = "Unable to upload objects"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, this, cockpitLiteProperties.getProperties(), message, e); } } private void compareRemoteAndLocalFiles( final Map objectKeyToFilepathMap, final Map s3ObjectsMap, final boolean upload) { final HyperlinkActivatedListener hyperlinkListener = this; (new Thread(new Runnable() { public void run() { try { // Compare objects being downloaded and existing local files. final String statusText = "Comparing " + s3ObjectsMap.size() + " object" + (s3ObjectsMap.size() > 1 ? "s" : "") + " in S3 with " + objectKeyToFilepathMap.size() + " local file" + (objectKeyToFilepathMap.size() > 1 ? "s" : ""); startProgressDialog(statusText, "", 0, 100, null, null); // Calculate total files size. File[] files = objectKeyToFilepathMap.values().toArray(new File[objectKeyToFilepathMap.size()]); final long filesSizeTotal[] = new long[1]; for (int i = 0; i < files.length; i++) { filesSizeTotal[0] += files[i].length(); } // Monitor generation of MD5 hash, and provide feedback via the progress bar. BytesProgressWatcher progressWatcher = new BytesProgressWatcher(filesSizeTotal[0]) { @Override public void updateBytesTransferred(long byteCount) { super.updateBytesTransferred(byteCount); String detailsText = formatBytesProgressWatcherDetails(this, true); int progressValue = (int)((double)getBytesTransferred() * 100 / getBytesToTransfer()); updateProgressDialog(statusText, detailsText, progressValue); } }; FileComparerResults comparisonResults = FileComparer.getInstance() .buildDiscrepancyLists(objectKeyToFilepathMap, s3ObjectsMap, progressWatcher); stopProgressDialog(); if (upload) { performFilesUpload(comparisonResults, objectKeyToFilepathMap); } else { performObjectsDownload(comparisonResults, s3ObjectsMap); } } catch (RuntimeException e) { stopProgressDialog(); throw e; } catch (Exception e) { stopProgressDialog(); String message = "Unable to " + (upload? "upload" : "download") + " objects"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, hyperlinkListener, cockpitLiteProperties.getProperties(), message, e); } } })).start(); } /** * Retrieves details about objects including metadata etc by invoking the method * {@link S3ServiceMulti#getObjectsHeads}. * * This is generally done as a prelude * to some further action, such as displaying the objects' details or downloading the objects. * The real action occurs in the method s3ServiceEventPerformed for handling * GetObjectHeadsEvent events. * @param candidateObjects */ private void retrieveObjectsDetails(final S3Object[] candidateObjects) { // Identify which of the candidate objects have incomplete metadata. ArrayList s3ObjectsIncompleteList = new ArrayList(); for (int i = 0; i < candidateObjects.length; i++) { if (!candidateObjects[i].isMetadataComplete()) { s3ObjectsIncompleteList.add(candidateObjects[i]); } } log.debug("Of " + candidateObjects.length + " object candidates for HEAD requests " + s3ObjectsIncompleteList.size() + " are incomplete, performing requests for these only"); final S3Object[] incompleteObjects = (S3Object[]) s3ObjectsIncompleteList .toArray(new S3Object[s3ObjectsIncompleteList.size()]); (new Thread() { @Override public void run() { try { SignatureRequest[] signatureRequests = requestSignedRequests( SignatureRequest.SIGNATURE_TYPE_HEAD, incompleteObjects); if (signatureRequests != null) { String[] signedRequests = new String[signatureRequests.length]; for (int i = 0; i < signedRequests.length; i++) { signedRequests[i] = signatureRequests[i].getSignedUrl(); } s3ServiceMulti.getObjectsHeads(signedRequests); } else { // Listing failed ErrorDialog.showDialog(ownerFrame, null, cockpitLiteProperties.getProperties(), "Sorry, you do not have the permission to view object details", null); } } catch (Exception e) { stopProgressDialog(); log.error("Gatekeeper permissions check failed", e); ErrorDialog.showDialog(ownerFrame, null, cockpitLiteProperties.getProperties(), "Permissions check failed, please try again", e); } }; }).start(); } /** * Performs the real work of downloading files by comparing the download candidates against * existing files, prompting the user whether to overwrite any pre-existing file versions, * and starting {@link S3ServiceMulti#downloadObjects} where the real work is done. * */ private void performObjectsDownload(FileComparerResults comparisonResults, Map s3DownloadObjectsMap) { try { // Determine which files to download, prompting user whether to over-write existing files List objectKeysForDownload = new ArrayList(); objectKeysForDownload.addAll(comparisonResults.onlyOnServerKeys); int newFiles = comparisonResults.onlyOnServerKeys.size(); int unchangedFiles = comparisonResults.alreadySynchronisedKeys.size(); int changedFiles = comparisonResults.updatedOnClientKeys.size() + comparisonResults.updatedOnServerKeys.size(); if (unchangedFiles > 0 || changedFiles > 0) { // Ask user whether to replace existing unchanged and/or existing changed files. log.debug("Files for download clash with existing local files, prompting user to choose which files to replace"); List options = new ArrayList(); String message = "Of the " + (newFiles + unchangedFiles + changedFiles) + " object(s) being downloaded:\n\n"; if (newFiles > 0) { message += newFiles + " file(s) are new.\n\n"; options.add(DOWNLOAD_NEW_FILES_ONLY); } if (changedFiles > 0) { message += changedFiles + " file(s) have changed.\n\n"; options.add(DOWNLOAD_NEW_AND_CHANGED_FILES); } if (unchangedFiles > 0) { message += unchangedFiles + " file(s) already exist and are unchanged.\n\n"; options.add(DOWNLOAD_ALL_FILES); } message += "Please choose which file(s) you wish to download:"; Object response = JOptionPane.showInputDialog( ownerFrame, message, "Replace file(s)?", JOptionPane.QUESTION_MESSAGE, null, options.toArray(), DOWNLOAD_NEW_AND_CHANGED_FILES); if (response == null) { return; } if (DOWNLOAD_NEW_FILES_ONLY.equals(response)) { // No change required to default objectKeysForDownload list. } else if (DOWNLOAD_ALL_FILES.equals(response)) { objectKeysForDownload.addAll(comparisonResults.updatedOnClientKeys); objectKeysForDownload.addAll(comparisonResults.updatedOnServerKeys); objectKeysForDownload.addAll(comparisonResults.alreadySynchronisedKeys); } else if (DOWNLOAD_NEW_AND_CHANGED_FILES.equals(response)) { objectKeysForDownload.addAll(comparisonResults.updatedOnClientKeys); objectKeysForDownload.addAll(comparisonResults.updatedOnServerKeys); } else { // Download cancelled. return; } } log.debug("Downloading " + objectKeysForDownload.size() + " objects"); if (objectKeysForDownload.size() == 0) { return; } // Create array of objects for download. final S3Object[] objects = new S3Object[objectKeysForDownload.size()]; int objectIndex = 0; for (Iterator iter = objectKeysForDownload.iterator(); iter.hasNext();) { objects[objectIndex++] = (S3Object) s3DownloadObjectsMap.get(iter.next()); } (new Thread() { @Override public void run() { try { SignatureRequest[] signedRequests = requestSignedRequests( SignatureRequest.SIGNATURE_TYPE_GET, objects); if (signedRequests != null) { // Setup files to write to, creating parent directories when necessary. downloadObjectsToFileMap = new HashMap(); ArrayList downloadPackageList = new ArrayList(); for (int i = 0; i < signedRequests.length; i++) { S3Object object = signedRequests[i].buildObject(); File file = new File(downloadDirectory, object.getKey()); // Create local directories corresponding to objects flagged as dirs. if (object.isDirectoryPlaceholder()) { file = new File(downloadDirectory, ObjectUtils.convertDirPlaceholderKeyNameToDirName( objects[i].getKey())); file.mkdirs(); } DownloadPackage downloadPackage = ObjectUtils.createPackageForDownload( object, file, true, false, null); if (downloadPackage == null) { continue; } downloadPackage.setSignedUrl(signedRequests[i].getSignedUrl()); downloadObjectsToFileMap.put(object.getKey(), file); downloadPackageList.add(downloadPackage); } DownloadPackage[] downloadPackagesArray = (DownloadPackage[]) downloadPackageList.toArray(new DownloadPackage[downloadPackageList.size()]); // Perform downloads. s3ServiceMulti.downloadObjects(downloadPackagesArray); } } catch (Exception e) { log.error("Download failed", e); ErrorDialog.showDialog(ownerFrame, null, cockpitLiteProperties.getProperties(), "Download failed, please try again", e); } } }).start(); } catch (RuntimeException e) { throw e; } catch (Exception e) { String message = "Unable to download objects"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, this, cockpitLiteProperties.getProperties(), message, e); } } private SignatureRequest[] requestSignedRequests(String operationType, S3Object[] objects) { try { startProgressPanel(this, "Checking permissions", 0, null); GatekeeperMessage responseMessage = gkClient.requestActionThroughGatekeeper( operationType, userBucketName, objects, cockpitLiteProperties.getProperties()); stopProgressPanel(this); String gatekeeperErrorCode = responseMessage.getApplicationProperties() .getProperty(GatekeeperMessage.APP_PROPERTY_GATEKEEPER_ERROR_CODE); if (gatekeeperErrorCode == null) { // Confirm that all the signatures requested were approved for (int i = 0; i < responseMessage.getSignatureRequests().length; i++) { if (responseMessage.getSignatureRequests()[i].getSignedUrl() == null) { // Some permissions missing. return null; } } return responseMessage.getSignatureRequests(); } else { // No permissions return null; // ErrorDialog.showDialog(ownerFrame, null, appProperties.getProperties(), // "Sorry, you do not have the necessary permissions", null); } } catch (Exception e) { stopProgressPanel(this); log.error("Gatekeeper permissions check failed", e); ErrorDialog.showDialog(ownerFrame, null, cockpitLiteProperties.getProperties(), "Permissions check failed, please try again", e); } return null; } /** * This method is an {@link S3ServiceEventListener} action method that is invoked when this * application's S3ServiceMulti triggers a DownloadObjectsEvent. *

* This method merely updates the progress dialog as objects are downloaded. * * @param event */ public void s3ServiceEventPerformed(DownloadObjectsEvent event) { if (ServiceEvent.EVENT_STARTED == event.getEventCode()) { ThreadWatcher watcher = event.getThreadWatcher(); // Show percentage of bytes transferred, if this info is available. if (watcher.isBytesTransferredInfoAvailable()) { startProgressPanel(event.getUniqueOperationId(), "Download " + byteFormatterTerse.formatByteSize(watcher.getBytesTransferred()) + "/" + byteFormatterTerse.formatByteSize(watcher.getBytesTotal()), 100, event.getThreadWatcher().getCancelEventListener()); // ... otherwise just show the number of completed threads. } else { startProgressPanel(event.getUniqueOperationId(), "Download " + event.getThreadWatcher().getCompletedThreads() + "/" + event.getThreadWatcher().getThreadCount(), (int) event.getThreadWatcher().getThreadCount(), event.getThreadWatcher().getCancelEventListener()); } } else if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { ThreadWatcher watcher = event.getThreadWatcher(); // Show percentage of bytes transferred, if this info is available. if (watcher.isBytesTransferredInfoAvailable()) { int percentage = (int) (((double)watcher.getBytesTransferred() / watcher.getBytesTotal()) * 100); updateProgressPanel(event.getUniqueOperationId(), "Download " + byteFormatterTerse.formatByteSize(watcher.getBytesTransferred()) + "/" + byteFormatterTerse.formatByteSize(watcher.getBytesTotal()) + " (" + byteFormatterTerse.formatByteSize(watcher.getBytesPerSecond()) + "/s, " + timeFormatterTerse.formatTime(watcher.getTimeRemaining()) + ")", percentage); } // ... otherwise just show the number of completed threads. else { ThreadWatcher progressStatus = event.getThreadWatcher(); String statusText = "Download " + progressStatus.getCompletedThreads() + " of " + progressStatus.getThreadCount() + " objects"; updateProgressPanel(event.getUniqueOperationId(), statusText, (int) progressStatus.getCompletedThreads()); } } else if (ServiceEvent.EVENT_COMPLETED == event.getEventCode()) { stopProgressPanel(event.getUniqueOperationId()); } else if (ServiceEvent.EVENT_CANCELLED == event.getEventCode()) { stopProgressPanel(event.getUniqueOperationId()); } else if (ServiceEvent.EVENT_ERROR == event.getEventCode()) { stopProgressPanel(event.getUniqueOperationId()); String message = "Unable to download object(s)"; log.error(message, event.getErrorCause()); ErrorDialog.showDialog(ownerFrame, this, cockpitLiteProperties.getProperties(), message, event.getErrorCause()); } } private void performFilesUpload(FileComparerResults comparisonResults, Map objectKeyToFilepathMap) { try { // Determine which files to upload, prompting user whether to over-write existing files List fileKeysForUpload = new ArrayList(); fileKeysForUpload.addAll(comparisonResults.onlyOnClientKeys); int newFiles = comparisonResults.onlyOnClientKeys.size(); int unchangedFiles = comparisonResults.alreadySynchronisedKeys.size(); int changedFiles = comparisonResults.updatedOnClientKeys.size() + comparisonResults.updatedOnServerKeys.size(); if (unchangedFiles > 0 || changedFiles > 0) { // Ask user whether to replace existing unchanged and/or existing changed files. log.debug("Files for upload clash with existing S3 objects, prompting user to choose which files to replace"); List options = new ArrayList(); String message = "Of the " + objectKeyToFilepathMap.size() + " file(s) being uploaded:\n\n"; if (newFiles > 0) { message += newFiles + " file(s) are new.\n\n"; options.add(UPLOAD_NEW_FILES_ONLY); } if (changedFiles > 0) { message += changedFiles + " file(s) have changed.\n\n"; options.add(UPLOAD_NEW_AND_CHANGED_FILES); } if (unchangedFiles > 0) { message += unchangedFiles + " file(s) already exist and are unchanged.\n\n"; options.add(UPLOAD_ALL_FILES); } message += "Please choose which file(s) you wish to upload:"; Object response = JOptionPane.showInputDialog( ownerFrame, message, "Replace file(s)?", JOptionPane.QUESTION_MESSAGE, null, options.toArray(), UPLOAD_NEW_AND_CHANGED_FILES); if (response == null) { return; } if (UPLOAD_NEW_FILES_ONLY.equals(response)) { // No change required to default fileKeysForUpload list. } else if (UPLOAD_ALL_FILES.equals(response)) { fileKeysForUpload.addAll(comparisonResults.updatedOnClientKeys); fileKeysForUpload.addAll(comparisonResults.updatedOnServerKeys); fileKeysForUpload.addAll(comparisonResults.alreadySynchronisedKeys); } else if (UPLOAD_NEW_AND_CHANGED_FILES.equals(response)) { fileKeysForUpload.addAll(comparisonResults.updatedOnClientKeys); fileKeysForUpload.addAll(comparisonResults.updatedOnServerKeys); } else { // Upload cancelled. stopProgressDialog(); return; } } if (fileKeysForUpload.size() == 0) { return; } final String[] statusText = new String[1]; statusText[0] = "Prepared 0 of " + fileKeysForUpload.size() + " file(s) for upload"; startProgressDialog(statusText[0], "", 0, 100, null, null); long bytesToProcess = 0; for (Iterator iter = fileKeysForUpload.iterator(); iter.hasNext();) { File file = new File(objectKeyToFilepathMap.get(iter.next().toString())); bytesToProcess += file.length(); } BytesProgressWatcher progressWatcher = new BytesProgressWatcher(bytesToProcess) { @Override public void updateBytesTransferred(long byteCount) { super.updateBytesTransferred(byteCount); String detailsText = formatBytesProgressWatcherDetails(this, false); int progressValue = (int)((double)getBytesTransferred() * 100 / getBytesToTransfer()); updateProgressDialog(statusText[0], detailsText, progressValue); } }; // Populate S3Objects representing upload files with metadata etc. final S3Object[] objects = new S3Object[fileKeysForUpload.size()]; int objectIndex = 0; for (Iterator iter = fileKeysForUpload.iterator(); iter.hasNext();) { String fileKey = iter.next().toString(); File file = new File(objectKeyToFilepathMap.get(fileKey)); S3Object newObject = ObjectUtils .createObjectForUpload(fileKey, file, null, false, progressWatcher); statusText[0] = "Prepared " + (objectIndex + 1) + " of " + fileKeysForUpload.size() + " file(s) for upload"; objects[objectIndex++] = newObject; } stopProgressDialog(); // Confirm we have permission to do this. SignatureRequest[] signedRequests = requestSignedRequests( SignatureRequest.SIGNATURE_TYPE_PUT, objects); if (signedRequests != null) { // Upload the files. SignedUrlAndObject[] urlAndObjs = new SignedUrlAndObject[signedRequests.length]; for (int i = 0; i < signedRequests.length; i++) { urlAndObjs[i] = new SignedUrlAndObject( signedRequests[i].getSignedUrl(), objects[i]); } s3ServiceMulti.putObjects(urlAndObjs); } } catch (RuntimeException e) { throw e; } catch (Exception e) { stopProgressDialog(); String message = "Unable to upload object(s)"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, this, cockpitLiteProperties.getProperties(), message, e); } } /** * This method is an {@link S3ServiceEventListener} action method that is invoked when this * application's S3ServiceMulti triggers a CreateObjectsEvent. *

* This method merely updates the progress dialog as files are uploaded. * * @param event */ public void s3ServiceEventPerformed(final CreateObjectsEvent event) { if (ServiceEvent.EVENT_STARTED == event.getEventCode()) { ThreadWatcher watcher = event.getThreadWatcher(); // Show percentage of bytes transferred, if this info is available. if (watcher.isBytesTransferredInfoAvailable()) { startProgressPanel(event.getUniqueOperationId(), "Upload " + byteFormatterTerse.formatByteSize(watcher.getBytesTransferred()) + "/" + byteFormatterTerse.formatByteSize(watcher.getBytesTotal()), 100, event.getThreadWatcher().getCancelEventListener()); } // ... otherwise show the number of completed threads. else { startProgressPanel(event.getUniqueOperationId(), "Upload 0/" + watcher.getThreadCount(), (int) watcher.getThreadCount(), event.getThreadWatcher().getCancelEventListener()); } } else if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { SwingUtilities.invokeLater(new Runnable() { public void run() { for (int i = 0; i < event.getCreatedObjects().length; i++) { objectTableModel.addObject(event.getCreatedObjects()[i]); } } }); ThreadWatcher watcher = event.getThreadWatcher(); // Show percentage of bytes transferred, if this info is available. if (watcher.isBytesTransferredInfoAvailable()) { if (watcher.getBytesTransferred() >= watcher.getBytesTotal()) { // Upload is completed, just waiting on resonse from S3. updateProgressPanel(event.getUniqueOperationId(), "Confirming", 100); } else { int percentage = (int) (((double)watcher.getBytesTransferred() / watcher.getBytesTotal()) * 100); updateProgressPanel(event.getUniqueOperationId(), "Upload " + byteFormatterTerse.formatByteSize(watcher.getBytesTransferred()) + "/" + byteFormatterTerse.formatByteSize(watcher.getBytesTotal()) + " (" + byteFormatterTerse.formatByteSize(watcher.getBytesPerSecond()) + "/s, " + timeFormatterTerse.formatTime(watcher.getTimeRemaining()) + ")", percentage); } } // ... otherwise show the number of completed threads. else { ThreadWatcher progressStatus = event.getThreadWatcher(); updateProgressPanel(event.getUniqueOperationId(), "Upload " + progressStatus.getCompletedThreads() + "/" + progressStatus.getThreadCount(), (int) progressStatus.getCompletedThreads()); } } else if (ServiceEvent.EVENT_COMPLETED == event.getEventCode()) { SwingUtilities.invokeLater(new Runnable() { public void run() { updateObjectsSummary(); } }); stopProgressPanel(event.getUniqueOperationId()); } else if (ServiceEvent.EVENT_CANCELLED == event.getEventCode()) { SwingUtilities.invokeLater(new Runnable() { public void run() { updateObjectsSummary(); } }); stopProgressPanel(event.getUniqueOperationId()); } else if (ServiceEvent.EVENT_ERROR == event.getEventCode()) { stopProgressPanel(event.getUniqueOperationId()); String message = "Unable to upload object(s)"; log.error(message, event.getErrorCause()); ErrorDialog.showDialog(ownerFrame, this, cockpitLiteProperties.getProperties(), message, event.getErrorCause()); } } private void generatePublicGetUrl() { final S3Object[] objects = getSelectedObjects(); if (objects.length != 1) { log.warn("Ignoring Generate Public URL object command, can only operate on a single object"); return; } S3Object currentObject = objects[0]; try { String hostAndBucket = null; if (userVanityHost != null) { hostAndBucket = userVanityHost; } else { boolean disableDnsBuckets = false; String s3Endpoint = Jets3tProperties.getInstance(Constants.JETS3T_PROPERTIES_FILENAME) .getStringProperty("s3service.s3-endpoint", Constants.S3_DEFAULT_HOSTNAME); hostAndBucket = ServiceUtils.generateS3HostnameForBucket( userBucketName, disableDnsBuckets, s3Endpoint); if (!ServiceUtils.isBucketNameValidDNSName(userBucketName)) { // If bucket name isn't DNS compatible, we must include the bucket // name as a URL path item. hostAndBucket += "/" + userBucketName; } } String url = "http://" + hostAndBucket + "/" + userPath + currentObject.getKey(); // Display signed URL String dialogText = "Public URL for '" + currentObject.getKey() + "'."; // Ensure dialog text is at least 150 characters (to force dialog to be wider) if (dialogText.length() < 150) { int charsShort = 150 - dialogText.length(); StringBuffer padding = new StringBuffer(); for (int i = 0; i < charsShort / 2; i++) { padding.append(" "); } dialogText = padding.toString() + dialogText + padding.toString(); } JOptionPane.showInputDialog(ownerFrame, dialogText, "URL", JOptionPane.INFORMATION_MESSAGE, null, null, url); } catch (NumberFormatException e) { String message = "Hours must be a valid decimal value; eg 3, 0.1"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, this, cockpitLiteProperties.getProperties(), message, e); } catch (Exception e) { String message = "Unable to generate public GET URL"; log.error(message, e); ErrorDialog.showDialog(ownerFrame, this, cockpitLiteProperties.getProperties(), message, e); } } private void deleteSelectedObjects() { final S3Object[] objects = getSelectedObjects(); if (objects.length == 0) { log.warn("Ignoring delete object(s) command, no currently selected objects"); return; } int response = JOptionPane.showConfirmDialog(ownerFrame, (objects.length == 1 ? "Are you sure you want to delete '" + objects[0].getKey() + "'?" : "Are you sure you want to delete " + objects.length + " object(s)" ), "Delete Object(s)?", JOptionPane.YES_NO_OPTION); if (response == JOptionPane.NO_OPTION) { return; } new Thread() { @Override public void run() { try { SignatureRequest[] signatureRequests = requestSignedRequests( SignatureRequest.SIGNATURE_TYPE_DELETE, objects); if (signatureRequests != null) { String[] signedRequests = new String[signatureRequests.length]; for (int i = 0; i < signedRequests.length; i++) { signedRequests[i] = signatureRequests[i].getSignedUrl(); } s3ServiceMulti.deleteObjects(signedRequests); } else { ErrorDialog.showDialog(ownerFrame, null, cockpitLiteProperties.getProperties(), "Sorry, you do not have the permission to delete files", null); } } catch (Exception e) { stopProgressDialog(); log.error("Gatekeeper permissions check failed", e); ErrorDialog.showDialog(ownerFrame, null, cockpitLiteProperties.getProperties(), "Permissions check failed, please try again", e); } } }.start(); } /** * This method is an {@link S3ServiceEventListener} action method that is invoked when this * application's S3ServiceMulti triggers a DeleteObjectsEvent. *

* This method merely updates the progress dialog as objects are deleted. * * @param event */ public void s3ServiceEventPerformed(final DeleteObjectsEvent event) { if (ServiceEvent.EVENT_STARTED == event.getEventCode()) { startProgressDialog( "Deleted 0 of " + event.getThreadWatcher().getThreadCount() + " object(s)", "", 0, (int) event.getThreadWatcher().getThreadCount(), "Cancel Delete Objects", event.getThreadWatcher().getCancelEventListener()); } else if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { SwingUtilities.invokeLater(new Runnable() { public void run() { for (int i = 0; i < event.getDeletedObjects().length; i++) { objectTableModel.removeObject( event.getDeletedObjects()[i]); } } }); ThreadWatcher progressStatus = event.getThreadWatcher(); String statusText = "Deleted " + progressStatus.getCompletedThreads() + " of " + progressStatus.getThreadCount() + " object(s)"; updateProgressDialog(statusText, "", (int) progressStatus.getCompletedThreads()); } else if (ServiceEvent.EVENT_COMPLETED == event.getEventCode()) { SwingUtilities.invokeLater(new Runnable() { public void run() { updateObjectsSummary(); } }); stopProgressDialog(); } else if (ServiceEvent.EVENT_CANCELLED == event.getEventCode()) { stopProgressDialog(); } else if (ServiceEvent.EVENT_ERROR == event.getEventCode()) { stopProgressDialog(); String message = "Unable to delete object(s)"; log.error(message, event.getErrorCause()); ErrorDialog.showDialog(ownerFrame, this, cockpitLiteProperties.getProperties(), message, event.getErrorCause()); } } /** * This method is an {@link S3ServiceEventListener} action method that is invoked when this * application's S3ServiceMulti triggers a GetObjectHeadsEvent. *

* This method merely updates the progress dialog as object details (heads) are retrieved. * * @param event */ public void s3ServiceEventPerformed(final GetObjectHeadsEvent event) { if (ServiceEvent.EVENT_STARTED == event.getEventCode()) { if (event.getThreadWatcher().getThreadCount() > 0) { startProgressDialog("Retrieved details for 0 of " + event.getThreadWatcher().getThreadCount() + " object(s)", "", 0, (int) event.getThreadWatcher().getThreadCount(), "Cancel Retrieval", event.getThreadWatcher().getCancelEventListener()); } } else if (ServiceEvent.EVENT_IN_PROGRESS == event.getEventCode()) { final ThreadWatcher progressStatus = event.getThreadWatcher(); // Store detail-complete objects in table. SwingUtilities.invokeLater(new Runnable() { public void run() { synchronized (lock) { // Retain selected status of objects for downloads or properties for (int i = 0; i < event.getCompletedObjects().length; i++) { S3Object object = event.getCompletedObjects()[i]; int modelIndex = objectTableModel.addObject(object); log.debug("Updated table with " + object.getKey() + ", content-type=" + object.getContentType()); if (isDownloadingObjects) { s3DownloadObjectsMap.put(object.getKey(), object); log.debug("Updated object download list with " + object.getKey() + ", content-type=" + object.getContentType()); } else if (isUploadingFiles) { s3ExistingObjectsMap.put(object.getKey(), object); log.debug("Updated object upload list with " + object.getKey() + ", content-type=" + object.getContentType()); } int viewIndex = objectTableModelSorter.viewIndex(modelIndex); if (isDownloadingObjects || isViewingObjectProperties) { objectsTable.addRowSelectionInterval(viewIndex, viewIndex); } } } } }); // Update progress of GetObject requests. String statusText = "Retrieved details for " + progressStatus.getCompletedThreads() + " of " + progressStatus.getThreadCount() + " object(s)"; updateProgressDialog(statusText, "", (int) progressStatus.getCompletedThreads()); } else if (ServiceEvent.EVENT_COMPLETED == event.getEventCode()) { // Stop GetObjectHead progress display. stopProgressDialog(); synchronized (lock) { if (isDownloadingObjects) { compareRemoteAndLocalFiles(filesAlreadyInDownloadDirectoryMap, s3DownloadObjectsMap, false); isDownloadingObjects = false; } else if (isUploadingFiles) { compareRemoteAndLocalFiles(objectKeyToFilepathMap, s3ExistingObjectsMap, true); isUploadingFiles = false; } else if (isViewingObjectProperties) { SwingUtilities.invokeLater(new Runnable() { public void run() { ItemPropertiesDialog.showDialog(ownerFrame, getSelectedObjects(), cockpitLiteProperties.getProperties(), // Only admin users with all rights can view metadata (userCanUpload && userCanDownload && userCanACL && userCanDelete)); isViewingObjectProperties = false; } }); } } } else if (ServiceEvent.EVENT_CANCELLED == event.getEventCode()) { stopProgressDialog(); } else if (ServiceEvent.EVENT_ERROR == event.getEventCode()) { stopProgressDialog(); String message = "Unable to retrieve object(s) details"; log.error(message, event.getErrorCause()); ErrorDialog.showDialog(ownerFrame, this, cockpitLiteProperties.getProperties(), message, event.getErrorCause()); } } private String formatTransferDetails(ThreadWatcher watcher) { long bytesPerSecond = watcher.getBytesPerSecond(); String detailsText = byteFormatter.formatByteSize(bytesPerSecond) + "/s"; if (watcher.isTimeRemainingAvailable()) { long secondsRemaining = watcher.getTimeRemaining(); detailsText += " - Time remaining: " + timeFormatterTerse.formatTime(secondsRemaining); } return detailsText; } private String formatBytesProgressWatcherDetails(BytesProgressWatcher watcher, boolean includeBytes) { long secondsRemaining = watcher.getRemainingTime(); String detailsText = (includeBytes ? byteFormatter.formatByteSize(watcher.getBytesTransferred()) + " of " + byteFormatter.formatByteSize(watcher.getBytesToTransfer()) + " - " : "") + "Time remaining: " + timeFormatterTerse.formatTime(secondsRemaining); return detailsText; } /** * Follows hyperlinks clicked on by a user. This is achieved differently depending on whether * Cockpit is running as an applet or as a stand-alone application: *

    *
  • Application: Detects the default browser application for the user's system (using * BareBonesBrowserLaunch) and opens the link as a new window in that browser
  • *
  • Applet: Opens the link in the current browser using the applet's context
  • *
* * @param url * the url to open * @param target * the target pane to open the url in, eg "_blank". This may be null. */ public void followHyperlink(URL url, String target) { if (!isStandAloneApplication) { if (target == null) { getAppletContext().showDocument(url); } else { getAppletContext().showDocument(url, target); } } else { BareBonesBrowserLaunch.openURL(url.toString()); } } /** * Implementation method for the CredentialsProvider interface. *

* Based on sample code: * InteractiveAuthenticationExample * */ public Credentials getCredentials(AuthScheme authscheme, String host, int port, boolean proxy) throws CredentialsNotAvailableException { if (authscheme == null) { return null; } try { Credentials credentials = null; if (authscheme instanceof NTLMScheme) { AuthenticationDialog pwDialog = new AuthenticationDialog( ownerFrame, "Authentication Required", "Host " + host + ":" + port + " requires Windows authentication", true); pwDialog.setVisible(true); if (pwDialog.getUser().length() > 0) { credentials = new NTCredentials(pwDialog.getUser(), pwDialog.getPassword(), host, pwDialog.getDomain()); } pwDialog.dispose(); } else if (authscheme instanceof RFC2617Scheme) { AuthenticationDialog pwDialog = new AuthenticationDialog( ownerFrame, "Authentication Required", "

Host " + host + ":" + port + "" + " requires authentication for the realm:
" + authscheme.getRealm() + "
", false); pwDialog.setVisible(true); if (pwDialog.getUser().length() > 0) { credentials = new UsernamePasswordCredentials(pwDialog.getUser(), pwDialog.getPassword()); } pwDialog.dispose(); } else { throw new CredentialsNotAvailableException("Unsupported authentication scheme: " + authscheme.getSchemeName()); } return credentials; } catch (IOException e) { throw new CredentialsNotAvailableException(e.getMessage(), e); } } private boolean isObjectFilteringActive() { if (!filterObjectsCheckBox.isSelected()) { return false; } else { if (filterObjectsPrefix.getText().length() > 0) { return true; } else { return false; } } } public void s3ServiceEventPerformed(CreateBucketsEvent event) { // Not applicable in this app. } public void s3ServiceEventPerformed(CopyObjectsEvent event) { // Not applicable in this app. } public static String getAclDescription(AccessControlList acl) { if (acl == null) { return ACL_UNKNOWN_DESCRIPTION; } for (GrantAndPermission gap: acl.getGrantAndPermissions()) { if (GroupGrantee.ALL_USERS.equals(gap.getGrantee()) && Permission.PERMISSION_READ.equals(gap.getPermission())) { return ACL_PUBLIC_DESCRIPTION; } } if (AccessControlList.REST_CANNED_PUBLIC_READ.equals(acl)) { return ACL_PUBLIC_DESCRIPTION; } return ACL_PRIVATE_DESCRIPTION; } private class ContextMenuListener extends MouseAdapter { @Override public void mousePressed(MouseEvent e) { showContextMenu(e); } @Override public void mouseReleased(MouseEvent e) { showContextMenu(e); } private void showContextMenu(MouseEvent e) { if (e.isPopupTrigger()) { // Select item under context-click. if (e.getSource() instanceof JList) { JList jList = (JList) e.getSource(); int locIndex = jList.locationToIndex(e.getPoint()); if (locIndex >= 0) { jList.setSelectedIndex(locIndex); } } else if (e.getSource() instanceof JTable) { JTable jTable = (JTable) e.getSource(); int rowIndex = jTable.rowAtPoint(e.getPoint()); if (rowIndex >= 0) { jTable.addRowSelectionInterval(rowIndex, rowIndex); } } // Show context popup menu. if (e.getSource().equals(objectsTable)) { showObjectPopupMenu((JComponent)e.getSource(), e.getX(), e.getY()); } } } } /** * Runs Cockpit as a stand-alone application. * @param args * @throws Exception */ public static void main(String args[]) throws Exception { JFrame ownerFrame = new JFrame("JetS3t Cockpit-Lite"); ownerFrame.addWindowListener(new WindowListener() { public void windowOpened(WindowEvent e) { } public void windowClosing(WindowEvent e) { e.getWindow().dispose(); } public void windowClosed(WindowEvent e) { } public void windowIconified(WindowEvent e) { } public void windowDeiconified(WindowEvent e) { } public void windowActivated(WindowEvent e) { } public void windowDeactivated(WindowEvent e) { } }); // Read arguments as properties of the form: '=' Properties argumentProperties = new Properties(); if (args.length > 0) { for (int i = 0; i < args.length; i++) { String arg = args[i]; int delimIndex = arg.indexOf("="); if (delimIndex >= 0) { String name = arg.substring(0, delimIndex); String value = arg.substring(delimIndex + 1); argumentProperties.put(name, value); } else { System.out.println("Ignoring property argument with incorrect format: " + arg); } } } new CockpitLite(ownerFrame, argumentProperties); } } jets3t-0.8.1+dfsg.orig/src/org/jets3t/apps/cockpitlite/ToggleAclDialog.java0000644000000000000000000001462511427702124023403 0ustar /* * JetS3t : Java S3 Toolkit * Project hosted at http://bitbucket.org/jmurty/jets3t/ * * Copyright 2007 James Murty * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jets3t.apps.cockpitlite; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Properties; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.LookAndFeel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jets3t.gui.HyperlinkActivatedListener; import org.jets3t.gui.JHtmlLabel; import org.jets3t.gui.skins.SkinsFactory; /** * Dialog for the user to toggle ACL settings of an object to/from public/private. * * @author James Murty */ public class ToggleAclDialog extends JDialog implements ActionListener { private static final Log log = LogFactory.getLog(ToggleAclDialog.class); private Properties applicationProperties = null; private boolean isPublicObject = false; private HyperlinkActivatedListener hyperlinkListener = null; private SkinsFactory skinsFactory = null; private final Insets insetsZero = new Insets(0, 0, 0, 0); private final Insets insetsDefault = new Insets(3, 5, 3, 5); private JRadioButton privateRadioButton = null; private JRadioButton publicRadioButton = null; public ToggleAclDialog(Frame ownerFrame, boolean isPublicObject, HyperlinkActivatedListener hyperlinkListener, Properties applicationProperties) { super(ownerFrame, "Toggle privacy settings", true); this.hyperlinkListener = hyperlinkListener; this.applicationProperties = applicationProperties; this.isPublicObject = isPublicObject; initGui(); } public ToggleAclDialog(JDialog ownerDialog, boolean isPublicObject, HyperlinkActivatedListener hyperlinkListener, Properties applicationProperties) { super(ownerDialog, "Change privacy", true); this.hyperlinkListener = hyperlinkListener; this.applicationProperties = applicationProperties; this.isPublicObject = isPublicObject; initGui(); } public boolean isPublicAclSet() { return publicRadioButton.isSelected(); } /** * Initialises all GUI elements. */ private void initGui() { // Initialise skins factory. skinsFactory = SkinsFactory.getInstance(applicationProperties); // Set Skinned Look and Feel. LookAndFeel lookAndFeel = skinsFactory.createSkinnedMetalTheme("SkinnedLookAndFeel"); try { UIManager.setLookAndFeel(lookAndFeel); } catch (UnsupportedLookAndFeelException e) { log.error("Unable to set skinned LookAndFeel", e); } this.setResizable(false); this.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE); JHtmlLabel messageLabel = skinsFactory .createSkinnedJHtmlLabel("ToggleAclDialogMessage", hyperlinkListener); messageLabel.setText("File privacy setting:"); messageLabel.setHorizontalAlignment(JLabel.CENTER); privateRadioButton = skinsFactory.createSkinnedJRadioButton("ToggleAclDialogPrivateRadioButton"); privateRadioButton.setText("Private file"); publicRadioButton = skinsFactory.createSkinnedJRadioButton("ToggleAclDialogPublicRadioButton"); publicRadioButton.setText("Public file"); ButtonGroup buttonGroup = new ButtonGroup(); buttonGroup.add(privateRadioButton); buttonGroup.add(publicRadioButton); publicRadioButton.setSelected(isPublicObject); privateRadioButton.setSelected(!isPublicObject); JButton okButton = skinsFactory.createSkinnedJButton("ToggleAclDialogOkButton"); okButton.setName("OK"); okButton.setText("OK"); okButton.addActionListener(this); this.getRootPane().setDefaultButton(okButton); JPanel buttonsPanel = skinsFactory.createSkinnedJPanel("ToggleAclDialogButtonsPanel"); buttonsPanel.setLayout(new GridBagLayout()); buttonsPanel.add(privateRadioButton, new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); buttonsPanel.add(publicRadioButton, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); buttonsPanel.add(okButton, new GridBagConstraints(0, 1, 2, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, insetsZero, 0, 0)); int row = 0; this.getContentPane().setLayout(new GridBagLayout()); this.getContentPane().add(messageLabel, new GridBagConstraints(0, row++, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, insetsDefault, 0, 0)); this.getContentPane().add(buttonsPanel, new GridBagConstraints(0, row++, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insetsDefault, 0, 0)); this.pack(); this.setLocationRelativeTo(this.getOwner()); } public void actionPerformed(ActionEvent e) { if ("OK".equals(e.getActionCommand())) { this.setVisible(false); } } public static void main(String[] args) { JFrame ownerFrame = new JFrame("Test"); ToggleAclDialog dialog = new ToggleAclDialog(ownerFrame, false, null, new Properties()); dialog.setVisible(true); dialog.dispose(); ownerFrame.dispose(); } } jets3t-0.8.1+dfsg.orig/src/org/apache/0002755000000000000000000000000011332474152014303 5ustar jets3t-0.8.1+dfsg.orig/src/org/apache/commons/0002755000000000000000000000000011332474152015756 5ustar jets3t-0.8.1+dfsg.orig/src/org/apache/commons/httpclient/0002755000000000000000000000000011332474152020134 5ustar jets3t-0.8.1+dfsg.orig/src/org/apache/commons/httpclient/contrib/0002755000000000000000000000000011332474152021574 5ustar jets3t-0.8.1+dfsg.orig/src/org/apache/commons/httpclient/contrib/proxy/0002755000000000000000000000000011550404122022745 5ustar jets3t-0.8.1+dfsg.orig/src/org/apache/commons/httpclient/contrib/proxy/PluginProxyTestApplet.java0000644000000000000000000001477611335606546030152 0ustar /* * $HeadURL: https://svn.apache.org/repos/asf/jakarta/commons/proper/httpclient/branches/HTTPCLIENT_3_0_BRANCH/src/contrib/org/apache/commons/httpclient/contrib/proxy/PluginProxyTestApplet.java $ * $Revision$ * $Date$ * * ==================================================================== * * Copyright 1999-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * */ package org.apache.commons.httpclient.contrib.proxy; import java.awt.BorderLayout; import java.awt.Container; import java.awt.FlowLayout; import java.awt.GridLayout; import java.awt.LayoutManager; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.net.URL; import javax.swing.JApplet; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.SwingUtilities; import org.apache.commons.httpclient.ProxyHost; /** *

* DISCLAIMER: HttpClient developers DO NOT actively support this component. * The component is provided as a reference material, which may be inappropriate * for use without additional customization. *

*/ public class PluginProxyTestApplet extends JApplet { private JTextField urlTextField = new JTextField(); private JPanel grid = null; private JLabel hostLabel = null; private JLabel portLabel = null; public PluginProxyTestApplet() { } public void init() { Container content = getContentPane(); content.setLayout(new BorderLayout()); // Proxy info table grid = getPanel(new GridLayout(2,3,2,2)); grid.add(getHeaderLabel("URL")); grid.add(getHeaderLabel("Proxy Host")); grid.add(getHeaderLabel("Proxy Port")); grid.add(urlTextField); hostLabel = getLabel(""); portLabel = getLabel(""); grid.add(hostLabel); grid.add(portLabel); grid.validate(); content.add(grid, BorderLayout.CENTER); // Button panel - SOUTH JPanel buttonPanel = getPanel(new FlowLayout()); JButton button = new JButton("Detect Proxy"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { SwingUtilities.invokeLater(new Runnable() { public void run() { detectProxy(); } }); } }); buttonPanel.add(button); content.add(buttonPanel, BorderLayout.SOUTH); // version panel - NORTH JPanel versionPanel = getPanel(new FlowLayout()); String javaVersion = System.getProperty("java.runtime.version"); JLabel versionLabel = getLabel("Java Version: "+javaVersion); versionPanel.add(versionLabel); content.add(versionPanel, BorderLayout.NORTH); validate(); super.setSize(400,100); } private JPanel getPanel(LayoutManager layout) { JPanel result = new JPanel(layout); return result; } private JLabel getHeaderLabel(String text) { JLabel result = new JLabel("" + text + ""); result.setHorizontalAlignment(JLabel.CENTER); return result; } private JLabel getLabel(String text) { JLabel result = new JLabel(text); result.setHorizontalAlignment(JLabel.CENTER); return result; } private void detectProxy() { String urlString = urlTextField.getText(); if (urlString == null || "".equals(urlString)) { JOptionPane.showMessageDialog(super.getRootPane(), "URL can't be empty", "Missing URL", JOptionPane.ERROR_MESSAGE); return; } if (!urlString.startsWith("http://")) { urlString = "http://" + urlString; } try { URL url = new URL(urlString); ProxyHost hostInfo = PluginProxyUtil.detectProxy(url); if (hostInfo != null) { hostLabel.setText(hostInfo.getHostName()); portLabel.setText(""+hostInfo.getPort()); } else { hostLabel.setText("none"); portLabel.setText("none"); } grid.validate(); } catch (ProxyDetectionException e) { JOptionPane.showMessageDialog(getRootPane(), e.getMessage() , "Proxy Detection Failed", JOptionPane.ERROR_MESSAGE); e.printStackTrace(); } catch (Exception e) { JOptionPane.showMessageDialog(getRootPane(), e.getMessage() , "Unexpected Exception", JOptionPane.ERROR_MESSAGE); e.printStackTrace(); } } public String getProxyHost(String urlString) { String result = urlString; try { URL url = new URL(urlString); ProxyHost hostInfo = PluginProxyUtil.detectProxy(url); if (hostInfo != null) { result = hostInfo.getHostName(); } } catch (Exception e) { e.printStackTrace(); } return result; } public int getProxyPort(String urlString) { int result = 80; try { URL url = new URL(urlString); ProxyHost hostInfo = PluginProxyUtil.detectProxy(url); if (hostInfo != null) { result = hostInfo.getPort(); } } catch (Exception e) { e.printStackTrace(); } return result; } } jets3t-0.8.1+dfsg.orig/src/org/apache/commons/httpclient/contrib/proxy/PluginProxyUtil.java0000644000000000000000000003420011550404114026744 0ustar /* * $HeadURL: https://svn.apache.org/repos/asf/jakarta/commons/proper/httpclient/branches/HTTPCLIENT_3_0_BRANCH/src/contrib/org/apache/commons/httpclient/contrib/proxy/PluginProxyUtil.java $ * $Revision$ * $Date$ * * ==================================================================== * * Copyright 1999-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * */ package org.apache.commons.httpclient.contrib.proxy; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.net.URL; import java.util.Locale; import java.util.Properties; import org.apache.commons.httpclient.ProxyHost; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * A utility class that gives applets the ability to detect proxy host settings. * This was adapted from a post from Chris Forster on 20030227 to a Sun Java * forum here: * http://forum.java.sun.com/thread.jspa?threadID=364342&tstart=120 * * The algorithm - which relies on Sun java plugin internal classes in some * cases - was maintained, but the following changes were made: * * 1. Logging was used to allow control of debug type messages. * 2. Reflection is used instead of direct references to Sun internal classes * to avoid the need to have these classes in the CLASSPATH to compile. * 3. Removed the use of global variables to allow this class to be used in * a multi-threaded environment. * 4. Add the use of exception to indicate to the caller when proxy detection * failed as opposed to when no proxy is configured. * *

* DISCLAIMER: HttpClient developers DO NOT actively support this component. * The component is provided as a reference material, which may be inappropriate * for use without additional customization. *

*/ public class PluginProxyUtil { /** Log object for this class */ private static final Log LOG = LogFactory.getLog(PluginProxyUtil.class); /** * This is used internally to indicate that no proxy detection succeeded * and no proxy setting is to be used - failover is unnecessary */ private static final ProxyHost NO_PROXY_HOST = new ProxyHost("",80); /** * The system property that is used to convey proxy information in some VM's */ private static final String PLUGIN_PROXY_CONFIG_PROP = "javaplugin.proxy.config.list"; /** * Returns the Proxy Host information using settings from the java plugin. * * @param sampleURL the url target for which proxy host information is * required * @return the proxy host info (name and port) or null if a direct * connection is allowed to the target url. * @throws ProxyDetectionException if detection failed */ public static ProxyHost detectProxy(URL sampleURL) throws ProxyDetectionException { ProxyHost result = null; String javaVers = System.getProperty("java.runtime.version"); if (LOG.isDebugEnabled()) { LOG.debug("About to attempt auto proxy detection under Java " + "version:"+javaVers); } // If specific, known detection methods fail may try fallback // detection method boolean invokeFailover = false; if (javaVers.startsWith("1.3")) { result = detectProxySettingsJDK13(sampleURL); if (result == null) { invokeFailover = true; } } else if (javaVers.startsWith("1.4") || (javaVers.startsWith("1.5") || javaVers.startsWith("1.6"))) { result = detectProxySettingsJDK14_JDK15_JDK16(sampleURL); if (result == null) { invokeFailover = true; } } else { if (LOG.isDebugEnabled()) { LOG.debug("Sun Plugin reported java version not 1.3.X, " + "1.4.X, 1.5.X or 1.6.X - trying failover detection..."); } invokeFailover = true; } if (invokeFailover) { if (LOG.isDebugEnabled()) { LOG.debug("Using failover proxy detection..."); } result = getPluginProxyConfigSettings(); } if (NO_PROXY_HOST.equals(result)) { result = null; } return result; } /** * Use Sun-specific internal plugin proxy classes for 1.3.X * Look around for the 1.3.X plugin proxy detection class. Without it, * cannot autodetect... * * @param sampleURL the URL to check proxy settings for * @return ProxyHost the host and port of the proxy that should be used * @throws ProxyDetectionException if detection failed */ private static ProxyHost detectProxySettingsJDK13(URL sampleURL) throws ProxyDetectionException { ProxyHost result = null; try { // Attempt to discover proxy info by asking internal plugin // code to locate proxy path to server sampleURL... Class pluginProxyHandler = Class.forName("sun.plugin.protocol.PluginProxyHandler"); Method getDefaultProxyHandlerMethod = pluginProxyHandler.getDeclaredMethod("getDefaultProxyHandler", null); Object proxyHandlerObj = getDefaultProxyHandlerMethod.invoke(null, null); if (proxyHandlerObj != null) { Class proxyHandlerClass = proxyHandlerObj.getClass(); Method getProxyInfoMethod = proxyHandlerClass.getDeclaredMethod("getProxyInfo", new Class[]{URL.class}); Object proxyInfoObject = getProxyInfoMethod.invoke(proxyHandlerObj, new Object[] { sampleURL }); if (proxyInfoObject != null) { Class proxyInfoClass = proxyInfoObject.getClass(); Method getProxyMethod = proxyInfoClass.getDeclaredMethod("getProxy", null); boolean useProxy = (getProxyMethod.invoke(proxyInfoObject, null) != null); if (useProxy) { String proxyIP = (String)getProxyMethod.invoke(proxyInfoObject, null); Method getProxyPortMethod = proxyInfoClass.getDeclaredMethod("getPort", null); Integer portInteger = (Integer)getProxyPortMethod.invoke(proxyInfoObject, null); int proxyPort = portInteger.intValue(); if (LOG.isDebugEnabled()) { LOG.debug("1.3.X: proxy=" + proxyIP+ " port=" + proxyPort); } result = new ProxyHost(proxyIP, proxyPort); } else { if (LOG.isDebugEnabled()) { LOG.debug("1.3.X reported NULL for " + "proxyInfo.getProxy (no proxy assumed)"); } result = NO_PROXY_HOST; } } else { if (LOG.isDebugEnabled()) { LOG.debug("NULL proxyInfo in 1.3.X auto proxy " + "detection, (no proxy assumed)"); } result = NO_PROXY_HOST; } } else { throw new ProxyDetectionException( "Sun Plugin 1.3.X failed to provide a default proxy handler"); } } catch (RuntimeException e) { throw e; } catch (Exception e) { LOG.debug("Sun Plugin 1.3.X proxy detection class not " + "found, will try failover detection" /*, e*/); } return result; } /** * Returns the proxy information for the specified sampleURL using JRE 1.4+ * specific plugin classes. * * Notes: * Plugin 1.4+ Final added * com.sun.java.browser.net.* classes ProxyInfo & ProxyService... * Use those with JREs => 1.4+ * * @param sampleURL the URL to check proxy settings for * @return ProxyHost the host and port of the proxy that should be used */ private static ProxyHost detectProxySettingsJDK14_JDK15_JDK16(URL sampleURL) { ProxyHost result = null; try { // Look around for the 1.4+ plugin proxy detection class... // Without it, cannot autodetect... Class ProxyServiceClass = Class.forName("com.sun.java.browser.net.ProxyService"); Method getProxyInfoMethod = ProxyServiceClass.getDeclaredMethod("getProxyInfo", new Class[] {URL.class}); Object proxyInfoArrayObj = getProxyInfoMethod.invoke(null, new Object[] {sampleURL}); if (proxyInfoArrayObj == null || Array.getLength(proxyInfoArrayObj) == 0) { if (LOG.isDebugEnabled()) { LOG.debug("1.4+ reported NULL proxy (no proxy assumed)"); } result = NO_PROXY_HOST; } else { Object proxyInfoObject = Array.get(proxyInfoArrayObj, 0); Class proxyInfoClass = proxyInfoObject.getClass(); Method getHostMethod = proxyInfoClass.getDeclaredMethod("getHost",null); String proxyIP = (String)getHostMethod.invoke(proxyInfoObject, null); Method getPortMethod = proxyInfoClass.getDeclaredMethod("getPort",null); Integer portInteger = (Integer)getPortMethod.invoke(proxyInfoObject, null); int proxyPort = portInteger.intValue(); if (LOG.isDebugEnabled()) { LOG.debug("1.4+ Proxy info get Proxy:"+proxyIP+ " get Port:"+proxyPort); } result = new ProxyHost(proxyIP, proxyPort); } } catch (RuntimeException e) { throw e; } catch (Exception e) { LOG.debug("Sun Plugin 1.4+ proxy detection class not found, " + "will try failover detection" /*, e*/); } return result; } /** * Returns the proxy host information found by inspecting the system * property "javaplugin.proxy.config.list". * * @return ProxyHost the host and port of the proxy that should be used * @throws ProxyDetectionException if an exception is encountered while * parsing the value of * PLUGIN_PROXY_CONFIG_PROP */ private static ProxyHost getPluginProxyConfigSettings() throws ProxyDetectionException { ProxyHost result = null; try { Properties properties = System.getProperties(); String proxyList = properties.getProperty("javaplugin.proxy.config.list"); if (LOG.isDebugEnabled()) { LOG.debug("Plugin Proxy Config List Property:"+proxyList); } boolean useProxy = (proxyList != null); if (useProxy) { proxyList = proxyList.toUpperCase(Locale.getDefault()); // Using HTTP proxy as proxy for HTTP proxy tunnelled SSL // socket (should be listed FIRST).... // 1/14/03 1.3.1_06 appears to omit HTTP portion of // reported proxy list... Mod to accomodate this... // Expecting proxyList of "HTTP=XXX.XXX.XXX.XXX:Port" OR // "XXX.XXX.XXX.XXX:Port" & assuming HTTP... String proxyIP=""; if (proxyList.indexOf("HTTP=") > -1) { proxyIP = proxyList.substring(proxyList.indexOf("HTTP=")+5, proxyList.indexOf(":")); } else { proxyIP = proxyList.substring(0, proxyList.indexOf(":")); } int endOfPort = proxyList.indexOf(","); if (endOfPort < 1) endOfPort = proxyList.length(); String portString = proxyList.substring(proxyList.indexOf(":")+1,endOfPort); int proxyPort = Integer.parseInt(portString); if (LOG.isDebugEnabled()) { LOG.debug("proxy " + proxyIP+" port " + proxyPort); } result = new ProxyHost(proxyIP, proxyPort); } else { LOG.debug("No configured plugin proxy list"); result = NO_PROXY_HOST; } } catch (Exception e) { if (LOG.isDebugEnabled()) { LOG.debug("Exception during failover auto proxy detection, " + ", e:"+e); throw new ProxyDetectionException( "Encountered unexpected exception while attempting " + "to parse proxy information stored in "+ PLUGIN_PROXY_CONFIG_PROP, e); } } return result; } } jets3t-0.8.1+dfsg.orig/src/org/apache/commons/httpclient/contrib/proxy/ProxyDetectionException.java0000644000000000000000000000511211335606546030463 0ustar /* * $HeadURL: https://svn.apache.org/repos/asf/jakarta/commons/proper/httpclient/branches/HTTPCLIENT_3_0_BRANCH/src/contrib/org/apache/commons/httpclient/contrib/proxy/ProxyDetectionException.java $ * $Revision$ * $Date$ * * ==================================================================== * * Copyright 1999-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * */ package org.apache.commons.httpclient.contrib.proxy; import org.apache.commons.httpclient.util.ExceptionUtil; /** * Signals a problem with auto-detecting the proxy information using the java * plugin. * *

* DISCLAIMER: HttpClient developers DO NOT actively support this component. * The component is provided as a reference material, which may be inappropriate * for use without additional customization. *

*/ public class ProxyDetectionException extends Exception { /** * Creates a new ProxyDetectionException with a null detail message. */ public ProxyDetectionException() { super(); } /** * Creates a new ProxyDetectionException with the specified detail message. * * @param message The exception detail message */ public ProxyDetectionException(String message) { super(message); } /** * Creates a new ProxyDetectionException with the specified detail message * and cause. * * @param message the exception detail message * @param cause the Throwable that caused this exception, or * null if the cause is unavailable, unknown, or not * a Throwable */ public ProxyDetectionException(String message, Throwable cause) { super(message); ExceptionUtil.initCause(this, cause); } }