public inbox for [email protected]
help / color / mirror / Atom feedFrom: Murtuza Zabuawala <[email protected]>
To: Harshal Dhumal <[email protected]>
Cc: pgadmin-hackers <[email protected]>
Cc: Sanket Mehta <[email protected]>
Subject: Re: [PATCH] Tables node (pgAdmin4)
Date: Wed, 18 May 2016 15:20:02 +0530
Message-ID: <CAKKotZQKV3nkCz8ADOV1ExoSaKWHdH4rY17xW9K3B-4qLree3Q@mail.gmail.com> (raw)
In-Reply-To: <CAFiP3vw+yN2kYktjdmJEHL8Ug8R+k_HxhN+E+pozpC=d_zs1=Q@mail.gmail.com>
References: <CAKKotZRCf07F_SGHi4KawBtLHPSeKz5Uvzwu6ddQ=bKc1FDRRw@mail.gmail.com>
<CAFiP3vw61T0n--F4vYXALdtrkBKznBegBPq5Ds=6uZrg02vWXQ@mail.gmail.com>
<CAFOhELea6nCtX_T78o_3mNKJC0_emirXKGm3nq8d6mvSZV57pg@mail.gmail.com>
<CAFiP3vypf7KEmToKsBqn1--qf_PzMV+p-d9bsMj04eoYnj5_tQ@mail.gmail.com>
<CAKKotZQumWW_cvhvgyFc7_1Lvs8npkPW57FgVN_+wPPSurBDOw@mail.gmail.com>
<CAKKotZQMR5zsbDAiAhUEQ46yhNE51BONu0DYjEY1WFSJbBqK+w@mail.gmail.com>
<CAFiP3vwBUX5Ez51Fk_s+t67hRW-uZ6ViMcuTg4e+oPf+k5KqTg@mail.gmail.com>
<CAFOhELdg9-TB=fdpGDLNkjYve9vBxYttE_PzmahsrNMQv4nn4Q@mail.gmail.com>
<CAFiP3vxO9tej3WXYeLjZk6MgQYR0C-hp9UUWmog1E7iDvvqFmQ@mail.gmail.com>
<CAFOhELd=_vuqwR0eGLL=KhxGaQCP6n9mcXP1GijcWh1ecCpegw@mail.gmail.com>
<CAFiP3vw5nx2Wdt9ci-MNRV+H+dO-x9KUSZtk16EZKjdox+KRxg@mail.gmail.com>
<CAFiP3vz9=gtNuoGEt+oxt+UYfE=7=dTUQZpCxgGkVWUhS=Kafw@mail.gmail.com>
<CA+yw=mPp8CY+jd3FUXeV-KSd+82dztXYWySJVLuL9eoE9hrbfQ@mail.gmail.com>
<CAFiP3vw+yN2kYktjdmJEHL8Ug8R+k_HxhN+E+pozpC=d_zs1=Q@mail.gmail.com>
List-Unsubscribe: <mailto:[email protected]?body=unsub%20pgadmin-hackers>
Hi,
PFA table add-on patch version 8.2
--
Regards,
Murtuza Zabuawala
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Wed, May 18, 2016 at 2:42 PM, Harshal Dhumal <
[email protected]> wrote:
> Hi,
>
> PFA patch for table node (version 8.1). apply this patch on version 7
> patch. Not all issue are fixed in this patch. Murtuza will be sending
> version 8.2 witch will have resolution for remaining issues. Apply version
> 8.2 patch on version 8.1
>
> --
> *Harshal Dhumal*
> *Software Engineer *
>
>
>
> EenterpriseDB <http://www.enterprisedb.com;
>
> On Tue, May 17, 2016 at 10:12 PM, Sanket Mehta <
> [email protected]> wrote:
>
>> Hi Harshal,
>>
>>
>> Below are my review comments:
>>
>> I got below warning when I tried to apply the patch for table node as
>> mentioned below:
>>
>> Table creation:
>>
>> - Trailing white spaces warnings
>>
>> $ git apply
>> /projects/patches/pgadmin4/Table/table_14_May_V6.patch
>>
>> /projects/patches/pgadmin4/Table/table_14_May_V6.patch:6008: trailing
>> whitespace.
>> return false;
>>
>> /projects/patches/pgadmin4/Table/table_14_May_V6.patch:6016: trailing
>> whitespace.
>> return false;
>> warning: 2 lines add whitespace errors.
>>
>
> Fixed (These were introduced due to rules node.)
>
>
>>
>> - In Table creation dialog, while adding a new primary key, it does
>> not allow to change the tablespace to empty. (which is not the case in case
>> of tablespace in table)
>>
>> Fixed
>
>>
>> - In Table creation dialog, while adding a new column, data type and
>> name field must be mandatory. otherwise while clicking on save it gives
>> below error
>>
>> File
>> "/projects/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py",
>> line 1319, in _parse_format_columns
>> c['cltype'] = self._cltype_formatter(c['cltype'])
>> KeyError: 'cltype
>>
> Fixed
>
>
>>
>> - In Table creation dialog, While adding a new column, in primary
>> check box is needed to click twice in order to check it. Ideally it should
>> be checked by only one click.
>>
>> This is Backgrid behaviour.
>
>>
>> - In Table creation dialog, While adding a new column, primary key
>> should not be allowed to added unless user has provided name and data type
>> for at least one column.
>>
>> Fixed
>
>>
>> - currently if user has clicked on add column button and immediately
>> click on add primary key button, it will add a row in primary key data grid
>>
>> Fixed
>
>>
>> - When delete table/drop cascade is apply on any table, i got a
>> javascript error as mentioned below
>>
>> node.js:94 Uncaught TypeError: self.canDrop.apply is not
>> a function
>>
> Already fixed in other commit.
>
>
>>
>> - Once the above error generated, every time user tries to open a
>> context menu by right clicking on any existing table, that same error comes
>>
>> Already fixed in other commit.
>
>>
>> - In table creation dialog, if table is inherited from another table,
>> if a new primary key is added manually there, the create sql will not have
>> an entry for primary key
>>
>> Fixed
>
>>
>> - In table creation dialog, if primary key check box is checked while
>> adding the row, a new row is added in primary key datagrid but unchecking
>> the primary key checkbox from column datagrid, does not removes that row
>> from primary key data grid.
>>
>> Fixed.
>
>>
>> - In AutoVacuum tab, if user provides any invalid value to any
>> parameter, then a error message should be prompted, only background color
>> change would not tell user to change the value.
>>
>> Expected behaviour.
>
>>
>> - In table creation dialog, security label are not being added.
>> javascript error is coming as mentioned below:
>> {"success": 0, "info": "", "result": null, "data": null,
>> "errormsg": "can't adapt type 'Undefined'"}
>>
>> Fixed
>
>>
>> - In Table creation dialog, while adding foreign key, in action tab.
>> if user click on 'x' button in "on update" or "on delete" select2 control,
>> it gives error "Uncaught SyntaxError: Unexpected end of input"
>>
>> Fixed
>
>>
>> - In Table creation dialog, while adding a check constraint,
>> "validated" button does not work properly
>>
>> Fixed.
>
>>
>> - After successfully creation of table, "table name cannot be empty"
>> error is not getting cleared.
>>
>> Not reproducible.
>
>>
>> - In Table creation dialog, if user has added an empty column without
>> entering its name or type and trying to add check constraint, it will add
>> an empty constraint
>>
>> Expected behaviour (Columns are not mandatory for check constrains)
>
>>
>> - In Table creation dialog, while adding an exclude constraint, for
>> "character varying" column type, no operators are being listed
>>
>> There are no operators for character varying data type.
>
>>
>> - In Table creation dialog, while adding an exclude constraint, below
>> mentioned error comes if user removes operator class by clicking 'x' on
>> that control Uncaught TypeError: Cannot read property 'id' of undefined
>>
>> TODO
>
>>
>> - In Table creation dialog, SQL is not getting generated for exclude
>> constraint
>>
>> Fixed
>
>>
>> - In Table creation dialog, schema should be prefixed with table name
>> in "of type" control
>>
>> Fixed
>
>>
>> - In Table creation dialog, while adding privileges, it always shows
>> default privileges even if user has selected different privileges. (This
>> works fine once user edit the privileges in edit table mode and shows only
>> those privileges which user selects). Ashesh, please confirm the behaviour.
>>
>> Privileges are set correctly. Only it shows in incorrect order.
>
>
>> Table edit mode:
>>
>> - If in edit mode, any constraint is already having any comment, then
>> remove it. It will not create the SQL for the same.
>>
>>
> Fixed
>
>>
>> - Changing Schema will give server error
>>
>> This is generic issue for each node.
>
>
>> Column Creation:
>>
>> - Save button is enabled by default
>> - Data type validation is not provided. Save button is enabled just
>> after providing column name
>> - Length field limitation is not provided. (i.e. for numeric type,
>> length should be allowed greater than 1000)
>>
>> *Fixed*
> Exclusion constraint creation:
>>
>> - Access method should not be allowed to be empty. (currently by
>> clicking 'x' will remove the selection in it)
>>
>> Access method is optional.
>
>
>> Index creation:
>>
>> - No error message for name field when empty
>> - No error message when column name is not provided while adding a
>> column in index
>> - While adding a column if no name is provided, "None" appears in SQL
>> tab which will give error on OK button click
>> - when comment is provided while creation, it gives error saying
>> index does not exists. because schema name is not added before it.
>>
>> *Fixed*
> Rule creation:
>>
>> - Name is empty error does not come till user enters something in
>> definition tab
>> - DO INSTEAD button does not make any difference to SQL (it works in
>> edit mode)
>>
>> *Surinder will send patch*
> Rule edit mode:
>>
>> - Add comment in edit mode, check the SQL in sql tab. Now come back
>> to general tab and removes comment and check the sql tab again.
>> SQL for comment is still there with empty string as comment
>>
>> *Surinder will send patch*
> Trigger Creation:
>>
>> - SQL is not proper when creating a trigger. "()" should be appended
>> to function name in SQL.
>> It gives error while creating a trigger
>> - "+" sign is visible in browser tree in front of trigger. either On
>> expanding trigger, it should show the trigger function name or that "+"
>> sign should not appear
>>
>> *Fixed*
> Trigger edit node:
>>
>
>> - On removing comment, nothing happens. No sql is being created.
>> Comment is still there in properties.
>>
>> *Fixed*
>
>> Regards,
>> Sanket Mehta
>> Sr Software engineer
>> Enterprisedb
>>
>
>
>
> --
> Sent via pgadmin-hackers mailing list ([email protected])
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgadmin-hackers
>
>
--
Sent via pgadmin-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgadmin-hackers
Attachments:
[application/octet-stream] table_v8.2.patch (14.1K, 3-table_v8.2.patch)
download | inline diff:
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/__init__.py
index 49d2c7b..5bcb456 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/__init__.py
@@ -369,7 +369,7 @@ class ColumnsView(PGChildNodeView, DataTypeReader):
seclabels = []
for seclbls in data['seclabels']:
k, v = seclbls.split('=')
- seclabels.append({'provider': k, 'security_label': v})
+ seclabels.append({'provider': k, 'label': v})
data['seclabels'] = seclabels
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/templates/column/js/column.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/templates/column/js/column.js
index 15716c8..688ac24 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/templates/column/js/column.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/templates/column/js/column.js
@@ -89,17 +89,21 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
var t = pgBrowser.tree, i = item, d = itemData, parents = [];
// To iterate over tree to check parent node
while (i) {
- // If it is schema then allow user to create table
- if (_.indexOf(['view', 'mview'], d._type) > -1) {
- return false;
- }
parents.push(d._type);
i = t.hasParent(i) ? t.parent(i) : null;
d = i ? t.itemData(i) : null;
}
- }
- else {
- return true;
+
+ // Check if menu is allowed ?
+ if(_.indexOf(parents, 'catalog') > -1 ||
+ _.indexOf(parents, 'view') > -1 ||
+ _.indexOf(parents, 'mview') > -1) {
+ return false;
+ } else if(_.indexOf(parents, 'table') > -1) {
+ return true;
+ }
+ } else {
+ return false;
}
},
hasDepends: true,
@@ -406,64 +410,73 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
canDelete: true
},{
id: 'seclabels', label: '{{ _('Security Labels') }}',
- model: Backform.SecurityModel, editable: false, type: 'collection',
+ model: pgAdmin.Browser.SecurityModel,
+ editable: false, type: 'collection',
group: '{{ _('Security') }}', mode: ['edit', 'create'],
- min_version: 90200, canAdd: true,
+ min_version: 90100, canAdd: true,
canEdit: false, canDelete: true, control: 'unique-col-collection'
}
],
- validate: function() {
+ validate: function(keys) {
var err = {},
changedAttrs = this.changed,
msg = undefined;
- this.errorModel.clear();
- if (_.has(changedAttrs,this.get('name'))
- && _.isUndefined(this.get('name'))
+ // Nothing to validate
+ if (keys.length == 0) {
+ this.errorModel.clear();
+ return null;
+ } else {
+ this.errorModel.clear();
+ }
+
+ if (_.isUndefined(this.get('name'))
|| String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
msg = '{{ _('Column name can not be empty.') }}';
this.errorModel.set('name', msg);
return msg;
- } else if (_.has(changedAttrs,this.get('attowner'))
- && _.isUndefined(this.get('attowner'))
- || String(this.get('attowner')).replace(/^\s+|\s+$/g, '') == '') {
- msg = '{{ _('Schema can not be empty.') }}';
- this.errorModel.set('attowner', msg);
- return msg;
- } else if (_.has(changedAttrs,this.get('attowner'))
- && _.isUndefined(this.get('attowner'))
- || String(this.get('attowner')).replace(/^\s+|\s+$/g, '') == '') {
- msg = '{{ _('Owner can not be empty.') }}';
- this.errorModel.set('attowner', msg);
+ }
+
+ if (_.isUndefined(this.get('cltype'))
+ || String(this.get('cltype')).replace(/^\s+|\s+$/g, '') == '') {
+ msg = '{{ _('Column type can not be empty.') }}';
+ this.errorModel.set('cltype', msg);
return msg;
- } else if (_.has(changedAttrs,this.get('attlen'))
- && _.isUndefined(this.get('attlen'))
- || String(this.get('attlen')).replace(/^\s+|\s+$/g, '') == '') {
+ }
+
+ if (!_.isUndefined(this.get('cltype'))
+ && !_.isUndefined(this.get('attlen'))
+ && !_.isNull(this.get('attlen'))
+ && this.get('attlen') !== '') {
// Validation for Length field
if (this.get('attlen') < this.get('min_val'))
- msg = _("Length should not be less than " + this.get('min_val'))
+ msg = '{{ _('Length should not be less than: ') }}' + this.get('min_val');
if (this.get('attlen') > this.get('max_val'))
- msg = _("Length should not be greater than " + this.get('max_val'))
+ msg = '{{ _('Length should not be greater than: ') }}' + this.get('max_val');
// If we have any error set then throw it to user
if(msg) {
this.errorModel.set('attlen', msg)
return msg;
}
- } else if (_.has(changedAttrs,this.get('attprecision'))
- && _.isUndefined(this.get('attprecision'))
- || String(this.get('attprecision')).replace(/^\s+|\s+$/g, '') == '') {
+ }
+
+ if (!_.isUndefined(this.get('cltype'))
+ && !_.isUndefined(this.get('attprecision'))
+ && !_.isNull(this.get('attprecision'))
+ && this.get('attprecision') !== '') {
// Validation for precision field
if (this.get('attprecision') < this.get('min_val'))
- msg = _("Precision should not be less than " + this.get('min_val'))
+ msg = '{{ _('Precision should not be less than: ') }}' + this.get('min_val');
if (this.get('attprecision') > this.get('max_val'))
- msg = _("Precision should not be greater than " + this.get('max_val'))
+ msg = '{{ _('Precision should not be greater than: ') }}' + this.get('max_val');
// If we have any error set then throw it to user
if(msg) {
this.errorModel.set('attprecision', msg)
return msg;
}
- return null;
- }
+ }
+
+ return null;
},
isInhertedColumn: function() {
},
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/templates/index/js/index.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/templates/index/js/index.js
index 96882d7..56cc0df 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/templates/index/js/index.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/templates/index/js/index.js
@@ -75,6 +75,16 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
}
}
],
+ validate: function() {
+ this.errorModel.clear();
+
+ if (_.isUndefined(this.get('colname'))
+ || String(this.get('colname')).replace(/^\s+|\s+$/g, '') == '') {
+ msg = '{{ _('Column Name can not be empty.') }}';
+ this.errorModel.set('colname', msg);
+ return msg;
+ }
+ },
// We will check if we are under schema node
inSchema: function() {
if(this.node_info && 'catalog' in this.node_info) {
@@ -165,7 +175,8 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
name: undefined,
nspname: undefined,
tabname: undefined,
- spcname: undefined
+ spcname: 'pg_default',
+ amname: 'btree'
},
schema: [{
id: 'name', label: '{{ _('Name') }}', cell: 'string',
@@ -176,6 +187,7 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
},{
id: 'spcname', label:'{{ _('Tablespace') }}', cell: 'string',
control: 'node-list-by-name', node: 'tablespace',
+ select2: {'allowClear': true},
type: 'text', mode: ['properties', 'create', 'edit'],
disabled: 'inSchema', filter: function(d) {
// If tablespace name is not "pg_global" then we need to exclude them
@@ -189,7 +201,7 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
id: 'amname', label:'{{ _('Access Method') }}', cell: 'string',
type: 'text', mode: ['properties', 'create', 'edit'],
disabled: 'inSchemaWithModelCheck', url: 'get_access_methods',
- group: '{{ _('Definition') }}',
+ group: '{{ _('Definition') }}', select2: {'allowClear': true},
control: Backform.NodeAjaxOptionsControl.extend({
// When access method changes we need to clear columns collection
onChange: function() {
@@ -199,7 +211,7 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
current_am = self.model.get('amname'),
// previous access method
previous_am = self.model.previous('amname');
- if (current_am != previous_am) {
+ if (current_am != previous_am && self.model.get('columns').length !== 0) {
var msg = '{{ _('Changing access method will clear columns collection') }}';
alertify.confirm(msg, function (e) {
// User clicks Ok, lets clear collection
@@ -283,19 +295,50 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
disabled: 'inSchema'
}
],
- validate: function() {
+ validate: function(keys) {
var err = {},
changedAttrs = this.changed,
msg = undefined;
- this.errorModel.clear();
- if (_.has(changedAttrs,this.get('name'))
- && _.isUndefined(this.get('name'))
+ // Nothing to validate
+ if (keys.length == 0) {
+ this.errorModel.clear();
+ return null;
+ } else {
+ this.errorModel.clear();
+ }
+
+ if (_.isUndefined(this.get('name'))
|| String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
msg = '{{ _('Name can not be empty.') }}';
this.errorModel.set('name', msg);
return msg;
}
+ if (_.isUndefined(this.get('spcname'))
+ || String(this.get('spcname')).replace(/^\s+|\s+$/g, '') == '') {
+ msg = '{{ _('Tablespace can not be empty.') }}';
+ this.errorModel.set('spcname', msg);
+ return msg;
+ }
+ if (_.isUndefined(this.get('amname'))
+ || String(this.get('amname')).replace(/^\s+|\s+$/g, '') == '') {
+ msg = '{{ _('Access method can not be empty.') }}';
+ this.errorModel.set('amname', msg);
+ return msg;
+ }
+ // Checks if all columns has names
+ var cols = this.get('columns');
+ if(cols && cols.length > 0) {
+ if(!_.every(cols.pluck('colname'))) {
+ msg = '{{ _('You must specify column name.') }}';
+ this.errorModel.set('columns', msg);
+ return msg;
+ }
+ } else if(cols){
+ msg = '{{ _('You must specify at least one column.') }}';
+ this.errorModel.set('columns', msg);
+ return msg;
+ }
return null;
},
// We will check if we are under schema node & in 'create' mode
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/alter.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/alter.sql
index 2098ddc..68a4444 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/alter.sql
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/alter.sql
@@ -5,7 +5,7 @@ ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
CLUSTER ON {{conn|qtIdent(data.name)}};
{% endif %}
{## Changes description ##}
-{% if data.description %}
+{% if data.description is defined %}
-COMMENT ON INDEX {{conn|qtIdent(data.name)}}
+COMMENT ON INDEX {{conn|qtIdent(data.schema, data.name)}}
IS {{data.description|qtLiteral}};{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/update.sql
index cb8583b..f2acd6c 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/update.sql
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/update.sql
@@ -14,11 +14,11 @@ ALTER INDEX {{conn|qtIdent(data.schema, data.name)}}
SET TABLESPACE {{conn|qtIdent(data.spcname)}};
{% endif %}
{## Alter index to use cluster type ##}
-{% if data.indisclustered and o_data.indisclustered != data.indisclustered %}
+{% if data.indisclustered is defined and o_data.indisclustered != data.indisclustered %}
ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
CLUSTER ON {{conn|qtIdent(data.name)}};
{% endif %}
{## Changes description ##}
-{% if data.description and o_data.description != data.description %}
+{% if data.description is defined and o_data.description != data.description %}
COMMENT ON INDEX {{conn|qtIdent(data.schema, data.name)}}
IS {{data.description|qtLiteral}};{% endif %}
\ No newline at end of file
view thread (49+ messages) latest in thread
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected], [email protected], [email protected]
Subject: Re: [PATCH] Tables node (pgAdmin4)
In-Reply-To: <CAKKotZQKV3nkCz8ADOV1ExoSaKWHdH4rY17xW9K3B-4qLree3Q@mail.gmail.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox