private void moveToRight() {
    int buttonId = 0;
    switch (mHandler.currentNavigation) {
      case R.id.device_button:
        mHandler.loadBrowseDir();
        buttonId = R.id.video_button;
        break;
      case R.id.video_button:
        buttonId = R.id.picture_button;
        break;
      case R.id.picture_button:
        buttonId = R.id.music_button;
        break;
      case R.id.music_button:
        buttonId = R.id.file_button;
        break;
      case R.id.file_button:
        mHandler.saveBrowseDir();
        buttonId = R.id.device_button;
        break;
    }
    Button bt = (Button) findViewById(buttonId);
    mHandler.currentNavigation = buttonId;

    delayToRefresh();

    mHandler.setButtonSelected(bt);
  }
  @SuppressWarnings("unchecked")
  protected void dispatch(Event event) {
    // all events go thru this loop
    if (LOG.isDebugEnabled()) {
      LOG.debug("Dispatching the event " + event.getClass().getName() + "." + event.toString());
    }

    Class<? extends Enum> type = event.getType().getDeclaringClass();

    try {
      EventHandler handler = eventDispatchers.get(type);
      if (handler != null) {
        handler.handle(event);
      } else {
        throw new Exception("No handler for registered for " + type);
      }
    } catch (Throwable t) {
      // TODO Maybe log the state of the queue
      LOG.fatal("Error in dispatcher thread", t);
      // If serviceStop is called, we should exit this thread gracefully.
      if (exitOnDispatchException
          && (ShutdownHookManager.get().isShutdownInProgress()) == false
          && stopped == false) {
        Thread shutDownThread = new Thread(createShutDownThread());
        shutDownThread.setName("AsyncDispatcher ShutDown handler");
        shutDownThread.start();
      }
    }
  }
  /**
   * Add EventHandler to handlers list & search through the EventHandlers EventTypes, placing it in
   * the correct lists, so Events can be filtered correctly.
   */
  public final void addEventHandler(final EventHandler _handler) {
    if (exists(_handler) == true) {
      Logger.println(_handler.getName() + "already exists within " + name, Logger.Verbosity.MAJOR);
      return;
    }

    handlers.add(_handler);

    final ArrayList<EventType> types = _handler.getWantedEventTypes();
    if (types.isEmpty() == true || types.contains(Event.ALL_EVENT_TYPES) == true) {
      // Due to legacy we must assumme that a types size of 0,
      // represents a developer wishing to recieve all Events.
      // If the types contains ALL_EVENT_TYPES then only add it
      // to the ALL_EVENT_TYPES EventQueue.
      eventQueues.get(Event.ALL_EVENT_TYPES).addEventHandler(_handler);
      return;
    }

    for (final EventType type : types) {
      if (eventQueues.containsKey(type) == false) {
        addEventQueue(type, new EventQueue(type));
      }

      eventQueues.get(type).addEventHandler(_handler);
    }
  }
  /*
   * (non-Javadoc)
   * This will check if the user is at root dir. If so, if they press back
   * again, it will close the app.
   * @see android.app.Activity#onKeyDown(int, android.view.KeyEvent)
   */
  @Override
  public boolean onKeyDown(int keycode, KeyEvent event) {
    String current = flmg.getCurrentDir();

    if (keycode == KeyEvent.KEYCODE_SEARCH) {
      showDialog(SEARCH_B);

      return true;

    } else if (keycode == KeyEvent.KEYCODE_BACK && use_back_key && !current.equals("/")) {
      if (handler.isMultiSelected()) {
        table.killMultiSelect();
        Toast.makeText(Main.this, "Multi-select is now off", Toast.LENGTH_SHORT).show();
      }

      handler.updateDirectory(flmg.getPreviousDir());
      path_label.setText(flmg.getCurrentDir());

      return true;

    } else if (keycode == KeyEvent.KEYCODE_BACK && use_back_key && current.equals("/")) {
      Toast.makeText(Main.this, "Press back again to quit.", Toast.LENGTH_SHORT).show();
      use_back_key = false;
      path_label.setText(flmg.getCurrentDir());

      return false;

    } else if (keycode == KeyEvent.KEYCODE_BACK && !use_back_key && current.equals("/")) {
      finish();

      return false;
    }
    return false;
  }
    public void run() {
      try {
        while (selectable) {
          // The select() will be woke up if some new connection
          // have occurred, or if the selector has been explicitly
          // woke up
          if (selector.select() > 0) {
            Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();

            while (selectedKeys.hasNext()) {
              SelectionKey key = selectedKeys.next();
              selectedKeys.remove();

              if (key.isValid()) {
                EventHandler processor = ((EventHandler) key.attachment());
                processor.process(key);
              }
            }
          }
        }

      } catch (IOException ioe) {
        LOGGER.log(Level.WARNING, "Error while waiting for events", ioe);
      } finally {
        if (selectable) {
          LOGGER.log(
              Level.WARNING, "Unexpected death of thread {0}", Thread.currentThread().getName());
        } else {
          LOGGER.log(
              Level.FINE,
              "Thread {0} termination initiated by call to AgentServer.close()",
              Thread.currentThread().getName());
        }
      }
    }
  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    SharedPreferences.Editor editor = settings.edit();
    boolean check;
    int color;

    /* resultCode must equal RESULT_CANCELED because the only way
     * out of that activity is pressing the back button on the phone
     * this publishes a canceled result code not an ok result code
     */
    if (requestCode == SETTING_REQ && resultCode == RESULT_CANCELED) {
      // save the information we get from settings activity
      check = data.getBooleanExtra("HIDDEN", false);
      color = data.getIntExtra("COLOR", -1);

      editor.putBoolean(PREFS_HIDDEN, check);
      editor.putInt(PREFS_COLOR, color);
      editor.commit();

      flmg.setShowHiddenFiles(check);
      handler.setTextColor(color);
      handler.updateDirectory(flmg.getNextDir(flmg.getCurrentDir(), true));
    }
  }
  @Override
  public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo info) {
    super.onCreateContextMenu(menu, v, info);

    boolean multi_data = handler.hasMultiSelectData();
    AdapterContextMenuInfo _info = (AdapterContextMenuInfo) info;
    selected_list_item = handler.getData(_info.position);

    if (flmg.isDirectory(selected_list_item)) {
      menu.setHeaderTitle("Folder operations");
      menu.add(0, D_MENU_DELETE, 0, "Delete Folder");
      menu.add(0, D_MENU_RENAME, 0, "Rename Folder");
      menu.add(0, D_MENU_COPY, 0, "Copy Folder");
      menu.add(0, D_MENU_ZIP, 0, "Zip Folder");
      menu.add(0, D_MENU_PASTE, 0, "Paste into folder").setEnabled(holding_file || multi_data);
      menu.add(0, D_MENU_UNZIP, 0, "Extract here").setEnabled(holding_zip);

    } else {
      menu.setHeaderTitle("File Operations");
      menu.add(0, F_MENU_DELETE, 0, "Delete File");
      menu.add(0, F_MENU_RENAME, 0, "Rename File");
      menu.add(0, F_MENU_COPY, 0, "Copy File");
      menu.add(0, F_MENU_ATTACH, 0, "Email File");
    }
  }
Exemple #8
0
    @Override
    public void run() {
      Looper.prepare();
      Looper myLooper = Looper.myLooper();
      Looper mainLooper = Looper.getMainLooper();

      String msgobj;

      if (null == myLooper) {
        mOwnLooperThreadHandler = new EventHandler(mainLooper);
        msgobj =
            "OwnLooperThread has no looper and handleMessage function executed in main thread!";
      } else {
        mOwnLooperThreadHandler = new EventHandler(myLooper);
        msgobj =
            "This is from OwnLooperThread self and handleMessage function executed in NoLooperThread!";
      }

      mOwnLooperThreadHandler.removeMessages(0);

      // 给自己发送消息
      Message msg = mOwnLooperThreadHandler.obtainMessage(3, 1, 1, msgobj);
      mOwnLooperThreadHandler.sendMessage(msg);
      Looper.loop();
    }
Exemple #9
0
 @Override
 public void run() {
   Looper myLooper = Looper.myLooper();
   Looper mainLooper = Looper.getMainLooper();
   String msgobj;
   if (null == myLooper) {
     // 这里获得的是主线程的Looper,由于NoLooperThread没有自己的looper所以这里肯定会被执行
     mNoLooperThreadHandler = new EventHandler(mainLooper);
     msgobj = "NoLooperThread has no looper and handleMessage function executed in main thread!";
   } else {
     mNoLooperThreadHandler = new EventHandler(myLooper);
     msgobj =
         "This is from NoLooperThread self and handleMessage function executed in NoLooperThread!";
   }
   mNoLooperThreadHandler.removeMessages(0);
   if (bpostRunnable == false) {
     // send message to main thread
     Message msg = mNoLooperThreadHandler.obtainMessage(2, 1, 1, msgobj);
     mNoLooperThreadHandler.sendMessage(msg);
     Log.e(TAG, "NoLooperThread id:--------+>" + this.getId());
   } else {
     // 下面new出来的实现了Runnable接口的对象中run函数是在Main Thread中执行,不是在NoLooperThread中执行 记得 null == myLooper么
     // 注意Runnable是一个接口,它里面的run函数被执行时不会再新建一个线程
     // 您可以在run上加断点然后在eclipse调试中看它在哪个线程中执行
     mNoLooperThreadHandler.post(
         new Runnable() {
           public void run() {
             // TODO Auto-generated method stub
             tv.setText("update UI through handler post runnalbe mechanism!");
             Log.e(TAG, "update UI id:--------+>" + Thread.currentThread().getId());
             noLooperThread.stop();
           }
         });
   }
 }
 public String toString() {
   final StringBuffer buffer = new StringBuffer();
   buffer.append("[ Event Queue: " + name + ", ");
   for (final EventHandler handler : handlers) {
     buffer.append(handler.getName() + ", ");
   }
   buffer.append("]");
   return buffer.toString();
 }
Exemple #11
0
 /** This method is called by the build system to report an event. */
 @Override
 public synchronized void handle(Event e) {
   if (e.getKind() != EventKind.ERROR && e.getTag() != null && !showOutput(e.getTag())) {
     return;
   }
   for (EventHandler handler : handlers) {
     handler.handle(e);
   }
 }
 /**
  * Submit the event to the queue for handling.
  *
  * @param event
  */
 void submit(final EventHandler event) {
   // If there is a listener for this type, make sure we call the before
   // and after process methods.
   EventHandlerListener listener = this.eventHandlerListeners.get(event.getEventType());
   if (listener != null) {
     event.setListener(listener);
   }
   this.threadPoolExecutor.execute(event);
 }
 private void updateCacheStatus(int type, int info, long[] segments) {
   if (mEventHandler != null) {
     Message m = mEventHandler.obtainMessage(MEDIA_CACHING_UPDATE);
     Bundle b = m.getData();
     b.putInt(MEDIA_CACHING_TYPE, type);
     b.putInt(MEDIA_CACHING_INFO, info);
     b.putLongArray(MEDIA_CACHING_SEGMENTS, segments);
     mEventHandler.sendMessage(m);
   }
 }
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.main);

    /*read settings*/
    settings = getSharedPreferences(PREFS_NAME, 0);
    boolean hide = settings.getBoolean(PREFS_HIDDEN, false);
    int color = settings.getInt(PREFS_COLOR, -1);

    flmg = new FileManager();
    flmg.setShowHiddenFiles(hide);

    handler = new EventHandler(Main.this, flmg);
    handler.setTextColor(color);
    table = handler.new TableRow();

    /*sets the ListAdapter for our ListActivity and
     *gives our EventHandler class the same adapter
     */
    handler.setListAdapter(table);
    setListAdapter(table);

    /* register context menu for our list view */
    registerForContextMenu(getListView());

    path_label = (TextView) findViewById(R.id.path_label);
    detail_label = (TextView) findViewById(R.id.detail_label);
    path_label.setText("path: /sdcard");

    handler.setUpdateLabel(path_label, detail_label);

    ImageButton help_b = (ImageButton) findViewById(R.id.help_button);
    help_b.setOnClickListener(handler);

    ImageButton home_b = (ImageButton) findViewById(R.id.home_button);
    home_b.setOnClickListener(handler);

    ImageButton back_b = (ImageButton) findViewById(R.id.back_button);
    back_b.setOnClickListener(handler);

    ImageButton info_b = (ImageButton) findViewById(R.id.info_button);
    info_b.setOnClickListener(handler);

    ImageButton manage_b = (ImageButton) findViewById(R.id.manage_button);
    manage_b.setOnClickListener(handler);

    ImageButton multi_b = (ImageButton) findViewById(R.id.multiselect_button);
    multi_b.setOnClickListener(handler);

    ImageButton operation_b = (ImageButton) findViewById(R.id.multioperation_button);
    operation_b.setOnClickListener(handler);
  }
 @Override
 public void dispatch(Event event) throws NoEventHandler {
   EventHandler handler = map.get(event.type);
   if (handler != null)
     try {
       handler.handleEvent(event);
     } catch (JSONException e) {
       e.printStackTrace();
     }
   else throw new NoEventHandler(event.type);
 }
 @Override
 public void send(EventHandler e) {
   e.startNonterminal(name, begin);
   int pos = begin;
   for (Symbol c : children) {
     if (pos < c.begin) e.whitespace(pos, c.begin);
     c.send(e);
     pos = c.end;
   }
   if (pos < end) e.whitespace(pos, end);
   e.endNonterminal(name, end);
 }
Exemple #17
0
  public void registerEventHandler(EventHandler<?> _handler) {
    if (_handler == null) return;

    Array<EventHandler<?>> handlers = eventsHandlerByType.get(_handler.getType());
    if (handlers == null) {
      handlers = eventsHandlerArrayPool.obtain();
      eventsHandlerByType.put(_handler.getType(), handlers);
    }

    if (!handlers.contains(_handler, true)) {
      handlers.add(_handler);
    }
  }
Exemple #18
0
  public void onClick(View v) {
    // TODO Auto-generated method stub
    switch (v.getId()) {
      case 101:
        // 主线程发送消息给自己
        Looper looper = Looper.myLooper(); // get the Main looper related with the main thread
        // 如果不给任何参数的话会用当前线程对应的Looper(这里就是Main Looper)为Handler里面的成员mLooper赋值
        mHandler = new EventHandler(looper);
        // 清除整个MessageQueue里的消息
        mHandler.removeMessages(0);
        String obj = "This main thread's message and received by itself!";

        Message msg = mHandler.obtainMessage(1, 1, 1, obj);
        // 将Message对象送入到main thread的MessageQueue里面
        mHandler.sendMessage(msg);
        break;
      case 102:
        // other线程发送消息给主线程
        bpostRunnable = false;
        noLooperThread = new NoLooperThread();
        noLooperThread.start();
        break;
      case 103:
        // other thread获取它自己发送的消息
        tv.setText("please look at the error level log for other thread received message");
        ownLooperThread = new OwnLooperThread();
        ownLooperThread.start();
        break;
      case 104:
        // other thread通过Post Runnable方式发送消息给主线程
        bpostRunnable = true;
        noLooperThread = new NoLooperThread();
        noLooperThread.start();
        break;
      case 105:
        // 主线程发送消息给other thread
        if (null != mOtherThreadHandler) {
          tv.setText(
              "please look at the error level log for other thread received message from main thread");
          String msgObj = "message from mainThread";
          Message mainThreadMsg = mOtherThreadHandler.obtainMessage(1, 1, 1, msgObj);
          mOtherThreadHandler.sendMessage(mainThreadMsg);
        }
        break;
      case 106:
        finish();
        break;
    }
  }
  /**
   * Test method for {@link
   * org.jvoicexml.interpreter.ObjectExecutorThread#execute(org.jvoicexml.interpreter.VoiceXmlInterpreterContext,
   * org.jvoicexml.interpreter.VoiceXmlInterpreter,
   * org.jvoicexml.interpreter.FormInterpretationAlgorithm,
   * org.jvoicexml.interpreter.formitem.ObjectFormItem)} .
   *
   * @exception Exception Test failed.
   * @exception JVoiceXMLEvent Test failed.
   */
  @Test
  public void testExecute() throws Exception, JVoiceXMLEvent {
    final VoiceXmlDocument doc = new VoiceXmlDocument();
    final Vxml vxml = doc.getVxml();
    final Form form = vxml.appendChild(Form.class);
    final Subdialog subdialog = form.appendChild(Subdialog.class);
    subdialog.setName("test");
    final Form subform = vxml.appendChild(Form.class);
    subform.setId("subid");
    final Var var = subform.appendChild(Var.class);
    var.setName("testparam");
    final Block block = subform.appendChild(Block.class);
    final Assign assign = block.appendChild(Assign.class);
    assign.setName("testparam");
    assign.setExpr("testparam * 2");
    final Return ret = block.appendChild(Return.class);
    ret.setNamelist("testparam");
    final SubdialogFormItem item = new SubdialogFormItem(context, subdialog);
    final Dialog dialog = new ExecutablePlainForm();
    dialog.setNode(form);
    final FormInterpretationAlgorithm fia = new FormInterpretationAlgorithm(context, null, dialog);
    final EventHandler handler =
        new org.jvoicexml.interpreter.event.JVoiceXmlEventHandler(null, null);
    final EventBus eventbus = context.getEventBus();
    eventbus.subscribe("", handler);
    handler.collect(context, null, fia, item);

    final URI uri = new URI("#subid");
    final Map<String, Object> params = new java.util.HashMap<String, Object>();
    params.put("testparam", new Integer(4));
    final JVoiceXmlApplication application = new JVoiceXmlApplication(null);
    application.addDocument(new URI("test"), doc);

    final SubdialogExecutorThread executor =
        new SubdialogExecutorThread(uri, context, application, params, eventbus);

    executor.start();
    executor.join();
    ReturnEvent event = null;
    try {
      handler.processEvent(item);
    } catch (ReturnEvent e) {
      event = e;
    }
    Assert.assertNotNull(event);
    final Map<String, Object> variables = event.getVariables();
    Assert.assertEquals(1, variables.size());
    Assert.assertEquals(8, variables.get("testparam"));
  }
  @Override
  public boolean onKeyDown(int keycode, KeyEvent event) {
    String current = mFileMag.getCurrentDir();

    if (keycode == KeyEvent.KEYCODE_BACK && mUseBackKey && !current.equals("/")) {

      mHandler.updateDirectory(mFileMag.getPreviousDir());
      mPathLabel.setText(mFileMag.getCurrentDir());
      return true;

    } else if (keycode == KeyEvent.KEYCODE_BACK && mUseBackKey && current.equals("/")) {

      Toast.makeText(FileImportActivity.this, R.string.root_directory_tip, Toast.LENGTH_SHORT)
          .show();

      mUseBackKey = false;
      mPathLabel.setText(mFileMag.getCurrentDir());

      return false;

    } else if (keycode == KeyEvent.KEYCODE_BACK && !mUseBackKey && current.equals("/")) {
      finish();

      return false;
    }
    return false;
  }
  public void PrintOldAndNew(PrintStream out) {
    switch (mnEventId) {
      case AccessibleEventId.STATE_CHANGED:
        try {
          int nOldValue = AnyConverter.toInt(maEvent.OldValue);
          out.println(
              "    turning off state "
                  + nOldValue
                  + " ("
                  + NameProvider.getStateName(nOldValue)
                  + ")");
        } catch (com.sun.star.lang.IllegalArgumentException e) {
        }
        try {
          int nNewValue = AnyConverter.toInt(maEvent.NewValue);
          out.println(
              "    turning on state "
                  + nNewValue
                  + " ("
                  + NameProvider.getStateName(nNewValue)
                  + ")");
        } catch (com.sun.star.lang.IllegalArgumentException e) {
        }
        break;

      default:
        super.PrintOldAndNew(out);
    }
  }
Exemple #22
0
  /** Post a MNS Event to the MNS thread */
  public void sendMnsEvent(
      int masId, String msg, String handle, String folder, String old_folder, String msgType) {
    if (V) {
      Log.v(TAG, "sendMnsEvent()");
      Log.v(TAG, "msg: " + msg);
      Log.v(TAG, "handle: " + handle);
      Log.v(TAG, "folder: " + folder);
      Log.v(TAG, "old_folder: " + old_folder);
      Log.v(TAG, "msgType: " + msgType);
    }
    int location = -1;

    /* Send the notification, only if it was not initiated
     * by MCE. MEMORY_FULL and MEMORY_AVAILABLE cannot be
     * MCE initiated
     */
    if (msg.equals(MEMORY_AVAILABLE) || msg.equals(MEMORY_FULL)) {
      location = -1;
    } else {
      location = findLocationMceInitiatedOperation(handle);
    }

    if (location == -1) {
      String str = MapUtils.mapEventReportXML(msg, handle, folder, old_folder, msgType);
      if (V) Log.v(TAG, "Notification to MAS " + masId + ", msgType = " + msgType);
      mSessionHandler.obtainMessage(MNS_SEND_EVENT, masId, -1, str).sendToTarget();
    } else {
      removeMceInitiatedOperation(location);
    }
  }
Exemple #23
0
 /** See {@link android.webkit.WebSettings#setMediaPlaybackRequiresUserGesture}. */
 public void setMediaPlaybackRequiresUserGesture(boolean require) {
   synchronized (mXWalkSettingsLock) {
     if (mMediaPlaybackRequiresUserGesture != require) {
       mMediaPlaybackRequiresUserGesture = require;
       mEventHandler.updateWebkitPreferencesLocked();
     }
   }
 }
Exemple #24
0
 /** See {@link android.webkit.WebSettings#setDatabaseEnabled}. */
 public void setDatabaseEnabled(boolean flag) {
   synchronized (mXWalkSettingsLock) {
     if (mDatabaseEnabled != flag) {
       mDatabaseEnabled = flag;
       mEventHandler.updateWebkitPreferencesLocked();
     }
   }
 }
Exemple #25
0
 /** See {@link android.webkit.WebSettings#setUseWideViewPort}. */
 public void setUseWideViewPort(boolean use) {
   synchronized (mXWalkSettingsLock) {
     if (mUseWideViewport != use) {
       mUseWideViewport = use;
       mEventHandler.updateWebkitPreferencesLocked();
     }
   }
 }
Exemple #26
0
 /** See {@link android.webkit.WebSettings#setSupportMultipleWindows}. */
 public void setSupportMultipleWindows(boolean support) {
   synchronized (mXWalkSettingsLock) {
     if (mSupportMultipleWindows != support) {
       mSupportMultipleWindows = support;
       mEventHandler.updateWebkitPreferencesLocked();
     }
   }
 }
Exemple #27
0
 /** See {@link android.webkit.WebSettings#setJavaScriptCanOpenWindowsAutomatically}. */
 public void setJavaScriptCanOpenWindowsAutomatically(boolean flag) {
   synchronized (mXWalkSettingsLock) {
     if (mJavaScriptCanOpenWindowsAutomatically != flag) {
       mJavaScriptCanOpenWindowsAutomatically = flag;
       mEventHandler.updateWebkitPreferencesLocked();
     }
   }
 }
Exemple #28
0
 /** See {@link android.webkit.WebSettings#setLoadsImagesAutomatically}. */
 public void setLoadsImagesAutomatically(boolean flag) {
   synchronized (mXWalkSettingsLock) {
     if (mLoadsImagesAutomatically != flag) {
       mLoadsImagesAutomatically = flag;
       mEventHandler.updateWebkitPreferencesLocked();
     }
   }
 }
Exemple #29
0
 /** See {@link android.webkit.WebSettings#setAllowFileAccessFromFileURLs}. */
 public void setAllowFileAccessFromFileURLs(boolean flag) {
   synchronized (mXWalkSettingsLock) {
     if (mAllowFileAccessFromFileURLs != flag) {
       mAllowFileAccessFromFileURLs = flag;
       mEventHandler.updateWebkitPreferencesLocked();
     }
   }
 }
  public void init() {
    frame = new JFrame();
    frame.setLayout(new FlowLayout());
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setTitle("PersistentFrameTest");
    frame.setSize(400, 200);

    JButton loadButton = new JButton("Load");
    frame.add(loadButton);
    loadButton.addActionListener(EventHandler.create(ActionListener.class, this, "load"));

    JButton saveButton = new JButton("Save");
    frame.add(saveButton);
    saveButton.addActionListener(EventHandler.create(ActionListener.class, this, "save"));

    frame.setVisible(true);
  }