def initialize(app_name = nil, opaque = 0)
        @PROG_NAME = self.class.name
        @LOGGER = Juno::Logger.instance
        app_name = JUNO_INTERNAL_APPNAME if app_name.to_s.empty?

        meta_data_component = Juno::IO::MetadataComponent.new
        meta_data_component.set_request_uuid
        meta_data_component.set_source_info(app_name: app_name, ip: IPAddr.new(Juno::Utils.local_ips[0]), port: 0)

        protocol_header = Juno::IO::ProtocolHeader.new
        protocol_header.opcode = Juno::IO::ProtocolHeader::OpCodes::Nop
        protocol_header.opaque = opaque

        @operation_message = Juno::IO::OperationMessage.new
        @operation_message.metadata_component = meta_data_component
        @operation_message.protocol_header = protocol_header
      end

# @param operation_message [Juno::IO::OperationMessage] (optional, default: Juno::Net::PingMessage::JUNO_INTERNAL_APPNAME)
# @param opaque [Integer] (optional, default: 0)


def sync_today_stars(info, latest_stars)
  today = Time.now.strftime('%Y-%m-%d')
  if info.nil? || !info.include?('_')
    [today, latest_stars, 0]
  else
    date, total_stars, change_stars = info.split('_')
    if date != today
      change_stars = 0
    end
    if latest_stars.to_i == 0
      [today, total_stars, change_stars]
    else
      change_stars = change_stars.to_i + (latest_stars.to_i - total_stars.to_i)
      [today, latest_stars, change_stars]
    end
  end
end


def list_encoding_names
      SUPPORTED_ENCODINGS
    end

# Lists all the encodings that are supported


def list_model_names
      MODEL_TO_ENCODING_NAME.keys
    end

# Lists all the models that are supported


def without_extended_rule_configs(rules)
        rules.reject { |(name, _)|
          ["Style/InvertibleUnlessCondition", "Lint/SafeNavigationChain"].include?(name)
        }.to_h
      end


def without_warnings(&blk)
        original_verbose = $VERBOSE
        $VERBOSE = nil
        yield
      ensure
        $VERBOSE = original_verbose
      end

# This is also not fantastic, but because loading RuboCop before loading


def attributes
      record.attributes
    end

# @return [Hash] the record's attributes


def loaded_nested_attribute_names
      nested_attribute_names & loaded_has_many_associations_by_name.keys
    end

# Attribute names that the record `accepts_nested_attributes_for` that have been loaded into memory


def parent_attribute_names
      record.class.reflections.each_with_object([]) do |(name, reflection), memo|
        memo << reflection.foreign_key if reflection.macro == :belongs_to
      end
    end

# Attribute names for all the record's `belongs_to` associations


def transform(format: :json, **options)
      case format
      # when :json then extract(**options).to_json
      when :json then Oj.dump extract(**options), symbol_keys: false
      else raise NotImplementedError
      end
    end

# @raise [NotImplementedError] if the specified format is not supported


def test_to_h
      m = TestMessage.new(:optional_bool => true, :optional_double => -10.100001, :optional_string => 'foo', :repeated_string => ['bar1', 'bar2'], :repeated_msg => [TestMessage2.new(:foo => 100)])
      expected_result = {
        :optional_bool=>true,
        :optional_bytes=>"",
        :optional_double=>-10.100001,
        :optional_enum=>:Default,
        :optional_float=>0.0,
        :optional_int32=>0,
        :optional_int64=>0,
        :optional_msg=>nil,
        :optional_string=>"foo",
        :optional_uint32=>0,
        :optional_uint64=>0,
        :repeated_bool=>[],
        :repeated_bytes=>[],
        :repeated_double=>[],
        :repeated_enum=>[],
        :repeated_float=>[],
        :repeated_int32=>[],
        :repeated_int64=>[],
        :repeated_msg=>[{:foo => 100}],
        :repeated_string=>["bar1", "bar2"],
        :repeated_uint32=>[],
        :repeated_uint64=>[]
      }
      assert_equal expected_result, m.to_h

      m = MapMessage.new(
        :map_string_int32 => {"a" => 1, "b" => 2},
        :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
                            "b" => TestMessage2.new(:foo => 2)},
        :map_string_enum => {"a" => :A, "b" => :B})
      expected_result = {
        :map_string_int32 => {"a" => 1, "b" => 2},
        :map_string_msg => {"a" => {:foo => 1}, "b" => {:foo => 2}},
        :map_string_enum => {"a" => :A, "b" => :B}
      }
      assert_equal expected_result, m.to_h
    end


def initialize(
      llm:,
      tools: [],
      instructions: nil,
      tool_choice: "auto",
      parallel_tool_calls: true,
      messages: [],
      # Callbacks
      add_message_callback: nil,
      tool_execution_callback: nil,
      &block
    )
      unless tools.is_a?(Array) && tools.all? { |tool| tool.class.singleton_class.included_modules.include?(Langchain::ToolDefinition) }
        raise ArgumentError, "Tools must be an array of objects extending Langchain::ToolDefinition"
      end

      @llm = llm
      @llm_adapter = LLM::Adapter.build(llm)

      @add_message_callback = add_message_callback if validate_callback!("add_message_callback", add_message_callback)
      @tool_execution_callback = tool_execution_callback if validate_callback!("tool_execution_callback", tool_execution_callback)

      self.messages = messages
      @tools = tools
      @parallel_tool_calls = parallel_tool_calls
      self.tool_choice = tool_choice
      self.instructions = instructions
      @block = block
      @state = :ready

      @total_prompt_tokens = 0
      @total_completion_tokens = 0
      @total_tokens = 0
    end

# @param tool_execution_callback [Proc] A callback function (Proc or lambda) that is called right before a tool function is executed


def add_messages(messages:)
      messages.each do |message_hash|
        add_message(**message_hash.slice(:content, :role, :tool_calls, :tool_call_id))
      end
    end

# @return [Array<Langchain::Message>] The messages


def run!
      run(auto_tool_execution: true)
    end


def replace_system_message!(content:)
      messages.delete_if(&:system?)
      return if content.nil?

      message = build_message(role: "system", content: content)
      messages.unshift(message)
    end


def validate_tool_choice!(tool_choice)
      allowed_tool_choices = llm_adapter.allowed_tool_choices.concat(available_tool_names)
      unless allowed_tool_choices.include?(tool_choice)
        raise ArgumentError, "Tool choice must be one of: #{allowed_tool_choices.join(", ")}"
      end
    end

# TODO: If tool_choice = "tool_function_name" and then tool is removed from the assistant, should we set tool_choice back to "auto"?


def handle_system_message
      Langchain.logger.warn("#{self.class} - At least one user message is required after a system message")
      :completed
    end


def handle_unexpected_message
      Langchain.logger.error("#{self.class} - Unexpected message role encountered: #{messages.last.standard_role}")
      :failed
    end


def handle_user_or_tool_message
      response = chat_with_llm

      add_message(role: response.role, content: response.chat_completion, tool_calls: response.tool_calls)
      record_used_tokens(response.prompt_tokens, response.completion_tokens, response.total_tokens)

      set_state_for(response: response)
    end

# Handle user or tool message scenario by processing the LLM response


def run_tools(tool_calls)
      # Iterate over each function invocation and submit tool output
      tool_calls.each do |tool_call|
        run_tool(tool_call)
      end
    end

# @param tool_calls [Array<Hash>] The tool calls to run


def build(&block)
      instance_eval(&block)
      @schema
    end


def validate_parameters(name:, type:, enum:, required:)
      if @parent_type == "object"
        if name.nil?
          raise ArgumentError, "Name must be provided for properties of an object"
        end
        unless name.is_a?(Symbol)
          raise ArgumentError, "Invalid name '#{name}'. Name must be a symbol"
        end
      end

      unless VALID_TYPES.include?(type)
        raise ArgumentError, "Invalid type '#{type}'. Valid types are: #{VALID_TYPES.join(", ")}"
      end

      unless enum.nil? || enum.is_a?(Array)
        raise ArgumentError, "Invalid enum '#{enum}'. Enum must be nil or an array"
      end

      unless [true, false].include?(required)
        raise ArgumentError, "Invalid required '#{required}'. Required must be a boolean"
      end
    end

# @raise [ArgumentError] If any parameter is invalid


def initialize(content: nil, image_url: nil)
      raise ArgumentError, "Either content or image_url must be provided" if content.nil? && image_url.nil?

      @content = content
      @image_url = image_url
    end

# @param image_url [String, nil] Optional URL to an image.


def tool_role
            raise NotImplementedError, "Subclasses must implement tool_role"
          end

# Role name used to return the tool output


def build_message(role:, content: nil, image_url: nil, tool_calls: [], tool_call_id: nil)
            Messages::MistralAIMessage.new(role: role, content: content, image_url: image_url, tool_calls: tool_calls, tool_call_id: tool_call_id)
          end

# @return [Messages::MistralAIMessage] The Mistral AI message


def extract_tool_call_args(tool_call:)
            tool_call_id = tool_call.dig("id")

            function_name = tool_call.dig("function", "name")
            tool_name, method_name = function_name.split("__")

            tool_arguments = tool_call.dig("function", "arguments")
            tool_arguments = if tool_arguments.is_a?(Hash)
              Langchain::Utils::HashTransformer.symbolize_keys(tool_arguments)
            else
              JSON.parse(tool_arguments, symbolize_names: true)
            end

            [tool_call_id, tool_name, method_name, tool_arguments]
          end

# Extract the tool call information from the OpenAI tool call hash


def available_tool_names(tools)
            build_tools(tools).map { |tool| tool.dig(:function, :name) }
          end

# Get the available tool names for Mistral AI


def build_message(role:, content: nil, image_url: nil, tool_calls: [], tool_call_id: nil)
            Messages::OllamaMessage.new(role: role, content: content, image_url: image_url, tool_calls: tool_calls, tool_call_id: tool_call_id)
          end

# @return [Messages::OllamaMessage] The Ollama message


def initialize(
          role:,
          content: nil,
          image_url: nil,
          tool_calls: [],
          tool_call_id: nil
        )
          raise ArgumentError, "Role must be one of #{ROLES.join(", ")}" unless ROLES.include?(role)
          raise ArgumentError, "Tool calls must be an array of hashes" unless tool_calls.is_a?(Array) && tool_calls.all? { |tool_call| tool_call.is_a?(Hash) }

          @role = role
          # Some Tools return content as a JSON hence `.to_s`
          @content = content.to_s
          @image_url = image_url
          @tool_calls = tool_calls
          @tool_call_id = tool_call_id
        end

# @param tool_call_id [String] The ID of the tool call


def assistant_hash
          {
            role: "assistant",
            content: content,
            tool_calls: tool_calls,
            prefix: false
          }
        end

# @return [Hash] The message as an MistralAI API-compatible hash, with the role as "assistant"


def build_content_array
          content_details = []

          if content && !content.empty?
            content_details << {
              type: "text",
              text: content
            }
          end

          if image_url
            content_details << {
              type: "image_url",
              image_url: image_url
            }
          end

          content_details
        end

# @return [Array<Hash>] An array of content hashes, with keys :type and :text or :image_url.


def system?
          role == "system"
        end

# @return [Boolean] true/false whether this message are system instructions


def tool?
          role == "tool"
        end

# @return [Boolean] true/false whether this message is a tool call


def chunks
        splitter = Baran::MarkdownSplitter.new(
          chunk_size: chunk_size,
          chunk_overlap: chunk_overlap
        )

        splitter.chunks(text).map do |chunk|
          Langchain::Chunk.new(text: chunk[:text])
        end
      end


def chunks
        splitter = Baran::RecursiveCharacterTextSplitter.new(
          chunk_size: chunk_size,
          chunk_overlap: chunk_overlap,
          separators: separators
        )

        splitter.chunks(text).map do |chunk|
          Langchain::Chunk.new(text: chunk[:text])
        end
      end


def initialize(llm:, batch_size: 3)
          @llm = llm
          @batch_size = batch_size
        end

# @param batch_size [Integer] Batch size, i.e., number of generated questions to compare to the original question


def answer_relevance
          @answer_relevance ||= Langchain::Evals::Ragas::AnswerRelevance.new(llm: llm)
        end

# @return [Langchain::Evals::Ragas::AnswerRelevance] Class instance


def chat(...)
      raise NotImplementedError, "#{self.class.name} does not support chat"
    end

# @raise NotImplementedError if not supported by the LLM


def chat_parameters(params = {})
      @chat_parameters ||= Langchain::LLM::Parameters::Chat.new(
        parameters: params
      )
    end


def summarize(text:)
      response = client.summarize(text: text)
      response.dig("summary")
    end

# Generate a summary in English for a given text


def initialize(url: "http://localhost:11434", api_key: nil, default_options: {})
      depends_on "faraday"
      @url = url
      @api_key = api_key
      @defaults = DEFAULTS.merge(default_options)
      chat_parameters.update(
        model: {default: @defaults[:chat_model]},
        temperature: {default: @defaults[:temperature]},
        template: {},
        stream: {default: false},
        response_format: {default: @defaults[:response_format]},
        options: {default: @defaults[:options]}
      )
      chat_parameters.remap(response_format: :format)
    end


def complete(
      prompt:,
      model: defaults[:completion_model],
      images: nil,
      format: nil,
      system: nil,
      template: nil,
      context: nil,
      raw: nil,
      mirostat: nil,
      mirostat_eta: nil,
      mirostat_tau: nil,
      num_ctx: nil,
      num_gqa: nil,
      num_gpu: nil,
      num_thread: nil,
      repeat_last_n: nil,
      repeat_penalty: nil,
      temperature: defaults[:temperature],
      seed: nil,
      stop: nil,
      tfs_z: nil,
      num_predict: nil,
      top_k: nil,
      top_p: nil,
      stop_sequences: nil,
      &block
    )
      if stop_sequences
        stop = stop_sequences
      end

      parameters = {
        prompt: prompt,
        model: model,
        images: images,
        format: format,
        system: system,
        template: template,
        context: context,
        stream: block_given?, # rubocop:disable Performance/BlockGivenWithExplicitBlock
        raw: raw
      }.compact

      llm_parameters = {
        mirostat: mirostat,
        mirostat_eta: mirostat_eta,
        mirostat_tau: mirostat_tau,
        num_ctx: num_ctx,
        num_gqa: num_gqa,
        num_gpu: num_gpu,
        num_thread: num_thread,
        repeat_last_n: repeat_last_n,
        repeat_penalty: repeat_penalty,
        temperature: temperature,
        seed: seed,
        stop: stop,
        tfs_z: tfs_z,
        num_predict: num_predict,
        top_k: top_k,
        top_p: top_p
      }

      parameters[:options] = llm_parameters.compact
      responses_stream = []

      client.post("api/generate", parameters) do |req|
        req.options.on_data = json_responses_chunk_handler do |parsed_chunk|
          responses_stream << parsed_chunk

          block&.call(OllamaResponse.new(parsed_chunk, model: parameters[:model]))
        end
      end

      generate_final_completion_response(responses_stream, parameters[:model])
    end


def chat_completion
        raise NotImplementedError
      end


def get_format_instructions
      parser.get_format_instructions
    end

# calls get_format_instructions on the @parser


def initialize(schema:)
      @schema = validate_schema!(schema)
    end

# @param schema [JSON::Schema] The json schema


def clean_content(content)
        content
          .gsub(/\[cid:[^\]]+\]/, "") # Remove embedded image references
          .gsub(URI::DEFAULT_PARSER.make_regexp(%w[http https])) { |match| "<#{match}>" } # Format URLs
          .gsub(/\r\n?/, "\n") # Normalize line endings to Unix style
          .gsub(/[\u200B-\u200D\uFEFF]/, "") # Remove zero width spaces and similar characters
          .gsub(/<\/?[^>]+>/, "") # Remove any HTML tags that might have sneaked in
      end

# Clean and format the extracted content


def parse(data)
        data.read
      end

# Parse the document and return the text


def initialize(template:, input_variables:, validate_template: true)
      @template = template
      @input_variables = input_variables
      @validate_template = validate_template

      validate(template: @template, input_variables: @input_variables) if @validate_template
    end


def describe_table(table)
      # TODO: There's probably a clear way to do all of this below

      primary_key_columns = []
      primary_key_column_count = db.schema(table).count { |column| column[1][:primary_key] == true }

      schema = "CREATE TABLE #{table}(\n"
      db.schema(table).each do |column|
        schema << "#{column[0]} #{column[1][:type]}"
        if column[1][:primary_key] == true
          schema << " PRIMARY KEY" if primary_key_column_count == 1
        else
          primary_key_columns << column[0]
        end
        schema << " COMMENT '#{column[1][:comment]}'" if column[1][:comment]
        schema << ",\n" unless column == db.schema(table).last && primary_key_column_count == 1
      end
      if primary_key_column_count > 1
        schema << "PRIMARY KEY (#{primary_key_columns.join(",")})"
      end
      db.foreign_key_list(table).each do |fk|
        schema << ",\n" if fk == db.foreign_key_list(table).first
        schema << "FOREIGN KEY (#{fk[:columns]&.first}) REFERENCES #{fk[:table]}(#{fk[:key]&.first})"
        schema << ",\n" unless fk == db.foreign_key_list(table).last
      end
      schema << ");\n"

      tool_response(content: schema)
    end

# @return [Langchain::Tool::Response] The schema for the table


def search(
      query:,
      search_depth: "basic",
      include_images: false,
      include_answer: false,
      include_raw_content: false,
      max_results: 5,
      include_domains: [],
      exclude_domains: []
    )
      uri = URI("https://api.tavily.com/search")
      request = Net::HTTP::Post.new(uri)
      request.content_type = "application/json"
      request.body = {
        api_key: @api_key,
        query: query,
        search_depth: search_depth,
        include_images: include_images,
        include_answer: include_answer,
        include_raw_content: include_raw_content,
        max_results: max_results,
        include_domains: include_domains,
        exclude_domains: exclude_domains
      }.to_json

      response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
        http.request(request)
      end
      tool_response(content: response.body)
    end

# @return [Langchain::Tool::Response] The search results in JSON format.


def calculate_similarity
        return nil unless vector_a.is_a? Array
        return nil unless vector_b.is_a? Array
        return nil if vector_a.size != vector_b.size

        dot_product = 0
        vector_a.zip(vector_b).each do |v1i, v2i|
          dot_product += v1i * v2i
        end

        a = vector_a.map { |n| n**2 }.reduce(:+)
        b = vector_b.map { |n| n**2 }.reduce(:+)

        dot_product / (Math.sqrt(a) * Math.sqrt(b))
      end

# @return [Float] The cosine similarity between the two vectors


def update_texts(...)
      raise NotImplementedError, "#{self.class.name} does not support updating texts"
    end

# Method supported by Vectorsearch DB to update a list of texts to the index


def similarity_search_by_vector(...)
      raise NotImplementedError, "#{self.class.name} does not support similarity search by vector"
    end

# You must generate your own vector using the same LLM that generated the embeddings stored in the Vectorsearch DB.


def ask(...)
      raise NotImplementedError, "#{self.class.name} does not support asking questions"
    end

# Method supported by Vectorsearch DB to answer a question given a context (data) pulled from your Vectorsearch DB.


def similarity_search(
      query:,
      k: 4
    )
      embedding = llm.embed(text: query).embedding

      similarity_search_by_vector(
        embedding: embedding,
        k: k
      )
    end

# @return [Chroma::Resources::Embedding] The response from the server


def ask(question:, k: 4, &block)
      search_results = similarity_search(query: question, k: k)

      context = search_results.map do |result|
        result.document
      end

      context = context.join("\n---\n")

      prompt = generate_rag_prompt(question: question, context: context)

      messages = [{role: "user", content: prompt}]
      response = llm.chat(messages: messages, &block)

      response.context = context
      response
    end

# @return [String] The answer to the question


def delete_default_schema
      es_client.indices.delete(
        index: index_name
      )
    end

# @return [Elasticsearch::Response] Index deletion


def similarity_search_by_vector(embedding: [], k: 10, query: {})
      if embedding.empty? && query.empty?
        raise "Either embedding or query should pass as an argument"
      end

      query = default_query(embedding) if query.empty?

      es_client.search(body: {query: query, size: k}).body
    end

# @return [Elasticsearch::Response] The response from the server


def add_texts(texts:, ids: nil)
      validated_ids = ids
      if ids.nil?
        validated_ids = texts.map { SecureRandom.uuid }
      elsif ids.length != texts.length
        raise "The number of ids must match the number of texts"
      end

      data = texts.map.with_index do |text, idx|
        {Doc: text, Embedding: llm.embed(text: text).embedding, ID: validated_ids[idx]}
      end

      status_code, response = @client.database.insert(@table_name, data)
      raise "Failed to insert texts: #{response}" if status_code != 200
      JSON.parse(response)
    end

# @param ids [Array<String>] The unique ids to add to the index, in the same order as the texts; if nil, it will be random uuids


def get_default_schema
      client.collections.describe(collection_name: index_name)
    end

# @return [Hash] The response from the server


def remove_texts(ids:)
      @db[table_name.to_sym].where(id: ids).delete
    end

# @return [Integer] The number of texts removed from the index


def find(ids: [])
      client.points.get_all(
        collection_name: index_name,
        ids: ids,
        with_payload: true,
        with_vector: true
      )
    end


def remove_texts(ids:)
      client.points.delete(
        collection_name: index_name,
        points: ids
      )
    end


def get_default_schema
      client.collections.get(collection_name: index_name)
    end


def similarity_search_by_vector(
      embedding:,
      k: 4
    )
      response = client.points.search(
        collection_name: index_name,
        limit: k,
        vector: embedding,
        with_payload: true,
        with_vector: true
      )
      response.dig("result")
    end


def similarity_search_by_vector(embedding:, k: 4)
      near_vector = "{ vector: #{embedding} }"

      client.query.get(
        class_name: index_name,
        near_vector: near_vector,
        limit: k.to_s,
        fields: "__id content _additional { id }"
      )
    end

# Return documents similar to the vector


def ask(question:, k: 4, &block)
      search_results = similarity_search(query: question, k: k)

      context = search_results.map do |result|
        result.dig("content").to_s
      end
      context = context.join("\n---\n")

      prompt = generate_rag_prompt(question: question, context: context)

      messages = [{role: "user", content: prompt}]
      response = llm.chat(messages: messages, &block)

      response.context = context
      response
    end


const initializePlayers = () => {
      new window.YT.Player('player1', {
        events: {
          onStateChange: (event: any) => {
            if (event.data === window.YT.PlayerState.PLAYING) {
              const player2Frame = document.getElementById(
                'player2'
              ) as HTMLIFrameElement;
              player2Frame?.contentWindow?.postMessage(
                '{"event":"command","func":"pauseVideo","args":""}',
                '*'
              );
            }
          },
        },
      });

      new window.YT.Player('player2', {
        events: {
          onStateChange: (event: any) => {
            if (event.data === window.YT.PlayerState.PLAYING) {
              const player1Frame = document.getElementById(
                'player1'
              ) as HTMLIFrameElement;
              player1Frame?.contentWindow?.postMessage(
                '{"event":"command","func":"pauseVideo","args":""}',
                '*'
              );
            }
          },
        },
      });
    };


function createAssertionError(
  options: ExtendedAssertionErrorConstructorOptions,
): AssertionError {
  const error = new AssertionError(options);
  if (options.generatedMessage) {
    error.generatedMessage = true;
  }
  return error;
}

// TODO(uki00a): This function is a workaround for setting the `generatedMessage` property flexibly.


parallel() {
		return new RelateQueryWriter({
			...this.#state,
			parallel: true
		});
	}

/**
	 * Run the query in parallel
	 *
	 * @returns The query writer
	 */


function flatten(obj: any, path: any = []) {
    // Iterate over the object's keys

    if (Array.isArray(obj)) {
      flat[`${path.join('.')}`] = obj;
    } else {
      for (const key of Object.keys(obj)) {
        // If the value is an object, recurse
        if (key === 'ids' && path.length > 0) {
          flat[`${path.join('.')}`] = obj[key];
        } else if (key === 'props') {
          flat[`${path.join('.')}.${key}`] = obj[key];
        } else if (typeof obj[key] === 'object') {
          flatten(obj[key], [...path, key]);
        } else {
          flat[`${path.join('.')}`] = obj[key];
        }
      }
    }
  }

// Recursive function to flatten the object


public calculateDamage() {
		return Math.max(
			this.damage * this.damageMultiplier - this.damageReduction,
			0,
		)
	}

/** Calculates the damage for this attack */


function parseUntil(text: string, until: Array<string>): [string, string] {
	// We take characters until we get to something that is probably a parser
	let out = ''
	let i = 0

	let isEscaped = text[0] == '\\'
	let nextChar: string | undefined = text[0]

	while (true) {
		if (!isEscaped) {
			out += nextChar
		}
		i++

		if (i >= text.length) {
			break
		}
		nextChar = text.at(i)
		if (nextChar == undefined) {
			break
		}

		if (!isEscaped && until.includes(nextChar)) {
			break
		}

		isEscaped = nextChar === '\\'
	}

	if (text[text.length - 1] == '\\') {
		out += '\\'
	}

	return [out, text.slice(i)]
}

/* Parse the raw text that is part of a text mode or emoji node, handling escape sequences. */


getNodeLocation(node: t.Type) {
    return this.observer.getNodeLocation(node);
  }

/**
   * Get the nearest parent Node and its relative path of a given AST node in the State.
   */


public async initOpeParam(context: vscode.ExtensionContext): Promise<RefreshPrjConfig> {
        const os = process.platform;
        const extensionPath = hdlPath.toSlash(context.extensionPath);
        const workspacePath = this.getWorkspacePath();
        const propertyJsonPath = hdlPath.join(workspacePath, '.vscode', 'property.json');
        const propertySchemaPath = hdlPath.join(extensionPath, 'project', 'property-schema.json');
        const propertyInitPath = hdlPath.join(extensionPath, 'project', 'property-init.json');

        opeParam.setBasicInfo(os,
                              extensionPath,
                              workspacePath,
                              propertyJsonPath,
                              propertySchemaPath,
                              propertyInitPath);

        opeParam.prjInfo.initContextPath(extensionPath, workspacePath);
        const refreshPrjConfig: RefreshPrjConfig = {mkdir: true};
        if (fs.existsSync(propertyJsonPath)) {
            const rawPrjInfo = hdlFile.readJSON(propertyJsonPath) as RawPrjInfo;
            opeParam.mergePrjInfo(rawPrjInfo);
        } else {
            refreshPrjConfig.mkdir = false;
        }

        // 创建用户目录
        hdlDir.mkdir(opeParam.dideHome);
        // 同步部分文件
        const cachePPySchema = hdlPath.join(opeParam.dideHome, 'property-schema.json');
        const propertySchema = opeParam.propertySchemaPath;
        if (fs.existsSync(cachePPySchema) && checkJson(cachePPySchema)) {
            hdlFile.copyFile(cachePPySchema, propertySchema);
        }

        return refreshPrjConfig;
    }

/**
     * init opeParam
     * @param context
     */


async updateLinter(path: string) {
    }

// 下一个版本丢弃，完全由后端承担这部分功能


private async verifyKnownTicket(
    client: PoolClient,
    serializedPCD: SerializedPCD
  ): Promise<VerifyTicketResult> {
    if (!serializedPCD.type) {
      throw new Error("input was not a serialized PCD");
    }

    if (
      serializedPCD.type !== EdDSATicketPCDPackage.name &&
      serializedPCD.type !== ZKEdDSAEventTicketPCDPackage.name
    ) {
      throw new Error(
        `serialized PCD was wrong type, '${serializedPCD.type}' instead of '${EdDSATicketPCDPackage.name}' or '${ZKEdDSAEventTicketPCDPackage.name}'`
      );
    }

    let eventId: string;
    let productId: string;
    let publicKey: EdDSAPublicKey;

    if (serializedPCD.type === EdDSATicketPCDPackage.name) {
      const pcd = await EdDSATicketPCDPackage.deserialize(serializedPCD.pcd);

      if (!EdDSATicketPCDPackage.verify(pcd)) {
        return {
          success: true,
          value: { verified: false, message: "Could not verify PCD." }
        };
      }

      eventId = pcd.claim.ticket.eventId;
      productId = pcd.claim.ticket.productId;
      publicKey = pcd.proof.eddsaPCD.claim.publicKey;
    } else {
      const pcd = await ZKEdDSAEventTicketPCDPackage.deserialize(
        serializedPCD.pcd
      );

      if (!ZKEdDSAEventTicketPCDPackage.verify(pcd)) {
        return {
          success: true,
          value: { verified: false, message: "Could not verify PCD." }
        };
      }

      if (
        !(pcd.claim.partialTicket.eventId && pcd.claim.partialTicket.productId)
      ) {
        return {
          success: true,
          value: {
            verified: false,
            message: "PCD does not reveal the correct fields."
          }
        };
      }

      // Watermarks can be up to four hours old
      if (Date.now() - parseInt(pcd.claim.watermark) > ONE_HOUR_MS * 4) {
        return {
          success: true,
          value: {
            verified: false,
            message: "PCD watermark has expired."
          }
        };
      }

      eventId = pcd.claim.partialTicket.eventId;
      productId = pcd.claim.partialTicket.productId;
      publicKey = pcd.claim.signer;
    }

    const knownTicketType = await fetchKnownTicketByEventAndProductId(
      client,
      eventId,
      productId
    );

    // If we found a known ticket type, compare public keys
    if (
      knownTicketType &&
      isEqualEdDSAPublicKey(JSON.parse(knownTicketType.public_key), publicKey)
    ) {
      // We can say that the submitted ticket can be verified as belonging
      // to a known group
      return {
        success: true,
        value: {
          verified: true,
          publicKeyName: knownTicketType.known_public_key_name,
          group: knownTicketType.ticket_group,
          eventName: knownTicketType.event_name
        }
      };
    } else {
      return {
        success: true,
        value: {
          verified: false,
          message: "Not a recognized ticket"
        }
      };
    }
  }

/**
   * Verifies a ticket based on:
   * 1) verification of the PCD (that it is correctly formed, with a proof
   *    matching the claim)
   * 2) whether the ticket matches the ticket types known to us, e.g. Zuzalu
   *    or Zuconnect tickets
   *
   */


public async handlePollFeed(
    pipelineId: string,
    req: PollFeedRequest
  ): Promise<PollFeedResponseValue> {
    return traced(SERVICE_NAME, "handlePollFeed", async (span) => {
      logger(LOG_TAG, `handlePollFeed`, pipelineId, str(req));
      span?.setAttribute("feed_id", req.feedId);
      const pipelineSlot =
        await this.pipelineSubservice.ensurePipelineSlotExists(pipelineId);
      tracePipeline(pipelineSlot.definition);
      const pipeline =
        await this.pipelineSubservice.ensurePipelineStarted(pipelineId);
      const feed = ensureFeedIssuanceCapability(pipeline, req.feedId);
      const feedResponse = await feed.issue(req);
      traceFlattenedObject(span, {
        result: {
          actionCount: feedResponse.actions.length,
          pcdCount: getPcdsFromActions(feedResponse.actions).length
        }
      });
      return feedResponse;
    });
  }

/**
   * Handles incoming requests that hit a Pipeline-specific feed for PCDs
   * for every single pipeline that has this capability that this server manages.
   */


public static findCircuit(
    familyName: string,
    circuitName: string,
    circuitFamily: ProtoPODGPCCircuitDesc[] = ProtoPODGPC.CIRCUIT_FAMILY
  ): ProtoPODGPCCircuitDesc | undefined {
    if (familyName && familyName !== PROTO_POD_GPC_FAMILY_NAME) {
      return undefined;
    }
    for (const circuitDesc of circuitFamily) {
      if (circuitName && circuitDesc.name === circuitName) {
        return circuitDesc;
      }
    }
    return undefined;
  }

/**
   * Finds the description of a circuit in this family by name.
   *
   * @param familyName the circuit family name
   * @param circuitName the name of the circuit
   * @param [circuitFamily=ProtoPODGPC.CIRCUIT_FAMILY] the circuit family to
   *   search
   * @returns the circuit description, or undefined if the name is
   *   unrecognized.
   */


function replacer(key: unknown, value: unknown): unknown {
  if (key === "message" && value instanceof Array) {
    return value.map((num: bigint) => num.toString(16));
  } else {
    return value;
  }
}

/**
 * The replacer is used by `JSON.stringify` and, in this package, it is used within the
 * PCD's `serialize` function. It is called for each property on the JSON object and
 * converts the value of the property from a list of big integers to a list of hexadecimal
 * strings when the property's key name equals "message".
 * @param key The object property key.
 * @param value The object property value.
 * @returns The original value of the property or the converted one.
 */


_tableNameFromId<TableName extends TableNamesInDataModel<DataModel>>(
    id: GenericId<TableName>,
  ): TableName | null {
    for (const tableName of Object.keys(this.triggers.registered)) {
      if (
        this.innerDb.normalizeId(
          tableName as TableNamesInDataModel<DataModel>,
          id,
        )
      ) {
        return tableName as TableName;
      }
    }
    return null;
  }


private get firstFourDocs() {
    return this.args.docs.slice(0, 4);
  }

/**
   * (Up to) the first four docs. The default documents shown.
   */


protected get allApprovers() {
    return this.approverGroups.concat(this.approvers);
  }

/**
   * A computed property that returns all approvers and approverGroups.
   * Passed to the EditableField component to render the list of approvers and groups.
   * Recomputes when the approvers or approverGroups arrays change.
   */


protected get titleTooltipText(): string {
    return `Documents and links that are relevant to this work.`;
  }

/**
   * The text passed to the TooltipIcon beside the title.
   */


protected get jiraIsEnabled() {
    return !!this.configSvc.config.jira_url;
  }

/**
   * Whether Jira is configured for the project.
   * Determines whether to show the Jira-related UI.
   */


protected get projectID() {
    if ("objectID" in this.args.project) {
      return this.args.project.objectID;
    } else {
      return this.args.project.id;
    }
  }

/**
   * The project ID used as our LinkTo model.
   * If the project is an Algolia result, it has an `objectID`.
   * If the project is retrieved from the back-end, it has an `id`.
   */


async function loaderAdvancedConfig() {
  const testCrawlApp = createCrawl({
    log: false,
    baseUrl: 'http://localhost:8888'
  })

  const res = await testCrawlApp.crawlData({
    targets: ['/data', '/data'],
    proxy: { urls: ['http://localhost:7890'] },
    timeout: 10000,
    intervalTime: { max: 1000 },
    maxRetry: 0
  })

  return res.reduce((prev, item) => prev && item.isSuccess, true)
}


_singleRealTransform2(outOff, off, step) {
    const out = this._out;
    const data = this._data;

    const evenR = data[off];
    const oddR = data[off + step];

    const leftR = evenR + oddR;
    const rightR = evenR - oddR;

    out[outOff] = leftR;
    out[outOff + 1] = 0;
    out[outOff + 2] = rightR;
    out[outOff + 3] = 0;
  }


public async listener(t: number) {
        let isExecCommand = false;
        this.intervalID = window.setInterval(async () => {
            if (!Zotero.ZoteroCitation) {
                return this.clear();
            }
            if (!Zotero.Integration.currentSession || isExecCommand) {
                return;
            }
            const sessions = Zotero.Integration.sessions;
            const _sessions = this.sessions;
            for (const sessionID in sessions) {
                const session = sessions[sessionID];
                let _session: SessionData;
                if (!(session.agent as string).includes("Word")) {
                    continue;
                }
                // 初始化对象的session
                if (sessionID in _sessions) {
                    _session = _sessions[sessionID];
                } else {
                    _sessions[sessionID] = _session = { search: undefined, idData: {}, pending: true } as SessionData;
                    await this.initSearch(sessionID);
                    _session.pending = false;
                }
                // 其它线程search正在创建，则退出本次执行
                if (_session.pending == true && !_session.search) {
                    return;
                }
                const citationsByItemID = session.citationsByItemID;
                // 分析排序
                const sortedItemIDs = this.getSortedItemIDs(session.citationsByIndex);
                this.updateCitations(sessionID, citationsByItemID, sortedItemIDs, session.styleClass);
            }
        }, t);
        window.addEventListener("close", (event) => {
            event.preventDefault();
            try {
                this.clear();
            } catch {
                /* empty */
            }
            window.setTimeout(() => {
                window.close();
            });
        });
        const execCommand = Zotero.Integration.execCommand;
        const _sessions = this.sessions;
        // @ts-ignore ignore
        Zotero.Integration.execCommand = async function (agent, command, docId) {
            // eslint-disable-next-line prefer-rest-params
            console.log(...arguments);
            isExecCommand = true;
            // eslint-disable-next-line prefer-rest-params
            await execCommand(...arguments);
            isExecCommand = false;
            if (docId.endsWith("__doc__")) {
                return;
            }
            const id = window.setInterval(async () => {
                const sessionID = Zotero.Integration?.currentSession?.sessionID;
                if (!sessionID) {
                    console.log("sessionID is null, waiting...");
                    return;
                }
                window.clearInterval(id);
                console.log("clear interval");
                let _session;
                while (!((_session ??= _sessions[sessionID]) && _session.search)) {
                    await Zotero.Promise.delay(10);
                }
                console.log(_sessions);
                // 判断是否为插件修改过的名称，如果是则更新
                // 若为用户更改则不进行更新
                if ([sessionID, _session.lastName].indexOf(_session.search.name) != -1) {
                    let targetName = docId
                    try {
                        targetName = PathUtils.split(docId).slice(-1)[0];
                    } catch { }
                    console.log(`${_session.search.name}->${targetName}`);
                    // 修复Mac储存
                    if (targetName && targetName.trim().length > 0) {
                        _session.search.name = _session.lastName = targetName;
                        await _session.search.saveTx({ skipSelect: true });
                    }
                }
            }, 0);
        };
    }


const _classicalRegister = (
  startX: number,
  gateY: number,
  endX: number,
  wireY: number,
): SVGElement => {
  const wirePadding = 1;
  // Draw vertical lines
  const vLine1: SVGElement = line(
    startX + wirePadding,
    gateY,
    startX + wirePadding,
    wireY - wirePadding,
    "register-classical",
  );
  const vLine2: SVGElement = line(
    startX - wirePadding,
    gateY,
    startX - wirePadding,
    wireY + wirePadding,
    "register-classical",
  );

  // Draw horizontal lines
  const hLine1: SVGElement = line(
    startX + wirePadding,
    wireY - wirePadding,
    endX,
    wireY - wirePadding,
    "register-classical",
  );
  const hLine2: SVGElement = line(
    startX - wirePadding,
    wireY + wirePadding,
    endX,
    wireY + wirePadding,
    "register-classical",
  );

  return group([vLine1, vLine2, hLine1, hLine2]);
};

/**
 * Generates the SVG representation of a classical register.
 *
 * @param startX Start x coord.
 * @param gateY  y coord of measurement gate.
 * @param endX   End x coord.
 * @param wireY  y coord of wire.
 *
 * @returns SVG representation of the given classical register.
 */


maybeWidened<T extends Token>(t: T): T | PackageObjectToken {
        if (options.widening && t instanceof ObjectToken && this.widened.has(t))
            return this.a.canonicalizeToken(new PackageObjectToken(t.getPackageInfo(), t.kind));
        else
            return t;
    }

/**
     * If the provided token is an object token that has been widened, the corresponding package object token is returned.
     * Otherwise the provided token is returned as is.
     */


getSecretKey(): string {
    return encodeRoochSercetKey(
      this.keypair.secretKey.slice(0, PRIVATE_KEY_SIZE),
      this.getKeyScheme(),
    )
  }

/**
   * The Bech32 secret key string for this Ed25519 keypair
   */


flag(): number {
    return SIGNATURE_SCHEME_TO_FLAG['Secp256k1']
  }

/**
   * Return the Rooch address associated with this Secp256k1 public key
   */


function deserializeValue(value: any, options: EJSONOptions = {}) {
  if (typeof value === 'number') {
    // TODO(NODE-4377): EJSON js number handling diverges from BSON
    const in32BitRange = value <= BSON_INT32_MAX && value >= BSON_INT32_MIN;
    const in64BitRange = value <= BSON_INT64_MAX && value >= BSON_INT64_MIN;

    if (options.relaxed || options.legacy) {
      return value;
    }

    if (Number.isInteger(value) && !Object.is(value, -0)) {
      // interpret as being of the smallest BSON integer type that can represent the number exactly
      if (in32BitRange) {
        return new Int32(value);
      }
      if (in64BitRange) {
        if (options.useBigInt64) {
          // eslint-disable-next-line no-restricted-globals -- This is allowed here as useBigInt64=true
          return BigInt(value);
        }
        return Long.fromNumber(value);
      }
    }

    // If the number is a non-integer or out of integer range, should interpret as BSON Double.
    return new Double(value);
  }

  // from here on out we're looking for bson types, so bail if its not an object
  if (value == null || typeof value !== 'object') return value;

  // upgrade deprecated undefined to null
  if (value.$undefined) return null;

  const keys = Object.keys(value).filter(
    k => k.startsWith('$') && value[k] != null
  ) as (keyof typeof keysToCodecs)[];
  for (let i = 0; i < keys.length; i++) {
    const c = keysToCodecs[keys[i]];
    if (c) return c.fromExtendedJSON(value, options);
  }

  if (value.$date != null) {
    const d = value.$date;
    const date = new Date();

    if (options.legacy) {
      if (typeof d === 'number') date.setTime(d);
      else if (typeof d === 'string') date.setTime(Date.parse(d));
      else if (typeof d === 'bigint') date.setTime(Number(d));
      else throw new BSONRuntimeError(`Unrecognized type for EJSON date: ${typeof d}`);
    } else {
      if (typeof d === 'string') date.setTime(Date.parse(d));
      else if (Long.isLong(d)) date.setTime(d.toNumber());
      else if (typeof d === 'number' && options.relaxed) date.setTime(d);
      else if (typeof d === 'bigint') date.setTime(Number(d));
      else throw new BSONRuntimeError(`Unrecognized type for EJSON date: ${typeof d}`);
    }
    return date;
  }

  if (value.$code != null) {
    const copy = Object.assign({}, value);
    if (value.$scope) {
      copy.$scope = deserializeValue(value.$scope);
    }

    return Code.fromExtendedJSON(value);
  }

  if (isDBRefLike(value) || value.$dbPointer) {
    const v = value.$ref ? value : value.$dbPointer;

    // we run into this in a "degenerate EJSON" case (with $id and $ref order flipped)
    // because of the order JSON.parse goes through the document
    if (v instanceof DBRef) return v;

    const dollarKeys = Object.keys(v).filter(k => k.startsWith('$'));
    let valid = true;
    dollarKeys.forEach(k => {
      if (['$ref', '$id', '$db'].indexOf(k) === -1) valid = false;
    });

    // only make DBRef if $ keys are all valid
    if (valid) return DBRef.fromExtendedJSON(v);
  }

  return value;
}


advanceOperationTime(operationTime: Timestamp): void {
    if (this.operationTime == null) {
      this.operationTime = operationTime;
      return;
    }

    if (operationTime.greaterThan(this.operationTime)) {
      this.operationTime = operationTime;
    }
  }

/**
   * Advances the operationTime for a ClientSession.
   *
   * @param operationTime - the `BSON.Timestamp` of the operation type it is desired to advance to
   */


last(): T | null {
    // If the list is empty, value will be the head's null
    return this.head.prev.value;
  }

/** Returns the last item in the list, does not remove */


function isFieldOnly(node: any): boolean {
    return node && node.type === "column_ref";
  }

// Helper function to check if a node is a field-only reference (column_ref without literal)


function onDrop(event:any ,offSet:any = {x:0,y:0}) {
    if (
      pipelineObj.hasInputNode &&
      pipelineObj.draggedNode.io_type == "input"
    ) {
      $q.notify({
        message: "Only 1 source node is allowed",
        color: "negative",
        position: "bottom",
        timeout: 2000,
    });
      return;
    }

    const position = screenToFlowCoordinate({
      x: event.clientX + offSet.x,
      y: event.clientY + offSet.y,
    });

    const nodeId = getUUID();

    const newNode = {
      id: nodeId,
      type: pipelineObj.draggedNode.io_type || "default",
      io_type: pipelineObj.draggedNode.io_type || "default",
      position,
      data: { label: nodeId, node_type: pipelineObj.draggedNode.subtype },
    };

    /**
     * Align node position after drop, so it's centered to the mouse
     *
     * We can hook into events even in a callback, and we can remove the event listener after it's been called.
     */
    const { off } = onNodesInitialized(() => {
      updateNode(nodeId, (node) => ({
        position: {
          x: node.position.x - node.dimensions.width / 2,
          y: node.position.y - node.dimensions.height / 2,
        },
      }));

      off();
    });

    pipelineObj.currentSelectedNodeData = newNode;
    pipelineObj.dialog.name = newNode.data.node_type;
    pipelineObj.dialog.show = true;
    pipelineObj.isEditNode = false;

  }

/**
   * Handles the drop event.
   *
   * @param {DragEvent} event
   */


function parseConstraints(constraints?: EdgeConstraint[]): EdgeConstraint[] {
    if (!constraints) {
        return [];
    }

    return constraints.map((c) => {
        const constraintType = c.type;
        const { source, target } = c;

        return {
            ...c,
            source,
            target,
            type: constraintType,
        };
    });
}

/**
 * Parse initially defined constraints.
 * Reverses backward directed edges.
 *
 * @param constraints constraints to parse
 */


const NavigateTo: ActionHandler<NavigateToImpl> = (ctx, actionImpl): void => {
    const isValidUrl = isValidHttpUrl(actionImpl.url);

    if (!isValidUrl) {
        throw new Error(`Invalid URL: ${actionImpl.url}`);
    }

    if (actionImpl.new_tab) {
        window.open(actionImpl.url, actionImpl.new_tab ? '_blank' : undefined);
    } else {
        ctx.history.push(actionImpl.url);
    }
};

/**
 * Front-end handler for NavigateTo action.
 * Navigates to a specified URL.
 */


const UpdateVariable: ActionHandler<UpdateVariableImpl> = async (ctx, actionImpl) => {
    let varAtom;
    let eventName: 'PLAIN_VARIABLE_LOADED' | 'URL_VARIABLE_LOADED';

    // Make sure the variable is registered
    switch (actionImpl.variable.__typename) {
        case 'Variable':
            varAtom = getOrRegisterPlainVariable(actionImpl.variable, ctx.wsClient, ctx.taskCtx, ctx.extras);
            eventName = 'PLAIN_VARIABLE_LOADED';
            break;
        case 'UrlVariable':
            varAtom = getOrRegisterUrlVariable(actionImpl.variable);
            eventName = 'URL_VARIABLE_LOADED';
            break;
        case 'DataVariable':
            throw new Error('DataVariable is not supported in UpdateVariable action');
    }

    let newValue;

    if (actionImpl.value === INPUT) {
        newValue = ctx.input;
    } else if (actionImpl.value === TOGGLE) {
        // normally we'd use the updater form here, but we need to know what value we're
        // toggling to emit the correct event, and the updater must be pure
        const value = await ctx.snapshot.getLoadable(varAtom).toPromise();
        newValue = !value;
    } else {
        newValue = actionImpl.value;
    }

    ctx.set(varAtom, newValue);
    ctx.eventBus.publish(eventName, { variable: actionImpl.variable as any, value: newValue });
};

/**
 * Front-end handler for UpdateVariable action.
 */


function cleanSessionCache(sessionToken: string): void {
    for (const storage of [sessionStorage, localStorage]) {
        const keys = Object.keys(storage);

        keys.forEach((key) => {
            // Remove keys related to a different Dara session
            if (key.startsWith('dara-session') && !key.startsWith(`dara-session-${sessionToken}`)) {
                storage.removeItem(key);
            }
        });
    }
}

/**
 * Clean up session storage cache.
 * Purges sessionStorage persisted values which are related to a different session than the current one.
 *
 * @param sessionToken current session token
 */


function Modal(props: ModalProps): JSX.Element {
    const [mounted, setMounted] = useState(false);
    const [renderModal, setRenderModal] = useState(false);

    // Internal state is updated using the useEffect to delay it to the next tick. This allows for the components css
    // animations to work correctly
    useEffect(() => {
        setRenderModal(props.render);
    }, [props.render]);

    useEffect(() => {
        if (renderModal) {
            const keyHandler = (e: KeyboardEvent): void => {
                if (e.key === Key.ESCAPE && props.onAttemptClose) {
                    props.onAttemptClose();
                }
            };
            document.addEventListener('keydown', keyHandler);
            return () => {
                document.removeEventListener('keydown', keyHandler);
            };
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [renderModal, props.onAttemptClose]);

    if (!props.render && !mounted) {
        return null;
    }

    const onTransitionEnd = (): void => {
        setMounted(props.render);
        if (!props.render && props.onClosed) {
            props.onClosed();
        }
    };

    const stopPropagation = (e: React.MouseEvent<HTMLDivElement>): void => {
        e.stopPropagation();
    };

    return ReactDOM.createPortal(
        <Background id={props.id} onClick={props.onAttemptClose} onTransitionEnd={onTransitionEnd} render={renderModal}>
            <ModalWrapper
                className={`cl-modal-content ${props.className ?? ''}`}
                onClick={stopPropagation}
                render={renderModal}
                style={props.style}
            >
                {props.children}
            </ModalWrapper>
        </Background>,
        document.body
    );
}

/**
 * A simple modal component, accepts children and a render property. It handles attaching the modal to the body of the
 * document and transitioning it in and out of view as required
 *
 * @param {ModalProps} props - the component props
 */


const EllipsisH = (props: IconProps): JSX.Element => {
    return <StyledFAIcon icon={faEllipsisH} {...props} />;
};

/**
 * EllipsisH icon from FontAwesome
 *
 * @param {IconProps} props - the component props
 */


const Dizzy = (props: IconProps): JSX.Element => {
    return <StyledFAIcon icon={faDizzy} {...props} />;
};

/**
 * Dizzy icon from FontAwesome
 *
 * @param {IconProps} props - the component props
 */


const HouseMedicalCircleExclamation = (props: IconProps): JSX.Element => {
    return <StyledFAIcon icon={faHouseMedicalCircleExclamation} {...props} />;
};

/**
 * HouseMedicalCircleExclamation icon from FontAwesome
 *
 * @param {IconProps} props - the component props
 */


const RoadSpikes = (props: IconProps): JSX.Element => {
    return <StyledFAIcon icon={faRoadSpikes} {...props} />;
};

/**
 * RoadSpikes icon from FontAwesome
 *
 * @param {IconProps} props - the component props
 */


const PersonCircleMinus = (props: IconProps): JSX.Element => {
    return <StyledFAIcon icon={faPersonCircleMinus} {...props} />;
};

/**
 * PersonCircleMinus icon from FontAwesome
 *
 * @param {IconProps} props - the component props
 */


const PlaneLock = (props: IconProps): JSX.Element => {
    return <StyledFAIcon icon={faPlaneLock} {...props} />;
};

/**
 * PlaneLock icon from FontAwesome
 *
 * @param {IconProps} props - the component props
 */


const List = (props: IconProps): JSX.Element => {
    return <StyledFAIcon icon={faList} {...props} />;
};

/**
 * List icon from FontAwesome
 *
 * @param {IconProps} props - the component props
 */


const UserSecret = (props: IconProps): JSX.Element => {
    return <StyledFAIcon icon={faUserSecret} {...props} />;
};

/**
 * UserSecret icon from FontAwesome
 *
 * @param {IconProps} props - the component props
 */


update() {
    this.getOrInitRenderWatcher().update()
  }


removeAttribute(name: string) {
    if (this._$nodeAttributes) {
      delete this._$nodeAttributes[name]
    }
    const be = this._$backendElement
    if (be) {
      if (ENV.DEV) performanceMeasureStart('backend.removeAttribute')
      be.removeAttribute(name)
      if (ENV.DEV) performanceMeasureEnd()
    }
    if (this._$mutationObserverTarget) {
      MutationObserverTarget.callAttrObservers(this, {
        type: 'properties',
        target: this,
        nameType: 'attribute',
        attributeName: name,
      })
    }
  }


const shortenNumber = (number: number): string | number => {
    if (number > 0 && number < 1) return number.toString().replace("0.", ".");
    return number;
  };

// Removes leading zero before floating point if necessary


public clear(): this
    {
        this._geometry.clear();
        this._lineStyle.reset();
        this._fillStyle.reset();

        this._boundsID++;
        this._matrix = null;
        this._holeMode = false;
        this.currentPath = null;

        return this;
    }

/**
     * Clears the graphics that were drawn to this Graphics object, and resets fill and line style settings.
     * @returns - This Graphics object. Good for chaining method calls
     */


ceil(resolution = 1, eps = 0.001): this
    {
        const x2 = Math.ceil((this.x + this.width - eps) * resolution) / resolution;
        const y2 = Math.ceil((this.y + this.height - eps) * resolution) / resolution;

        this.x = Math.floor((this.x + eps) * resolution) / resolution;
        this.y = Math.floor((this.y + eps) * resolution) / resolution;

        this.width = x2 - this.x;
        this.height = y2 - this.y;

        return this;
    }

/**
     * Enlarges rectangle that way its corners lie on grid
     * @param resolution - resolution
     * @param eps - precision
     * @returns Returns itself.
     */


function hierarchyConv(state) {
  const parent = {
    name: "root",
    children: [],
  };

  function addNodeToTree(key, value, parent) {
    if (Array.isArray(value) && value.length > 0) {
      const node = { name: key, children: [] };
      parent.children.push(node);
      value.forEach((item, index) => {
        addNodeToTree(`[${index}]`, item, node);
      });
    } else if (typeof value === "object" && Object.keys(value).length > 0) {
      const node = { name: key, children: [] };
      parent.children.push(node);
      Object.entries(value).forEach(([key, val]) => {
        addNodeToTree(key, val, node);
      });
    } else {
      if (typeof value === "object") {
        const node = { name: key, attributes: { value: "empty" } };
        parent.children.push(node);
      } else {
        const node = { name: key, attributes: { value } };
        parent.children.push(node);
      }
    }
  }

  addNodeToTree("state", state, parent);
  return parent.children[0];
}

/*
hierarchyConv takes in the state to display in the visualization tree,
and converts it to a format readable by D3.

const example = {
  name: 'State',
  children: [
    {
      name: 'member1',
      attributes: {
        value: 'org1',
      },
    },
    {
      name: 'member2',
      children: [
        name: 'member3',
        attributes: {
          value: 'org2'
        }
      ]
    }
  ]
}
 */


function parseQueryString(query) {
  const params = {};
  query.split('&').forEach(function (part) {
    // 使用正则表达式匹配键和值，直到遇到第一个等号为止
    const regex = /^(.*?)=(.*)/;
    const match = part.match(regex);
    if (match) {
      const key = decodeURIComponent(match[1]);
      const value = decodeURIComponent(match[2]);
      params[key] = value;
    }
  });
  return params;
}


get clientGroupID(): Promise<string> {
    return this.#impl.clientGroupID;
  }

/**
   * The client group ID for this instance of Replicache. Instances of
   * Replicache will have the same client group ID if and only if they have
   * the same name, mutators, indexes, schema version, format version, and
   * browser profile.
   */


const filterOutput = (
  dataFromCSV: any,
  output: string | string[] | string[][]
) => {
  if (output === '*') {
    return nanifyEmptyValues(dataFromCSV);
  }

  if (Array.isArray(output)) {
    /** Check if it's a multidimensional array. */
    if (Array.isArray(output[0])) {
      const result: any = {};

      output.forEach(outputField => {
        /** Check if there is no renaming request, then export as is */
        const outputTitle = outputField[1] || outputField[0];
        result[outputTitle] = fieldAccessor(outputField[0], dataFromCSV);
      });

      return result;
    }

    const outputTitle = output[1] || output[0];

    return {
      [outputTitle as string]: fieldAccessor(output[0], dataFromCSV),
    };
  }

  return {
    [output]: fieldAccessor(output, dataFromCSV),
  };
};

/**
 * 1. If output is anything, then removes query data from csv record to escape duplicates.
 * 2. Otherwise checks if it's a miltidimensional array, then grabs multiple fields ().
 * 3. If not, then returns single field.
 * 4. In case if it's string, then
 */


const computeNode = async (node: Node, params: ComputeParams): Promise<any> => {
  const pipeline = node.pipeline || (params.pipeline as PhasedPipeline);
  const config = node.config || params.config;
  const defaults = node.defaults || params.defaults;
  const noFlags = !params.observe && !params.regroup && !params.compute;

  debugLogger.setExecutingPluginName();
  warnIfConfigProvided(node);

  if (node.children) {
    return traverse(node.children, {
      ...params,
      pipeline,
      defaults,
      config,
    });
  }

  let outputStorage = structuredClone(node.inputs) as PluginParams[];
  outputStorage = mergeDefaults(outputStorage, defaults);
  const pipelineCopy = structuredClone(pipeline) || {};

  /** Checks if pipeline is not an array or empty object. */
  if (
    Array.isArray(pipelineCopy) ||
    (typeof pipelineCopy === 'object' &&
      pipelineCopy !== null &&
      Object.keys(pipelineCopy).length === 0)
  ) {
    logger.warn(EMPTY_PIPELINE);
  }

  /**
   * If iteration is on observe pipeline, then executes observe plugins and sets the inputs value.
   */
  if ((noFlags || params.observe) && pipelineCopy.observe) {
    while (pipelineCopy.observe.length !== 0) {
      const pluginName = pipelineCopy.observe.shift() as string;
      console.debug(OBSERVING(pluginName));
      debugLogger.setExecutingPluginName(pluginName);

      const plugin = params.pluginStorage.get(pluginName);
      const nodeConfig = config && config[pluginName];

      outputStorage = await plugin.execute(outputStorage, nodeConfig);
      node.inputs = outputStorage;

      if (params.context.explainer) {
        addExplainData({
          pluginName,
          metadata: plugin.metadata,
        });
      }
    }
  }

  /**
   * If regroup is requested, execute regroup strategy, delete child's inputs, outputs and empty regroup array.
   */
  if ((noFlags || params.regroup) && pipelineCopy.regroup) {
    const originalOutputs = params.append ? node.outputs || [] : [];

    if (!isRegrouped(pipelineCopy.regroup, outputStorage, childNames)) {
      node.children = Regroup(
        outputStorage,
        originalOutputs,
        pipelineCopy.regroup
      );

      delete node.inputs;
      delete node.outputs;

      debugLogger.setExecutingPluginName();
      console.debug(REGROUPING);

      return traverse(node.children, {
        ...params,
        pipeline: {
          ...pipelineCopy,
          regroup: undefined,
        },
        defaults,
        config,
      });
    } else {
      console.debug(SKIPPING_REGROUP);
    }
  }

  console.debug('\n');

  /**
   * If iteration is on compute plugin, then executes compute plugins and sets the outputs value.
   */
  if ((noFlags || params.compute) && pipelineCopy.compute) {
    const originalOutputs = params.append ? node.outputs || [] : [];

    while (pipelineCopy.compute.length !== 0) {
      const pluginName = pipelineCopy.compute.shift() as string;
      const plugin = params.pluginStorage.get(pluginName);
      const nodeConfig = config && config[pluginName];

      console.debug(COMPUTING_PIPELINE_FOR_NODE(pluginName));
      debugLogger.setExecutingPluginName(pluginName);

      outputStorage = await plugin.execute(outputStorage, nodeConfig);

      debugLogger.setExecutingPluginName();

      node.outputs = outputStorage;

      if (params.context.explainer) {
        addExplainData({
          pluginName,
          metadata: plugin.metadata,
        });
      }
    }

    if (params.append) {
      node.outputs = originalOutputs.concat(node.outputs || []);
    }
  }

  console.debug('\n');
};

/**
 * 1. If the node has it's own pipeline, defaults or config then use that,
 *    otherwise use whatever has been passed down from further up the tree.
 * 2. If it's a grouping node, then first of all computes all it's children.
 *    This is doing a depth first traversal.
 * 3. Otherwise merges the defaults into the inputs.
 * 4. Iterates over pipeline phases (observe, regroup, compute).
 * 5. Observe plugins are used to insert input values
 *    (isolated execution can be achived by passing `--observe` flag to CLI command).
 * 6. Regroup plugin is used to group existing inputs by criteria
 *    (isolated execution can be achived by passing `--regroup` flag to CLI command).
 *    Since it creates new children for node, existing inputs and outputs are dropped and recursive traversal is called
 *    for newbord child component.
 * 7. Compute plugins are used to do desired computations and appending the result to outputs
 *    (isolated execution can be achived by passing `--compute` flag to CLI command).
 */


public claim(): BitPosition {
		const { recycled } = this;

		// Claim the next bit.
		const claimed = (recycled.length > 0) ? recycled.pop() : (this.next++);

		// Update the field.
		this.asField = BitField.or(this.asField, BitField.fromPosition(claimed as BitPosition));
		return claimed as BitPosition;
	}

/**
	 * Claims a bit from the registry.
	 */


async function getFileStats(filePath: string): Promise<FileInfo> {
  const stats = await fs.stat(filePath);
  return {
    size: stats.size,
    created: stats.birthtime,
    modified: stats.mtime,
    accessed: stats.atime,
    isDirectory: stats.isDirectory(),
    isFile: stats.isFile(),
    permissions: stats.mode.toString(8).slice(-3),
  };
}


cliqueEpochTransitionSigners(): EthjsAddress[] {
		this._requireClique('cliqueEpochTransitionSigners')
		if (!this.cliqueIsEpochTransition()) {
			const msg = this._errorMsg('Signers are only included in epoch transition blocks (clique)')
			throw new Error(msg)
		}

		const start = CLIQUE_EXTRA_VANITY
		const end = this.extraData.length - CLIQUE_EXTRA_SEAL
		const signerBytes = this.extraData.subarray(start, end)

		const signerList: Uint8Array[] = []
		const signerLength = 20
		for (let start = 0; start <= signerBytes.length - signerLength; start += signerLength) {
			signerList.push(signerBytes.subarray(start, start + signerLength))
		}
		return signerList.map((buf) => new EthjsAddress(buf))
	}

/**
	 * Returns a list of signers
	 * (only clique PoA, throws otherwise)
	 *
	 * This function throws if not called on an epoch
	 * transition block and should therefore be used
	 * in conjunction with {@link BlockHeader.cliqueIsEpochTransition}
	 */


async emulateMessageToAccountEvent(requestParameters: EmulateMessageToAccountEventRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<AccountEvent> {
        const response = await this.emulateMessageToAccountEventRaw(requestParameters, initOverrides);
        return await response.value();
    }

/**
     * Emulate sending message to blockchain
     */


async emulateMessageToTrace(requestParameters: EmulateMessageToTraceRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<Trace> {
        const response = await this.emulateMessageToTraceRaw(requestParameters, initOverrides);
        return await response.value();
    }


async getAccountNominatorsPoolsRaw(requestParameters: GetAccountNominatorsPoolsRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<AccountStaking>> {
        if (requestParameters['accountId'] == null) {
            throw new runtime.RequiredError(
                'accountId',
                'Required parameter "accountId" was null or undefined when calling getAccountNominatorsPools().'
            );
        }

        const queryParameters: any = {};

        const headerParameters: runtime.HTTPHeaders = {};

        const response = await this.request({
            path: `/v2/staking/nominator/{account_id}/pools`.replace(`{${"account_id"}}`, encodeURIComponent(String(requestParameters['accountId']))),
            method: 'GET',
            headers: headerParameters,
            query: queryParameters,
        }, initOverrides);

        return new runtime.JSONApiResponse(response, (jsonValue) => AccountStakingFromJSON(jsonValue));
    }

/**
     * All pools where account participates
     */


public static sendQueryToStats(
        chain?: Chain,
        requestBody?: {
            project_id: number;
            name?: string;
            query?: string;
            gpt_message?: string;
            /**
             * cyclic execution of requests
             */
            repeat_interval?: number;
        },
    ): CancelablePromise<StatsQueryResult> {
        return __request(OpenAPI, {
            method: 'POST',
            url: '/api/v1/services/stats/query',
            query: {
                'chain': chain,
            },
            body: requestBody,
            mediaType: 'application/json',
            errors: {
                400: `Something went wrong on client side`,
                403: `Access token is missing or invalid`,
                404: `The specified resource was not found`,
                500: `Something went wrong on server side`,
            },
        });
    }

/**
     * Send query to stats service
     * @param chain chain
     * @param requestBody Data that is expected
     * @returns StatsQueryResult Query result
     * @throws ApiError
     */


destroy() {
    this.deactivate();
    this._listeners = [];
  }

/**
   * Destroy the current list by deactivating the
   * listeners and clearing the internal list
   */


public withHeader(header: string) {
        return Link.header(this.path, header, this.embed, this.display);
    }

/** Convert a file link into a link to a specific header. */


async expectConstraintCount(expected: number, exact?: boolean) {
    const count = await this.getConstraintCount();
    if (count < expected) {
      throw new AssertionError({
        message: 'Circuit is under-constrained',
        expected,
        actual: count,
      });
    }

    if (exact && count !== expected) {
      throw new AssertionError({
        message: 'Circuit is over-constrained',
        expected,
        actual: count,
      });
    }
  }

/** Asserts that the circuit has enough constraints.
   *
   * By default, this function checks if there **at least** `expected` many constraints in the circuit.
   * If `exact` option is set to `true`, it will also check if the number of constraints is exactly equal to
   * the `expected` amount.
   *
   * If first check fails, it means the circuit is under-constrained. If the second check fails, it means
   * the circuit is over-constrained.
   */


private static onKeyDown(characterLimit: number, event: KeyboardEvent) {
    const inputElement = event.target as HTMLElement;
    const textContent = inputElement.textContent;
    if (textContent && textContent.length >= characterLimit
        && !TextInputEvents.PERMITTED_KEYS.has(event.key) && !TextInputEvents.isKeyCombinationPermitted(event)) {
      event.preventDefault();
    }
  }


set(key: K, val: V): Promise<void> {
    return execInWriteTx(this.store, tx => tx.setIndex(serializeKey(this.prefix, key), this.encoder.pack(val)));
  }

/**
   * Sets the value at the given key.
   * @param key - The key to set the value at
   * @param val - The value to set
   */


openMultiMap<K extends Key, V>(name: string): AztecMultiMap<K, V> & AztecAsyncMultiMap<K, V> {
    return new LmdbAztecMap(this.#multiMapData, name);
  }

/**
   * Creates a new AztecMultiMap in the store. A multi-map stores multiple values for a single key automatically.
   * @param name - Name of the map
   * @returns A new AztecMultiMap
   */


public getLatestLeafPreimageCopy(index: bigint, includeUncommitted: boolean): IndexedTreeLeafPreimage | undefined {
    const preimage = !includeUncommitted
      ? this.getDbPreimage(index)
      : this.getCachedPreimage(index) ?? this.getDbPreimage(index);
    return preimage && this.leafPreimageFactory.clone(preimage);
  }

/**
   * Gets the latest LeafPreimage copy.
   * @param index - Index of the leaf of which to obtain the LeafPreimage copy.
   * @param includeUncommitted - If true, the uncommitted changes are included in the search.
   * @returns A copy of the leaf preimage at the given index or undefined if the leaf was not found.
   */


public getBlock(index: number): L2Block {
    const block = this.provingState?.blocks[index]?.block;
    if (!block) {
      throw new Error(`Block at index ${index} not available`);
    }
    return block;
  }

/** Returns the block as built for a given index. */


public async getFunctionArtifactByName(
    contractAddress: AztecAddress,
    functionName: string,
  ): Promise<FunctionArtifact | undefined> {
    const tree = await this.getTreeForAddress(contractAddress);
    return tree.getArtifact().functions.find(f => f.name === functionName);
  }

/**
   * Retrieves the artifact of a specified function within a given contract.
   * The function is identified by its name, which is unique within a contract.
   * Throws if the contract has not been added to the database.
   *
   * @param contractAddress - The AztecAddress representing the contract containing the function.
   * @param functionName - The name of the function.
   * @returns The corresponding function's artifact as an object
   */


public override loadFromExecutionCache(hash: Fr): Promise<Fr[]> {
    return Promise.resolve(this.executionCache.getPreimage(hash));
  }

/**
   * Gets values from the execution cache.
   * @param hash - Hash of the values.
   * @returns The values.
   */


range_adjacent_to_cursor(cursor: number, left: boolean, loose = false, include_edge = false) {
		const ranges = left ? this.ranges.slice().reverse() : this.ranges;
		if (include_edge) {
			return ranges.find(range =>
				left ? ((loose ? range.from : range.to) < cursor) : (cursor < (loose ? range.to : range.from))
			);
		} else {
			return ranges.find(range =>
				left ? ((loose ? range.from : range.to) <= cursor) : (cursor <= (loose ? range.to : range.from))
			);
		}
	}

/**
	 * Get the range that is (not directly) adjacent to the cursor in given direction
	 * @param cursor - Cursor position in the document
	 * @param left - Whether to look left or right of the cursor
	 * @param loose - Whether to include ranges that are partially adjacent to the cursor
	 * @param include_edge - Whether to include the edges of the range
	 */


static mSpeedEvent(list: IAriaDownProgress[]) {
    const downingStore = useDowningStore()
    const settingStore = useSettingStore()
    const DowningList = downingStore.ListDataRaw

    if (list == undefined) list = []
    const dellist: string[] = []
    let hasSpeed = 0
    for (let n = 0; n < DowningList.length; n++) {
      if (DowningList[n].Down.DownSpeedStr != '') {
        const gid = DowningList[n].Info.GID
        let isFind = false
        for (let m = 0; m < list.length; m++) {
          if (list[m].gid != gid) continue
          if (list[m].gid == gid && list[m].status == 'active') {
            isFind = true
            break
          }
        }
        if (!isFind) {
          if (DowningList[n].Down.DownState != '已暂停') DowningList[n].Down.DownState = '队列中'
          DowningList[n].Down.DownSpeed = 0
          DowningList[n].Down.DownSpeedStr = ''
        }
      }
    }
    const ariaRemote = !settingStore.AriaIsLocal

    const saveList: IStateDownFile[] = []
    for (let i = 0; i < list.length; i++) {
      try {
        const gid = list[i].gid
        const isComplete = list[i].status === 'complete'
        const isDowning = isComplete || list[i].status === 'active' || list[i].status === 'waiting'
        const isStop = list[i].status === 'paused' || list[i].status === 'removed'
        const isError = list[i].status === 'error'

        for (let j = 0; j < DowningList.length; j++) {
          if (DowningList[j].Info.ariaRemote != ariaRemote) continue
          if (DowningList[j].Info.GID == gid) {
            const downItem = DowningList[j]
            const down = downItem.Down
            const totalLength = parseInt(list[i].totalLength) || 0
            down.DownSize = parseInt(list[i].completedLength) || 0
            down.DownSpeed = parseInt(list[i].downloadSpeed) || 0
            down.DownSpeedStr = humanSize(down.DownSpeed) + '/s'
            down.DownProcess = Math.floor((down.DownSize * 100) / (totalLength + 1)) % 100

            down.IsCompleted = isComplete
            down.IsDowning = isDowning
            down.IsFailed = isError
            down.IsStop = isStop

            if (list[i].errorCode && list[i].errorCode != '0') {
              down.FailedCode = parseInt(list[i].errorCode) || 0
              down.FailedMessage = FormatAriaError(list[i].errorCode, list[i].errorMessage)
            }

            if (isComplete) {
              down.DownSize = downItem.Info.size
              down.DownSpeed = 0
              down.DownSpeedStr = ''
              down.DownProcess = 100
              down.FailedCode = 0
              down.FailedMessage = ''

              down.DownState = '校验中'
              const check = AriaHashFile(downItem)
              if (check.Check) {
                if (useSettingStore().downFinishAudio && !sound.playing()) {
                  sound.play()
                }
                downingStore.mUpdateDownState({
                  DownID: check.DownID,
                  DownState: '已完成',
                  IsFailed: false,
                  IsDowning: true,
                  IsStop: false,
                  IsCompleted: true,
                  FailedMessage: ''
                })
              } else {
                downingStore.mUpdateDownState({
                  DownID: check.DownID,
                  DownState: '已出错',
                  IsFailed: true,
                  IsDowning: false,
                  IsStop: true,
                  IsCompleted: false,
                  FailedMessage: '移动文件失败，请重新下载'
                })
              }
            } else if (isStop) {
              down.DownState = '已暂停'
              down.DownSpeed = 0
              down.DownSpeedStr = ''
              down.FailedCode = 0
              down.FailedMessage = ''
            } else if (isStop || isError) {
              down.DownState = '已出错'
              down.DownSpeed = 0
              down.DownSpeedStr = ''
              down.AutoTry = Date.now()
              if (down.FailedMessage == '') down.FailedMessage = '下载失败'
            } else if (isDowning) {
              hasSpeed += down.DownSpeed
              let lasttime = ((totalLength - down.DownSize) / (down.DownSpeed + 1)) % 356400
              if (lasttime < 1) lasttime = 1
              down.DownState =
                down.DownProcess.toString() +
                '% ' +
                (lasttime / 3600).toFixed(0).padStart(2, '0') +
                ':' +
                ((lasttime % 3600) / 60).toFixed(0).padStart(2, '0') +
                ':' +
                (lasttime % 60).toFixed(0).padStart(2, '0')
              if (SaveTimeWait > 10) saveList.push(downItem)
            } else {
              //console.log('update', DowningList[j]);
            }
            if (isStop || isError) {
              dellist.push(gid)
            }
            downingStore.mRefreshListDataShow(true)
            break
          }
        }
      } catch {
      }
    }

    if (saveList.length > 0) DBDown.saveDownings(JSON.parse(JSON.stringify(saveList)))
    if (dellist.length > 0) AriaDeleteList(dellist).then()
    if (SaveTimeWait > 10) SaveTimeWait = 0
    else SaveTimeWait++
    useFootStore().mSaveDownTotalSpeedInfo(hasSpeed && humanSizeSpeed(hasSpeed) || '')
  }

/**
   * 速度事件方法
   */


size(): number {
    return this.#compiledIndex.size();
  }

/**
   * Returns the number of vectors currently indexed.
   * @return {number} The number of vectors currently indexed.
   */


private parseExp(exp: string) {
    const res = { isOK: false, code: undefined }
    if (!exp) return res
    try {
      const ast = parser.parse(`var _=(${exp})`)
      res.isOK = true
      traverse.default(ast, {
        ReferencedIdentifier: (path) => {
          // 检索出引用标识符
          this._bindingVars.add(path.node.name)
        },
        SequenceExpression() {
          res.isOK = false
        }
      } as any)
    } catch (e) {
      res.isOK = false
    }
    return res
  }


watchTouchMove() {
    // 防止重复监听，导致多次触发事件
    if (this.isWatchTouchMove) return
    this.isWatchTouchMove = true

    const parent: Element = this.getScrollParent()
    const callback = (ratio) => {
      if (ratio >= 0.5 && this.lastTrigger !== 1) {
        this.lastTrigger = 1
        if (!this.hasAppeared) {
          this.dispatchEvent(new CustomEvent('firstappear'))
          this.hasAppeared = true
        }
        this.dispatchEvent(new CustomEvent('appear'))
      }
      if (ratio < 0.5 && this.lastTrigger === 1) {
        this.lastTrigger = 0
        this.dispatchEvent(new CustomEvent('disappear'))
      }
    }

    requestAnimationFrame(() => {
      // 为了确保元素渲染出来调用
      const ratio = getElementVisibleRatio(this)
      callback(ratio)
    })

    this.listener = throttle(
      () => {
        const ratio = getElementVisibleRatio(this)
        callback(ratio)
      },
      66,
      { leading: true, trailing: true }
    )

    parent.addEventListener('scroll', this.listener)
  }


private async runExtendedRunner(options: RunnerOptions): Promise<Runner> {
    const RunnerExtended = this.hooks.extendRunner.call(Runner, options)
    const runner = new RunnerExtended(
      options.config,
      options.userConfig,
      options.context
    )
    this.currentRunners.add(runner)
    await runner.run(options.command, options.plugins)
    return runner
  }


async viewAddressBondsInfo(address: IAddress): Promise<{
    totalStakedAmount: BigNumber.Value;
    userStakedAmount: BigNumber.Value;
    livelinessScore: number;
  }> {
    const interaction = this.contract.methodsExplicit.getAddressBondsInfo([
      new AddressValue(address)
    ]);
    const query = interaction.buildQuery();
    const queryResponse = await this.networkProvider.queryContract(query);
    const endpointDefinition = interaction.getEndpoint();
    const { firstValue, returnCode } = new ResultsParser().parseQueryResponse(
      queryResponse,
      endpointDefinition
    );
    if (returnCode.isSuccess()) {
      const returnValue = firstValue?.valueOf();
      return {
        totalStakedAmount: returnValue.field0.valueOf(),
        userStakedAmount: returnValue.field1.valueOf(),
        livelinessScore: new BigNumber(returnValue.field2.valueOf())
          .div(100)
          .toNumber()
      };
    } else {
      throw new ErrContractQuery('viewAddressBondsInfo', returnCode.toString());
    }
  }

/**
   * Returns the address bonds info
   * @param address address to query
   *
   */


function getTmpZombiePath() {
    return process.env.MOON_ZOMBIE_DIR;
}

/// Returns the /tmp/zombie-52234... path


get defaultValue(): T {
      return this.config.defaultValue()
   }


protected setOwnSerial(next: Field_matrix_serial): void {
      this.assignNewSerial(next)

      const cells = this.serial.selected ?? this.config.default ?? []
      const selectedCells = new Set(cells.map(({ row, col }) => this.getCellkey(row, col)))

      // make sure every cell has the right value
      for (const [x, row] of this.config.rows.entries()) {
         for (const [y, col] of this.config.cols.entries()) {
            const cellKey = this.getCellkey(row, col)
            const value = selectedCells.has(cellKey)
            const prev = this.store.get(cellKey)
            if (prev == null) this.store.set(cellKey, { x, y, col, row, value })
            else prev.value = value
         }
      }

      this.patchSerial((draft) => void (draft.selected = this.activeCells))
   }


setOff(): void {
      this.setActive(false)
   }


get pythonModuleByNodeNameInCushy(): Map<NodeNameInCushy, ComfyPythonModule> { return this.parseObjectInfo.pythonModuleByNodeNameInCushy } // prettier-ignore

// forward to underlying parsedObjectInfo


getExecutable_orExtract(appID: CushyAppID): Maybe<Executable> {
      if (this._EXECUTABLES) return this._EXECUTABLES.find((executable) => appID === executable.appID)
      this.evaluateAndUpdateAppsAndViews()
      return this._EXECUTABLES!.find((executable) => appID === executable.appID)
   }

/** more costly variation of getExecutable_orNull */


addCustomV2<T extends any>(fn: FC<T>, props: T): void {
      const uid = uniqueIDByMemoryRef(fn)
      const panel = registerCustomPanel(uid, fn)
      this.open('Custom', { uid: panel.uid, props })
   }

/**
    * @experimental
    * @unstable
    */


function slugify(str: string | undefined): string | undefined {
	if (!str) return;
	return str
		.toString()
		.trim()
		.toLowerCase()
		.replace(/[^\w ]+/g, '')
		.replace(/ +/g, '-');
}

// Slugify a string for hyphens and underscores


async list_music_update(userName: string, musicInfos: LX.List.ListActionMusicUpdate, isRemote: boolean = false) {
    const userSpace = getUserSpace(userName)
    // const changedIds =
    await userSpace.listManage.listDataManage.listMusicUpdateInfo(musicInfos)
    // await checkUpdateList(changedIds)
    this.emit('list_music_update', userName, musicInfos, isRemote)
    listUpdated()
  }

/**
   * 批量更新歌曲信息
   * @param musicInfos 歌曲&列表信息
   * @param isRemote 是否属于远程操作
   */


resolveName(name: string): Address | undefined {
    return this.nameToReg.get(name)?.addr;
  }

/** Find wallet address for a given Daimo name, or undefined if not found. */


const isCommonjs = (code: string) =>
  /\b(?:require|module|exports)\b/.test(
    code.replace(/\/\*(.|[\r\n])*?\*\//gm, '').replace(/\/\/.*/g, ''),
  );


public getCacheConfiguration(): CancelablePromise<{
        result: {
            clearCacheCronSchedule: string;
        };
    }> {
        return this.httpRequest.request({
            method: 'GET',
            url: '/configuration/cache',
            errors: {
                400: `Bad Request`,
                404: `Not Found`,
                500: `Internal Server Error`,
            },
        });
    }

/**
     * Get cache configuration
     * Get cache configuration
     * @returns any Default Response
     * @throws ApiError
     */


async function getCurrentNonceState(
  walletAddress: Address,
  chainId: number,
): Promise<NonceState> {
  const [onchainNonce, largestSentNonce] = await Promise.all([
    getLastUsedOnchainNonce(chainId, walletAddress),
    inspectNonce(chainId, walletAddress),
  ]);

  return {
    onchainNonce: onchainNonce,
    largestSentNonce: largestSentNonce,
  };
}


function readInfoBits(b: Bitmap) {
  const readBit = (x: number, y: number, out: number) => (out << 1) | (b.data[y][x] ? 1 : 0);
  const size = b.height;
  // Version information
  let version1 = 0;
  for (let y = 5; y >= 0; y--)
    for (let x = size - 9; x >= size - 11; x--) version1 = readBit(x, y, version1);
  let version2 = 0;
  for (let x = 5; x >= 0; x--)
    for (let y = size - 9; y >= size - 11; y--) version2 = readBit(x, y, version2);
  // Format information
  let format1 = 0;
  for (let x = 0; x < 6; x++) format1 = readBit(x, 8, format1);
  format1 = readBit(7, 8, format1);
  format1 = readBit(8, 8, format1);
  format1 = readBit(8, 7, format1);
  for (let y = 5; y >= 0; y--) format1 = readBit(8, y, format1);
  let format2 = 0;
  for (let y = size - 1; y >= size - 7; y--) format2 = readBit(8, y, format2);
  for (let x = size - 8; x < size; x++) format2 = readBit(x, 8, format2);
  return { version1, version2, format1, format2 };
}


scale(factor: number): Bitmap {
    if (!Number.isSafeInteger(factor) || factor > 1024)
      throw new Error(`invalid scale factor: ${factor}`);
    const { height, width } = this;
    const res = new Bitmap({ height: factor * height, width: factor * width });
    return res.rect(
      { x: 0, y: 0 },
      Infinity,
      ({ x, y }) => this.data[Math.floor(y / factor)][Math.floor(x / factor)]
    );
  }

// Each pixel size is multiplied by factor


const openNewCamera = () => {
    window.api.openNewCamera()
  }


const deleteSessionData = async (payload: SessionData) => {
      if (sessionDataList.value.length === 1) {
        await deleteSession()
      } else {
        const { id, session_id } = payload
        const sql = `DELETE FROM session_data WHERE id = '${id}' AND session_id = '${session_id}';`
        await executeSQL(sql)
      }

      Message.success(t('message.deleteSuccess'))

      getSessionData()
    }


addReviewedCommitId(commentBody: string, commitId: string): string {
    const start = commentBody.indexOf(COMMIT_ID_START_TAG)
    const end = commentBody.indexOf(COMMIT_ID_END_TAG)
    if (start === -1 || end === -1) {
      return `${commentBody}\n${COMMIT_ID_START_TAG}\n<!-- ${commitId} -->\n${COMMIT_ID_END_TAG}`
    }
    const ids = commentBody.substring(start + COMMIT_ID_START_TAG.length, end)
    return `${commentBody.substring(
      0,
      start + COMMIT_ID_START_TAG.length
    )}${ids}<!-- ${commitId} -->\n${commentBody.substring(end)}`
  }


async members(): Promise<User[]> {
    return [new User()];
  }


myField(): string {
    return "Hello World";
  }


const debounced = (): void => {
      // Base64 decode the data
      const data: DataStore = store.data || {};

      // Loop over each stored capability
      for (const name of Object.keys(this.#stores)) {
        // Get the prefix offset for the keys
        const offset = `${name}-`.length;

        // Get any keys that match the capability name prefix
        const filtered: DataStore = {};

        // Loop over each key in the secret
        for (const key of Object.keys(data)) {
          // Match on the capability name as a prefix
          if (startsWith(name, key)) {
            // Strip the prefix and store the value
            filtered[key.slice(offset)] = data[key];
          }
        }

        // Send the data to the receiver callback
        this.#stores[name].receive(filtered);
      }

      // Call the onReady callback if this is the first time the secret has been read
      if (this.#onReady) {
        this.#onReady();
        this.#onReady = undefined;
      }
    };

// Wrap the update in a debounced function


confirmHeight(_i: number, heightGetter: THeightGetter) {
    let i = _i;
    if (i > this.lastI) {
      this.calcHeights(i, heightGetter);
      return;
    }
    const h = heightGetter(i);
    if (h === this.heights[i]) {
      return;
    }
    const chg = h - this.heights[i];
    this.heights[i] = h;
    // shift the y positions by `chg` for all known y positions
    while (++i <= this.lastI) {
      this.ys[i] += chg;
    }
    if (this.ys[this.lastI + 1] != null) {
      this.ys[this.lastI + 1] += chg;
    }
  }

/**
   * Get the latest height for index `_i`. If it's in new terretory
   * (_i > lastI), find the heights (and y-values) leading up to it. If it's in
   * known territory (_i <= lastI) and the height is different than what is
   * known, recalculate subsequent y values, but don't confirm the heights of
   * those items, just update based on the difference.
   */


get transformer_(): Promise<any> {
    if (this._isDisposed) {
      throw new Error(
        'This TransformedTargetRegressor instance has already been disposed'
      )
    }

    if (!this._isInitialized) {
      throw new Error(
        'TransformedTargetRegressor must call init() before accessing transformer_'
      )
    }

    return (async () => {
      // invoke accessor
      await this._py
        .ex`attr_TransformedTargetRegressor_transformer_ = bridgeTransformedTargetRegressor[${this.id}].transformer_`

      // convert the result from python to node.js
      return this
        ._py`attr_TransformedTargetRegressor_transformer_.tolist() if hasattr(attr_TransformedTargetRegressor_transformer_, 'tolist') else attr_TransformedTargetRegressor_transformer_`
    })()
  }

/**
    Transformer used in [`fit`](https://scikit-learn.org/stable/modules/generated/#sklearn.compose.TransformedTargetRegressor.fit "sklearn.compose.TransformedTargetRegressor.fit") and [`predict`](https://scikit-learn.org/stable/modules/generated/#sklearn.compose.TransformedTargetRegressor.predict "sklearn.compose.TransformedTargetRegressor.predict").
   */


async mahalanobis(opts: {
    /**
      The observations, the Mahalanobis distances of the which we compute. Observations are assumed to be drawn from the same distribution than the data used in fit.
     */
    X?: ArrayLike[]
  }): Promise<NDArray> {
    if (this._isDisposed) {
      throw new Error(
        'This EllipticEnvelope instance has already been disposed'
      )
    }

    if (!this._isInitialized) {
      throw new Error('EllipticEnvelope must call init() before mahalanobis()')
    }

    // set up method params
    await this._py
      .ex`pms_EllipticEnvelope_mahalanobis = {'X': np.array(${opts['X'] ?? undefined}) if ${opts['X'] !== undefined} else None}

pms_EllipticEnvelope_mahalanobis = {k: v for k, v in pms_EllipticEnvelope_mahalanobis.items() if v is not None}`

    // invoke method
    await this._py
      .ex`res_EllipticEnvelope_mahalanobis = bridgeEllipticEnvelope[${this.id}].mahalanobis(**pms_EllipticEnvelope_mahalanobis)`

    // convert the result from python to node.js
    return this
      ._py`res_EllipticEnvelope_mahalanobis.tolist() if hasattr(res_EllipticEnvelope_mahalanobis, 'tolist') else res_EllipticEnvelope_mahalanobis`
  }

/**
    Compute the squared Mahalanobis distances of given observations.
   */


async score(opts: {
    /**
      Test data of which we compute the likelihood, where `n_samples` is the number of samples and `n_features` is the number of features. `X_test` is assumed to be drawn from the same distribution than the data used in fit (including centering).
     */
    X_test?: ArrayLike[]

    /**
      Not used, present for API consistency by convention.
     */
    y?: any
  }): Promise<number> {
    if (this._isDisposed) {
      throw new Error(
        'This GraphicalLassoCV instance has already been disposed'
      )
    }

    if (!this._isInitialized) {
      throw new Error('GraphicalLassoCV must call init() before score()')
    }

    // set up method params
    await this._py
      .ex`pms_GraphicalLassoCV_score = {'X_test': np.array(${opts['X_test'] ?? undefined}) if ${opts['X_test'] !== undefined} else None, 'y': ${opts['y'] ?? undefined}}

pms_GraphicalLassoCV_score = {k: v for k, v in pms_GraphicalLassoCV_score.items() if v is not None}`

    // invoke method
    await this._py
      .ex`res_GraphicalLassoCV_score = bridgeGraphicalLassoCV[${this.id}].score(**pms_GraphicalLassoCV_score)`

    // convert the result from python to node.js
    return this
      ._py`res_GraphicalLassoCV_score.tolist() if hasattr(res_GraphicalLassoCV_score, 'tolist') else res_GraphicalLassoCV_score`
  }

/**
    Compute the log-likelihood of `X_test` under the estimated Gaussian model.

    The Gaussian model is defined by its mean and covariance matrix which are represented respectively by `self.location_` and `self.covariance_`.
   */


async get_precision(opts: {
    /**
      The precision matrix associated to the current covariance object.
     */
    precision_?: ArrayLike[]
  }): Promise<any> {
    if (this._isDisposed) {
      throw new Error('This MinCovDet instance has already been disposed')
    }

    if (!this._isInitialized) {
      throw new Error('MinCovDet must call init() before get_precision()')
    }

    // set up method params
    await this._py
      .ex`pms_MinCovDet_get_precision = {'precision_': np.array(${opts['precision_'] ?? undefined}) if ${opts['precision_'] !== undefined} else None}

pms_MinCovDet_get_precision = {k: v for k, v in pms_MinCovDet_get_precision.items() if v is not None}`

    // invoke method
    await this._py
      .ex`res_MinCovDet_get_precision = bridgeMinCovDet[${this.id}].get_precision(**pms_MinCovDet_get_precision)`

    // convert the result from python to node.js
    return this
      ._py`res_MinCovDet_get_precision.tolist() if hasattr(res_MinCovDet_get_precision, 'tolist') else res_MinCovDet_get_precision`
  }

/**
    Getter for the precision matrix.
   */


get location_(): Promise<NDArray> {
    if (this._isDisposed) {
      throw new Error(
        'This ShrunkCovariance instance has already been disposed'
      )
    }

    if (!this._isInitialized) {
      throw new Error(
        'ShrunkCovariance must call init() before accessing location_'
      )
    }

    return (async () => {
      // invoke accessor
      await this._py
        .ex`attr_ShrunkCovariance_location_ = bridgeShrunkCovariance[${this.id}].location_`

      // convert the result from python to node.js
      return this
        ._py`attr_ShrunkCovariance_location_.tolist() if hasattr(attr_ShrunkCovariance_location_, 'tolist') else attr_ShrunkCovariance_location_`
    })()
  }

/**
    Estimated location, i.e. the estimated mean.
   */


get n_components_(): Promise<number> {
    if (this._isDisposed) {
      throw new Error('This IncrementalPCA instance has already been disposed')
    }

    if (!this._isInitialized) {
      throw new Error(
        'IncrementalPCA must call init() before accessing n_components_'
      )
    }

    return (async () => {
      // invoke accessor
      await this._py
        .ex`attr_IncrementalPCA_n_components_ = bridgeIncrementalPCA[${this.id}].n_components_`

      // convert the result from python to node.js
      return this
        ._py`attr_IncrementalPCA_n_components_.tolist() if hasattr(attr_IncrementalPCA_n_components_, 'tolist') else attr_IncrementalPCA_n_components_`
    })()
  }

/**
    The estimated number of components. Relevant when `n_components=None`.
   */


get classes_(): Promise<NDArray> {
    if (this._isDisposed) {
      throw new Error('This DummyClassifier instance has already been disposed')
    }

    if (!this._isInitialized) {
      throw new Error(
        'DummyClassifier must call init() before accessing classes_'
      )
    }

    return (async () => {
      // invoke accessor
      await this._py
        .ex`attr_DummyClassifier_classes_ = bridgeDummyClassifier[${this.id}].classes_`

      // convert the result from python to node.js
      return this
        ._py`attr_DummyClassifier_classes_.tolist() if hasattr(attr_DummyClassifier_classes_, 'tolist') else attr_DummyClassifier_classes_`
    })()
  }

/**
    Unique class labels observed in `y`. For multi-output classification problems, this attribute is a list of arrays as each output has an independent set of possible classes.
   */