import threading
import time

import OpenRTM_aist

import RTC, RTC__POA

DEFAULT_PERIOD = 0.000001

##
# @if jp
# @class PeriodicExecutionContext
# @brief PeriodicExecutionContext クラス
#
# Periodic Sampled Data Processing(周期実行用)ExecutionContextクラス。
#
# @since 0.4.0
#
# @else
# @class PeriodicExecutionContext
# @brief PeriodicExecutionContext class
# @endif
class PeriodicExecutionContext(OpenRTM_aist.ExecutionContextBase,
                               RTC__POA.ExecutionContextService,
                               OpenRTM_aist.Task):
  """
  """

  ##
  # @if jp
  # @brief コンストラクタ
  #
  # コンストラクタ
  # 設定された値をプロファイルに設定する。
  #
  # @else
  # @brief Constructor
  # @endif
  def __init__(self):
    self._rtcout = OpenRTM_aist.Manager.instance().getLogbuf("rtobject.periodic_ec")
    self._rtcout.RTC_TRACE("PeriodicExecutionContext.__init__()")
    OpenRTM_aist.ExecutionContextBase.__init__(self, "periodic_ec")
    OpenRTM_aist.Task.__init__(self)

    self._svc = False
    self._nowait = False
    self._svcmutex = threading.RLock()
    self._workerthread = self.WorkerThreadCtrl()

    global DEFAULT_PERIOD
    self.setObjRef(self._this())
    self.setKind(RTC.PERIODIC)
    self.setRate(1.0 / DEFAULT_PERIOD)
    self._rtcout.RTC_DEBUG("Actual rate: %d [sec], %d [usec]",
                           (self._profile.getPeriod().sec(), self._profile.getPeriod().usec()))

    self._cpu = []

    return

  ##
  # @if jp
  # @brief 終了関数
  #
  # @param self
  # @param Task
  #
  # @else
  # @brief
  # @param self
  # @param Task
  # @endif
  def exit(self, Task=OpenRTM_aist.Task):
    import OpenRTM_aist.Guard
    self._rtcout.RTC_TRACE("PeriodicExecutionContext.__del__()")
    guard = OpenRTM_aist.Guard.ScopedLock(self._svcmutex)
    self._svc = False
    del guard

    guard = OpenRTM_aist.ScopedLock(self._workerthread._mutex)
    self._workerthread._cond.acquire()
    self._workerthread._running = True
    self._workerthread._cond.notify()
    self._workerthread._cond.release()
    del guard
    self.wait()
    Task.__del__(self)
    OpenRTM_aist.ExecutionContextBase.exit(self)
    return

  ##
  # @if jp
  # @brief 初期化関数
  #
  # @param self
  # @param props プロパティ
  #
  # @else
  # @brief
  # @param self
  # @param props
  # @endif
  def init(self, props):
    OpenRTM_aist.ExecutionContextBase.init(self, props)
    self.setCpuAffinity(props)
    self._rtcout.RTC_DEBUG("init() done")

  ##
  # @if jp
  # @brief コンポーネントのアクティビティスレッド関数
  #
  # コンポーネントの内部アクティビティスレッドの実行関数。
  # ACE_Task サービスクラスメソッドのオーバーライド。
  #
  # @else
  #
  # @brief Create internal activity thread
  #
  # Run by a daemon thread to handle deferred processing.
  # ACE_Task class method override.
  #
  # @endif
  def svc(self):
    self._rtcout.RTC_TRACE("svc()")
    count_ = 0

    if len(self._cpu) > 0:
      ret = OpenRTM_aist.setThreadAffinity(self._cpu)
      if ret == False:
        self._rtcout.RTC_ERROR("CPU affinity mask setting failed")

    while self.threadRunning():
      OpenRTM_aist.ExecutionContextBase.invokeWorkerPreDo(self)
      # Thread will stopped when all RTCs are INACTIVE.
      # Therefore WorkerPreDo(updating state) have to be invoked
      # before stopping thread.
      guard = OpenRTM_aist.ScopedLock(self._workerthread._mutex)
      while not self._workerthread._running:
        self._workerthread._cond.wait()
      del guard

      t0_ = OpenRTM_aist.Time()
      OpenRTM_aist.ExecutionContextBase.invokeWorkerDo(self)
      OpenRTM_aist.ExecutionContextBase.invokeWorkerPostDo(self)
      t1_ = OpenRTM_aist.Time()

      period_ = self.getPeriod()

      if count_ > 1000:
        exctm_ = (t1_ - t0_).getTime().toDouble()
        slptm_ = period_.toDouble() - exctm_
        self._rtcout.RTC_PARANOID("Period:    %f [s]", period_.toDouble())
        self._rtcout.RTC_PARANOID("Execution: %f [s]", exctm_)
        self._rtcout.RTC_PARANOID("Sleep:     %f [s]", slptm_)

      t2_ = OpenRTM_aist.Time()

      if not self._nowait and period_.toDouble() > ((t1_ - t0_).getTime().toDouble()):
        if count_ > 1000:
          self._rtcout.RTC_PARANOID("sleeping...")
        slptm_ = period_.toDouble() - (t1_ - t0_).getTime().toDouble()
        time.sleep(slptm_)

      if count_ > 1000:
        t3_ = OpenRTM_aist.Time()
        self._rtcout.RTC_PARANOID("Slept:     %f [s]", (t3_ - t2_).getTime().toDouble())
        count_ = 0
      count_ += 1

    self._rtcout.RTC_DEBUG("Thread terminated.")
    return 0

  ##
  # @if jp
  # @brief ExecutionContext用アクティビティスレッドを生成する
  # @else
  # @brief Generate internal activity thread for ExecutionContext
  # @endif
  #
  # int PeriodicExecutionContext::open(void *args)
  def open(self, *args):
    self._rtcout.RTC_TRACE("open()")
    self.activate()
    return 0

  ##
  # @if jp
  # @brief ExecutionContext 用のスレッド実行関数
  #
  # ExecutionContext 用のスレッド終了時に呼ばれる。
  # コンポーネントオブジェクトの非アクティブ化、マネージャへの通知を行う。
  # これは ACE_Task サービスクラスメソッドのオーバーライド。
  #
  # @param self
  # @param flags 終了処理フラグ
  #
  # @return 終了処理結果
  #
  # @else
  #
  # @brief Close activity thread
  #
  # close() method is called when activity thread svc() is returned.
  # This method deactivate this object and notify it to manager.
  # ACE_Task class method override.
  #
  # @endif
  def close(self, flags):
    self._rtcout.RTC_TRACE("close()")
    return 0

  ##
  # @if jp
  # @brief ExecutionContext 実行状態確認関数
  #
  # この操作は ExecutionContext が Runnning 状態の場合に true を返す。
  # Executioncontext が Running の間、当該 Executioncontext に参加している
  # 全てのアクティブRTコンポーネントが、 ExecutionContext の実行種類に応じて
  # 実行される。
  #
  # @param self
  #
  # @return 状態確認関数(動作中:true、停止中:false)
  #
  # @else
  #
  # @brief Check for ExecutionContext running state
  #
  # This operation shall return true if the context is in the Running state.
  # While the context is Running, all Active RTCs participating
  # in the context shall be executed according to the context’s execution
  # kind.
  #
  # @endif
  def is_running(self):
    self._rtcout.RTC_TRACE("is_running()")
    return OpenRTM_aist.ExecutionContextBase.isRunning(self)

  ##
  # @if jp
  # @brief ExecutionContext の実行を開始
  #
  # ExecutionContext の実行状態を Runnning とするためのリクエストを発行する。
  # ExecutionContext の状態が遷移すると ComponentAction::on_startup が
  # 呼び出される。
  # 参加しているRTコンポーネントが、初期化されるまで ExecutionContext を開始
  # することはできない。
  # ExecutionContext は複数回開始/停止を繰り返すことができる。
  #
  # @param self
  #
  # @return ReturnCode_t 型のリターンコード
  #
  # @else
  #
  # @brief Start ExecutionContext
  #
  # Request that the context enter the Running state.
  # Once the state transition occurs, the ComponentAction::on_startup
  # operation will be invoked.
  # An execution context may not be started until the RT components that
  # participate in it have been initialized.
  # An execution context may be started and stopped multiple times.
  #
  # @endif
  def start(self):
    return OpenRTM_aist.ExecutionContextBase.start(self)

  ##
  # @if jp
  # @brief ExecutionContext の実行を停止
  #
  # ExecutionContext の状態を Stopped とするためのリクエストを発行する。
  # 遷移が発生した場合は、 ComponentAction::on_shutdown が呼び出される。
  # 参加しているRTコンポーネントが終了する前に ExecutionContext を停止する
  # 必要がある。
  # ExecutionContext は複数回開始/停止を繰り返すことができる。
  #
  # @param self
  #
  # @return ReturnCode_t 型のリターンコード
  #
  # @else
  #
  # @brief Stop ExecutionContext
  #
  # Request that the context enter the Stopped state.
  # Once the transition occurs, the ComponentAction::on_shutdown operation
  # will be invoked.
  # An execution context must be stopped before the RT components that
  # participate in it are finalized.
  # An execution context may be started and stopped multiple times.
  #
  # @endif
  def stop(self):
    return OpenRTM_aist.ExecutionContextBase.stop(self)

  ##
  # @if jp
  # @brief ExecutionContext の実行周期(Hz)を取得する
  #
  # Active 状態にてRTコンポーネントが実行される周期(単位:Hz)を取得する。
  #
  # @param self
  #
  # @return 処理周期(単位:Hz)
  #
  # @else
  #
  # @brief Get ExecutionRate
  #
  # This operation shall return the rate (in hertz) at which its Active
  # participating RTCs are being invoked.
  #
  # @endif
  def get_rate(self):
    return OpenRTM_aist.ExecutionContextBase.getRate(self)

  ##
  # @if jp
  # @brief ExecutionContext の実行周期(Hz)を設定する
  #
  # Active 状態にてRTコンポーネントが実行される周期(単位:Hz)を設定する。
  # 実行周期の変更は、 DataFlowComponentAction の on_rate_changed によって
  # 各RTコンポーネントに伝達される。
  #
  # @param self
  # @param rate 処理周期(単位:Hz)
  #
  # @return ReturnCode_t 型のリターンコード
  #
  # @else
  #
  # @brief Set ExecutionRate
  #
  # This operation shall set the rate (in hertz) at which this context’s
  # Active participating RTCs are being called.
  # If the execution kind of the context is PERIODIC, a rate change shall
  # result in the invocation of on_rate_changed on any RTCs realizing
  # DataFlowComponentAction that are registered with any RTCs participating
  # in the context.
  #
  # @endif
  def set_rate(self, rate):
    return OpenRTM_aist.ExecutionContextBase.setRate(self, rate)

  ##
  # @if jp
  # @brief RTコンポーネントをアクティブ化する
  #
  # Inactive 状態にあるRTコンポーネントをActive に遷移させ、アクティブ化する。
  # この操作が呼ばれた結果、 on_activate が呼び出される。
  # 指定したRTコンポーネントが参加者リストに含まれない場合は、 BAD_PARAMETER
  # が返される。
  # 指定したRTコンポーネントの状態が Inactive 以外の場合は、
  #  PRECONDITION_NOT_MET が返される。
  #
  # @param self
  # @param comp アクティブ化対象RTコンポーネント
  #
  # @return ReturnCode_t 型のリターンコード
  #
  # @else
  #
  # @brief Activate a RT-component
  #
  # The given participant RTC is Inactive and is therefore not being invoked
  # according to the execution context’s execution kind. This operation
  # shall cause the RTC to transition to the Active state such that it may
  # subsequently be invoked in this execution context.
  # The callback on_activate shall be called as a result of calling this
  # operation. This operation shall not return until the callback has
  # returned, and shall result in an error if the callback does.
  #
  # @endif
  def activate_component(self, comp):
    return OpenRTM_aist.ExecutionContextBase.activateComponent(self, comp)

  ##
  # @if jp
  # @brief RTコンポーネントを非アクティブ化する
  #
  # Inactive 状態にあるRTコンポーネントを非アクティブ化し、
  # Inactive に遷移させる。
  # この操作が呼ばれた結果、 on_deactivate が呼び出される。
  # 指定したRTコンポーネントが参加者リストに含まれない場合は、 BAD_PARAMETER
  # が返される。
  # 指定したRTコンポーネントの状態が Active 以外の場合は、
  # PRECONDITION_NOT_MET が返される。
  #
  # @param self
  # @param comp 非アクティブ化対象RTコンポーネント
  #
  # @return ReturnCode_t 型のリターンコード
  #
  # @else
  #
  # @brief Deactivate a RT-component
  #
  # The given RTC is Active in the execution context. Cause it to transition
  # to the Inactive state such that it will not be subsequently invoked from
  # the context unless and until it is activated again.
  # The callback on_deactivate shall be called as a result of calling this
  # operation. This operation shall not return until the callback has
  # returned, and shall result in an error if the callback does.
  #
  # @endif
  def deactivate_component(self, comp):
    return OpenRTM_aist.ExecutionContextBase.deactivateComponent(self, comp)

  ##
  # @if jp
  # @brief RTコンポーネントをリセットする
  #
  # Error 状態のRTコンポーネントの復帰を試みる。
  # この操作が呼ばれた結果、 on_reset が呼び出される。
  # 指定したRTコンポーネントが参加者リストに含まれない場合は、 BAD_PARAMETER
  # が返される。
  # 指定したRTコンポーネントの状態が Error 以外の場合は、 PRECONDITION_NOT_MET
  # が返される。
  #
  # @param self
  # @param comp リセット対象RTコンポーネント
  #
  # @return ReturnCode_t 型のリターンコード
  #
  # @else
  #
  # @brief Reset a RT-component
  #
  # Attempt to recover the RTC when it is in Error.
  # The ComponentAction::on_reset callback shall be invoked. This operation
  # shall not return until the callback has returned, and shall result in an
  # error if the callback does. If possible, the RTC developer should
  # implement that callback such that the RTC may be returned to a valid
  # state.
  #
  # @endif
  def reset_component(self, comp):
    return OpenRTM_aist.ExecutionContextBase.resetComponent(self, comp)

  ##
  # @if jp
  # @brief RTコンポーネントの状態を取得する
  #
  # 指定したRTコンポーネントの状態(LifeCycleState)を取得する。
  # 指定したRTコンポーネントが参加者リストに含まれない場合は、 CREATED_STATE
  # が返される。
  #
  # @param self
  # @param comp 状態取得対象RTコンポーネント
  #
  # @return 現在の状態(LifeCycleState)
  #
  # @else
  #
  # @brief Get RT-component's state
  #
  # This operation shall report the LifeCycleState of the given participant
  # RTC.
  #
  # @endif
  def get_component_state(self, comp):
    return OpenRTM_aist.ExecutionContextBase.getComponentState(self, comp)

  ##
  # @if jp
  # @brief ExecutionKind を取得する
  #
  # 本 ExecutionContext の ExecutionKind を取得する
  #
  # @param self
  #
  # @return ExecutionKind
  #
  # @else
  #
  # @brief Get the ExecutionKind
  #
  # This operation shall report the execution kind of the execution context.
  #
  # @endif
  def get_kind(self):
    return OpenRTM_aist.ExecutionContextBase.getKind(self)

  ##
  # @if jp
  # @brief RTコンポーネントを追加する
  #
  # 指定したRTコンポーネントを参加者リストに追加する。
  # 追加されたRTコンポーネントは attach_context が呼ばれ、Inactive 状態に遷移
  # する。
  # 指定されたRTコンポーネントがnullの場合は、BAD_PARAMETER が返される。
  # 指定されたRTコンポーネントが DataFlowComponent 以外の場合は、
  # BAD_PARAMETER が返される。
  #
  # @param self
  # @param comp 追加対象RTコンポーネント
  #
  # @return ReturnCode_t 型のリターンコード
  #
  # @else
  #
  # @brief Add a RT-component
  #
  # The operation causes the given RTC to begin participating in the
  # execution context.
  # The newly added RTC will receive a call to
  # LightweightRTComponent::attach_context and then enter the Inactive state.
  #
  # @endif
  def add_component(self, comp):
    return OpenRTM_aist.ExecutionContextBase.addComponent(self, comp)

  ##
  # @if jp
  # @brief RTコンポーネントを参加者リストから削除する
  #
  # 指定したRTコンポーネントを参加者リストから削除する。
  # 削除されたRTコンポーネントは detach_context が呼ばれる。
  # 指定されたRTコンポーネントが参加者リストに登録されていない場合は、
  # BAD_PARAMETER が返される。
  #
  # @param self
  # @param comp 削除対象RTコンポーネント
  #
  # @return ReturnCode_t 型のリターンコード
  #
  # @else
  #
  # @brief Remove the RT-component from participant list
  #
  # This operation causes a participant RTC to stop participating in the
  # execution context.
  # The removed RTC will receive a call to
  # LightweightRTComponent::detach_context.
  #
  # @endif
  def remove_component(self, comp):
    return OpenRTM_aist.ExecutionContextBase.removeComponent(self, comp)

  ##
  # @if jp
  # @brief ExecutionContextProfile を取得する
  #
  # 本 ExecutionContext のプロファイルを取得する。
  #
  # @param self
  #
  # @return ExecutionContextProfile
  #
  # @else
  #
  # @brief Get the ExecutionContextProfile
  #
  # This operation provides a profile “descriptor” for the execution
  # context.
  #
  # @endif
  def get_profile(self):
    return OpenRTM_aist.ExecutionContextBase.getProfile(self)

  # virtual RTC::ReturnCode_t onStarted();
  def onStarted(self):
    # change EC thread state
    guard = OpenRTM_aist.ScopedLock(self._svcmutex)
    if not self._svc:
      self._svc = True
      self.open(0)
    del guard

    if self.isAllNextState(RTC.INACTIVE_STATE):
      guard = OpenRTM_aist.ScopedLock(self._workerthread._mutex)
      self._workerthread._running = False
      del guard
    else:
      guard = OpenRTM_aist.ScopedLock(self._workerthread._mutex)
      self._workerthread._running = True
      self._workerthread._cond.acquire()
      self._workerthread._cond.notify()
      self._workerthread._cond.release()
      del guard
    return RTC.RTC_OK

  # virtual RTC::ReturnCode_t onStopping();
  def onStopping(self):
    # stop thread
    guard = OpenRTM_aist.ScopedLock(self._workerthread._mutex)
    self._workerthread._running = False
    return RTC.RTC_OK

  def onAddedComponent(self, rtobj):
    guard = OpenRTM_aist.ScopedLock(self._workerthread._mutex)
    if self._workerthread._running == False:
      self._worker.updateComponentList()
    return RTC.RTC_OK

  def onRemovedComponent(self, rtobj):
    guard = OpenRTM_aist.ScopedLock(self._workerthread._mutex)
    if self._workerthread._running == False:
      self._worker.updateComponentList()
    return RTC.RTC_OK

  # virtual RTC::ReturnCode_t
  # onWaitingActivated(RTC_impl::RTObjectStateMachine* comp, long int count);
  def onWaitingActivated(self, comp, count):
    self._rtcout.RTC_TRACE("onWaitingActivated(count = %d)", count)
    self._rtcout.RTC_PARANOID("curr: %s, next: %s",
                              (self.getStateString(comp.getStates().curr),
                               self.getStateString(comp.getStates().next)))
    # Now comp's next state must be ACTIVE state
    # If worker thread is stopped, restart worker thread.
    if self.isRunning():
      guard = OpenRTM_aist.ScopedLock(self._workerthread._mutex)
      if self._workerthread._running == False:
        self._workerthread._running = True
        self._workerthread._cond.acquire()
        self._workerthread._cond.notify()
        self._workerthread._cond.release()
      del guard
    return RTC.RTC_OK

  # virtual RTC::ReturnCode_t
  # onActivated(RTC_impl::RTObjectStateMachine* comp, long int count);
  def onActivated(self, comp, count):
    self._rtcout.RTC_TRACE("onActivated(count = %d)", count)
    self._rtcout.RTC_PARANOID("curr: %s, next: %s",
                              (self.getStateString(comp.getStates().curr),
                               self.getStateString(comp.getStates().next)))
    # count = -1; Asynch mode. Since onWaitingActivated is not
    # called, onActivated() have to send restart singnal to worker
    # thread.
    # count > 0: Synch mode.

    # Now comp's next state must be ACTIVE state
    # If worker thread is stopped, restart worker thread.
    if self.isRunning():
      guard = OpenRTM_aist.ScopedLock(self._workerthread._mutex)
      if self._workerthread._running == False:
        self._workerthread._running = True
        self._workerthread._cond.acquire()
        self._workerthread._cond.notify()
        self._workerthread._cond.release()
      del guard
    return RTC.RTC_OK

  # virtual RTC::ReturnCode_t
  # onWaitingDeactivated(RTC_impl::RTObjectStateMachine* comp, long int count);
  def onWaitingDeactivated(self, comp, count):
    self._rtcout.RTC_TRACE("onWaitingDeactivated(count = %d)", count)
    self._rtcout.RTC_PARANOID("curr: %s, next: %s",
                              (self.getStateString(comp.getStates().curr),
                               self.getStateString(comp.getStates().next)))
    if self.isAllNextState(RTC.INACTIVE_STATE):
      guard = OpenRTM_aist.ScopedLock(self._workerthread._mutex)
      if self._workerthread._running == True:
        self._workerthread._running = False
        self._rtcout.RTC_TRACE("All RTCs are INACTIVE. Stopping worker thread.")
      del guard

    return RTC.RTC_OK

  # virtual RTC::ReturnCode_t
  # onDeactivated(RTC_impl::RTObjectStateMachine* comp, long int count);
  def onDeactivated(self, comp, count):
    self._rtcout.RTC_TRACE("onDeactivated(count = %d)", count)
    self._rtcout.RTC_PARANOID("curr: %s, next: %s",
                              (self.getStateString(comp.getStates().curr),
                               self.getStateString(comp.getStates().next)))
    if self.isAllNextState(RTC.INACTIVE_STATE):
      guard = OpenRTM_aist.ScopedLock(self._workerthread._mutex)
      if self._workerthread._running == True:
        self._workerthread._running = False
        self._rtcout.RTC_TRACE("All RTCs are INACTIVE. Stopping worker thread.")
      del guard

    return RTC.RTC_OK

  # virtual RTC::ReturnCode_t
  # onWaitingReset(RTC_impl::RTObjectStateMachine* comp, long int count);
  def onWaitingReset(self, comp, count):
    self._rtcout.RTC_TRACE("onWaitingReset(count = %d)", count)
    self._rtcout.RTC_PARANOID("curr: %s, next: %s",
                              (self.getStateString(comp.getStates().curr),
                               self.getStateString(comp.getStates().next)))
    if self.isAllNextState(RTC.INACTIVE_STATE):
      guard = OpenRTM_aist.ScopedLock(self._workerthread._mutex)
      if self._workerthread._running == True:
        self._workerthread._running = False
        self._rtcout.RTC_TRACE("All RTCs are INACTIVE. Stopping worker thread.")
      del guard

    return RTC.RTC_OK

  # virtual RTC::ReturnCode_t
  # onReset(RTC_impl::RTObjectStateMachine* comp, long int count);
  def onReset(self, comp, count):
    self._rtcout.RTC_TRACE("onReset(count = %d)", count)
    self._rtcout.RTC_PARANOID("curr: %s, next: %s",
                              (self.getStateString(comp.getStates().curr),
                               self.getStateString(comp.getStates().next)))
    if self.isAllNextState(RTC.INACTIVE_STATE):
      guard = OpenRTM_aist.ScopedLock(self._workerthread._mutex)
      if self._workerthread._running == True:
        self._workerthread._running = False
        self._rtcout.RTC_TRACE("All RTCs are INACTIVE. Stopping worker thread.")
      del guard

    return RTC.RTC_OK

  # bool threadRunning()
  def threadRunning(self):
    guard = OpenRTM_aist.ScopedLock(self._svcmutex)
    return self._svc

  def setCpuAffinity(self, props):
    self._rtcout.RTC_TRACE("setCpuAffinity()")

    affinity_str = props.getProperty("cpu_affinity")
    if affinity_str:
      self._rtcout.RTC_DEBUG("CPU affinity property: %s",affinity_str)

      tmp = affinity_str.split(",")
      self._cpu = []
      for num in tmp:
        try:
          self._cpu.append(int(num))
          self._rtcout.RTC_DEBUG("CPU affinity int value: %d added.",int(num))
        except ValueError:
          pass

  ##
  # @if jp
  # @class WorkerThreadCtrl
  # @brief worker 用状態変数クラス
  #
  # @else
  # @class WorkerThreadCtrl
  # @brief Condition variable class for worker
  # @endif
  class WorkerThreadCtrl:

    ##
    # @if jp
    # @brief コンストラクタ
    #
    # コンストラクタ
    #
    # @param self
    #
    # @else
    # @brief Constructor
    # @endif
    def __init__(self):
      self._mutex = threading.RLock()
      self._cond = threading.Condition(self._mutex)
      self._running = False

##
# @if jp
# @brief ExecutionContext を初期化する
#
# ExecutionContext 起動用ファクトリを登録する。
#
# @param manager マネージャオブジェクト
#
# @else
#
# @endif
def PeriodicExecutionContextInit(manager):
  OpenRTM_aist.ExecutionContextFactory.instance().addFactory("PeriodicExecutionContext",
                                                             OpenRTM_aist.PeriodicExecutionContext,
                                                             OpenRTM_aist.ECDelete)
  return


import numpy as np
import game
import config

class Node:
    def __init__(self, state, player, tree):
        self.s = state
        self.player = player
        self.tree = tree

        self.edges = []

        self.tree.add_node(self)

    def __hash__(self):
        return hash(tuple(self.s))

    def create_node(self, action):
        new_state = game.move(self.s.copy(), action, self.player)
        if self.tree.check_state(new_state):
            # print("NODE EXISTED")
            new_node = self.tree.get_node(new_state)
        else:
            new_node = Node(new_state, -self.player, self.tree)
            # self.add_node(new_node)

        return new_node

    def update_root(self, action):
        return self.create_node(action)

    """def simulate2(self, nn):
        if self.children:
            p = self.probabilities()
            self.children[np.random.choice(np.flatnonzero(p == np.max(p)))].simulate(nn)
        else:
            outcome = game.check_game_over(self.s)
            if outcome is None:
                self.expand_fully(nn)
                v = nn.get_preds(self)[0]
            else: v = outcome
            if self.parent:
                self.backfill(v)"""

    def simulate(self, nn):
        breadcrumbs = []
        root = self
        while root.edges:
            p = root.probabilities2(root == self)
            edge = root.edges[np.random.choice(np.flatnonzero(p == np.max(p)))]
            # edge = root.edges[np.argmax(p)] #
            breadcrumbs.append(edge)
            root = edge.out_node
        outcome = game.check_game_over(root.s)
        if outcome is None:
            nodes = (self,) + tuple(edge.out_node for edge in breadcrumbs)
            (v, p) = nn.get_preds(nodes)
            root.expand_fully(p)
        else: v = outcome * root.player
        root.backfill(v, breadcrumbs)

    def expand_fully(self, prior):
        # for action in sorted(game.get_legal_moves(self.s)): #
        for action in game.get_legal_moves(self.s):
            new_node = self.create_node(action)
            edge = Edge(self, new_node, action, prior[action])
            self.edges.append(edge)

    def probabilities2(self, is_root):
        if is_root:
            epsilon = config.EPSILON
            nu = np.random.dirichlet([config.ALPHA] * len(self.edges))
            # nu = [0.1] * len(self.edges) #
        else:
            epsilon = 0
            nu = [0] * len(self.edges)
        nb = sum(edge.n for edge in self.edges)
        return [edge.q + edge.u(epsilon, nu[i], nb) for i, edge in enumerate(self.edges)]

    """def backfill2(self, v):
        self.n += 1
        self.w += v * -self.player
        self.q = self.w / self.n
        if self.parent: self.parent.backfill2(v)"""

    def backfill(self, v, breadcrumbs):
        for edge in breadcrumbs:
            edge.n += 1
            edge.w += v * self.player * edge.player
            edge.q = edge.w / edge.n

class Edge:
    def __init__(self, in_node, out_node, action, prior):
        self.in_node = in_node
        self.out_node = out_node
        self.player = in_node.player
        self.action = action

        self.n = 0
        self.w = 0
        self.q = 0
        self.p = prior

    def u(self, epsilon, nuidx, nb):
        return config.CPUCT * ((1 - epsilon) * self.p + nuidx * epsilon) * np.sqrt(nb) / (1 + self.n)

class Tree:
    def __init__(self):
        self.saved_nodes = {}

    def check_state(self, state):
        return hash(tuple(state)) in self.saved_nodes

    def add_node(self, node):
        self.saved_nodes[hash(node)] = node

    def get_node(self, state):
        return self.saved_nodes[hash(tuple(state))]


'''
Ce script extrait les donnees sur le coronavirus d'un fichier html (ou js)
trace l'evolution quotidienne du nombre de deces/reanimation/cas
G Vigé - 3/4/2020
'''

import numpy as np
import matplotlib.pyplot as plt
import json
import re

format = 2

if format==2:
    fich = open("index.js", "r")
    contenu = fich.read()
    fich.close()
    x = re.findall("JSON.parse\(\'\[\{\"casConfirmes(.*?)\'\)", contenu)
    s="[{\"casConfirmes" + x[0] #'[{"casConfirmes"
    #pas trouve un moyen propre de convertir l'UTF8
    s = s.replace("\\xe9", "é")
    s = s.replace("\\xce","I")
    s = s.replace("\\xf4","ô")
    s = s.replace("\\'","'")
    s = s.replace("\\xe8","è")
    liste = json.loads(s)
elif format==1:
    #ancien format (html)
    fich = open("a.html", "r")
    contenu = fich.read()
    fich.close()
    x = re.findall("\"data\":\[(.*?)\]", contenu) #x est une liste (a un element)
    s="["+x[0]+"]" #la chaine doit commencer et finir par des crochets
    liste = json.loads(s)

cas=[0]; deces=[0]; reanimation=[0]; hospitalises=[0]
for dic in liste:
    if dic["code"]=="FRA":
        if ('casConfirmes' in dic):
            cas=cas+[dic['casConfirmes']]
        else:
            cas=cas+[cas[-1]]
        if ('deces' in dic):
            deces=deces+[dic['deces']]
        else:
            deces=deces+[deces[-1]]
        if ('reanimation' in dic):
            reanimation=reanimation+[dic['reanimation']]
        else:
            reanimation=reanimation+[reanimation[-1]]
        if ('hospitalises' in dic):
            hospitalises=hospitalises+[dic['hospitalises']]
        else:
            hospitalises=hospitalises+[hospitalises[-1]]

#plt.plot(cas, label="casConfirmes")
#plt.plot(deces, label="deces")

#moyenne glissante
n=len(deces)
delta_rea = np.array(reanimation[1:])- np.array(reanimation[0:-1])
delta_deces = np.array(deces[1:])- np.array(deces[0:-1])
x=np.linspace(1,n-1,n-1)

plt.subplot(121)
plt.plot(x,reanimation[1:], 'p:',label="reanimation")
plt.legend()

plt.subplot(122)
plt.plot(x,delta_rea, 'b:',label="delta reanimation")
plt.plot(x,delta_deces,'r:', label="deces/jour")

def lissage(x,y,p):
    '''Fonction qui debruite une courbe par une moyenne glissante sur 2P+1 points'''
    xout=[]
    yout=[]
    xout = x[p: -p]
    for index in range(p, len(y)-p):
        average = np.mean(y[index-p : index+p+1])
        yout.append(average)
    #pour le point suivant la moyenne est faite sur le nb de pts dispo
    for j in range(1,p+1):
        average = np.mean(y[index-p+j : index+p+1])
        yout.append(average)
        xout = np.append(xout,x[-p+j-1])
    return xout,yout

x_lisse, y_lisse = lissage(x,delta_rea, 3)
plt.plot(x_lisse, y_lisse, 'b-',label="lissage")
x_lisse, y_lisse = lissage(x,delta_deces, 3)
plt.plot(x_lisse, y_lisse, 'r-',label="lissage")
plt.legend()
plt.show()


from django.conf import settings
from django.utils.translation import ugettext_lazy as _

# Special palette color value to watch for custom name input
PALETTE_NAME_CUSTOM = "other"

# Palette base choices contains required items that allways stand at the end
# of choices
PALETTEITEM_BASE_CHOICES = [
    (PALETTE_NAME_CUSTOM, _("Other")),
]

# Enabled dump format choices
DUMP_FORMATS_CHOICES = [
    (k, v["name"]) for k, v in settings.PALETTE_DUMP_FORMATS.items()
]


#! python3
# Name: Jack Shao
# File: phoneAndEmail.py
# Description: Finds all phone numbers and email addresses in the clipboard

import pyperclip
import re
import requests
import bs4
import sys

def tag_visible(element):
    if element.parent.name in ['style', 'script', 'head', 'title', 'meta', '[document]']:
        return False
    if isinstance(element, bs4.element.Comment):
        return False
    return True

def text_from_html(body):
    soup = bs4.BeautifulSoup(body, 'html.parser')
    texts = soup.findAll(text=True)
    visible_texts = filter(tag_visible, texts)
    return ' '.join(visible_texts)

phoneRegex = re.compile(r'''(
                            (\d{3}|\(\d{3}\))?              # area code
                            (\s|-|\.)?                      # separator
                            (\d{3})                         # first 3 digits
                            (\s|-|\.)                       # separator
                            (\d{4})                         # last 4 digits
                            (\s*(ext|x|ext.)\s*(\d{2,5}))?  # extension
                            )''', re.VERBOSE)

emailRegex = re.compile(r'''(
                             [a-zA-Z0-9._%+-]+  # username
                             @                  # @ sign
                             [a-zA-Z0-9.-]+     # domain name
                             (\.[a-zA-Z]{2,4})  # dot something
                             )''', re.VERBOSE)

if len(sys.argv) == 1:
    # get text from clipboard
    text = str(pyperclip.paste())
elif len(sys.argv) == 2:
    # get text from web page
    res = requests.get(sys.argv[1])
    res.raise_for_status()
    text = text_from_html(res.text)
else:
    print('Error: too many arguments')
    quit()

matches = []

# add all numbers and emails to matches list
for groups in phoneRegex.findall(text):
    phoneNum = '-'.join([groups[1], groups[3], groups[5]])  # join numbers with dash in between
    # check for extension and add if it exists
    if groups[8] != '':
        phoneNum += ' x' + groups[8]
        print(groups[8] + '|')
    matches.append(phoneNum)
for groups in emailRegex.findall(text):
    matches.append(groups[0])

# copy matches to clipboard and print results
if len(matches) > 0:
    pyperclip.copy('\n'.join(matches))
    print('Copied to clipboard:')
    print('\n'.join(matches))
else:
    print('No phone numbers or email addresses found.')


import unittest
from datetime import date, timedelta

import factory

from ynab.api import ImportIdGenerator
from ynab.transactions import (
    MAX_COMPARE_DAYS,
    Transaction,
    pretty_format_transactions,
    transactions_difference,
)

class TransactionFactory(factory.Factory):
    class Meta:
        model = Transaction

    date = factory.Faker("date_object")
    payee_name = factory.Faker("name")
    memo = factory.Faker("sentence")
    milliunit_amount = factory.Faker("pyint", min_value=1000)
    import_id = factory.LazyAttribute(
        lambda o: ImportIdGenerator().generate(o.date, o.milliunit_amount)
    )  # note: if two transactions are created on the same date they will have incorrect import ids

class TestTransactionsDifference(unittest.TestCase):
    no_difference = ([], [])

    def test_amount_equal_various_date_offsets(self):
        a = TransactionFactory()

        def b(offset):
            return TransactionFactory(
                date=a.date + timedelta(days=offset),
                milliunit_amount=a.milliunit_amount,
            )

        # if the offset is less than two days there is no difference
        self.assert_diff([a], [b(-1)], expected=self.no_difference)
        self.assert_diff([a], [b(+2)], expected=self.no_difference)

        # if the offset is greater than MAX_COMPARE_DAYS days then the two lists have
        # nothing in common
        b_ = b(-MAX_COMPARE_DAYS - 1)
        self.assert_diff([a], [b_], expected=([a], [b_]))

    def test_duplicates_respected(self):
        t = TransactionFactory()
        self.assert_diff([t, t], [t, t, t], expected=([], [t]))

    def test_empty_lists(self):
        self.assert_diff([], [], expected=self.no_difference)

    def test_best_match_on_memo(self):
        t = TransactionFactory(memo="This is a sentence", milliunit_amount=1000)
        t_different = TransactionFactory(
            memo="Something completely different", milliunit_amount=1000, date=t.date,
        )
        t_similar = TransactionFactory(
            memo="This is almost a sentence", milliunit_amount=1000, date=t.date,
        )

        expected = ([], [t_different])
        with self.subTest(msg="Different first"):
            self.assert_diff([t], [t_different, t_similar], expected)

        with self.subTest(msg="Similar first"):
            self.assert_diff([t], [t_similar, t_different], expected)

    def assert_diff(self, transactions_a, transactions_b, expected):
        diff = transactions_difference(transactions_a, transactions_b)
        self.assertEqual(diff, expected)

class TestPrettyFormatTransactions(unittest.TestCase):
    def test(self):
        transactions = [
            Transaction(
                date=date(2017, 5, 2),
                payee_name="Mr Tibbles",
                memo="Goes to market",
                milliunit_amount=123456789,
                import_id="foo",
            ),
            Transaction(
                date=date(2011, 1, 1),
                payee_name="This is a really very long payee name",
                memo="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed d",
                milliunit_amount=-962,
                import_id="bar",
            ),
            Transaction(
                date=date(2012, 1, 1),
                payee_name=None,
                memo=None,
                milliunit_amount=-962,
                import_id="bar",
            ),
        ]
        string = pretty_format_transactions(transactions)
        print(string)
        self.assertEqual(
            string.split("\n"),
            [
                "Date       Payee                Memo                                         Amount",
                "2017-05-02 Mr Tibbles           Goes to market                            123456.79",
                "2011-01-01 This is a really...  Lorem ipsum dolor sit amet,...                -0.96",
                "2012-01-01                                                                    -0.96",
            ],
        )


#!/usr/bin/env python
# coding: utf-8

# # Word + Hint JSON Creation

# In[ ]:

import json

wordlist = [
    {
        'word':'MISSISSIPPI',
        'hint':'Known for the river'
    },
    {
        'word':'RUSTLE',
        'hint':'Done with cattle and newspapers'
    },
    {
        'word':'WIZARDRY',
        'hint':'The arcane arts'
    },
    {
        'word':'TORNADOES',
        'hint':'Enemy of Dorothy'
    },
    {
        'word':'FRACTURE',
        'hint':'A break'
    },
    {
        'word':'INTERPRETED',
        'hint':'Not compiled'
    }
]

with open("words.json", "w") as outfile:
    json.dump(wordlist, outfile)

# # Functions

# In[ ]:

def ask_buy_vowel(): #Verifies response
    r = input("\nWould you like to buy a vowel for $250? Y/N ")
    while r not in ["Y", "y", "N", "n"]:
        r = input("Please select Y or N. ")
    return r

def ask_consonant(): #Ensures that the guess is non-numeric and either a consonant or a word
    g = input("Guess a consonant, or guess the word! ").upper()
    while g.isalpha() is False: #Checking for alphabetical character
        g = input("Please enter a consonant or guess the word. ")
    while g in ["A", "E", "I", "O", "U"]: #Checking for consonant
        g = input("Please enter a consonant or guess the word. ")
    return g

def ask_vowel(): #Ensures that the guess is a vowel
    g = input("Guess a vowel. ").upper()
    while g not in ["A", "E", "I", "O", "U"]: #Checking for consonant
        g = input("Please enter a vowel. ").upper()
    return g

import random

def new_word():
    #Select random word & its hint
    randomness = random.randint(0, len(wordlist) - 1)

    target = wordlist[randomness]["word"]
    hint = wordlist[randomness]["hint"]

    return [target, hint]

def new_board():
    #Build the word's "board"
    blank = []

    for ltr in target:
        blank.append('_')

    return blank

# # Game

# In[ ]:

#Import JSON word file
file = open('words.json')
words = file.read()
wordlist = json.loads(words)

#Create the wheel
wheel = list(range(100, 1000, 50))
wheel.append(1500)
wheel.append(2000)
wheel.append(3000)
wheel.append("BANKRUPT")
wheel.append("LOSE A TURN")
wheel.append("MYSTERY")

#Game controls
landed_on = 0
activeplayer = 0
currentround = 1 #Change to 3 to test final round

wallet = [0, 0, 0]

guess = ''
finalguesses = ['', '', '', '', '']
finalreveal = ["R", "S", "T", "L", "N", "E"]

buyavowel = False

response = ''

gameover = False

### Game Begins ###
print("Welcome to...\nWheel! Of! Fortune!")

while gameover is False:
    temp = new_word()
    target = temp[0]
    hint = temp[1]
    blank = new_board()
    while currentround != 3:
        print("\n===================================")
        print(f"Round {currentround}")
        print(f"Player {activeplayer + 1}'s turn")
        print(f"Player {activeplayer + 1}'s total winnings: ${wallet[activeplayer]}\n")
        print(f"Hint: {hint}")
        print(' '.join(blank))
        print("\nSpinning the wheel...")
        landedon = random.choice(wheel)

        #Check if player landed on BANKRUPT / LOSE A TURN / MYSTERY
        if landedon == "BANKRUPT" or landedon == "LOSE A TURN" or landedon == "MYSTERY":
            print(f"You landed on {landedon}!")
            if landedon == "MYSTERY":
                landedon = random.choice(["BANKRUPT", 1000])
            if landedon == "BANKRUPT": #Player landed on BANKRUPT
                wallet[activeplayer] = 0
                print("Oh no! Your total winnings have returned to zero, and your turn is over.")
                if activeplayer == 2:
                    print("On to the next round...")
                    currentround += 1
                    activeplayer = 0
                else:
                    activeplayer += 1
            elif landedon == "LOSE A TURN":
                print("Oh no! Your turn is over.")
                if activeplayer == 2:
                    print("On to the next round...")
                    currentround += 1
                    activeplayer = 0
                else:
                    activeplayer += 1
            else: #Player won $1000 from MYSTERY
                print("You win an extra $1000!")
                wallet[activeplayer] += 1000

        else: #Player landed on a cash value
            print(f"You landed on ${landedon}!\n")
            guess = ask_consonant()
            if len(guess) == 1:
                if guess in target:
                    for index, ltr in enumerate(target):
                        if ltr == guess:
                            blank[index] = guess
                    print(f"Good guess! You added ${landedon} to your total winnings!\n")
                    wallet[activeplayer] += landedon

                    print(f"{' '.join(blank)}\n")

                    buyavowel = True

                    while buyavowel is True:
                        response = ask_buy_vowel()
                        if response in ["Y", "y"]:
                            guess = ask_vowel()
                            if guess in target:
                                for index, ltr in enumerate(target):
                                    if ltr == guess:
                                        blank[index] = guess
                                print("\nGood guess!\n")
                                print(f"Hint: {hint}")
                                print(' '.join(blank))
                                print(f'Cash remaining: {wallet[activeplayer]}')
                            else:
                                print(f"Sorry, no {guess}!")
                        else: #Response is N/n
                            buyavowel = False
                else:
                    print(f"Sorry, no {guess}!")
                    if activeplayer == 2:
                        print("Too bad! On to the next round.")
                        currentround += 1
                        activeplayer = 0
                    else:
                        print(f"Pass the keyboard to player {activeplayer + 2}!")
                        activeplayer += 1
            else:
                if guess == target:
                    print(f"\nThe word was {target}!")
                    print(f"Good guess! You added ${landedon} to your total winnings!\n")
                    wallet[activeplayer] += landedon
                    if activeplayer == 2:
                        print("On to the next round!")
                        currentround += 1
                        activeplayer = 0
                    else:
                        print(f"Pass the keyboard to Player {activeplayer + 2}")
                        activeplayer += 1
                    temp = new_word()
                    target = temp[0]
                    hint = temp[1]
                    blank = new_board()
                else: #Guessed the word incorrectly
                    print("\nSorry, that wasn't the word!")
                    if activeplayer == 2:
                        print("On to the next round!")
                        currentround += 1
                        activeplayer = 0
                    else:
                        print(f"Pass the keyboard to Player {activeplayer + 2}")
                        activeplayer += 1
    else:
        if wallet[0] == wallet[1]:
            if wallet[1] == wallet[2]:
                activeplayer = random.randint(0, 2) #If all players have the same winnings, pick at random
        else:
            activeplayer = wallet.index(max(wallet))
        print("\n===================================")
        print(f"Welcome to the final round, Player {activeplayer + 1}!")
        print("If you win this bonus round, you'll win an additional $50,000 on top of your current winnings.\n")

        for index, ltr in enumerate(target):
            if ltr in finalreveal:
                blank[index] = target[index]
        print(" ".join(blank))
        print()
        print("Guess four consonants and one vowel.")

        for i in range(len(finalguesses) - 1):
            finalguesses[i] = input(f"Consonant {i + 1}: ").upper()
            while finalguesses[i].isalpha() is False: #Checking for alphabetical character
                finalguesses[i] = input("Please enter a consonant. ").upper()
            while finalguesses[i] in ["A", "E", "I", "O", "U"]:
                finalguesses[i] = input("Please enter a consonant. ").upper()

        finalguesses[4] = input("Vowel: ").upper()

        while finalguesses[4].isalpha() is False: #Checking for alphabetical character
            finalguesses[4] = input("Please enter a vowel. ").upper()
        while finalguesses[4] not in ["A", "E", "I", "O", "U"]:
            finalguesses[4] = input("Please enter a vowel. ").upper()

        for item in finalguesses:
            for index, ltr in enumerate(target):
                if ltr == item:
                    blank[index] = item

        print()
        print(" ".join(blank))

        validguess = False

        guess = input("You've got one shot to guess the word for $50,000! ").upper()

        while guess.isalpha() is False:
            guess = input("Please enter alphabetical text only! ").upper()

        while validguess is False:
            if len(guess) == 1: #Checking for full word
                guess = input("Please enter a word! ").upper()
            else:
                validguess = True

        if guess == target:
            print("Congratulations! You win!")
            wallet[activeplayer] += 50000
            print(f"Your total winnings are: ${wallet[activeplayer]}")
            print("\nSee you next time on...\nWheel! Of! Fortune!")
            gameover = True
            break
        else: #Guess was incorrect
            print("Sorry, but that's not the right word!")
            print(f"The word was: {target}")
            print(f"You're still taking home ${wallet[activeplayer]}!")
            print("\nSee you next time on...\nWheel! Of! Fortune!")
            gameover = True
            break


# 54. Spiral Matrix
class Solution:
    def spiralOrder(self, matrix):
        if not matrix: return matrix
        m, n = len(matrix), len(matrix[0])
        visited = [[False] * n for _ in range(m)]
        ans = []

        dirs = ((0,1), (1,0), (0,-1), (-1,0))
        cur = 0

        i = j = 0
        while len(ans) < m * n:
            if not visited[i][j]:
                ans.append(matrix[i][j])
                visited[i][j] = True

            di, dj = dirs[cur]
            ii, jj = i+di, j+dj
            if ii<0 or ii>=m or jj<0 or jj>=n or visited[ii][jj]:
                cur = (cur+1) % 4

            di, dj = dirs[cur]
            i, j = i+di, j+dj

        return ans


#!/usr/bin/env python3

import xml.etree.ElementTree as ET
import os, sys, json

def getRelativePathToKeilProject(projectPath, keilProjectPath, path):
    return os.path.relpath(os.path.join(projectPath, "./" + keilProjectPath + "/" + path), projectPath)

def generateTasksConfig(path, cmd):
    # 创建json字典
    outputJSON = {
        "tasks": [
            {
                "label": "build",
                "type": "shell",
                "command": cmd,
                "problemMatcher": {
                    "owner": "armcc",
                    "pattern":[
                        {
                            "regexp": "^\"\\.(.*)\", line (\\d+): (Error|Warning|Info):  (.*): (.+)",
                            "file": 1,
                            "line": 2,
                            "severity": 3,
                            "code": 4,
                            "message": 5
                        }
                    ]
                }
            }
        ],
        "version": "2.0.0"
    }
    with open(os.path.join(path, "./.vscode/tasks.json"), 'w') as file:
        json.dump(outputJSON, file, indent=4)

def generateBuildConfig(path, targetName, systemName, vmName, windowsPath):
    # 绝对路径keil配置文件路径
    keilConfigPath = ""
    # 相对path而言的keil项目配置文件
    keilProjectPath = ""
    # 搜索Keil配置文件
    for root, dirs, files in os.walk(path):
        for fileName in files:
            if os.path.splitext(fileName)[-1] == ".uvprojx":
                keilProjectPath = os.path.relpath(root, path)
                keilConfigPath = os.path.join(root, fileName)
    if keilConfigPath == "" or keilProjectPath == "":
        print("Failed to find keil config!")
        return
    root = ET.parse(keilConfigPath)
    # 寻找指定的target
    targets = root.findall("./Targets/Target")
    targetElement = None
    for target in targets:
        if targetName == "" or target.find("./TargetName").text == targetName:
            targetElement = target
            break
    if targetElement == None:
        if targetName != "":
            print("Target:", targetName, "not found!")
        else:
            print("No target found!")
        return
    targetName = targetElement.find("./TargetName").text
    # 创建.vscode文件夹
    try:
        os.mkdir(os.path.join(path, "./.vscode"))
    except FileExistsError:
        pass
    if systemName == "mac":
        windowsPath = windowsPath.replace("/", "\\")
        windowsPath = windowsPath.replace("\\","\\\\")
        cmd = "prlctl exec \"{}\" pd_keil_compile_tool.bat \"{}\"".format(vmName, windowsPath)
    else:
        batFileName = targetName.upper() + ".BAT"
        cmd = os.path.join("./", keilProjectPath, batFileName)
    print("Command:", cmd)
    generateTasksConfig(path, cmd)

def printUsage():
    print("Usage: python3 ./generate_build_config.py [YOUR_KEIL_CODE_PATH] [TARGET_NAME] [--mac | --windows] [VM_NAME] [WINDOWS_PROJECT_PATH]")

if __name__ == '__main__':
    if len(sys.argv) < 5:
        printUsage()
        exit(1)
    path = sys.argv[1]
    targetName = sys.argv[2]
    systemName = sys.argv[3][2:]
    vmName = sys.argv[4] if len(sys.argv) > 4 else ""
    windowsPath = sys.argv[5] if len(sys.argv) > 5 else ""
    if not os.path.exists(path):
        print(path, "not found! ")
        exit(1)
    if systemName != "mac" and systemName != "windows":
        printUsage()
        exit(1)
    if systemName == "mac" and (windowsPath == "" or vmName == ""):
        printUsage()
        exit(1)
    generateBuildConfig(path, targetName, systemName, vmName, windowsPath)


from gmrescrs import Gmres
from crsmatrix import Matrix
import numpy

max_matrix_size = 1000
max_iterations = 500
max_restart = 500

A = Matrix.tridiagonal(max_matrix_size)
b = numpy.ones((A.m, 1))

x, error, metadata = Gmres(A, b, max_iterations=max_iterations, restart_after=max_restart).solve()
error_time_values = []
delta = metadata[1]
dur = metadata[2][1:] # discard the first to match siz of deltas
for i in range(0, metadata[0]-1):
    et = delta[i] / dur[i]
    error_time_values.append(et)

handle = open('generated_data.csv', 'a')
handle.write('matrix_size,iteration_norm,error_delta_normed,duration,error_time\n')
for i in range(0, metadata[0]-1):
    iteration_norm = float(i + 1) / max_matrix_size
    items = [max_matrix_size, iteration_norm, delta[i], dur[i], error_time_values[i]]
    line = ','.join([str(s) for s in items]) + '\n'
    handle.write(line)


from __future__ import annotations

from typing import TYPE_CHECKING, Any

import pandas as pd

from great_expectations.compatibility.sqlalchemy import sqlalchemy as sa
from great_expectations.compatibility.sqlalchemy_and_pandas import (
    pandas_read_sql,
)
from great_expectations.core.metric_domain_types import MetricDomainTypes
from great_expectations.execution_engine import (
    PandasExecutionEngine,
    SparkDFExecutionEngine,
    SqlAlchemyExecutionEngine,
)
from great_expectations.expectations.metrics.metric_provider import metric_value
from great_expectations.expectations.metrics.table_metric_provider import (
    TableMetricProvider,
)
from great_expectations.validator.metric_configuration import MetricConfiguration
from great_expectations.validator.validator import Validator

if TYPE_CHECKING:
    from great_expectations.compatibility import pyspark

class TableHead(TableMetricProvider):
    metric_name = "table.head"
    value_keys = ("n_rows", "fetch_all")
    default_kwarg_values = {"n_rows": 5, "fetch_all": False}

    @metric_value(engine=PandasExecutionEngine)
    def _pandas(  # noqa: PLR0913
        cls,
        execution_engine: PandasExecutionEngine,
        metric_domain_kwargs: dict,
        metric_value_kwargs: dict,
        metrics: dict[str, Any],
        runtime_configuration: dict,
    ) -> pd.DataFrame:
        df, _, _ = execution_engine.get_compute_domain(
            metric_domain_kwargs, domain_type=MetricDomainTypes.TABLE
        )
        if metric_value_kwargs.get("fetch_all", cls.default_kwarg_values["fetch_all"]):
            return df
        n_rows: int = (
            metric_value_kwargs.get("n_rows")
            if metric_value_kwargs.get("n_rows") is not None
            else cls.default_kwarg_values["n_rows"]
        )
        return df.head(n=n_rows)

    @metric_value(engine=SqlAlchemyExecutionEngine)
    def _sqlalchemy(  # noqa: PLR0913
        cls,
        execution_engine: SqlAlchemyExecutionEngine,
        metric_domain_kwargs: dict,
        metric_value_kwargs: dict,
        metrics: dict[str, Any],
        runtime_configuration: dict,
    ) -> pd.DataFrame:
        selectable, _, _ = execution_engine.get_compute_domain(
            metric_domain_kwargs, domain_type=MetricDomainTypes.TABLE
        )

        n_rows: int = (
            metric_value_kwargs.get("n_rows")
            if metric_value_kwargs.get("n_rows") is not None
            else cls.default_kwarg_values["n_rows"]
        )

        # None means no limit
        limit: int | None = n_rows
        if metric_value_kwargs["fetch_all"]:
            limit = None

        selectable = sa.select("*").select_from(selectable).limit(limit).selectable

        try:
            with execution_engine.get_connection() as con:
                df = pandas_read_sql(
                    sql=selectable,
                    con=con,
                )
        except StopIteration:
            # empty table. At least try to get the column names
            validator = Validator(execution_engine=execution_engine)
            columns = validator.get_metric(
                MetricConfiguration("table.columns", metric_domain_kwargs)
            )
            df = pd.DataFrame(columns=columns)
        return df  # type: ignore[return-value]

    @metric_value(engine=SparkDFExecutionEngine)
    def _spark(  # noqa: PLR0913
        cls,
        execution_engine: SparkDFExecutionEngine,
        metric_domain_kwargs: dict,
        metric_value_kwargs: dict,
        metrics: dict[str, Any],
        runtime_configuration: dict,
    ) -> pd.DataFrame:
        df, _, _ = execution_engine.get_compute_domain(
            metric_domain_kwargs, domain_type=MetricDomainTypes.TABLE
        )
        rows: list[pyspark.Row] | list[dict]
        if metric_value_kwargs["fetch_all"]:
            rows = df.collect()
        else:
            n_rows: int = (
                metric_value_kwargs.get("n_rows")
                if metric_value_kwargs.get("n_rows") is not None
                else cls.default_kwarg_values["n_rows"]
            )
            if n_rows >= 0:
                rows = df.head(n=n_rows)
            else:
                rows = df.head(n=df.count() + n_rows)

        rows = [element.asDict() for element in rows]
        df = pd.DataFrame(data=rows)  # type: ignore[assignment]

        return df  # type: ignore[return-value]