text: #  MIT License
  #
  #  Copyright (c) 2020 Richard Mah (richard@geometrylabs.io) & Geometry Labs (geometrylabs.io)
  #
  #  Permission is hereby granted, free of charge, to any person obtaining a copy of
  #  this software and associated documentation files (the "Software"), to deal in
  #  the Software without restriction, including without limitation the rights to
  #  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  #  the Software, and to permit persons to whom the Software is furnished to do so,
  #  subject to the following conditions:
  #
  #  The above copyright notice and this permission notice shall be included in all
  #  copies or substantial portions of the Software.
  #
  #  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  #  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  #  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  #  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  #  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  #  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  
  import itertools
  
  from iconetl.misc.retriable_value_error import RetriableValueError
  from iconetl.misc.unfinalized_block_value_error import UnfinalizedBlockValueError
  
  
  def hex_to_dec(hex_string):
      if hex_string is None:
          return None
      if isinstance(hex_string, int):
          return hex_string
      try:
          return int(hex_string, 16)
      except ValueError:
          print("Not a hex string %s" % hex_string)
          return hex_string
  
  
  def dec_to_hex(dec_int):
      if dec_int is None:
          return None
      if isinstance(dec_int, str):
          return dec_int
      try:
          return hex(dec_int)
      except TypeError:
          print("Not a number %s" % dec_int)
          return dec_int
  
  
  def to_normalized_address(address):
      if address is None or not isinstance(address, str):
          return address
      return address.lower()
  
  
  def fix_tx_hash(hash):
      if hash[0:2] != "0x":
          return "0x" + hash
      return hash
  
  
  def validate_range(range_start_incl, range_end_incl):
      if range_start_incl < 0 or range_end_incl < 0:
          raise ValueError("range_start and range_end must be greater or equal to 0")
  
      if range_end_incl < range_start_incl:
          raise ValueError("range_end must be greater or equal to range_start")
  
  
  def rpc_response_batch_to_results(response):
      for response_item in response:
          yield rpc_response_to_result(response_item)
  
  
  def rpc_response_to_result(response):
      result = response.get("result")
      if result is None:
          error_message = "result is None in response {}.".format(response)
          if response.get("error") is None:
              error_message = error_message + " Make sure node is synced."
              raise RetriableValueError(error_message)
          elif response.get("error") is not None and is_unfinalized_block_error(
              response.get("error").get("code")
          ):
              raise UnfinalizedBlockValueError(error_message)
          elif response.get("error") is not None and is_retriable_error(
              response.get("error").get("code")
          ):
              raise RetriableValueError(error_message)
          raise ValueError(error_message)
      return result
  
  
  def is_unfinalized_block_error(error_code):
      if error_code is None:
          return False
  
      if not isinstance(error_code, int):
          return False
  
      if error_code == -31003:
          return True
  
      return False
  
  
  def is_retriable_error(error_code):
      if error_code is None:
          return False
  
      if not isinstance(error_code, int):
          return False
  
      if error_code == -32603 or (-32000 >= error_code >= -32099):
          return True
  
      return False
  
  
  def pairwise(iterable):
      """s -> (s0,s1), (s1,s2), (s2, s3), ..."""
      a, b = itertools.tee(iterable)
      next(b, None)
      return zip(a, b)
  