ketcher-react
Version:
Web-based molecule sketcher
1,113 lines (1,093 loc) • 2.12 MB
JavaScript
/****************************************************************************
* Copyright 2021 EPAM Systems
*
* 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.
***************************************************************************/
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var _defineProperty$1 = require('@babel/runtime/helpers/defineProperty');
var _slicedToArray$1 = require('@babel/runtime/helpers/slicedToArray');
var jsxRuntime = require('react/jsx-runtime');
var React = require('react');
require('intersection-observer');
require('element-closest-polyfill');
require('regenerator-runtime/runtime');
require('url-search-params-polyfill');
require('whatwg-fetch');
var _asyncToGenerator = require('@babel/runtime/helpers/asyncToGenerator');
var _regeneratorRuntime = require('@babel/runtime/regenerator');
var _classCallCheck$2 = require('@babel/runtime/helpers/classCallCheck');
var _createClass$2 = require('@babel/runtime/helpers/createClass');
var ketcherCore = require('ketcher-core');
var _objectWithoutProperties = require('@babel/runtime/helpers/objectWithoutProperties');
var _possibleConstructorReturn$2 = require('@babel/runtime/helpers/possibleConstructorReturn');
var _getPrototypeOf$2 = require('@babel/runtime/helpers/getPrototypeOf');
var _inherits$2 = require('@babel/runtime/helpers/inherits');
var clsx = require('clsx');
var _typeof$3 = require('@babel/runtime/helpers/typeof');
var Ajv = require('ajv');
var fp = require('lodash/fp');
var _toConsumableArray = require('@babel/runtime/helpers/toConsumableArray');
var _ = require('lodash');
var _taggedTemplateLiteral = require('@babel/runtime/helpers/taggedTemplateLiteral');
var styled = require('@emotion/styled');
var react = require('@emotion/react');
var KN = require('w3c-keyname');
var require$$0$2 = require('util');
var ReactDOM = require('react-dom');
var reactRedux = require('react-redux');
var redux = require('redux');
var CFB = require('cfb');
require('redux-logger');
var thunkMiddleware = require('redux-thunk');
var useResizeObserver = require('use-resize-observer/polyfilled');
var reactIntersectionObserver = require('react-intersection-observer');
var material = require('@mui/material');
var reselect = require('reselect');
var reactDeviceDetect = require('react-device-detect');
var _classPrivateFieldGet = require('@babel/runtime/helpers/classPrivateFieldGet');
var _classPrivateFieldSet = require('@babel/runtime/helpers/classPrivateFieldSet');
var _assertThisInitialized$2 = require('@babel/runtime/helpers/assertThisInitialized');
var subscription = require('subscription');
var reactContexify = require('react-contexify');
require('react-contexify/ReactContexify.css');
var MuiSelect = require('@mui/material/Select');
var Divider$2 = require('@mui/material/Divider');
var MenuItem = require('@mui/material/MenuItem');
var reactColorful = require('react-colorful');
var fileSaver$1 = require('file-saver');
var FontFaceObserver = require('font-face-observer');
var reactDropzone = require('react-dropzone');
var Accordion$2 = require('@mui/material/Accordion');
var AccordionSummary = require('@mui/material/AccordionSummary');
var AccordionDetails = require('@mui/material/AccordionDetails');
var Tabs$1 = require('@mui/material/Tabs');
var Tab = require('@mui/material/Tab');
require('draft-js/dist/Draft.css');
var draftJs = require('draft-js');
var createStyles = require('draft-js-custom-styles');
var _objectDestructuringEmpty = require('@babel/runtime/helpers/objectDestructuringEmpty');
var _extends$3n = require('@babel/runtime/helpers/extends');
var MuiAutocomplete = require('@mui/material/Autocomplete');
var client = require('react-dom/client');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n["default"] = e;
return Object.freeze(n);
}
var _defineProperty__default = /*#__PURE__*/_interopDefaultLegacy(_defineProperty$1);
var _slicedToArray__default = /*#__PURE__*/_interopDefaultLegacy(_slicedToArray$1);
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
var React__namespace = /*#__PURE__*/_interopNamespace(React);
var _asyncToGenerator__default = /*#__PURE__*/_interopDefaultLegacy(_asyncToGenerator);
var _regeneratorRuntime__default = /*#__PURE__*/_interopDefaultLegacy(_regeneratorRuntime);
var _classCallCheck__default = /*#__PURE__*/_interopDefaultLegacy(_classCallCheck$2);
var _createClass__default = /*#__PURE__*/_interopDefaultLegacy(_createClass$2);
var _objectWithoutProperties__default = /*#__PURE__*/_interopDefaultLegacy(_objectWithoutProperties);
var _possibleConstructorReturn__default = /*#__PURE__*/_interopDefaultLegacy(_possibleConstructorReturn$2);
var _getPrototypeOf__default = /*#__PURE__*/_interopDefaultLegacy(_getPrototypeOf$2);
var _inherits__default = /*#__PURE__*/_interopDefaultLegacy(_inherits$2);
var clsx__default = /*#__PURE__*/_interopDefaultLegacy(clsx);
var _typeof__default = /*#__PURE__*/_interopDefaultLegacy(_typeof$3);
var Ajv__default = /*#__PURE__*/_interopDefaultLegacy(Ajv);
var _toConsumableArray__default = /*#__PURE__*/_interopDefaultLegacy(_toConsumableArray);
var ___default = /*#__PURE__*/_interopDefaultLegacy(_);
var _taggedTemplateLiteral__default = /*#__PURE__*/_interopDefaultLegacy(_taggedTemplateLiteral);
var styled__default = /*#__PURE__*/_interopDefaultLegacy(styled);
var KN__namespace = /*#__PURE__*/_interopNamespace(KN);
var require$$0__default = /*#__PURE__*/_interopDefaultLegacy(require$$0$2);
var ReactDOM__default = /*#__PURE__*/_interopDefaultLegacy(ReactDOM);
var CFB__namespace = /*#__PURE__*/_interopNamespace(CFB);
var thunkMiddleware__default = /*#__PURE__*/_interopDefaultLegacy(thunkMiddleware);
var useResizeObserver__default = /*#__PURE__*/_interopDefaultLegacy(useResizeObserver);
var _classPrivateFieldGet__default = /*#__PURE__*/_interopDefaultLegacy(_classPrivateFieldGet);
var _classPrivateFieldSet__default = /*#__PURE__*/_interopDefaultLegacy(_classPrivateFieldSet);
var _assertThisInitialized__default = /*#__PURE__*/_interopDefaultLegacy(_assertThisInitialized$2);
var MuiSelect__default = /*#__PURE__*/_interopDefaultLegacy(MuiSelect);
var Divider__default = /*#__PURE__*/_interopDefaultLegacy(Divider$2);
var MenuItem__default = /*#__PURE__*/_interopDefaultLegacy(MenuItem);
var FontFaceObserver__default = /*#__PURE__*/_interopDefaultLegacy(FontFaceObserver);
var Accordion__default = /*#__PURE__*/_interopDefaultLegacy(Accordion$2);
var AccordionSummary__default = /*#__PURE__*/_interopDefaultLegacy(AccordionSummary);
var AccordionDetails__default = /*#__PURE__*/_interopDefaultLegacy(AccordionDetails);
var Tabs__default = /*#__PURE__*/_interopDefaultLegacy(Tabs$1);
var Tab__default = /*#__PURE__*/_interopDefaultLegacy(Tab);
var createStyles__default = /*#__PURE__*/_interopDefaultLegacy(createStyles);
var _objectDestructuringEmpty__default = /*#__PURE__*/_interopDefaultLegacy(_objectDestructuringEmpty);
var _extends__default = /*#__PURE__*/_interopDefaultLegacy(_extends$3n);
var MuiAutocomplete__default = /*#__PURE__*/_interopDefaultLegacy(MuiAutocomplete);
function createApi(structServiceProvider, defaultOptions) {
var _structService$destro;
var structService = structServiceProvider.createStructService(defaultOptions);
var info = structService.info();
return Object.assign(info, {
info: structService.info.bind(structService),
convert: structService.convert.bind(structService),
layout: structService.layout.bind(structService),
clean: structService.clean.bind(structService),
aromatize: structService.aromatize.bind(structService),
dearomatize: structService.dearomatize.bind(structService),
calculateCip: structService.calculateCip.bind(structService),
automap: structService.automap.bind(structService),
check: structService.check.bind(structService),
calculate: structService.calculate.bind(structService),
recognize: structService.recognize.bind(structService),
generateImageAsBase64: structService.generateImageAsBase64.bind(structService),
getInChIKey: structService.getInChIKey.bind(structService),
toggleExplicitHydrogens: structService.toggleExplicitHydrogens.bind(structService),
destroy: (_structService$destro = structService.destroy) === null || _structService$destro === void 0 ? void 0 : _structService$destro.bind(structService)
});
}
var appContext = React__default["default"].createContext({});
var errorsContext = React__default["default"].createContext({});
var settingsContext = React__default["default"].createContext({});
var formContext = React__default["default"].createContext(null);
var basicAtoms = ['H', 'C', 'N', 'O', 'S', 'P', 'F', 'Cl', 'Br', 'I'];
var atomCuts = {
H: 'h',
C: 'c',
N: 'n',
O: 'o',
S: 's',
P: 'p',
F: 'f',
Cl: 'l',
Br: 'b',
I: 'i',
A: 'a',
Q: 'q',
R: 'r',
K: 'k',
M: 'm',
Si: 'Shift+s',
Na: 'Shift+n',
X: 'x',
D: 'd',
B: 'Shift+b'
};
var atoms = Object.keys(atomCuts).reduce(function (res, label) {
res["atom-".concat(label.toLowerCase())] = {
title: "Atom ".concat(label),
shortcut: atomCuts[label],
action: {
tool: 'atom',
opts: {
label: label
}
}
};
return res;
}, {});
function copyAs(type) {
var state = global.currentState;
var editor = state.editor;
var struct = editor.structSelected();
var errorHandler = editor.errorHandler;
var serializer;
try {
switch (type) {
case 'mol':
{
serializer = new ketcherCore.MolSerializer();
break;
}
case 'ket':
{
serializer = new ketcherCore.KetSerializer();
break;
}
default:
{
serializer = new ketcherCore.KetSerializer();
break;
}
}
var simpleObjectOrText = Boolean(struct.simpleObjects.size || struct.texts.size);
if (simpleObjectOrText && serializer instanceof ketcherCore.MolSerializer) {
errorHandler('This feature is not available for Simple objects and Text objects');
return null;
}
var structData = serializer.serialize(struct);
if (window.clipboardData) {
window.clipboardData.setData('text', structData);
} else {
navigator.clipboard.writeText(structData);
}
} catch (e) {
ketcherCore.KetcherLogger.error('copyAs.js::copyAs', e);
errorHandler('This feature is not available in your browser');
}
}
function copyImageToClipboard() {
return _copyImageToClipboard.apply(this, arguments);
}
function _copyImageToClipboard() {
_copyImageToClipboard = _asyncToGenerator__default["default"]( _regeneratorRuntime__default["default"].mark(function _callee() {
var state, editor, server, options, struct, errorHandler, factory, service, structStr, ketcher, image, item;
return _regeneratorRuntime__default["default"].wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
state = global.currentState;
editor = state.editor;
server = state.server;
options = state.options;
struct = editor.structSelected();
errorHandler = editor.errorHandler;
_context.prev = 6;
factory = new ketcherCore.FormatterFactory(server);
service = factory.create('ket', options);
_context.next = 11;
return service.getStructureFromStructAsync(struct);
case 11:
structStr = _context.sent;
ketcher = new ketcherCore.Ketcher(editor, server, {}, factory);
_context.next = 15;
return ketcher.generateImage(structStr, {
outputFormat: 'png',
backgroundColor: '255, 255, 255',
bondThickness: options.settings.bondThickness || ketcherCore.defaultBondThickness
});
case 15:
image = _context.sent;
item = new ClipboardItem(_defineProperty__default["default"]({}, image.type, image));
_context.next = 19;
return navigator.clipboard.write([item]);
case 19:
_context.next = 25;
break;
case 21:
_context.prev = 21;
_context.t0 = _context["catch"](6);
ketcherCore.KetcherLogger.error('copyImageToClipboard.js::copyImageToClipboard', _context.t0);
errorHandler('This feature is not available in your browser');
case 25:
case "end":
return _context.stop();
}
}, _callee, null, [[6, 21]]);
}));
return _copyImageToClipboard.apply(this, arguments);
}
function isHidden(options, buttonName) {
var _options$buttons;
return Boolean((_options$buttons = options.buttons) === null || _options$buttons === void 0 || (_options$buttons = _options$buttons[buttonName]) === null || _options$buttons === void 0 ? void 0 : _options$buttons.hidden);
}
var debugObj = {
'force-update': {
shortcut: 'Ctrl+Shift+r',
action: function action(editor) {
editor.update(true);
},
hidden: function hidden(options) {
return isHidden(options, 'force-update');
}
},
'qs-serialize': {
shortcut: 'Alt+Shift+r',
action: function action(editor) {
var molSerializer = new ketcherCore.MolSerializer();
var molStr = molSerializer.serialize(editor.struct());
var molQs = 'mol=' + encodeURIComponent(molStr).replace(/%20/g, '+');
var qs = document.location.search;
document.location.search = !qs ? '?' + molQs
: qs.search('mol=') === -1 ? qs + '&' + molQs : qs.replace(/mol=[^&$]*/, molQs);
}
},
hidden: function hidden(options) {
return isHidden(options, 'qs-serialize');
}
};
var classes$Q = {"cliparea":"cliparea-module_cliparea__GdPrN"};
function _createForOfIteratorHelper$h(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray$i(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
function _unsupportedIterableToArray$i(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray$i(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$i(o, minLen); }
function _arrayLikeToArray$i(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
function _callSuper$e(t, o, e) { return o = _getPrototypeOf__default["default"](o), _possibleConstructorReturn__default["default"](t, _isNativeReflectConstruct$g() ? Reflect.construct(o, e || [], _getPrototypeOf__default["default"](t).constructor) : o.apply(t, e)); }
function _isNativeReflectConstruct$g() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct$g = function _isNativeReflectConstruct() { return !!t; })(); }
var ieCb = typeof window !== 'undefined' ? window.clipboardData : {};
var CLIP_AREA_BASE_CLASS = 'cliparea';
var needSkipCopyEvent = false;
var ClipArea = function (_Component) {
_inherits__default["default"](ClipArea, _Component);
function ClipArea(props) {
var _this;
_classCallCheck__default["default"](this, ClipArea);
_this = _callSuper$e(this, ClipArea, [props]);
_this.textAreaRef = React.createRef();
return _this;
}
_createClass__default["default"](ClipArea, [{
key: "componentDidMount",
value: function componentDidMount() {
var _this2 = this;
var el = this.textAreaRef.current;
this.target = this.props.target || el.parentNode;
this.listeners = {
mouseup: function mouseup(event) {
if (el === event.target || !isActiveElement(event.target) && _this2.props.focused()) {
autoselect(el);
}
},
mousedown: function mousedown(event) {
if (event.shiftKey && !isActiveElement(event.target)) event.preventDefault();
},
copy: function copy(event) {
if (!_this2.props.focused()) {
return;
}
if (ketcherCore.isClipboardAPIAvailable()) {
_this2.props.onCopy().then(function (data) {
if (!data) {
return;
}
_copy(data).then(function () {
event.preventDefault();
ketcherCore.notifyCopyCut();
});
});
} else {
if (needSkipCopyEvent) {
needSkipCopyEvent = false;
return;
}
needSkipCopyEvent = true;
_this2.props.onCopy().then(function (data) {
addEventListener('copy', function (evt) {
legacyCopy(evt.clipboardData, data);
evt.preventDefault();
}, {
once: true
});
document.execCommand('copy');
});
event.preventDefault();
}
},
cut: function () {
var _cut = _asyncToGenerator__default["default"]( _regeneratorRuntime__default["default"].mark(function _callee(event) {
var data;
return _regeneratorRuntime__default["default"].wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
if (_this2.props.focused()) {
_context.next = 2;
break;
}
return _context.abrupt("return");
case 2:
if (ketcherCore.isClipboardAPIAvailable()) {
_this2.props.onCut().then(function (data) {
if (!data) {
return;
}
_copy(data).then(function () {
event.preventDefault();
ketcherCore.notifyCopyCut();
});
});
} else {
data = _this2.props.onLegacyCut();
if (data) {
legacyCopy(event.clipboardData, data);
}
event.preventDefault();
}
case 3:
case "end":
return _context.stop();
}
}, _callee);
}));
function cut(_x) {
return _cut.apply(this, arguments);
}
return cut;
}(),
paste: function paste(event) {
if (!_this2.props.focused()) {
return;
}
if (ketcherCore.isClipboardAPIAvailable()) {
navigator.clipboard.read().then(function (data) {
if (!data) {
return;
}
_this2.props.onPaste(data).then(function () {
event.preventDefault();
ketcherCore.notifyRequestCompleted();
});
});
} else {
var data = legacyPaste(event.clipboardData, _this2.props.formats);
if (data) {
_this2.props.onLegacyPaste(data);
}
event.preventDefault();
}
},
keydown: function () {
var _keydown = _asyncToGenerator__default["default"]( _regeneratorRuntime__default["default"].mark(function _callee2(event) {
var _navigator$clipboard, clipboardData, data, _window$ketcher$edito, _window$ketcher$edito2;
return _regeneratorRuntime__default["default"].wrap(function _callee2$(_context2) {
while (1) switch (_context2.prev = _context2.next) {
case 0:
if (!(!_this2.props.focused() || !_this2.props.onPaste)) {
_context2.next = 2;
break;
}
return _context2.abrupt("return");
case 2:
if (!(ketcherCore.isControlKey(event) && event.altKey && event.code === 'KeyV')) {
_context2.next = 14;
break;
}
if (!((_navigator$clipboard = navigator.clipboard) !== null && _navigator$clipboard !== void 0 && _navigator$clipboard.read)) {
_context2.next = 13;
break;
}
_context2.next = 6;
return navigator.clipboard.read();
case 6:
clipboardData = _context2.sent;
_context2.next = 9;
return pasteByKeydown(clipboardData);
case 9:
data = _context2.sent;
if (data) {
_this2.props.onPaste(data, true);
}
_context2.next = 14;
break;
case 13:
(_window$ketcher$edito = (_window$ketcher$edito2 = window.ketcher.editor).errorHandler) === null || _window$ketcher$edito === void 0 || _window$ketcher$edito.call(_window$ketcher$edito2, "Your browser doesn't support pasting clipboard content via Ctrl-Alt-V. Please use Google Chrome browser or load SMARTS structure from .smarts file instead.");
case 14:
case "end":
return _context2.stop();
}
}, _callee2);
}));
function keydown(_x2) {
return _keydown.apply(this, arguments);
}
return keydown;
}()
};
Object.keys(this.listeners).forEach(function (en) {
_this2.target.addEventListener(en, _this2.listeners[en]);
});
}
}, {
key: "shouldComponentUpdate",
value: function shouldComponentUpdate() {
return false;
}
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
var _this3 = this;
Object.keys(this.listeners).forEach(function (en) {
_this3.target.removeEventListener(en, _this3.listeners[en]);
});
}
}, {
key: "render",
value: function render() {
return jsxRuntime.jsx("textarea", {
ref: this.textAreaRef,
className: clsx__default["default"](CLIP_AREA_BASE_CLASS, classes$Q.cliparea),
contentEditable: true,
autoFocus: true
,
suppressContentEditableWarning: true
});
}
}]);
return ClipArea;
}(React.Component);
function isActiveElement(el) {
if (el.tagName === 'INPUT' && el.type === 'button') return false;
return ['INPUT', 'SELECT', 'TEXTAREA', 'OPTION', 'LABEL'].includes(el.tagName);
}
function autoselect(cliparea) {
cliparea.value = ' ';
cliparea.select();
}
function _copy(_x3) {
return _copy2.apply(this, arguments);
}
function _copy2() {
_copy2 = _asyncToGenerator__default["default"]( _regeneratorRuntime__default["default"].mark(function _callee3(data) {
var clipboardItemData, clipboardItem, textData;
return _regeneratorRuntime__default["default"].wrap(function _callee3$(_context3) {
while (1) switch (_context3.prev = _context3.next) {
case 0:
_context3.prev = 0;
clipboardItemData = {};
Object.keys(data).forEach(function (mimeType) {
var mimeTypeToSet = mimeType === 'text/plain' ? mimeType : "web ".concat(mimeType);
clipboardItemData[mimeTypeToSet] = Promise.resolve(new Blob([data[mimeType]], {
type: mimeTypeToSet
}));
});
clipboardItem = new ClipboardItem(clipboardItemData);
if (!(clipboardItem.presentationStyle && clipboardItem.presentationStyle === 'unspecified')) {
_context3.next = 11;
break;
}
if (!navigator.clipboard.writeText) {
_context3.next = 9;
break;
}
textData = data['text/plain'] || JSON.stringify(data);
_context3.next = 9;
return navigator.clipboard.writeText(textData);
case 9:
_context3.next = 13;
break;
case 11:
_context3.next = 13;
return navigator.clipboard.write([clipboardItem]);
case 13:
_context3.next = 19;
break;
case 15:
_context3.prev = 15;
_context3.t0 = _context3["catch"](0);
ketcherCore.KetcherLogger.error('cliparea.jsx::copy', _context3.t0);
case 19:
case "end":
return _context3.stop();
}
}, _callee3, null, [[0, 15]]);
}));
return _copy2.apply(this, arguments);
}
function legacyCopy(clipboardData, data) {
if (!clipboardData && ieCb) {
ieCb.setData('text', data['text/plain']);
} else {
var curFmt = null;
clipboardData.setData('text/plain', data['text/plain']);
try {
Object.keys(data).forEach(function (fmt) {
curFmt = fmt;
clipboardData.setData(fmt, data[fmt]);
});
} catch (e) {
}
}
}
function legacyPaste(cb, formats) {
var data = {};
if (!cb && ieCb) {
data['text/plain'] = ieCb.getData('text');
} else {
data['text/plain'] = cb.getData('text/plain');
data = formats.reduce(function (res, fmt) {
var d = cb.getData(fmt);
if (d) res[fmt] = d;
return res;
}, data);
}
return data;
}
function pasteByKeydown(_x4) {
return _pasteByKeydown.apply(this, arguments);
}
function _pasteByKeydown() {
_pasteByKeydown = _asyncToGenerator__default["default"]( _regeneratorRuntime__default["default"].mark(function _callee4(clipboardData) {
var data, _iterator, _step, item, textPlain;
return _regeneratorRuntime__default["default"].wrap(function _callee4$(_context4) {
while (1) switch (_context4.prev = _context4.next) {
case 0:
data = {};
if (!(!clipboardData && ieCb)) {
_context4.next = 5;
break;
}
data['text/plain'] = ieCb.getData('text');
_context4.next = 26;
break;
case 5:
_iterator = _createForOfIteratorHelper$h(clipboardData);
_context4.prev = 6;
_iterator.s();
case 8:
if ((_step = _iterator.n()).done) {
_context4.next = 18;
break;
}
item = _step.value;
_context4.next = 12;
return item.getType('text/plain');
case 12:
textPlain = _context4.sent;
_context4.next = 15;
return textPlain.text();
case 15:
data['text/plain'] = _context4.sent;
case 16:
_context4.next = 8;
break;
case 18:
_context4.next = 23;
break;
case 20:
_context4.prev = 20;
_context4.t0 = _context4["catch"](6);
_iterator.e(_context4.t0);
case 23:
_context4.prev = 23;
_iterator.f();
return _context4.finish(23);
case 26:
return _context4.abrupt("return", data);
case 27:
case "end":
return _context4.stop();
}
}, _callee4, null, [[6, 20, 23, 26]]);
}));
return _pasteByKeydown.apply(this, arguments);
}
var actions = ['cut', 'copy', 'paste'];
function exec(action) {
var enabled = document.queryCommandSupported(action);
if (enabled) {
try {
enabled = document.execCommand(action) || window.ClipboardEvent || ieCb;
} catch (e) {
ketcherCore.KetcherLogger.error('cliparea.jsx::exec', e);
enabled = false;
}
}
return enabled;
}
function ownKeys$1v(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread$1v(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$1v(Object(t), !0).forEach(function (r) { _defineProperty__default["default"](e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$1v(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
var MeasurementUnits;
(function (MeasurementUnits) {
MeasurementUnits["Px"] = "px";
MeasurementUnits["Cm"] = "cm";
MeasurementUnits["Pt"] = "pt";
MeasurementUnits["Inch"] = "inch";
})(MeasurementUnits || (MeasurementUnits = {}));
var ImageResolution;
(function (ImageResolution) {
ImageResolution["high"] = "600";
ImageResolution["low"] = "72";
})(ImageResolution || (ImageResolution = {}));
var editor = {
resetToSelect: {
title: 'Reset to Select Tool',
"enum": [true, 'paste', false],
enumNames: ['on', 'After Paste', 'off'],
"default": 'paste'
},
rotationStep: {
title: 'Rotation Step, º',
type: 'integer',
minimum: 1,
maximum: 90,
"default": 15
}
};
var render = {
showValenceWarnings: {
title: 'Show valence warnings',
type: 'boolean',
description: 'slider',
"default": true
},
atomColoring: {
title: 'Atom coloring',
type: 'boolean',
description: 'slider',
"default": true
},
showStereoFlags: {
title: 'Show the Stereo flags',
type: 'boolean',
description: 'slider',
"default": true
},
stereoLabelStyle: {
title: "Label display at\xA0stereogenic\xA0centers",
"enum": [ketcherCore.StereLabelStyleType.IUPAC, ketcherCore.StereLabelStyleType.Classic, ketcherCore.StereLabelStyleType.On, ketcherCore.StereLabelStyleType.Off],
enumNames: ['IUPAC style', 'Classic', 'On', 'Off'],
"default": ketcherCore.StereLabelStyleType.IUPAC
},
colorOfAbsoluteCenters: {
title: ' Absolute Center color',
type: 'string',
"default": '#ff0000'
},
colorOfAndCenters: {
title: 'AND Centers color',
type: 'string',
"default": '#0000cd'
},
colorOfOrCenters: {
title: 'OR Centers color',
type: 'string',
"default": '#228b22'
},
colorStereogenicCenters: {
title: 'Color stereogenic centers',
"enum": [ketcherCore.StereoColoringType.LabelsOnly, ketcherCore.StereoColoringType.BondsOnly, ketcherCore.StereoColoringType.LabelsAndBonds, ketcherCore.StereoColoringType.Off],
enumNames: ['Labels Only', 'Bonds Only', 'Labels And Bonds', 'Off'],
"default": ketcherCore.StereoColoringType.LabelsOnly
},
autoFadeOfStereoLabels: {
title: 'Auto fade And/Or center labels',
type: 'boolean',
description: 'slider',
"default": true
},
absFlagLabel: {
title: 'Text of Absolute flag',
type: 'string',
"default": 'ABS'
},
andFlagLabel: {
title: 'Text of AND flag',
type: 'string',
"default": 'AND Enantiomer'
},
mixedFlagLabel: {
title: 'Text of Mixed flag',
type: 'string',
"default": 'Mixed'
},
ignoreChiralFlag: {
title: 'Ignore the chiral flag',
type: 'boolean',
description: 'slider',
"default": false
},
orFlagLabel: {
title: 'Text of OR flag',
type: 'string',
"default": 'OR Enantiomer'
},
font: {
title: 'Font',
type: 'string',
"default": '30px Arial'
},
fontsz: {
title: 'Font size',
type: 'number',
"default": 13,
minimum: 0.1,
maximum: 96
},
fontszUnit: {
title: 'Font size unit',
"enum": Object.values(MeasurementUnits),
enumNames: Object.values(MeasurementUnits),
"default": MeasurementUnits.Px
},
fontszsub: {
title: 'Sub font size',
type: 'number',
"default": 13,
minimum: 0.1,
maximum: 96
},
fontszsubUnit: {
title: 'Sub font size unit',
"enum": Object.values(MeasurementUnits),
enumNames: Object.values(MeasurementUnits),
"default": MeasurementUnits.Px
},
carbonExplicitly: {
title: 'Display carbon explicitly',
type: 'boolean',
description: 'slider',
"default": false
},
showCharge: {
title: 'Display charge',
type: 'boolean',
description: 'slider',
"default": true
},
showValence: {
title: 'Display valence',
type: 'boolean',
description: 'slider',
"default": true
},
showHydrogenLabels: {
title: 'Show hydrogen labels',
"enum": Object.values(ketcherCore.ShowHydrogenLabels),
enumNames: Object.values(ketcherCore.ShowHydrogenLabelNames),
"default": ketcherCore.ShowHydrogenLabels.TerminalAndHetero
},
aromaticCircle: {
title: 'Aromatic Bonds as circle',
type: 'boolean',
description: 'slider',
"default": true
},
bondSpacing: {
title: 'Bond spacing',
type: 'integer',
"default": 15,
minimum: 1,
maximum: 100
},
bondThickness: {
title: 'Bond thickness',
type: 'number',
"default": ketcherCore.defaultBondThickness,
minimum: 0.1,
maximum: 96
},
bondThicknessUnit: {
title: 'Bond thickness unit',
"enum": Object.values(MeasurementUnits),
enumNames: Object.values(MeasurementUnits),
"default": MeasurementUnits.Px
},
stereoBondWidth: {
title: 'Stereo (Wedge) bond width',
type: 'number',
"default": 6,
minimum: 0.1,
maximum: 96
},
stereoBondWidthUnit: {
title: 'Stereo (Wedge) bond width unit',
"enum": Object.values(MeasurementUnits),
enumNames: Object.values(MeasurementUnits),
"default": MeasurementUnits.Px
},
bondLength: {
title: 'Bond length',
type: 'number',
"default": 40,
minimum: 0.1,
maximum: 1000
},
bondLengthUnit: {
title: 'Bond length unit',
"enum": Object.values(MeasurementUnits),
enumNames: Object.values(MeasurementUnits),
"default": MeasurementUnits.Px
},
reactionComponentMarginSize: {
title: 'Reaction component margin size',
type: 'number',
"default": 20,
minimum: 0.1,
maximum: 1000
},
reactionComponentMarginSizeUnit: {
title: 'Reaction component margin size unit',
"enum": Object.values(MeasurementUnits),
enumNames: Object.values(MeasurementUnits),
"default": MeasurementUnits.Px
},
hashSpacing: {
title: 'Hash spacing',
type: 'number',
"default": 1.2,
minimum: 0.1,
maximum: 1000
},
hashSpacingUnit: {
title: 'Hash spacing unit',
"enum": Object.values(MeasurementUnits),
enumNames: Object.values(MeasurementUnits),
"default": MeasurementUnits.Px
},
imageResolution: {
title: 'Image resolution',
"enum": Object.values(ImageResolution),
enumNames: Object.keys(ImageResolution),
"default": ImageResolution.low
}
};
var server = {
'dearomatize-on-load': {
title: 'dearomatize-on-load',
type: 'boolean',
description: 'slider',
"default": false
},
'smart-layout': {
title: 'Smart-layout',
type: 'boolean',
description: 'slider',
"default": true
},
ignoreChiralFlag: {
title: 'Ignore the chiral flag',
type: 'boolean',
description: 'slider',
"default": false
},
'ignore-stereochemistry-errors': {
title: 'Ignore stereochemistry errors',
type: 'boolean',
description: 'slider',
"default": true
},
'mass-skip-error-on-pseudoatoms': {
title: 'Ignore pseudoatoms at mass',
type: 'boolean',
description: 'slider',
"default": false
},
'gross-formula-add-rsites': {
title: 'Add Rsites at mass calculation',
type: 'boolean',
description: 'slider',
"default": true
},
'gross-formula-add-isotopes': {
title: "Add Isotopes at\xA0mass\xA0calculation",
type: 'boolean',
description: 'slider',
"default": true
}
};
var SERVER_OPTIONS = Object.keys(server);
var debug = {
showAtomIds: {
title: 'Show atom Ids',
type: 'boolean',
description: 'slider',
"default": false
},
showBondIds: {
title: 'Show bonds Ids',
type: 'boolean',
description: 'slider',
"default": false
},
showHalfBondIds: {
title: 'Show half bonds Ids',
type: 'boolean',
description: 'slider',
"default": false
},
showLoopIds: {
title: 'Show loop Ids',
type: 'boolean',
description: 'slider',
"default": false
}
};
var miew = {
miewMode: {
title: 'Display mode',
"enum": ['LN', 'BS', 'LC'],
enumNames: ['Lines', 'Balls and Sticks', 'Licorice'],
"default": 'LN'
},
miewTheme: {
title: 'Background color',
"enum": ['light', 'dark'],
enumNames: ['Light', 'Dark'],
"default": 'light'
},
miewAtomLabel: {
title: 'Label coloring',
"enum": ['no', 'bright', 'blackAndWhite', 'black'],
enumNames: ['No', 'Bright', 'Black and White', 'Black'],
"default": 'bright'
}
};
var MIEW_OPTIONS = Object.keys(miew);
var optionsSchema = {
title: 'Settings',
type: 'object',
required: [],
properties: _objectSpread$1v(_objectSpread$1v(_objectSpread$1v(_objectSpread$1v(_objectSpread$1v({}, editor), render), server), debug), miew)
};
function getDefaultOptions() {
if (!optionsSchema.properties) return {};
return Object.keys(optionsSchema.properties).reduce(function (res, prop) {
res[prop] = optionsSchema.properties[prop]["default"];
return res;
}, {});
}
function validation(settings) {
if (_typeof__default["default"](settings) !== 'object' || settings === null) return null;
var ajv = new Ajv__default["default"]({
allErrors: true,
keywords: [{
keyword: 'enumNames',
schemaType: 'array'
}]
});
var validate = ajv.compile(optionsSchema);
validate(settings);
var errors = validate.errors || [];
var errorsProps = errors.map(function (el) {
return el.instancePath.slice(1);
});
return Object.keys(settings).reduce(function (res, prop) {
if (!optionsSchema.properties) return res;
if (optionsSchema.properties[prop] && errorsProps.indexOf(prop) === -1) res[prop] = settings[prop];
return res;
}, {});
}
var storage = {
warningMessage: 'Your changes will be lost after the tab closing. See Help (Note 2).',
isAvailable: function isAvailable() {
try {
var _storage = global.localStorage;
return _storage;
} catch (e) {
ketcherCore.KetcherLogger.error('storage-ext.js::storage::isAvailable', e);
return false;
}
},
getItem: function getItem(key) {
var item = null;
try {
item = JSON.parse(localStorage.getItem(key));
} catch (e) {
ketcherCore.KetcherLogger.error('storage-ext.js::storage::getItem', e);
}
return item;
},
setItem: function setItem(key, data) {
var isSet = null;
try {
localStorage.setItem(key, JSON.stringify(data));
isSet = true;
} catch (e) {
ketcherCore.KetcherLogger.error('storage-ext.js::storage::setItem', e);
isSet = false;
}
return isSet;
}
};
var templatesRawData$2 = "alpha-D-Allopyranose\n Ketcher 11161713142D 1 1.00000 0.00000 0\n\n 12 12 0 1 0 999 V2000\n -2.4110 3.5743 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -2.4110 1.6992 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -4.2304 0.7587 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -6.0499 1.6991 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -4.2360 3.5743 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -6.8478 2.9800 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -3.3208 3.1152 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -3.3208 2.1638 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -4.2360 1.6991 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -5.1456 2.1636 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -5.1456 3.1151 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -6.0499 3.5741 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 6 12 1 0 0 0\n 11 5 1 0 0 0\n 5 7 1 0 0 0\n 7 8 1 0 0 0\n 8 9 1 0 0 0\n 9 10 1 0 0 0\n 10 11 1 0 0 0\n 11 12 1 1 0 0\n 7 1 1 6 0 0\n 8 2 1 6 0 0\n 9 3 1 6 0 0\n 10 4 1 6 0 0\nM END\n> <group>\nalpha-D-Sugars\n\n> <atomid>\n0\n\n> <bondid>\n0\n\n$$$$\nalpha-D-Altropyranose\n Ketcher 11161713142D 1 1.00000 0.00000 0\n\n 12 12 0 1 0 999 V2000\n -0.9910 2.2903 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -0.9910 0.7936 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -2.2875 0.0452 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -3.5799 0.7935 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -2.2834 2.2903 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -4.1462 1.8062 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -1.6372 1.9161 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -1.6372 1.1678 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -2.2834 0.7935 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -2.9337 1.1677 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -2.9337 1.9160 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -3.5799 2.2902 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 6 12 1 0 0 0\n 11 5 1 0 0 0\n 5 7 1 0 0 0\n 7 8 1 0 0 0\n 8 9 1 0 0 0\n 9 10 1 0 0 0\n 10 11 1 0 0 0\n 11 12 1 1 0 0\n 7 1 1 6 0 0\n 8 2 1 1 0 0\n 9 3 1 6 0 0\n 10 4 1 6 0 0\nM END\n> <group>\nalpha-D-Sugars\n\n> <atomid>\n0\n\n> <bondid>\n0\n\n$$$$\nalpha-D-Arabinofuranose\n Ketcher 11161713142D 1 1.00000 0.00000 0\n\n 10 10 0 1 0 999 V2000\n -1.9332 3.1927 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -2.5926 1.1426 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -4.7765 1.1387 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -3.7048 3.4871 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -6.0588 2.4002 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -2.8825 2.8828 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -3.1801 1.9478 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -4.1909 1.9478 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -4.5142 2.8976 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -5.4573 3.1978 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 9 4 1 0 0 0\n 9 8 1 0 0 0\n 4 6 1 0 0 0\n 8 7 1 0 0 0\n 6 7 1 0 0 0\n 9 10 1 1 0 0\n 10 5 1 0 0 0\n 6 1 1 6 0 0\n 7 2 1 1 0 0\n 8 3 1 6 0 0\nM END\n> <group>\nalpha-D-Sugars\n\n> <atomid>\n0\n\n> <bondid>\n0\n\n$$$$\nalpha-D-Arabinopyranose\n Ketcher 11161713142D 1 1.00000 0.00000 0\n\n 10 10 0 1 0 999 V2000\n 15.5611 -5.2999 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n 15.5611 -7.3001 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n 13.8228 -8.3002 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n 12.0958 -7.3001 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n 13.8228 -5.2999 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n 14.6920 -5.8000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 14.6920 -6.7999 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 13.8228 -7.3001 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 12.9648 -6.7999 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 12.9648 -5.8000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 5 10 1 0 0 0\n 10 9 1 0 0 0\n 9 8 1 0 0 0\n 8 7 1 0 0 0\n 7 6 1 0 0 0\n 6 5 1 0 0 0\n 6 1 1 6 0 0\n 7 2 1 1 0 0\n 8 3 1 6 0 0\n 9 4 1 6 0 0\nM END\n> <group>\nalpha-D-Sugars\n\n$$$$\nalpha-D-Erythrofuranose\n Ketcher 11161713142D 1 1.00000 0.00000 0\n\n 8 8 0 1 0 999 V2000\n -2.3742 2.6418 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -2.8682 1.1059 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -4.4960 1.1030 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -3.7013 2.8623 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -3.0854 2.4096 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -3.3125 1.7091 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -4.0613 1.7091 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -4.3035 2.4207 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 8 4 1 0 0 0\n 8 7 1 0 0 0\n 4 5 1 0 0 0\n 7 6 1 0 0 0\n 5 6 1 0 0 0\n 5 1 1 6 0 0\n 6 2 1 6 0 0\n 7 3 1 6 0 0\nM END\n> <group>\nalpha-D-Sugars\n\n> <atomid>\n0\n\n> <bondid>\n0\n\n$$$$\nalpha-D-Galactopyranose\n Ketcher 11161713142D 1 1.00000 0.00000 0\n\n 12 12 0 1 0 999 V2000\n -1.5577 2.5236 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -1.5577 1.0270 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -2.8542 0.2785 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -4.1466 1.0269 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -2.8543 2.5236 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -4.7171 2.0395 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -2.2039 2.1495 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -2.2039 1.4011 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -2.8543 1.0269 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -3.5004 1.4010 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -3.5004 2.1494 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -4.1466 2.5235 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 6 12 1 0 0 0\n 11 5 1 0 0 0\n 5 7 1 0 0 0\n 7 8 1 0 0 0\n 8 9 1 0 0 0\n 9 10 1 0 0 0\n 10 11 1 0 0 0\n 11 12 1 1 0 0\n 7 1 1 6 0 0\n 8 2 1 6 0 0\n 9 3 1 1 0 0\n 10 4 1 1 0 0\nM END\n> <group>\nalpha-D-Sugars\n\n$$$$\nalpha-D-Glucopyranose\n Ketcher 11161713142D 1 1.00000 0.00000 0\n\n 12 12 0 1 0 999 V2000\n -2.1744 2.8153 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -2.1744 1.3186 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -3.4708 0.5702 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -4.7632 1.3185 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -3.4709 2.8153 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -5.3337 2.3312 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -2.8206 2.4411 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -2.8206 1.6928 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -3.4709 1.3185 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -4.1170 1.6927 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -4.1170 2.4410 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -4.7632 2.8152 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 6 12 1 0 0 0\n 11 5 1 0 0 0\n 5 7 1 0 0 0\n 7 8 1 0 0 0\n 8 9 1 0 0 0\n 9 10 1 0 0 0\n 10 11 1 0 0 0\n 11 12 1 1 0 0\n 7 1 1 6 0 0\n 8 2 1 6 0 0\n 9 3 1 1 0 0\n 10 4 1 6 0 0\nM END\n> <group>\nalpha-D-Sugars\n\n$$$$\nalpha-D-Gulopyranose\n Ketcher 11161713142D 1 1.00000 0.00000 0\n\n 12 12 0 1 0 999 V2000\n -2.1119 2.8570 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -2.1119 1.3603 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -3.4083 0.6119 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -4.7007 1.3602 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -3.4084 2.8570 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -5.2712 2.3728 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -2.7581 2.4828 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -2.7581 1.7345 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -3.4084 1.3602 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -4.0545 1.7344 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -4.0545 2.4827 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -4.7007 2.8569 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n