UNPKG

ketcher-react

Version:
1,048 lines (1,033 loc) 2.07 MB
/**************************************************************************** * 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. ***************************************************************************/ import _defineProperty$1 from '@babel/runtime/helpers/defineProperty'; import _slicedToArray$1 from '@babel/runtime/helpers/slicedToArray'; import { jsx, jsxs, Fragment } from 'react/jsx-runtime'; import * as React from 'react'; import React__default, { createRef, Component, useRef, useEffect, useLayoutEffect, useMemo, useState, createElement, forwardRef, useCallback, Fragment as Fragment$2, PureComponent, lazy, Suspense } from 'react'; import 'intersection-observer'; import 'element-closest-polyfill'; import 'regenerator-runtime/runtime'; import 'url-search-params-polyfill'; import 'whatwg-fetch'; import _asyncToGenerator from '@babel/runtime/helpers/asyncToGenerator'; import _regeneratorRuntime from '@babel/runtime/regenerator'; import _classCallCheck$2 from '@babel/runtime/helpers/classCallCheck'; import _createClass$2 from '@babel/runtime/helpers/createClass'; import { KetSerializer, MolSerializer, KetcherLogger, Ketcher, defaultBondThickness, FormatterFactory, isClipboardAPIAvailable, notifyCopyCut, notifyRequestCompleted, isControlKey, StereLabelStyleType, StereoColoringType, ShowHydrogenLabels, ShowHydrogenLabelNames, SettingsManager, SdfSerializer, KETCHER_SAVED_OPTIONS_KEY, Bond as Bond$2, Elements, AtomList, getAtomType, StereoLabel, isAttachmentBond, Atom as Atom$2, findStereoAtoms, RxnArrowMode, MULTITAIL_ARROW_TOOL_NAME, SimpleObjectMode, IMAGE_KEY, SGroup as SGroup$1, Pile, identifyStructFormat, SupportedFormat, MULTITAIL_ARROW_KEY, ChemicalMimeType, RenderStruct, Struct, ZoomTool, shortcutStr, MonomerMicromolecule, UnresolvedMonomer, FunctionalGroupsProvider, SaltsAndSolventsProvider, KetcherAsyncEvents, ElementColor, ketcherProvider, generateMenuShortcuts, Vec2, Scale, fromMultipleMove, FunctionalGroup, mergeMapOfItemsToSet, fromSgroupDeletion, fromFragmentDeletion, vectorUtils, fromBondAddition, Action, fromAtomAddition, fromAtomsAttrs, checkOverlapping, fromSeveralSgroupAddition, expandSGroupWithMultipleAttachmentPoint, SgContexts, fromSgroupAction, fromItemsFuse, ReBond, setExpandSGroup, fromBondsAttrs, OperationType, ReStruct, imageReferencePositionToCursor, multitailArrowReferenceLinesToCursor, multitailReferencePositionToCursor, CoordinateTransformation, MultitailArrowRefName, fromMultitailArrowHeadTailMove, fromMultitailArrowHeadTailsResize, fromMultitailArrowMove, fromArrowResizing, fromPaste, fromImageResize, fromSimpleObjectResizing, getItemsToFuse, getHoverToFuse, fromTextDeletion, fromTextUpdating, fromTemplateOnCanvas, fromTemplateOnBondAction, fromTemplateOnAtom, BondAttr, AtomAttr, formatProperties, runAsyncAction, getStructStringFromClipboardData, getStructure, initHotKeys, keyNorm, Fragment as Fragment$1, fromRGroupAttachmentPointUpdate, fromOneBondDeletion, bondChangingAction, fromChain, removeInfoLabelFromAtoms, fromStereoFlagUpdate, fromOneAtomDeletion, fromArrowDeletion, fromPlusDeletion, fromSimpleObjectDeletion, fromRGroupAttachmentPointDeletion, fromImageDeletion, fromMultitailArrowDeletion, notifyItemsToMergeInitializationComplete, RGroup as RGroup$2, fromRGroupFragment, fromUpdateIfThen, fromRGroupAttrs, fromArrowAddition, fromMultitailArrowCreation, fromPlusAddition, fromRotate, fromFlip, fromSimpleObjectAddition, fromTextCreation, fromImageMove, fromImageCreation, fromHighlightCreate, fromHighlightClear, getOptionsWithConvertedUnits, provideEditorSettings, fromNewCanvas, Render, Coordinates, fromDescriptorsAlign, fromSgroupAttachmentPointAddition, SGroupAttachmentPoint, fromSgroupAddition, atomGetAttr, fromBondFlipping, setExpandMonomerSGroup, fromMultitailArrowTailAdd, MultitailArrow, fromMultitailArrowTailRemove, AmbiguousMonomer, genericsList, getAtomCustomQuery, getFormatMimeTypeByFileName, getPropertiesByFormat, StereoFlag, getPropertiesByImgFormat, legacyCopy as legacyCopy$1, b64toBlob, Generics, TextCommand, DefaultStructServiceOptions } from 'ketcher-core'; import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProperties'; import _possibleConstructorReturn$2 from '@babel/runtime/helpers/possibleConstructorReturn'; import _getPrototypeOf$2 from '@babel/runtime/helpers/getPrototypeOf'; import _inherits$2 from '@babel/runtime/helpers/inherits'; import clsx from 'clsx'; import _typeof$3 from '@babel/runtime/helpers/typeof'; import Ajv from 'ajv'; import { pick, range as range$1, capitalize, without, omit, findLastIndex, findIndex, isEmpty, pickBy, isEqual, escapeRegExp, flow, filter, reduce, throttle, xor, debounce, upperFirst } from 'lodash/fp'; import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray'; import _, { isNumber, throttle as throttle$1, debounce as debounce$1, intersection, difference, cloneDeep, isEqual as isEqual$1, capitalize as capitalize$1, range as range$2, isEmpty as isEmpty$1, uniqBy, uniqueId } from 'lodash'; import _taggedTemplateLiteral from '@babel/runtime/helpers/taggedTemplateLiteral'; import styled from '@emotion/styled'; import { css } from '@emotion/react'; import * as KN from 'w3c-keyname'; import require$$0$2 from 'util'; import ReactDOM, { createPortal } from 'react-dom'; import { connect, useDispatch, useSelector, Provider } from 'react-redux'; import { combineReducers, createStore as createStore$1, applyMiddleware } from 'redux'; import * as CFB from 'cfb'; import 'redux-logger'; import thunkMiddleware from 'redux-thunk'; import useResizeObserver from 'use-resize-observer/polyfilled'; import { useInView } from 'react-intersection-observer'; import { IconButton as IconButton$1, Collapse, ClickAwayListener, Button as Button$1, Popover, ToggleButtonGroup, ToggleButton, Tooltip, MenuList, createTheme, ThemeProvider } from '@mui/material'; import { createSelector } from 'reselect'; import { isIE } from 'react-device-detect'; import _classPrivateFieldGet from '@babel/runtime/helpers/classPrivateFieldGet'; import _classPrivateFieldSet from '@babel/runtime/helpers/classPrivateFieldSet'; import _assertThisInitialized$2 from '@babel/runtime/helpers/assertThisInitialized'; import { Subscription, PipelineSubscription, DOMSubscription } from 'subscription'; import { Submenu, Item, Menu, useContextMenu } from 'react-contexify'; import 'react-contexify/ReactContexify.css'; import MuiSelect from '@mui/material/Select'; import Divider$2 from '@mui/material/Divider'; import MenuItem from '@mui/material/MenuItem'; import { HexColorPicker, HexColorInput } from 'react-colorful'; import { saveAs } from 'file-saver'; import FontFaceObserver from 'font-face-observer'; import { useDropzone } from 'react-dropzone'; import Accordion$2 from '@mui/material/Accordion'; import AccordionSummary from '@mui/material/AccordionSummary'; import AccordionDetails from '@mui/material/AccordionDetails'; import Tabs$1 from '@mui/material/Tabs'; import Tab from '@mui/material/Tab'; import 'draft-js/dist/Draft.css'; import { Modifier, EditorState, convertFromRaw, RichUtils, Editor as Editor$4, convertToRaw, getDefaultKeyBinding } from 'draft-js'; import createStyles from 'draft-js-custom-styles'; import _objectDestructuringEmpty from '@babel/runtime/helpers/objectDestructuringEmpty'; import _extends$3n from '@babel/runtime/helpers/extends'; import MuiAutocomplete from '@mui/material/Autocomplete'; import { createRoot } from 'react-dom/client'; 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.createContext({}); var errorsContext = React__default.createContext({}); var settingsContext = React__default.createContext({}); var formContext = React__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 MolSerializer(); break; } case 'ket': { serializer = new KetSerializer(); break; } default: { serializer = new KetSerializer(); break; } } var simpleObjectOrText = Boolean(struct.simpleObjects.size || struct.texts.size); if (simpleObjectOrText && serializer instanceof 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) { 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( _regeneratorRuntime.mark(function _callee() { var state, editor, server, options, struct, errorHandler, factory, service, structStr, ketcher, image, item; return _regeneratorRuntime.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 FormatterFactory(server); service = factory.create('ket', options); _context.next = 11; return service.getStructureFromStructAsync(struct); case 11: structStr = _context.sent; ketcher = new Ketcher(editor, server, {}, factory); _context.next = 15; return ketcher.generateImage(structStr, { outputFormat: 'png', backgroundColor: '255, 255, 255', bondThickness: options.settings.bondThickness || defaultBondThickness }); case 15: image = _context.sent; item = new ClipboardItem(_defineProperty$1({}, 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); 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 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$2(o), _possibleConstructorReturn$2(t, _isNativeReflectConstruct$g() ? Reflect.construct(o, e || [], _getPrototypeOf$2(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$2(ClipArea, _Component); function ClipArea(props) { var _this; _classCallCheck$2(this, ClipArea); _this = _callSuper$e(this, ClipArea, [props]); _this.textAreaRef = createRef(); return _this; } _createClass$2(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 (isClipboardAPIAvailable()) { _this2.props.onCopy().then(function (data) { if (!data) { return; } _copy(data).then(function () { event.preventDefault(); 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( _regeneratorRuntime.mark(function _callee(event) { var data; return _regeneratorRuntime.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 (isClipboardAPIAvailable()) { _this2.props.onCut().then(function (data) { if (!data) { return; } _copy(data).then(function () { event.preventDefault(); 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 (isClipboardAPIAvailable()) { navigator.clipboard.read().then(function (data) { if (!data) { return; } _this2.props.onPaste(data).then(function () { event.preventDefault(); notifyRequestCompleted(); }); }); } else { var data = legacyPaste(event.clipboardData, _this2.props.formats); if (data) { _this2.props.onLegacyPaste(data); } event.preventDefault(); } }, keydown: function () { var _keydown = _asyncToGenerator( _regeneratorRuntime.mark(function _callee2(event) { var _navigator$clipboard, clipboardData, data, _window$ketcher$edito, _window$ketcher$edito2; return _regeneratorRuntime.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 (!(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 jsx("textarea", { ref: this.textAreaRef, className: clsx(CLIP_AREA_BASE_CLASS, classes$Q.cliparea), contentEditable: true, autoFocus: true , suppressContentEditableWarning: true }); } }]); return ClipArea; }(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( _regeneratorRuntime.mark(function _callee3(data) { var clipboardItemData, clipboardItem, textData; return _regeneratorRuntime.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); 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( _regeneratorRuntime.mark(function _callee4(clipboardData) { var data, _iterator, _step, item, textPlain; return _regeneratorRuntime.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) { 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$1(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": [StereLabelStyleType.IUPAC, StereLabelStyleType.Classic, StereLabelStyleType.On, StereLabelStyleType.Off], enumNames: ['IUPAC style', 'Classic', 'On', 'Off'], "default": 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": [StereoColoringType.LabelsOnly, StereoColoringType.BondsOnly, StereoColoringType.LabelsAndBonds, StereoColoringType.Off], enumNames: ['Labels Only', 'Bonds Only', 'Labels And Bonds', 'Off'], "default": 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(ShowHydrogenLabels), enumNames: Object.values(ShowHydrogenLabelNames), "default": 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": 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$3(settings) !== 'object' || settings === null) return null; var ajv = new Ajv({ 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) { 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) { 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) { 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 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 1 0 0\nM END\n> <group>\nalpha-D-Sugars\n\n$$$$\nalpha-D-Idopyranose\n Ketcher 11161713142D 1 1.00000 0.00000 0\n\n 12 12 0 1 0 999 V2000\n -1.9244 2.7736 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -1.9244 1.2770 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -3.2208 0.5285 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -4.5132 1.2769 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -3.2209 2.7736 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -5.0837 2.2895 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n -2.5706 2.3995 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -2.5706 1.6511 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n -3.2209