graceguo-supercat closed pull request #6257: Add sql lab localStorage config
URL: https://github.com/apache/incubator-superset/pull/6257
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
diff --git a/superset/assets/spec/javascripts/sqllab/App_spec.jsx
b/superset/assets/spec/javascripts/sqllab/App_spec.jsx
index 72192c0afa..5ba0733403 100644
--- a/superset/assets/spec/javascripts/sqllab/App_spec.jsx
+++ b/superset/assets/spec/javascripts/sqllab/App_spec.jsx
@@ -7,7 +7,7 @@ import sinon from 'sinon';
import App from 'src/SqlLab/components/App';
import TabbedSqlEditors from 'src/SqlLab/components/TabbedSqlEditors';
-import { sqlLabReducer } from 'src/SqlLab/reducers';
+import sqlLabReducer from 'src/SqlLab/reducers/index';
describe('SqlLab App', () => {
const middlewares = [thunk];
diff --git
a/superset/assets/spec/javascripts/sqllab/ExploreResultsButton_spec.jsx
b/superset/assets/spec/javascripts/sqllab/ExploreResultsButton_spec.jsx
index 71647c83cb..25c899ea03 100644
--- a/superset/assets/spec/javascripts/sqllab/ExploreResultsButton_spec.jsx
+++ b/superset/assets/spec/javascripts/sqllab/ExploreResultsButton_spec.jsx
@@ -8,8 +8,8 @@ import fetchMock from 'fetch-mock';
import shortid from 'shortid';
import { queries, queryWithBadColumns } from './fixtures';
-import { sqlLabReducer } from '../../../src/SqlLab/reducers';
-import * as actions from '../../../src/SqlLab/actions';
+import sqlLabReducer from '../../../src/SqlLab/reducers/index';
+import * as actions from '../../../src/SqlLab/actions/sqlLab';
import ExploreResultsButton from
'../../../src/SqlLab/components/ExploreResultsButton';
import * as exploreUtils from '../../../src/explore/exploreUtils';
import Button from '../../../src/components/Button';
@@ -23,9 +23,9 @@ describe('ExploreResultsButton', () => {
const initialState = {
sqlLab: {
...sqlLabReducer(undefined, {}),
- common: {
- conf: { SUPERSET_WEBSERVER_TIMEOUT: 45 },
- },
+ },
+ common: {
+ conf: { SUPERSET_WEBSERVER_TIMEOUT: 45 },
},
};
const store = mockStore(initialState);
diff --git a/superset/assets/spec/javascripts/sqllab/actions_spec.js
b/superset/assets/spec/javascripts/sqllab/actions/sqlLab_spec.js
similarity index 97%
rename from superset/assets/spec/javascripts/sqllab/actions_spec.js
rename to superset/assets/spec/javascripts/sqllab/actions/sqlLab_spec.js
index 1260621a22..7953d636d9 100644
--- a/superset/assets/spec/javascripts/sqllab/actions_spec.js
+++ b/superset/assets/spec/javascripts/sqllab/actions/sqlLab_spec.js
@@ -2,8 +2,8 @@
import sinon from 'sinon';
import fetchMock from 'fetch-mock';
-import * as actions from '../../../src/SqlLab/actions';
-import { query } from './fixtures';
+import * as actions from '../../../../src/SqlLab/actions/sqlLab';
+import { query } from '../fixtures';
describe('async actions', () => {
let dispatch;
diff --git a/superset/assets/spec/javascripts/sqllab/fixtures.js
b/superset/assets/spec/javascripts/sqllab/fixtures.js
index 77a48067b1..02a6c127f4 100644
--- a/superset/assets/spec/javascripts/sqllab/fixtures.js
+++ b/superset/assets/spec/javascripts/sqllab/fixtures.js
@@ -1,5 +1,5 @@
import sinon from 'sinon';
-import * as actions from '../../../src/SqlLab/actions';
+import * as actions from '../../../src/SqlLab/actions/sqlLab';
export const mockedActions = sinon.stub(Object.assign({}, actions));
diff --git a/superset/assets/spec/javascripts/sqllab/reducers_spec.js
b/superset/assets/spec/javascripts/sqllab/reducers/sqlLab_spec.js
similarity index 68%
rename from superset/assets/spec/javascripts/sqllab/reducers_spec.js
rename to superset/assets/spec/javascripts/sqllab/reducers/sqlLab_spec.js
index 1a451f644a..964daa8fbd 100644
--- a/superset/assets/spec/javascripts/sqllab/reducers_spec.js
+++ b/superset/assets/spec/javascripts/sqllab/reducers/sqlLab_spec.js
@@ -1,6 +1,6 @@
-import * as r from '../../../src/SqlLab/reducers';
-import * as actions from '../../../src/SqlLab/actions';
-import { table, initialState as mockState } from './fixtures';
+import sqlLabReducer from '../../../../src/SqlLab/reducers/sqlLab';
+import * as actions from '../../../../src/SqlLab/actions/sqlLab';
+import { table, initialState as mockState } from '../fixtures';
const initialState = mockState.sqlLab;
@@ -12,7 +12,7 @@ describe('sqlLabReducer', () => {
queries: { [testQuery.id]: testQuery },
};
beforeEach(() => {
- newState = r.sqlLabReducer(newState,
actions.cloneQueryToNewTab(testQuery));
+ newState = sqlLabReducer(newState,
actions.cloneQueryToNewTab(testQuery));
});
it('should have at most one more tab', () => {
@@ -39,7 +39,7 @@ describe('sqlLabReducer', () => {
newState = { ...initialState };
defaultQueryEditor = newState.queryEditors[0];
qe = Object.assign({}, defaultQueryEditor);
- newState = r.sqlLabReducer(newState, actions.addQueryEditor(qe));
+ newState = sqlLabReducer(newState, actions.addQueryEditor(qe));
qe = newState.queryEditors[newState.queryEditors.length - 1];
});
it('should add a query editor', () => {
@@ -47,44 +47,44 @@ describe('sqlLabReducer', () => {
});
it('should remove a query editor', () => {
expect(newState.queryEditors).toHaveLength(2);
- newState = r.sqlLabReducer(newState, actions.removeQueryEditor(qe));
+ newState = sqlLabReducer(newState, actions.removeQueryEditor(qe));
expect(newState.queryEditors).toHaveLength(1);
});
it('should set q query editor active', () => {
- newState = r.sqlLabReducer(newState, actions.addQueryEditor(qe));
- newState = r.sqlLabReducer(newState,
actions.setActiveQueryEditor(defaultQueryEditor));
+ newState = sqlLabReducer(newState, actions.addQueryEditor(qe));
+ newState = sqlLabReducer(newState,
actions.setActiveQueryEditor(defaultQueryEditor));
expect(newState.tabHistory[newState.tabHistory.length -
1]).toBe(defaultQueryEditor.id);
});
it('should not fail while setting DB', () => {
const dbId = 9;
- newState = r.sqlLabReducer(newState, actions.queryEditorSetDb(qe, dbId));
+ newState = sqlLabReducer(newState, actions.queryEditorSetDb(qe, dbId));
expect(newState.queryEditors[1].dbId).toBe(dbId);
});
it('should not fail while setting schema', () => {
const schema = 'foo';
- newState = r.sqlLabReducer(newState, actions.queryEditorSetSchema(qe,
schema));
+ newState = sqlLabReducer(newState, actions.queryEditorSetSchema(qe,
schema));
expect(newState.queryEditors[1].schema).toBe(schema);
});
it('should not fail while setting autorun ', () => {
- newState = r.sqlLabReducer(newState, actions.queryEditorSetAutorun(qe,
false));
+ newState = sqlLabReducer(newState, actions.queryEditorSetAutorun(qe,
false));
expect(newState.queryEditors[1].autorun).toBe(false);
- newState = r.sqlLabReducer(newState, actions.queryEditorSetAutorun(qe,
true));
+ newState = sqlLabReducer(newState, actions.queryEditorSetAutorun(qe,
true));
expect(newState.queryEditors[1].autorun).toBe(true);
});
it('should not fail while setting title', () => {
const title = 'a new title';
- newState = r.sqlLabReducer(newState, actions.queryEditorSetTitle(qe,
title));
+ newState = sqlLabReducer(newState, actions.queryEditorSetTitle(qe,
title));
expect(newState.queryEditors[1].title).toBe(title);
});
it('should not fail while setting Sql', () => {
const sql = 'SELECT nothing from dev_null';
- newState = r.sqlLabReducer(newState, actions.queryEditorSetSql(qe, sql));
+ newState = sqlLabReducer(newState, actions.queryEditorSetSql(qe, sql));
expect(newState.queryEditors[1].sql).toBe(sql);
});
it('should set selectedText', () => {
const selectedText = 'TEST';
expect(newState.queryEditors[0].selectedText).toBeNull();
- newState = r.sqlLabReducer(
+ newState = sqlLabReducer(
newState, actions.queryEditorSetSelectedText(newState.queryEditors[0],
'TEST'));
expect(newState.queryEditors[0].selectedText).toBe(selectedText);
});
@@ -94,7 +94,7 @@ describe('sqlLabReducer', () => {
let newTable;
beforeEach(() => {
newTable = Object.assign({}, table);
- newState = r.sqlLabReducer(initialState, actions.mergeTable(newTable));
+ newState = sqlLabReducer(initialState, actions.mergeTable(newTable));
newTable = newState.tables[0];
});
it('should add a table', () => {
@@ -104,18 +104,18 @@ describe('sqlLabReducer', () => {
it('should merge the table attributes', () => {
// Merging the extra attribute
newTable.extra = true;
- newState = r.sqlLabReducer(newState, actions.mergeTable(newTable));
+ newState = sqlLabReducer(newState, actions.mergeTable(newTable));
expect(newState.tables).toHaveLength(1);
expect(newState.tables[0].extra).toBe(true);
});
it('should expand and collapse a table', () => {
- newState = r.sqlLabReducer(newState, actions.collapseTable(newTable));
+ newState = sqlLabReducer(newState, actions.collapseTable(newTable));
expect(newState.tables[0].expanded).toBe(false);
- newState = r.sqlLabReducer(newState, actions.expandTable(newTable));
+ newState = sqlLabReducer(newState, actions.expandTable(newTable));
expect(newState.tables[0].expanded).toBe(true);
});
it('should remove a table', () => {
- newState = r.sqlLabReducer(newState, actions.removeTable(newTable));
+ newState = sqlLabReducer(newState, actions.removeTable(newTable));
expect(newState.tables).toHaveLength(0);
});
});
@@ -128,22 +128,22 @@ describe('sqlLabReducer', () => {
newQuery = { ...query };
});
it('should start a query', () => {
- newState = r.sqlLabReducer(newState, actions.startQuery(newQuery));
+ newState = sqlLabReducer(newState, actions.startQuery(newQuery));
expect(Object.keys(newState.queries)).toHaveLength(1);
});
it('should stop the query', () => {
- newState = r.sqlLabReducer(newState, actions.startQuery(newQuery));
- newState = r.sqlLabReducer(newState, actions.stopQuery(newQuery));
+ newState = sqlLabReducer(newState, actions.startQuery(newQuery));
+ newState = sqlLabReducer(newState, actions.stopQuery(newQuery));
const q = newState.queries[Object.keys(newState.queries)[0]];
expect(q.state).toBe('stopped');
});
it('should remove a query', () => {
- newState = r.sqlLabReducer(newState, actions.startQuery(newQuery));
- newState = r.sqlLabReducer(newState, actions.removeQuery(newQuery));
+ newState = sqlLabReducer(newState, actions.startQuery(newQuery));
+ newState = sqlLabReducer(newState, actions.removeQuery(newQuery));
expect(Object.keys(newState.queries)).toHaveLength(0);
});
it('should refresh queries when polling returns empty', () => {
- newState = r.sqlLabReducer(newState, actions.refreshQueries({}));
+ newState = sqlLabReducer(newState, actions.refreshQueries({}));
});
});
});
diff --git a/superset/assets/src/SqlLab/App.jsx
b/superset/assets/src/SqlLab/App.jsx
index 9e242c3bb0..bd5906ac5b 100644
--- a/superset/assets/src/SqlLab/App.jsx
+++ b/superset/assets/src/SqlLab/App.jsx
@@ -5,8 +5,8 @@ import thunkMiddleware from 'redux-thunk';
import { hot } from 'react-hot-loader';
import { initFeatureFlags } from 'src/featureFlags';
-import getInitialState from './getInitialState';
-import rootReducer from './reducers';
+import getInitialState from './reducers/getInitialState';
+import rootReducer from './reducers/index';
import { initEnhancer } from '../reduxUtils';
import App from './components/App';
import setupApp from '../setup/setupApp';
@@ -20,14 +20,31 @@ setupApp();
const appContainer = document.getElementById('app');
const bootstrapData = JSON.parse(appContainer.getAttribute('data-bootstrap'));
initFeatureFlags(bootstrapData.common.feature_flags);
-const state = getInitialState(bootstrapData);
+const initialState = getInitialState(bootstrapData);
+const sqlLabPersistStateConfig = {
+ paths: ['sqlLab'],
+ config: {
+ slicer: paths => (state) => {
+ const subset = {};
+ paths.forEach((path) => {
+ // this line is used to remove old data from browser localStorage.
+ // we used to persist all redux state into localStorage, but
+ // it caused configurations passed from server-side got override.
+ // see PR 6257 for details
+ delete state[path].common; // eslint-disable-line no-param-reassign
+ subset[path] = state[path];
+ });
+ return subset;
+ },
+ },
+};
const store = createStore(
rootReducer,
- state,
+ initialState,
compose(
applyMiddleware(thunkMiddleware),
- initEnhancer(),
+ initEnhancer(true, sqlLabPersistStateConfig),
),
);
diff --git a/superset/assets/src/SqlLab/actions.js
b/superset/assets/src/SqlLab/actions/sqlLab.js
similarity index 98%
rename from superset/assets/src/SqlLab/actions.js
rename to superset/assets/src/SqlLab/actions/sqlLab.js
index aac81d6369..17e022b8c7 100644
--- a/superset/assets/src/SqlLab/actions.js
+++ b/superset/assets/src/SqlLab/actions/sqlLab.js
@@ -3,14 +3,14 @@ import JSONbig from 'json-bigint';
import { t } from '@superset-ui/translation';
import { SupersetClient } from '@superset-ui/connection';
-import { now } from '../modules/dates';
+import { now } from '../../modules/dates';
import {
addSuccessToast as addSuccessToastAction,
addDangerToast as addDangerToastAction,
addInfoToast as addInfoToastAction,
-} from '../messageToasts/actions';
-import getClientErrorObject from '../utils/getClientErrorObject';
-import COMMON_ERR_MESSAGES from '../utils/errorMessages';
+} from '../../messageToasts/actions/index';
+import getClientErrorObject from '../../utils/getClientErrorObject';
+import COMMON_ERR_MESSAGES from '../../utils/errorMessages';
export const RESET_STATE = 'RESET_STATE';
export const ADD_QUERY_EDITOR = 'ADD_QUERY_EDITOR';
diff --git a/superset/assets/src/SqlLab/components/App.jsx
b/superset/assets/src/SqlLab/components/App.jsx
index 8a0c084373..6613d071ab 100644
--- a/superset/assets/src/SqlLab/components/App.jsx
+++ b/superset/assets/src/SqlLab/components/App.jsx
@@ -8,7 +8,7 @@ import TabbedSqlEditors from './TabbedSqlEditors';
import QueryAutoRefresh from './QueryAutoRefresh';
import QuerySearch from './QuerySearch';
import ToastPresenter from '../../messageToasts/containers/ToastPresenter';
-import * as Actions from '../actions';
+import * as Actions from '../actions/sqlLab';
class App extends React.PureComponent {
constructor(props) {
diff --git a/superset/assets/src/SqlLab/components/ExploreResultsButton.jsx
b/superset/assets/src/SqlLab/components/ExploreResultsButton.jsx
index 06cddbc5f1..26a246c57a 100644
--- a/superset/assets/src/SqlLab/components/ExploreResultsButton.jsx
+++ b/superset/assets/src/SqlLab/components/ExploreResultsButton.jsx
@@ -9,7 +9,7 @@ import { t } from '@superset-ui/translation';
import shortid from 'shortid';
import { exportChart } from '../../explore/exploreUtils';
-import * as actions from '../actions';
+import * as actions from '../actions/sqlLab';
import InfoTooltipWithTrigger from '../../components/InfoTooltipWithTrigger';
import Button from '../../components/Button';
@@ -184,10 +184,10 @@ class ExploreResultsButton extends React.PureComponent {
ExploreResultsButton.propTypes = propTypes;
ExploreResultsButton.defaultProps = defaultProps;
-function mapStateToProps({ sqlLab }) {
+function mapStateToProps({ sqlLab, common }) {
return {
errorMessage: sqlLab.errorMessage,
- timeout: sqlLab.common ? sqlLab.common.conf.SUPERSET_WEBSERVER_TIMEOUT :
null,
+ timeout: common.conf ? common.conf.SUPERSET_WEBSERVER_TIMEOUT : null,
};
}
diff --git a/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx
b/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx
index 2937e159b3..295c32f8bb 100644
--- a/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx
+++ b/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx
@@ -4,7 +4,7 @@ import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { SupersetClient } from '@superset-ui/connection';
-import * as Actions from '../actions';
+import * as Actions from '../actions/sqlLab';
const QUERY_UPDATE_FREQ = 2000;
const QUERY_UPDATE_BUFFER_MS = 5000;
diff --git a/superset/assets/src/SqlLab/components/SouthPane.jsx
b/superset/assets/src/SqlLab/components/SouthPane.jsx
index eddc808231..3f6fb42d24 100644
--- a/superset/assets/src/SqlLab/components/SouthPane.jsx
+++ b/superset/assets/src/SqlLab/components/SouthPane.jsx
@@ -6,7 +6,7 @@ import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { t } from '@superset-ui/translation';
-import * as Actions from '../actions';
+import * as Actions from '../actions/sqlLab';
import QueryHistory from './QueryHistory';
import ResultSet from './ResultSet';
import { STATUS_OPTIONS, STATE_BSSTYLE_MAP } from '../constants';
diff --git a/superset/assets/src/SqlLab/components/TabbedSqlEditors.jsx
b/superset/assets/src/SqlLab/components/TabbedSqlEditors.jsx
index 43b73546cd..0fb5f21047 100644
--- a/superset/assets/src/SqlLab/components/TabbedSqlEditors.jsx
+++ b/superset/assets/src/SqlLab/components/TabbedSqlEditors.jsx
@@ -6,7 +6,7 @@ import { bindActionCreators } from 'redux';
import URI from 'urijs';
import { t } from '@superset-ui/translation';
-import * as Actions from '../actions';
+import * as Actions from '../actions/sqlLab';
import SqlEditor from './SqlEditor';
import { areArraysShallowEqual } from '../../reduxUtils';
import TabStatusIcon from './TabStatusIcon';
diff --git a/superset/assets/src/SqlLab/reducers/common.js
b/superset/assets/src/SqlLab/reducers/common.js
new file mode 100644
index 0000000000..738291c923
--- /dev/null
+++ b/superset/assets/src/SqlLab/reducers/common.js
@@ -0,0 +1,3 @@
+export default function commonReducer(state = {}) {
+ return state;
+}
diff --git a/superset/assets/src/SqlLab/getInitialState.js
b/superset/assets/src/SqlLab/reducers/getInitialState.js
similarity index 77%
rename from superset/assets/src/SqlLab/getInitialState.js
rename to superset/assets/src/SqlLab/reducers/getInitialState.js
index ba984c2b9c..14bd677d39 100644
--- a/superset/assets/src/SqlLab/getInitialState.js
+++ b/superset/assets/src/SqlLab/reducers/getInitialState.js
@@ -1,6 +1,6 @@
import shortid from 'shortid';
import { t } from '@superset-ui/translation';
-import getToastsFromPyFlashMessages from
'../messageToasts/utils/getToastsFromPyFlashMessages';
+import getToastsFromPyFlashMessages from
'../../messageToasts/utils/getToastsFromPyFlashMessages';
export default function getInitialState({ defaultDbId, ...restBootstrapData })
{
const defaultQueryEditor = {
@@ -24,10 +24,13 @@ export default function getInitialState({ defaultDbId,
...restBootstrapData }) {
tabHistory: [defaultQueryEditor.id],
tables: [],
queriesLastUpdate: Date.now(),
- ...restBootstrapData,
},
messageToasts: getToastsFromPyFlashMessages(
(restBootstrapData.common || {}).flash_messages || [],
),
+ common: {
+ flash_messages: restBootstrapData.common.flash_messages,
+ conf: restBootstrapData.common.conf,
+ },
};
}
diff --git a/superset/assets/src/SqlLab/reducers/index.js
b/superset/assets/src/SqlLab/reducers/index.js
new file mode 100644
index 0000000000..c1dcd2874d
--- /dev/null
+++ b/superset/assets/src/SqlLab/reducers/index.js
@@ -0,0 +1,11 @@
+import { combineReducers } from 'redux';
+
+import sqlLab from './sqlLab';
+import messageToasts from '../../messageToasts/reducers/index';
+import common from './common';
+
+export default combineReducers({
+ sqlLab,
+ messageToasts,
+ common,
+});
diff --git a/superset/assets/src/SqlLab/reducers.js
b/superset/assets/src/SqlLab/reducers/sqlLab.js
similarity index 96%
rename from superset/assets/src/SqlLab/reducers.js
rename to superset/assets/src/SqlLab/reducers/sqlLab.js
index 87d033251a..b8a27a97d4 100644
--- a/superset/assets/src/SqlLab/reducers.js
+++ b/superset/assets/src/SqlLab/reducers/sqlLab.js
@@ -1,11 +1,9 @@
-import { combineReducers } from 'redux';
import shortid from 'shortid';
import { t } from '@superset-ui/translation';
-import messageToasts from '../messageToasts/reducers';
import getInitialState from './getInitialState';
-import * as actions from './actions';
-import { now } from '../modules/dates';
+import * as actions from '../actions/sqlLab';
+import { now } from '../../modules/dates';
import {
addToObject,
alterInObject,
@@ -13,9 +11,9 @@ import {
removeFromArr,
getFromArr,
addToArr,
-} from '../reduxUtils';
+} from '../../reduxUtils';
-export const sqlLabReducer = function (state = {}, action) {
+export default function sqlLabReducer(state = {}, action) {
const actionHandlers = {
[actions.ADD_QUERY_EDITOR]() {
const tabHistory = state.tabHistory.slice();
@@ -276,9 +274,4 @@ export const sqlLabReducer = function (state = {}, action) {
return actionHandlers[action.type]();
}
return state;
-};
-
-export default combineReducers({
- sqlLab: sqlLabReducer,
- messageToasts,
-});
+}
diff --git a/superset/assets/src/reduxUtils.js
b/superset/assets/src/reduxUtils.js
index cc0b5810c3..baaa05bc93 100644
--- a/superset/assets/src/reduxUtils.js
+++ b/superset/assets/src/reduxUtils.js
@@ -68,14 +68,16 @@ export function addToArr(state, arrKey, obj, prepend =
false) {
return Object.assign({}, state, newState);
}
-export function initEnhancer(persist = true) {
- let enhancer = persist ? compose(persistState()) : compose();
- if (process.env.WEBPACK_MODE === 'development') {
+export function initEnhancer(persist = true, persistConfig = {}) {
+ const { paths, config } = persistConfig;
+ const composeEnhancers = process.env.WEBPACK_MODE === 'development'
/* eslint-disable-next-line no-underscore-dangle */
- const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ||
compose;
- enhancer = persist ? composeEnhancers(persistState()) : composeEnhancers();
- }
- return enhancer;
+ ? (window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose)
+ : compose;
+
+ return persist
+ ? composeEnhancers(persistState(paths, config))
+ : composeEnhancers();
}
export function areArraysShallowEqual(arr1, arr2) {
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
With regards,
Apache Git Services
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]