<commit_before>/*
 *    Debrief - the Open Source Maritime Analysis Application
 *    http://debrief.info
 *
 *    (C) 2000-2014, PlanetMayo Ltd
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the Eclipse Public License v1.0
 *    (http://www.eclipse.org/legal/epl-v10.html)
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 */
package org.mwc.cmap.core.operations;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.List;
import java.util.Vector;

import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.operations.AbstractOperation;
import org.eclipse.core.commands.operations.IOperationHistory;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.swt.dnd.ByteArrayTransfer;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
import org.mwc.cmap.core.CorePlugin;
import org.mwc.cmap.core.ui_support.OutlineNameSorter;

import Debrief.Wrappers.FixWrapper;
import Debrief.Wrappers.SensorContactWrapper;
import Debrief.Wrappers.SensorWrapper;
import Debrief.Wrappers.TMAContactWrapper;
import Debrief.Wrappers.TMAWrapper;
import Debrief.Wrappers.TrackWrapper;
import Debrief.Wrappers.Track.DynamicInfillSegment;
import MWC.GUI.Editable;
import MWC.GUI.HasEditables;
import MWC.GUI.Layer;
import MWC.GUI.Layers;
import MWC.GUI.NeedsToBeInformedOfRemove;
import MWC.GUI.Plottable;
import MWC.GUI.PlottablesType;
import MWC.GUI.Tools.Operations.RightClickCutCopyAdaptor.IsTransientForChildren;
import MWC.GenericData.HiResDate;
import MWC.GenericData.WorldDistance;
import MWC.GenericData.WorldLocation;
import MWC.GenericData.WorldVector;
import MWC.TacticalData.Fix;

public class RightClickCutCopyAdaptor
{

  // ////////////////////////////////////////////
  //
  // ///////////////////////////////////////////////
  public static class CopyItem extends CutItem
  {
    public CopyItem(final Editable[] data, final Clipboard clipboard,
        final HasEditables[] theParent, final Layers theLayers,
        final Layer[] updateLayer)
    {
      super(data, clipboard, theParent, theLayers, updateLayer);

      super.setText(toString());
      setActionDefinitionId(ActionFactory.COPY.getCommandId());
      super.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
          .getImageDescriptor(ISharedImages.IMG_TOOL_COPY));

    }

    public void execute()
    {

      // store the old data
      // storeOld();

      // we stick a pointer to the ACTUAL item on the clipboard - we
      // clone this item when we do a PASTE, so that multiple paste
      // operations can be performed

      // copy in the new data
      final EditableTransfer transfer = EditableTransfer.getInstance();
      _myClipboard.setContents(new Object[]
      {_data}, new Transfer[]
      {transfer});
    }

    @Override
    public void run()
    {
      final AbstractOperation myOperation = new AbstractOperation(getText())
      {
        /**
         * the Copy bit is common to execute and redo methods - so factor it out to here...
         * 
         */
        private void doCopy()
        {
          // remember the old contents
          rememberPreviousContents();

          _data = cloneThese(_data);

          // we stick a pointer to the ACTUAL item on the clipboard - we
          // clone this item when we do a PASTE, so that multiple paste
          // operations can be performed

          // copy in the new data
          final EditableTransfer transfer = EditableTransfer.getInstance();
          _myClipboard.setContents(new Object[]
          {_data}, new Transfer[]
          {transfer});
        }

        @Override
        public IStatus execute(final IProgressMonitor monitor,
            final IAdaptable info) throws ExecutionException
        {

          // we stick a CLONE on the clipboard - we
          // clone this item when we do a PASTE, so that multiple paste
          // operations can be performed

          doCopy();

          return Status.OK_STATUS;
        }

        @Override
        public IStatus redo(final IProgressMonitor monitor,
            final IAdaptable info) throws ExecutionException
        {

          doCopy();

          return Status.OK_STATUS;
        }

        @Override
        public IStatus undo(final IProgressMonitor monitor,
            final IAdaptable info) throws ExecutionException
        {
          // just restore the previous clipboard contents
          restorePreviousContents();

          return Status.OK_STATUS;
        }
      };
      if (CorePlugin.getUndoContext() != null)
      {
        myOperation.addContext(CorePlugin.getUndoContext());
      }
      CorePlugin.run(myOperation);
    }

    @Override
    public String toString()
    {
      String res = "Copy ";
      if (_data.length > 1)
      {
        res += _data.length + " selected items";
      }
      else
      {
        res += _data[0].getName();
      }
      return res;
    }
  }

  // /////////////////////////////////
  // member variables
  // ////////////////////////////////

  // /////////////////////////////////
  // constructor
  // ////////////////////////////////

  // ////////////////////////////////////////////
  //
  // ///////////////////////////////////////////////
  public static class CutItem extends Action
  {
    protected Editable[] _data;

    protected Clipboard _myClipboard;

    protected HasEditables[] _theParent;

    protected Layers _theLayers;

    protected Object _oldContents;

    protected Layer[] _updateLayer;

    public CutItem(final Editable[] data, final Clipboard clipboard,
        final HasEditables[] theParent, final Layers theLayers,
        final Layer[] updateLayer)
    {
      // remember parameters
      _data = data;
      _myClipboard = clipboard;
      _theParent = theParent;
      _theLayers = theLayers;
      _updateLayer = updateLayer;

      // formatting
      super.setText("Cut " + toString());
      setActionDefinitionId(ActionFactory.CUT.getCommandId());
      // and the icon
      setImageIcon();

    }

    // remember what used to be on the clipboard
    protected void rememberPreviousContents()
    {
      if (_myClipboard != null)
      {
        // copy in the new data
        final EditableTransfer transfer = EditableTransfer.getInstance();
        _oldContents = _myClipboard.getContents(transfer);
      }
    }

    // restore the previous contents of the clipboard
    protected void restorePreviousContents()
    {
      if (_myClipboard != null)
      {
        // just check that there were some previous contents
        if (_oldContents != null)
        {
          // copy in the new data
          final EditableTransfer transfer = EditableTransfer.getInstance();
          _myClipboard.setContents(new Object[]
          {_oldContents}, new Transfer[]
          {transfer});
        }
        // and forget what we're holding
        _oldContents = null;
      }

    }

    /**
		 * 
		 */
    @Override
    public void run()
    {
      final AbstractOperation myOperation = new AbstractOperation(getText())
      {
        private Plottable adjacentItemFor(final Object parentLayer,
            final Editable thisE)
        {
          final Plottable res;
          if (parentLayer instanceof PlottablesType)
          {
            final PlottablesType segs = (PlottablesType) parentLayer;
            final Enumeration<Editable> numer = segs.elements();
            res = findAdjacentEditable(thisE, numer);
          }
          else if (parentLayer instanceof HasEditables)
          {
            final HasEditables segs = (HasEditables) parentLayer;
            final Enumeration<Editable> numer = segs.elements();
            res = findAdjacentEditable(thisE, numer);
          }
          else
          {
            System.out.println("failed");
            res = null;
          }
          return res;
        }

        /**
         * the cut operation is common for execute and redo operations - so factor it out to here...
         * 
         */
        private void doCut()
        {
          final Vector<HasEditables> changedLayers = new Vector<HasEditables>();

          // remember the previous contents
          rememberPreviousContents();

          // copy in the new data
          final EditableTransfer transfer = EditableTransfer.getInstance();
          if (_myClipboard != null)
          {
            _myClipboard.setContents(new Object[]
            {_data}, new Transfer[]
            {transfer});
          }

          Plottable toBeSelected = null;

          for (int i = 0; i < _data.length; i++)
          {
            final Editable thisE = _data[i];
            final HasEditables parentLayer = _theParent[i];

            // is the parent the data object itself?
            if (parentLayer == null)
            {
              toBeSelected = adjacentItemFor(_theLayers, thisE);

              // no, it must be the top layers object
              _theLayers.removeThisLayer((Layer) thisE);

              // remember the layer, so we can provide
              // the Outline view with what to select (the previous visible layer)
              changedLayers.add((HasEditables) toBeSelected);
            }
            else
            {
              // special handling. On some occasions we wish to select
              // the previous item, if it's in a long list.
              toBeSelected = adjacentItemFor(parentLayer, thisE);

              // remove the new data from it's parent
              parentLayer.removeElement(thisE);

              // some objects want to know when they're removed
              if (thisE instanceof NeedsToBeInformedOfRemove)
              {
                // spread the good news
                ((NeedsToBeInformedOfRemove) thisE).beingRemoved();
              }

              // see if we need to track this layer change
              if (!changedLayers.contains(parentLayer))
              {
                changedLayers.add(parentLayer);
              }
            }
          }

          if (changedLayers.size() > 1)
          {
            _theLayers.fireExtended();
          }
          else if (changedLayers.size() == 1)
          {
            _theLayers.fireExtended(toBeSelected, changedLayers.firstElement());
          }
          else
          {
            // zero layers listed as changed. no 'firing' necessary
          }
        }

        @Override
        public IStatus execute(final IProgressMonitor monitor,
            final IAdaptable info) throws ExecutionException
        {
          doCut();
          return Status.OK_STATUS;
        }

        private Plottable findAdjacentEditable(final Editable thisE,
            final Enumeration<Editable> numer)
        {
          Plottable res = null;

          // put them into a list, so we can sort them properly
          final List<Editable> list = new ArrayList<Editable>();
          while (numer.hasMoreElements())
          {
            list.add(numer.nextElement());
          }

          final Comparator<Editable> comparator =
              new OutlineNameSorter.EditableComparer();

          // okm now sort them out
          Collections.sort(list, comparator);
          
          int indexOf = list.indexOf(thisE);
          if(indexOf== -1 || list.size()<1)
          {
              return res;
          }
          
          
          
          if(indexOf==(list.size()-1) && list.size()>1)
          {
            //last item of the list 
             res = (Plottable) list.get(list.size()-2);
             if (res instanceof DynamicInfillSegment)
             {
               final DynamicInfillSegment fill =
                   (DynamicInfillSegment) res;
               res = fill.getBeforeSegment();
             }
             return res;
          }
          
          //next item of the list 
           res = (Plottable) list.get(indexOf+1);
           if (res instanceof DynamicInfillSegment)
           {
             final DynamicInfillSegment fill =
                 (DynamicInfillSegment) res;
             res = fill.getAfterSegment();
           }
           return res;

        }

        @Override
        public IStatus redo(final IProgressMonitor monitor,
            final IAdaptable info) throws ExecutionException
        {
          doCut();
          return Status.OK_STATUS;
        }
<commit_msg>Single return point. Make return value final.  Minor logic correction (to handle single-value list)<commit_after>/*
 *    Debrief - the Open Source Maritime Analysis Application
 *    http://debrief.info
 *
 *    (C) 2000-2014, PlanetMayo Ltd
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the Eclipse Public License v1.0
 *    (http://www.eclipse.org/legal/epl-v10.html)
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 */
package org.mwc.cmap.core.operations;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.List;
import java.util.Vector;

import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.operations.AbstractOperation;
import org.eclipse.core.commands.operations.IOperationHistory;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.swt.dnd.ByteArrayTransfer;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
import org.mwc.cmap.core.CorePlugin;
import org.mwc.cmap.core.ui_support.OutlineNameSorter;

import Debrief.Wrappers.FixWrapper;
import Debrief.Wrappers.SensorContactWrapper;
import Debrief.Wrappers.SensorWrapper;
import Debrief.Wrappers.TMAContactWrapper;
import Debrief.Wrappers.TMAWrapper;
import Debrief.Wrappers.TrackWrapper;
import Debrief.Wrappers.Track.DynamicInfillSegment;
import MWC.GUI.Editable;
import MWC.GUI.HasEditables;
import MWC.GUI.Layer;
import MWC.GUI.Layers;
import MWC.GUI.NeedsToBeInformedOfRemove;
import MWC.GUI.Plottable;
import MWC.GUI.PlottablesType;
import MWC.GUI.Tools.Operations.RightClickCutCopyAdaptor.IsTransientForChildren;
import MWC.GenericData.HiResDate;
import MWC.GenericData.WorldDistance;
import MWC.GenericData.WorldLocation;
import MWC.GenericData.WorldVector;
import MWC.TacticalData.Fix;

public class RightClickCutCopyAdaptor
{

  // ////////////////////////////////////////////
  //
  // ///////////////////////////////////////////////
  public static class CopyItem extends CutItem
  {
    public CopyItem(final Editable[] data, final Clipboard clipboard,
        final HasEditables[] theParent, final Layers theLayers,
        final Layer[] updateLayer)
    {
      super(data, clipboard, theParent, theLayers, updateLayer);

      super.setText(toString());
      setActionDefinitionId(ActionFactory.COPY.getCommandId());
      super.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
          .getImageDescriptor(ISharedImages.IMG_TOOL_COPY));

    }

    public void execute()
    {

      // store the old data
      // storeOld();

      // we stick a pointer to the ACTUAL item on the clipboard - we
      // clone this item when we do a PASTE, so that multiple paste
      // operations can be performed

      // copy in the new data
      final EditableTransfer transfer = EditableTransfer.getInstance();
      _myClipboard.setContents(new Object[]
      {_data}, new Transfer[]
      {transfer});
    }

    @Override
    public void run()
    {
      final AbstractOperation myOperation = new AbstractOperation(getText())
      {
        /**
         * the Copy bit is common to execute and redo methods - so factor it out to here...
         * 
         */
        private void doCopy()
        {
          // remember the old contents
          rememberPreviousContents();

          _data = cloneThese(_data);

          // we stick a pointer to the ACTUAL item on the clipboard - we
          // clone this item when we do a PASTE, so that multiple paste
          // operations can be performed

          // copy in the new data
          final EditableTransfer transfer = EditableTransfer.getInstance();
          _myClipboard.setContents(new Object[]
          {_data}, new Transfer[]
          {transfer});
        }

        @Override
        public IStatus execute(final IProgressMonitor monitor,
            final IAdaptable info) throws ExecutionException
        {

          // we stick a CLONE on the clipboard - we
          // clone this item when we do a PASTE, so that multiple paste
          // operations can be performed

          doCopy();

          return Status.OK_STATUS;
        }

        @Override
        public IStatus redo(final IProgressMonitor monitor,
            final IAdaptable info) throws ExecutionException
        {

          doCopy();

          return Status.OK_STATUS;
        }

        @Override
        public IStatus undo(final IProgressMonitor monitor,
            final IAdaptable info) throws ExecutionException
        {
          // just restore the previous clipboard contents
          restorePreviousContents();

          return Status.OK_STATUS;
        }
      };
      if (CorePlugin.getUndoContext() != null)
      {
        myOperation.addContext(CorePlugin.getUndoContext());
      }
      CorePlugin.run(myOperation);
    }

    @Override
    public String toString()
    {
      String res = "Copy ";
      if (_data.length > 1)
      {
        res += _data.length + " selected items";
      }
      else
      {
        res += _data[0].getName();
      }
      return res;
    }
  }

  // /////////////////////////////////
  // member variables
  // ////////////////////////////////

  // /////////////////////////////////
  // constructor
  // ////////////////////////////////

  // ////////////////////////////////////////////
  //
  // ///////////////////////////////////////////////
  public static class CutItem extends Action
  {
    protected Editable[] _data;

    protected Clipboard _myClipboard;

    protected HasEditables[] _theParent;

    protected Layers _theLayers;

    protected Object _oldContents;

    protected Layer[] _updateLayer;

    public CutItem(final Editable[] data, final Clipboard clipboard,
        final HasEditables[] theParent, final Layers theLayers,
        final Layer[] updateLayer)
    {
      // remember parameters
      _data = data;
      _myClipboard = clipboard;
      _theParent = theParent;
      _theLayers = theLayers;
      _updateLayer = updateLayer;

      // formatting
      super.setText("Cut " + toString());
      setActionDefinitionId(ActionFactory.CUT.getCommandId());
      // and the icon
      setImageIcon();

    }

    // remember what used to be on the clipboard
    protected void rememberPreviousContents()
    {
      if (_myClipboard != null)
      {
        // copy in the new data
        final EditableTransfer transfer = EditableTransfer.getInstance();
        _oldContents = _myClipboard.getContents(transfer);
      }
    }

    // restore the previous contents of the clipboard
    protected void restorePreviousContents()
    {
      if (_myClipboard != null)
      {
        // just check that there were some previous contents
        if (_oldContents != null)
        {
          // copy in the new data
          final EditableTransfer transfer = EditableTransfer.getInstance();
          _myClipboard.setContents(new Object[]
          {_oldContents}, new Transfer[]
          {transfer});
        }
        // and forget what we're holding
        _oldContents = null;
      }

    }

    /**
		 * 
		 */
    @Override
    public void run()
    {
      final AbstractOperation myOperation = new AbstractOperation(getText())
      {
        private Plottable adjacentItemFor(final Object parentLayer,
            final Editable thisE)
        {
          final Plottable res;
          if (parentLayer instanceof PlottablesType)
          {
            final PlottablesType segs = (PlottablesType) parentLayer;
            final Enumeration<Editable> numer = segs.elements();
            res = findAdjacentEditable(thisE, numer);
          }
          else if (parentLayer instanceof HasEditables)
          {
            final HasEditables segs = (HasEditables) parentLayer;
            final Enumeration<Editable> numer = segs.elements();
            res = findAdjacentEditable(thisE, numer);
          }
          else
          {
            System.out.println("failed");
            res = null;
          }
          return res;
        }

        /**
         * the cut operation is common for execute and redo operations - so factor it out to here...
         * 
         */
        private void doCut()
        {
          final Vector<HasEditables> changedLayers = new Vector<HasEditables>();

          // remember the previous contents
          rememberPreviousContents();

          // copy in the new data
          final EditableTransfer transfer = EditableTransfer.getInstance();
          if (_myClipboard != null)
          {
            _myClipboard.setContents(new Object[]
            {_data}, new Transfer[]
            {transfer});
          }

          Plottable toBeSelected = null;

          for (int i = 0; i < _data.length; i++)
          {
            final Editable thisE = _data[i];
            final HasEditables parentLayer = _theParent[i];

            // is the parent the data object itself?
            if (parentLayer == null)
            {
              toBeSelected = adjacentItemFor(_theLayers, thisE);

              // no, it must be the top layers object
              _theLayers.removeThisLayer((Layer) thisE);

              // remember the layer, so we can provide
              // the Outline view with what to select (the previous visible layer)
              changedLayers.add((HasEditables) toBeSelected);
            }
            else
            {
              // special handling. On some occasions we wish to select
              // the previous item, if it's in a long list.
              toBeSelected = adjacentItemFor(parentLayer, thisE);

              // remove the new data from it's parent
              parentLayer.removeElement(thisE);

              // some objects want to know when they're removed
              if (thisE instanceof NeedsToBeInformedOfRemove)
              {
                // spread the good news
                ((NeedsToBeInformedOfRemove) thisE).beingRemoved();
              }

              // see if we need to track this layer change
              if (!changedLayers.contains(parentLayer))
              {
                changedLayers.add(parentLayer);
              }
            }
          }

          if (changedLayers.size() > 1)
          {
            _theLayers.fireExtended();
          }
          else if (changedLayers.size() == 1)
          {
            _theLayers.fireExtended(toBeSelected, changedLayers.firstElement());
          }
          else
          {
            // zero layers listed as changed. no 'firing' necessary
          }
        }

        @Override
        public IStatus execute(final IProgressMonitor monitor,
            final IAdaptable info) throws ExecutionException
        {
          doCut();
          return Status.OK_STATUS;
        }

        private Plottable findAdjacentEditable(final Editable thisE,
            final Enumeration<Editable> numer)
        {
          final Plottable res;

          // put them into a list, so we can sort them properly
          final List<Editable> list = new ArrayList<Editable>();
          while (numer.hasMoreElements())
          {
            list.add(numer.nextElement());
          }

          final Comparator<Editable> comparator =
              new OutlineNameSorter.EditableComparer();

          // ok now sort them out
          Collections.sort(list, comparator);
          
          // find the item that's about to be deleted
          final int indexOf = list.indexOf(thisE);
          
          // where is it in the list?
          if(indexOf== -1 || list.size()<=1)
          {
            // ok, empty list (or there's only us in the list)
            res = null;
          }
          else if(indexOf==(list.size()-1) && list.size()>1)
          {
            // last item on the list, can't move down. use previous
            final Plottable previous = (Plottable) list.get(list.size() - 2);
            
            // special handling for dynamic infill. It will get deleted 
            // when it's before/after leg get deleted.
            if (previous instanceof DynamicInfillSegment)
            {
              final DynamicInfillSegment fill = (DynamicInfillSegment) previous;
              res = fill.getBeforeSegment();
            }
            else
            {
              res = previous;
            }
          }
          else
          {
            // mid-list, just take next item of the list
            final Plottable next = (Plottable) list.get(indexOf + 1);

            // aah, not if it's an infill that's about to be deleted?
            if (next instanceof DynamicInfillSegment)
            {
              final DynamicInfillSegment fill = (DynamicInfillSegment) next;
              res = fill.getAfterSegment();
            }
            else
            {
              res = next;
            }
          }          
          return res;
        }

        @Override
        public IStatus redo(final IProgressMonitor monitor,
            final IAdaptable info) throws ExecutionException
        {
          doCut();
          return Status.OK_STATUS;
        }

{'fraction_non_alphanumeric': 0.10420401741612088, 'fraction_numerical': 0.0016830705060188066, 'mean_word_length': 1.8527293601920467, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6819589', 'n_tokens_mistral': 7191, 'n_tokens_neox': 6962, 'n_words': 1946}