diff options
author | Robby Workman <rworkman@slackbuilds.org> | 2013-12-04 09:13:32 +0100 |
---|---|---|
committer | Robby Workman <rworkman@slackbuilds.org> | 2013-12-06 00:00:09 -0600 |
commit | 93bc114aac4a1acf02c0236362d0e1654804740b (patch) | |
tree | b1336206c918be507839442a4d6e8fe92d7e6cdd /libraries/goffice0.8 | |
parent | 2a0c95152bd45ee36c1fa31fba70d17ed9d90a84 (diff) | |
download | slackbuilds-93bc114aac4a1acf02c0236362d0e1654804740b.tar.gz |
libraries/goffice0.8: Added (document utilities - version 0.8.x).
Signed-off-by: Matteo Bernardini <ponce@slackbuilds.org>
Diffstat (limited to 'libraries/goffice0.8')
-rw-r--r-- | libraries/goffice0.8/README | 1 | ||||
-rw-r--r-- | libraries/goffice0.8/go-conf-gsettings.c | 544 | ||||
-rw-r--r-- | libraries/goffice0.8/goffice0.8.SlackBuild | 105 | ||||
-rw-r--r-- | libraries/goffice0.8/goffice0.8.info | 10 | ||||
-rw-r--r-- | libraries/goffice0.8/slack-desc | 19 |
5 files changed, 679 insertions, 0 deletions
diff --git a/libraries/goffice0.8/README b/libraries/goffice0.8/README new file mode 100644 index 0000000000..bbea279ad7 --- /dev/null +++ b/libraries/goffice0.8/README @@ -0,0 +1 @@ +GOffice 0.8.x -- A glib/gtk set of document centric objects and utilities diff --git a/libraries/goffice0.8/go-conf-gsettings.c b/libraries/goffice0.8/go-conf-gsettings.c new file mode 100644 index 0000000000..3b230487a3 --- /dev/null +++ b/libraries/goffice0.8/go-conf-gsettings.c @@ -0,0 +1,544 @@ +/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +#include <string.h> + +struct _GOConfNode { + gchar *path; + gchar *id; + gchar *key; + GSettings *settings; +}; + +static GHashTable *installed_schemas, *closures; +void +_go_conf_init (void) +{ + char const * const *schemas = g_settings_list_schemas (); + char const * const *cur = schemas; + installed_schemas = g_hash_table_new (g_str_hash, g_str_equal); + while (*cur) { + g_hash_table_insert (installed_schemas, (gpointer) *cur, GUINT_TO_POINTER (TRUE)); + cur++; + } + closures = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) go_conf_closure_free); +} + +void +_go_conf_shutdown (void) +{ + g_hash_table_destroy (installed_schemas); + g_hash_table_destroy (closures); +} + +static gchar * +go_conf_format_id (gchar const *key) +{ + char *cur, *res; + if (!key) + return NULL; + res = g_strdup (key); + /* replace all slashes by dots */ + cur = res; + while ((cur = strchr (cur, '/')) && *cur) + *cur = '.'; + /* replace all underscores by hyphens */ + cur = res; + while ((cur = strchr (cur, '_')) && *cur) + *cur = '-'; + cur = res; + while (*cur) { + *cur = g_ascii_tolower (*cur); + cur++; + } + return res; +} + +GOConfNode * +go_conf_get_node (GOConfNode *parent, gchar const *key) +{ + GOConfNode *node; + + char *formatted = go_conf_format_id (key); + node = g_new0 (GOConfNode, 1); + if (parent) { + if (key && !parent->key) { + node->path = g_strconcat (parent->path, "/", key, NULL); + node->id = g_strconcat (parent->id, ".", formatted, NULL); + } else { + node->path = g_strdup (parent->path); + node->id = g_strdup (parent->id); + node->key = g_strdup (key? key: parent->key); + } + } else { + if (key[0] == '/') { + node->path = g_strdup (key); + node->id = g_strconcat ("org.gnome", formatted, NULL); + } else { + node->path = g_strconcat ("/apps/", key, NULL); + node->id = g_strconcat ("org.gnome.", formatted, NULL); + } + } + node->settings = g_hash_table_lookup (installed_schemas, node->id)? g_settings_new (node->id): NULL; + g_free (formatted); + if (!node->settings) { + char *last_dot = strrchr (node->id, '.'); + *last_dot = 0; + node->settings = g_hash_table_lookup (installed_schemas, node->id)? g_settings_new (node->id): NULL; + if (node->settings) + node->key = g_strdup (last_dot + 1); + else { + go_conf_free_node (node); + node = NULL; + } + } + return node; +} + +void +go_conf_free_node (GOConfNode *node) +{ + if (node) { + if (node->settings) + g_object_unref (node->settings); + g_free (node->path); + g_free (node->id); + g_free (node->key); + g_free (node); + } +} + +void +go_conf_sync (GOConfNode *node) +{ + g_settings_sync (); +} + +void +go_conf_set_bool (GOConfNode *node, gchar const *key, gboolean val) +{ + GOConfNode *real_node = go_conf_get_node (node, key); + if (!real_node) { + d (g_warning ("Unable to set key '%s'", key)); + return; + } + g_settings_set_boolean (real_node->settings, real_node->key, val); + go_conf_free_node (real_node); +} + +void +go_conf_set_int (GOConfNode *node, gchar const *key, gint val) +{ + GOConfNode *real_node = go_conf_get_node (node, key); + if (!real_node) { + d (g_warning ("Unable to set key '%s'", key)); + return; + } + g_settings_set_int (real_node->settings, real_node->key, val); + go_conf_free_node (real_node); +} + +void +go_conf_set_double (GOConfNode *node, gchar const *key, gdouble val) +{ + GOConfNode *real_node = go_conf_get_node (node, key); + if (!real_node) { + d (g_warning ("Unable to set key '%s'", key)); + return; + } + g_settings_set_double (real_node->settings, real_node->key, val); + go_conf_free_node (real_node); +} + +void +go_conf_set_string (GOConfNode *node, gchar const *key, gchar const *str) +{ + GOConfNode *real_node = go_conf_get_node (node, key); + if (!real_node) { + d (g_warning ("Unable to set key '%s'", key)); + return; + } + g_settings_set_string (real_node->settings, real_node->key, str); + go_conf_free_node (real_node); +} + +void +go_conf_set_str_list (GOConfNode *node, gchar const *key, GSList *list) +{ + GOConfNode *real_node = go_conf_get_node (node, key); + gssize n = g_slist_length (list); + char const ** strs; + GSList *ptr = list; + unsigned i = 0; + + if (!real_node) { + d (g_warning ("Unable to set key '%s'", key)); + return; + } + strs = g_new (char const*, n + 1); + for (; ptr; ptr = ptr->next) + strs[i++] = (char const *) ptr->data; + strs[n] = NULL; + g_settings_set_strv (real_node->settings, real_node->key, strs); + g_free (strs); + go_conf_free_node (real_node); +} + +static GVariant * +go_conf_get (GOConfNode *node, gchar const *key, GVariantType const *t) +{ + GVariant *res = g_settings_get_value (node->settings, key); + if (res == NULL) { + d (g_warning ("Unable to load key '%s'", key)); + return NULL; + } + + if (!g_variant_is_of_type (res, t)) { + char *tstr = g_variant_type_dup_string (t); + g_warning ("Expected `%s' got `%s' for key %s", + tstr, + g_variant_get_type_string (res), + key); + g_free (tstr); + g_variant_unref (res); + return NULL; + } + + return res; +} + +gboolean +go_conf_load_bool (GOConfNode *node, gchar const *key, gboolean default_val) +{ + gboolean res; + GVariant *val = NULL; + if (node) { + if (key && !strchr (key, '/') && !strchr (key, '.')) + val = go_conf_get (node, key, G_VARIANT_TYPE_BOOLEAN); + else if (node->key) + val = go_conf_get (node, node->key, G_VARIANT_TYPE_BOOLEAN); + } + if (val == NULL) { + GOConfNode *real_node = go_conf_get_node (node, key); + val = real_node? go_conf_get (real_node, real_node->key, G_VARIANT_TYPE_BOOLEAN): NULL; + go_conf_free_node (real_node); + } + + if (val != NULL) { + res = g_variant_get_boolean (val); + g_variant_unref (val); + } else { + d (g_warning ("Using default value '%s'", default_val ? "true" : "false")); + return default_val; + } + return res; +} + +gint +go_conf_load_int (GOConfNode *node, gchar const *key, gint minima, gint maxima, gint default_val) +{ + gint res = -1; + GVariant *val = NULL; + if (node) { + if (key && !strchr (key, '/') && !strchr (key, '.')) + val = go_conf_get (node, key, G_VARIANT_TYPE_INT32); + else if (node->key) + val = go_conf_get (node, node->key, G_VARIANT_TYPE_INT32); + } + if (val == NULL) { + GOConfNode *real_node = go_conf_get_node (node, key); + val = real_node? go_conf_get (real_node, real_node->key, G_VARIANT_TYPE_INT32): NULL; + go_conf_free_node (real_node); + } + if (val != NULL) { + res = g_variant_get_int32 (val); + g_variant_unref (val); + if (res < minima || maxima < res) { + g_warning ("Invalid value '%d' for %s. If should be >= %d and <= %d", + res, key, minima, maxima); + val = NULL; + } + } else { + d (g_warning ("Using default value '%d'", default_val)); + return default_val; + } + return res; +} + +gdouble +go_conf_load_double (GOConfNode *node, gchar const *key, + gdouble minima, gdouble maxima, gdouble default_val) +{ + gdouble res = -1; + GVariant *val = NULL; + if (node) { + if (key && !strchr (key, '/') && !strchr (key, '.')) + val = go_conf_get (node, key, G_VARIANT_TYPE_DOUBLE); + else if (node->key) + val = go_conf_get (node, node->key, G_VARIANT_TYPE_DOUBLE); + } + if (val == NULL) { + GOConfNode *real_node = go_conf_get_node (node, key); + val = real_node? go_conf_get (real_node, real_node->key, G_VARIANT_TYPE_DOUBLE): NULL; + go_conf_free_node (real_node); + } + if (val != NULL) { + res = g_variant_get_double (val); + g_variant_unref (val); + if (res < minima || maxima < res) { + g_warning ("Invalid value '%g' for %s. If should be >= %g and <= %g", + res, key, minima, maxima); + val = NULL; + } + } else { + d (g_warning ("Using default value '%g'", default_val)); + return default_val; + } + return res; +} + +gchar * +go_conf_load_string (GOConfNode *node, gchar const *key) +{ + char *res = NULL; + if (node) { + if (key && !strchr (key, '/') && !strchr (key, '.')) + res = g_settings_get_string (node->settings, key); + else if (node->key) + res = g_settings_get_string (node->settings, node->key); + } + if (res == NULL) { + GOConfNode *real_node = go_conf_get_node (node, key); + res = (real_node)? g_settings_get_string (real_node->settings, real_node->key): NULL; + go_conf_free_node (real_node); + } + return res; +} + +GSList * +go_conf_load_str_list (GOConfNode *node, gchar const *key) +{ + char **strs = NULL, **ptr; + GSList *list = NULL; + + if (node) { + if (key && !strchr (key, '/') && !strchr (key, '.')) + strs = g_settings_get_strv (node->settings, key); + else if (node->key) + strs = g_settings_get_strv (node->settings, node->key); + } + if (strs == NULL) { + GOConfNode *real_node = go_conf_get_node (node, key); + strs = real_node? g_settings_get_strv (node->settings, real_node->key): NULL; + go_conf_free_node (real_node); + } + if (strs) { + for (ptr = strs; *ptr; ptr++) + list = g_slist_prepend (list, g_strdup (*ptr)); + g_strfreev (strs); + } + + return list; +} + +gchar * +go_conf_get_short_desc (GOConfNode *node, gchar const *key) +{ + return NULL; +} + +gchar * +go_conf_get_long_desc (GOConfNode *node, gchar const *key) +{ + return NULL; +} + +gchar * +go_conf_get_value_as_str (GOConfNode *node, gchar const *key) +{ + gchar *value_string; + GVariant *value = NULL; + + if (node) { + if (key && !strchr (key, '/') && !strchr (key, '.')) + value = g_settings_get_value (node->settings, key); + else if (node->key) + value = g_settings_get_value (node->settings, node->key); + } + if (value == NULL) { + GOConfNode *real_node = go_conf_get_node (node, key); + value = real_node? g_settings_get_value (real_node->settings, real_node->key): NULL; + go_conf_free_node (real_node); + } + switch (g_variant_classify (value)) { + case 's': + value_string = g_strdup (g_variant_get_string (value, NULL)); + break; + case 'i': + value_string = g_strdup_printf ("%i", g_variant_get_int32 (value)); + break; + case 'd': + value_string = g_strdup_printf ("%f", g_variant_get_double (value)); + break; + case 'b': + value_string = g_strdup (go_locale_boolean_name (g_variant_get_boolean (value))); + break; + default: + value_string = g_strdup ("ERROR FIXME"); + break; + } + + return value_string; +} + +gboolean +go_conf_get_bool (GOConfNode *node, gchar const *key) +{ + gboolean res, failed = node == NULL; + if (!failed) { + if (key && !strchr (key, '/') && !strchr (key, '.')) + res = g_settings_get_boolean (node->settings, key); + else if (node->key) + res = g_settings_get_boolean (node->settings, node->key); + else + failed = TRUE; + } + if (failed) { + GOConfNode *real_node = go_conf_get_node (node, key); + res = (real_node)? g_settings_get_boolean (real_node->settings, real_node->key): FALSE; + go_conf_free_node (real_node); + } + return res; +} + +gint +go_conf_get_int (GOConfNode *node, gchar const *key) +{ + GOConfNode *real_node = go_conf_get_node (node, key); + gint res = (real_node)? g_settings_get_int (real_node->settings, real_node->key): 0; + go_conf_free_node (real_node); + return res; +} + +gdouble +go_conf_get_double (GOConfNode *node, gchar const *key) +{ + GOConfNode *real_node = go_conf_get_node (node, key); + gdouble res = (real_node)? g_settings_get_double (real_node->settings, real_node->key): 0.; + go_conf_free_node (real_node); + return res; +} + +gchar * +go_conf_get_string (GOConfNode *node, gchar const *key) +{ + GOConfNode *real_node = go_conf_get_node (node, key); + gchar *res = (real_node)? g_settings_get_string (real_node->settings, real_node->key): NULL; + go_conf_free_node (real_node); + return res; +} + +GSList * +go_conf_get_str_list (GOConfNode *node, gchar const *key) +{ + return go_conf_load_str_list (node, key); +} + +#if 0 +gboolean +go_conf_set_value_from_str (GOConfNode *node, gchar const *key, gchar const *val_str) +{ + switch (go_conf_node_get_key_type (node, key)) { + case G_TYPE_STRING: + go_conf_set_string (node, key, val_str); + break; + case G_TYPE_FLOAT: { + GODateConventions const *conv = NULL; /* workbook_date_conv (state->wb); */ + GnmValue *value = format_match_number (val_str, NULL, conv); + if (value != NULL) { + gnm_float the_float = value_get_as_float (value); + go_conf_set_double (node, key, the_float); + } + value_release (value); + break; + } + case G_TYPE_INT: { + GODateConventions const *conv = NULL; /* workbook_date_conv (state->wb); */ + GnmValue *value = format_match_number (val_str, NULL, conv); + if (value != NULL) { + gint the_int = value_get_as_int (value); + go_conf_set_int (node, key, the_int); + } + value_release (value); + break; + } + case G_TYPE_BOOLEAN: { + GODateConventions const *conv = NULL; /* workbook_date_conv (state->wb); */ + GnmValue *value = format_match_number (val_str, NULL, conv); + gboolean err, the_bool; + if (value != NULL) { + err = FALSE; + the_bool = value_get_as_bool (value, &err); + go_conf_set_bool (node, key, the_bool); + } + value_release (value); + break; + } + default: + g_warning ("Unsupported gconf type in preference dialog"); + } + + return TRUE; +} +#endif + +void +go_conf_remove_monitor (guint monitor_id) +{ + GOConfClosure *cls = g_hash_table_lookup (closures, GUINT_TO_POINTER (monitor_id)); + if (cls) { + g_signal_handler_disconnect (cls->node->settings, monitor_id); + g_hash_table_remove (closures, GUINT_TO_POINTER (monitor_id)); + } else + g_warning ("unkown GOConfMonitor id."); +} + +static void +cb_key_changed (GSettings *settings, + char *key, + GOConfClosure *cls) +{ + char *real_key; + if (cls->key) { + if (strcmp (cls->key, key)) + return; /* not the watched key */ + real_key = g_strdup (cls->real_key); + } else + real_key = g_strconcat (cls->real_key, "/", key, NULL); + cls->monitor (cls->node, real_key , cls->data); + g_free (real_key); +} + +guint +go_conf_add_monitor (GOConfNode *node, G_GNUC_UNUSED gchar const *key, + GOConfMonitorFunc monitor, gpointer data) +{ + guint ret; + GOConfClosure *cls; + + g_return_val_if_fail (node || key, 0); + g_return_val_if_fail (monitor != NULL, 0); + + cls = g_new (GOConfClosure, 1); + cls->monitor = monitor; + cls->node = node; + cls->data = data; + cls->key = g_strdup (key? key: node->key); + cls->real_key = (key)? g_strconcat (node->path, '/', key, NULL): g_strdup (node->path); + ret = g_signal_connect + (node->settings, + "changed", G_CALLBACK (cb_key_changed), + cls); + + g_hash_table_insert (closures, GUINT_TO_POINTER (ret), cls); + return ret; +} diff --git a/libraries/goffice0.8/goffice0.8.SlackBuild b/libraries/goffice0.8/goffice0.8.SlackBuild new file mode 100644 index 0000000000..395d303a02 --- /dev/null +++ b/libraries/goffice0.8/goffice0.8.SlackBuild @@ -0,0 +1,105 @@ +#!/bin/sh + +# Slackware build script for goffice + +# Copyright (c) 2007 alkos333 <me@alkos333.net> +# 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. +# +# 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. + +PRGNAM=goffice0.8 +VERSION=${VERSION:-0.8.17} +BUILD=${BUILD:-1} +TAG=${TAG:-_SBo} + +SRCNAM=goffice + +if [ -z "$ARCH" ]; then + case "$( uname -m )" in + i?86) ARCH=i486 ;; + arm*) ARCH=arm ;; + *) ARCH=$( uname -m ) ;; + esac +fi + +CWD=$(pwd) +TMP=${TMP:-/tmp/SBo} +PKG=$TMP/package-$PRGNAM +OUTPUT=${OUTPUT:-/tmp} + +if [ "$ARCH" = "i486" ]; then + SLKCFLAGS="-O2 -march=i486 -mtune=i686" + LIBDIRSUFFIX="" +elif [ "$ARCH" = "i686" ]; then + SLKCFLAGS="-O2 -march=i686 -mtune=i686" + LIBDIRSUFFIX="" +elif [ "$ARCH" = "x86_64" ]; then + SLKCFLAGS="-O2 -fPIC" + LIBDIRSUFFIX="64" +else + SLKCFLAGS="-O2" + LIBDIRSUFFIX="" +fi + +set -e + +rm -rf $PKG +mkdir -p $TMP $PKG $OUTPUT +cd $TMP +rm -rf $SRCNAM-$VERSION +tar xvf $CWD/$SRCNAM-$VERSION.tar.xz +cd $SRCNAM-$VERSION +chown -R root:root . +find -L . \ + \( -perm 777 -o -perm 775 -o -perm 750 -o -perm 711 -o -perm 555 \ + -o -perm 511 \) -exec chmod 755 {} \; -o \ + \( -perm 666 -o -perm 664 -o -perm 640 -o -perm 600 -o -perm 444 \ + -o -perm 440 -o -perm 400 \) -exec chmod 644 {} \; + +CFLAGS="$SLKCFLAGS" \ +CXXFLAGS="$SLKCFLAGS" \ +./configure \ + --prefix=/usr \ + --program-suffix="0.8" \ + --libdir=/usr/lib${LIBDIRSUFFIX} \ + --sysconfdir=/etc \ + --localstatedir=/var \ + --docdir=/usr/doc/$PRGNAM-$VERSION \ + --with-config-backend=gsettings \ + --build=$ARCH-slackware-linux + +# https://mail.gnome.org/archives/commits-list/2011-November/msg05571.html +cp $CWD/go-conf-gsettings.c goffice/app/ + +make +make install-strip DESTDIR=$PKG + +mkdir -p $PKG/usr/doc/$PRGNAM-$VERSION +cp -a AUTHORS BUGS COPYING ChangeLog INSTALL MAINTAINERS NEWS README \ + $PKG/usr/doc/$PRGNAM-$VERSION/ +cat $CWD/$PRGNAM.SlackBuild > $PKG/usr/doc/$PRGNAM-$VERSION/$PRGNAM.SlackBuild +find $PKG/usr/doc -type f -exec chmod 644 {} \; +(cd $PKG/usr/doc/$PRGNAM-$VERSION; ln -s /usr/share/gtk-doc/html/goffice html) + +mkdir -p $PKG/install +cat $CWD/slack-desc > $PKG/install/slack-desc + +cd $PKG +/sbin/makepkg -l y -c n $OUTPUT/$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.${PKGTYPE:-tgz} diff --git a/libraries/goffice0.8/goffice0.8.info b/libraries/goffice0.8/goffice0.8.info new file mode 100644 index 0000000000..6be8dd6c12 --- /dev/null +++ b/libraries/goffice0.8/goffice0.8.info @@ -0,0 +1,10 @@ +PRGNAM="goffice0.8" +VERSION="0.8.17" +HOMEPAGE="http://ftp.gnome.org/pub/GNOME/sources/goffice/" +DOWNLOAD="http://ftp.gnome.org/pub/GNOME/sources/goffice/0.8/goffice-0.8.17.tar.xz" +MD5SUM="e2bc2d2f51220d6883f0797d74c385b8" +DOWNLOAD_x86_64="" +MD5SUM_x86_64="" +REQUIRES="" +MAINTAINER="Robby Workman" +EMAIL="rworkman@slackbuilds.org" diff --git a/libraries/goffice0.8/slack-desc b/libraries/goffice0.8/slack-desc new file mode 100644 index 0000000000..bac7e12520 --- /dev/null +++ b/libraries/goffice0.8/slack-desc @@ -0,0 +1,19 @@ +# HOW TO EDIT THIS FILE: +# The "handy ruler" below makes it easier to edit a package description. +# Line up the first '|' above the ':' following the base package name, and +# the '|' on the right side marks the last column you can put a character in. +# You must make exactly 11 lines for the formatting to be correct. It's also +# customary to leave one space after the ':' except on otherwise blank lines. + + |-----handy-ruler------------------------------------------------------| +goffice0.8: GOffice 0.8 (document utilities) +goffice0.8: +goffice0.8: GOffice is a glib/gtk set of document centric +goffice0.8: objects and utilities. +goffice0.8: +goffice0.8: Homepage: http://ftp.gnome.org/pub/GNOME/sources/goffice/ +goffice0.8: +goffice0.8: +goffice0.8: +goffice0.8: +goffice0.8: |