# -*- coding: utf-8 -*-
"""
UtilPlot.py
ユーティリティモジュール

History by Y.Inamura
[inamura 170126] changed to send "map-format" data to M2Plot (for VisualContQ)
                 - add a new argument about file name extention to TempFile::GetTempName
[inamura 120512] add marker face status "fill" or "none"
[inamura 110303] add header info for CalcDspacing.
[inamura 110223] save and load default attribute value of FastPlot
"""
from wx import xrc

from matplotlib import __version__ as version
import sys,traceback,codecs,time
#sys.path.append("c:\\mlf\\1029") 
#sys.path.append("c:\source\\DataAcq\\src") 
import wx
import cStringIO, zlib
import os
import cPickle as pickle
import os.path
import tempfile

from xml.dom.minidom import parse

try:
    from Manyo import *
    import Manyo.MLF    
    MASKVALUE = Manyo.MLF.MLF_MASKVALUE
except:
    MASKVALUE = 1.0E15
    pass

# リソースファイル名称定義 
RESOURCEFILE = "FastVisualize"

# メッセージファイル名称定義
MESSAGEFILE = "Message.xml"
# マスク値定義
#MASKVALUE = 100000000.0
#MASKVALUE = 1.0E15

#######################################
#  IFEvtProp
#######################################  
class IFEvtProp(object):
    """
    イベントとプロパティ授受用のインターフェイスクラス
    """    

    dicInstance = {}
    
    #########################################
    def __new__(cls, idno=0):

        """
        idno 毎に異なるインスタンスを返すコンストラクタ
        (同一グループ間では共通のインスタンスを使用)
        @param  cls 　クラス
        @param  idno  グループID 
          　　　プロッタ番号をIDとして使用
        @retval クラスのインスタンス
        """ 

        # 指定されたID のクラスインスタンスが生成済みなら
        if cls.dicInstance.has_key(idno):
            # 生成済みのインスタンスを返す
            instance = cls.dicInstance[idno]
        else:    
            #クラスインスタンスが未生成なら新規に構築
            instance = object.__new__(cls)
        
        return instance 

    #########################################
    def __init__(self, idno=0):

        """
        インターフェイスクラスのコンストラクタ
        @param  idno  グループID 
        @retval クラスのインスタンス
        """ 
        # クラスインスタンスが登録済みなら
        if self.dicInstance.has_key(idno):
            # 何もしない
            return
        
        # クラスインスタンスを登録
        self.dicInstance[idno] = self
        
        # 登録リストを初期化
        self.InitIF()


    #########################################   
    def InitIF(self):
        """
        リスナーリストとプロパティディクショナリの初期化
        @param  無し
        @retval 無し
        """                 
        # リスナーリストの初期化
        self.listner = []
        # プロパティディクショナリの初期化
        self.property = {}
    
    #########################################   
    def AddListner(self, evtType, func):
        """
        イベントに対するリスナー登録追加
        @param  evtType  イベントタイプ(文字列)
        @param  func     イベント発生時に実行する関数
        @retval 無し
        """         
        # イベント発生時に実行する関数を登録 
        self.listner.append((evtType, func))
        
    #########################################    
    def AddProperty(self, propKey, func):
        """
        公開するプロパティを登録
        @param  propKey  属性名称(文字列)
        @param  func     プロパティが要求されたときに実行する関数(ラムダ式)
        @retval 無し
        """         
        # プロパティを返すラムダ式を登録 
        self.property[propKey] = func
         
    #########################################    
    def NotifyEvent(self, wid, evtType, value=None):
        """
        イベントに登録されている関数を実行
        (同一イベントに複数登録されている場合は、順番にすべて実行)
        @param  wid      イベント発生元のインスタンス
        @param  evtType  発生したイベントのタイプ(文字列)
        @param  value    イベントの値(省略可)
        @retval 無し
        """         
        # リスナーリストから、イベントに登録されているものを探す
        for listner in self.listner:
            evt, func = listner
            # イベントタイプが一致したなら
            if evt == evtType:
                # イベントに登録されている関数を全て実行
                apply(func, (wid,evtType,value)) 
                
    #########################################                            
    def GetProperty(self, propKey):
        """
        プロパティ取得
        @param  propKey  属性名称(文字列)
        @retval プロパティ
        """ 
        retval = None                
        # プロパティのkey から lambda 式を取得        
        try:
            try:
                func = self.property[propKey]
            except:
                raise PlotException('Common','C001',("Key error:"+propKey,"IFEvtProp:GetProperty"))
            else:
                # プロパティを取得(lambda 式実行)
                try:
                    retval = func()
                except:
                    raise PlotException('Common','C001',("Lambda execution","IFEvtProp:GetProperty"))
        except PlotException, ex:
            PlotMessage(None,ex)
       
        return retval
    

    
#######################################
#  Validator
#######################################         
class Validator(object):
    """
    入力値チェッククラス
    """
    #######################################
    def __init__(self, frame):
        """
        コンストラクタ
        @param  frame エラーメッセージ表示時の親ウィンドウ
        　      None の場合は、標準出力に表示  
        @retval 無
        """
        self.window = frame
    
    #######################################################
    def ValidateInteger(self, value, item, min=None, max=None):
        """
        整数の範囲チェック
        @param  Value 確認対象の数値
        @param  item エラーメッセージに入れる項目名(文字列)
        @param  min  最小値、None の場合は規定無し
        @param  max  最大値、None の場合は規定無し  
        @retval 評価結果　　True : OK,  False: NG
        """
        try:
            try:
                # 整数変換可能か
                num = int(value)
            except:
                raise PlotException('Common','C026',(item ,  ))
            # 範囲指定無しか
            if min == None and max == None:
                return True
            # 最小値と最大値が共に指定されているか
            elif min != None and max != None:
                # 範囲内か
                if num >= min and num <= max:
                    return True
                else:
                    strR0 = "%d" % min
                    strR1 = "%d" % max
                    raise PlotException('Common','C008',(item , strR0, strR1 ))
            # 最小値だけが指定されているか    
            elif min != None:    
                # 最小値より大きいか
                if num >= min:
                    return True
                else:
                    strR0 = "%d" % min
                    raise PlotException('Common','C010',(item , strR0))
            # 最大値だけが指定されているか
            elif max != None:
                # 最大値より小さいか
                if num <= max:
                    return True
                else:
                    strR1 = "%d" % max
                    raise PlotException('Common','C012',(item , strR1))
 
        except PlotException, ex:
             PlotMessage(self.window,ex)
             return False
        return True 
    
    #######################################################
    def ValidateNumeric(self, value, item, min=None, max=None):
        """
        実数の範囲チェック
        @param  value 確認対象の数値
        @param  item エラーメッセージに入れる項目名(文字列)
        @param  min  最小値、None の場合は規定無し
        @param  max  最大値、None の場合は規定無し  
        @retval 評価結果　　True : OK,  False: NG
        """
        try:
            try:
                # 数値に変換可能か
                num = float(value)
            except:
                raise PlotException('Common','C027',(item ,  ))
            # 範囲指定無しか
            if min == None and max == None:
                return True
            # 最小値と最大値が共に指定されているか
            elif min != None and max != None:
                # 範囲内か
                if num >= min and num <= max:
                    return True
                else:
                    strR0 = "%.3f" % min
                    strR1 = "%.3f" % max
                    raise PlotException('Common','C008',(item , strR0, strR1 )) 
            # 最小値だけが指定されているのか       
            elif min != None:
                # 最小値より大きいか
                if num >= min:
                    return True
                else:
                    strR0 = "%.3f" % min
                    raise PlotException('Common','C010',(item , strR0))
            # 最大値だけが指定されているのか
            elif max != None:
                # 最大値より小さいか
                if num <= max:
                    return True
                else:
                    strR1 = "%.3f" % max
                    raise PlotException('Common','C012',(item , strR1))
 
        except PlotException, ex:
             PlotMessage(self.window,ex)
             return False
        return True 
    
    #######################################################
    def ValidateString(self, string, item, min=None, Max=None):
        """
        文字列の入力チェック
        @param  string 確認対象の文字列
        @param  item 　エラーメッセージに入れる項目名(文字列)
        @param  min  　最小キャラクタ、None の場合は規定無し
        @param  max  　最大キャラクタ数、None の場合は規定無し  
        @retval 評価結果　　True : OK,  False: NG
        """
        try:
            try:
                # ASCII 文字列か
                unicode(string)
            except:
                raise PlotException('Common','C025',(item ,  ))
            # 範囲指定無しか
            if min == None and max == None:
                return True
            if min != None:
                # 最小値より小さいか
                if len(string) < min:
                    strR0 = "%d" % min
                    raise PlotException('Common','C009',(item , strR0))
            if max != None:
                # 最大値より小さいか
                if len(string) <= max:
                    return True
                else:
                    strR1 = "%d" % max
                    raise PlotException('Common','C012',(item , strR1))
            return True    
        except PlotException, ex:
             PlotMessage(self.window,ex)
             return False
        return True
    
    #######################################################
    def ValidateBoolean(self,value, item):
        """
        ブーリアン値の入力チェック
        @param  value  確認対象
        @param  item 　エラーメッセージに入れる項目名(文字列)
        @retval 評価結果　　True : OK,  False: NG
        """
        try:
            # True または False か
            if value == True or value == False:
                return True
            else:
                raise PlotException('Common','C028',(item , ))
        except PlotException, ex:
             PlotMessage(self.window,ex)
             return False
        return True 

    #######################################################
    def ValidateObject(self, object, item):
        """
        オブジェクトの入力チェック
        @param  object  確認対象
        @param  item 　エラーメッセージに入れる項目名(文字列)
        @retval 評価結果　　True : OK,  False: NG
        """
        try:
            # 指定されているか
            if object == None:
                raise PlotException('Common','C029',(item ,  ))
        except PlotException, ex:
             PlotMessage(self.window,ex)
             return False
        return True
  

#######################################
#  TraceAtt
#######################################  
class TraceAtt(object):
    """
    トレースの属性クラス
    """
    # 線種
    linestyle = ['-', ':','--', '-.','']
    # 線幅
    #linewidth = [0.5, 0.6,0.7, 0.8, 1.0, 1.2,1.5, 1.7,2.0,2.5]
    linewidth = [0.5,0.6,0.7,0.8,1.0,1.2,1.5,1.7,2.0,2.5,3.0,3.6,4.4,5.2,6.4,7.6,9.0,11.0,14.0,16.0]
    # 色
    color = ['*','b', 'g', 'r', 'c', 'm', 'y', 'k']
    # マーカの種類
    marker = ['', '.','o','s','v','d','+','x']
    # マーカサイズ
    #msize = [2.0, 2.8, 3.5, 4.0, 4.3,4.7,5.1,5.7, 6.4,7.0]
    msize = [2.0,2.4,2.8,3.3,3.8,4.4,5.0,5.6,6.2,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.5,16.0,18.0,20.0]
    # キャップサイズ
    csize = [0.5, 0.7, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0,5.0]
    # marker face status [inamura 120512]
    mface = ['fill','none']
    # デフォルトプロット属性
    #defaultTraceAttr = {"ls":"-","hs":0, "lw":5,"lc":"*","mk":"","ms":5,"mc":"*","eb":0,"es":5,"ec":"*"}
    ## New Default: no line, circle mark with error bar. [inamura 100819]
    #defaultTraceAttr = {"ls":"","hs":0, "lw":5,"lc":"*","mk":"o","ms":5,"mc":"*","eb":1,"es":5,"ec":"*"}
    ## New Default: added marker face option "fill" or "none" [inamura 120512]
    defaultTraceAttr = {"ls":"","hs":0, "lw":5,"lc":"*","mk":"o","ms":5,"mc":"*","eb":1,"es":5,"ec":"*","mf":"fill"}
    # 属性とデータ型
    attrType = {'autox':3,'autoy':3,
              'x0':2,'x1':2, 'y0':2,'y1':2,
              'overlay':3,
              'offsetx':1, 'offsety':1,
              'log':3,
              'tracenum':1,
              'page':1,
              'title1':0, 'title2':0,
              'xlabel':0, 'ylabel':0,
              'datanum':1,
              'traceattrs':4}

#######################################
#    Default of FastPlot Attributes
#    [inamura 120131]
#######################################
class DefaultFastPlotAtt(object):
    """
    Keep Default Attributes for FastPlot
    """
    def __init__(self):
        self.FileName = ".fastplotdefault.ini"
        self.HomeDir = os.environ["UTSUSEMI_USR_PRIV_HOME"]
        self.TraceAttKeys = TraceAtt().defaultTraceAttr.keys()
        self.DialogPathKeys = ["OPENPATH","SAVEPATH"]
        
        if os.path.exists( os.path.join(self.HomeDir,"ana","xml")):
            self.Path = os.path.join(self.HomeDir,"ana","xml",self.FileName)
        else:
            self.Path = os.path.join(self.HomeDir,self.FileName)
        if not os.path.exists( self.Path ):
            print "Make new initial file."
            Tattr = TraceAtt().defaultTraceAttr.copy()
            for key in self.DialogPathKeys:
                Tattr[key] = self.HomeDir
            self._save( Tattr )
        
    def _save( self, attrs ):
        try:
            fd = open( self.Path, "w" )
        except:
            print "Cannot open",self.Path
            raise "FileIOError",""
        pickle.dump(attrs,fd)
        fd.close()
    
    def _load( self ):
        try:
            fd = open( self.Path, "r" )
        except:
            print "Cannot open",self.Path
            return None
        #[inamura 151109]-->
        #ret = pickle.load(fd)
        try:
            ret = pickle.load(fd)
        except:
            ret = TraceAtt().defaultTraceAttr.copy()
        #<--[inamura 151109]
        fd.close()
        return ret
    
    def savePlotAtt(self,trace_att):
        load_dic = self._load()
        for key in trace_att.keys():
            load_dic[key] = trace_att[key]
        self._save( load_dic )

    def loadPlotAtt(self):
        load_dic = self._load()
        ret = TraceAtt().defaultTraceAttr.copy()  #[inamura 120514]
        for key in load_dic.keys():
            if not key in self.DialogPathKeys:
                ret[key] = load_dic[key]
        return ret
    
    def loadPath( self ):
        load_dic = self._load()
        ret = {}
        for key in self.DialogPathKeys:
            if load_dic.has_key( key ):
                ret[ key ] = load_dic[ key ]
            else:
                ret[ key ] = self.HomeDir
        
        return ret

    def savePath( self, key, path ):
        if not key in self.DialogPathKeys:
            return
        load_dic = self._load()
        load_dic[key] = path
        self._save( load_dic )
        
            
#######################################
#  VerHandleMatPlot
#######################################  
class VerHandlePlotLib(object):
    """
    matplotlib のバージョンの違いを吸収する     
    """
    ###################################################    
    def __init__(self):
        """
        コンストラクタ、matplotlib のバージョンを取得
        """
        # matplotlib のバージョン取得
        vers = version.split('.')
        self.verNo = int(vers[0])*1000 + int(vers[1])*10 + int(vers[0])
        
    ###################################################        
    def IfVerUp(self, ver):
        """
        テンポラリファイルの名称を取得
        (モジュール tempfile を使用してファイル名を取得すると、
        消せなくなるため、自分でファイル名を作成)
        @param  (int) バージョン番号　
        　　　　　　　0.90.0 以上であれば、900
                      1.01.1 以上であれば　1011
        @retval True : 指定されたバージョン以上
        　　　　False: 指定されたバージョン未満
        """  
        if self.verNo >= ver:
            return True
        else:
            return False
        
    ###################################################        
    def GetSubPlotPos(self, sbplot):
        """
        サブプロッタの位置情報取得
        @param  sbplot subplot(0.98未満)トまたは AxisPlot (0.98 以上)
        　　　　       のインスタンス
        @retval [x0, x1, x, y] のリスト
        """ 
        if self.IfVerUp(980):
            pos = sbplot.get_position()  
            posp = pos.get_points() 
            return [posp[0,0], posp[0,1], posp[1,0]-posp[0,0], posp[1,1]-posp[0,1]]
        else:
            return sbplot.get_position()
        
#######################################
#  MakeTempFile
#######################################  
class TempFile(object):
    """
    テンポラリファイルクラス     
    """
    ###################################################        
    def GetTempName(self,ext=""): ##[inamura 170126]
        """
        テンポラリファイルの名称を取得
        (モジュール tempfile を使用してファイル名を取得すると、
        消せなくなるため、自分でファイル名を作成)
        @param  無し
        @retval テンポラリファイル名称(フルパス)
                 名称取得に失敗した場合は、None を返す
        """ 
        # 現在の絶対時間(0.01秒単位)と、プロッタ番号よりテンポラリファイル名を作成
        tsec = int(time.time()*100.0)
        #tmpf = "tmp%d" % tsec
        tmpf = "tmp%d%s" %(tsec,ext) ##[inamura 170126]
        # テンポラリファイルの絶対パスを作成(指定されたテンポラリディレクトリの下)
        tmppath = os.path.join(tempfile.gettempdir(), tmpf)

    
        # テンポラリファイルの存在チェック
        for i in range(100):
            # 万一同じファイル名があったら、ファイル名を変更
            if os.path.exists(tmppath):
                #tmppath = "%s%d" % (tmppath, i)
                tmppath = "%s%d%s" % (tmppath, i, ext) ##[inamura 170126]
            else:
                # 無ければOK
                break
            if i == 99:
                return None
        
        return tmppath
    
    ###################################################        
    def MakeTempFile(self, object, temppath):
        """
        Python オブジェクトをシリアライズして
        テンポラリファイルに書き込む
        @param  object    シリアライズするオブジェクト
        @param  temppath  シリアライズしたオブジェクトを書きこむファイル
        @retval  0: 成功、1: テンポラリファイルオープン失敗、2: シリアライズ失敗
        """
        try:
            # テンポラリファイルを開く    
            fw = file(temppath,"wb")
        except:
            return 1
        try:
            # オブジェクトをバイナリモードでシリアライズ
            pickle.dump( object, fw, True )
        except:
            # テンポラリファイルをクローズ
            fw.close()
            return 2
        # テンポラリファイルをクローズ
        fw.close()
        # 正常終了
        return 0
                
    ###################################################        
    def ReadTempFile(self, temppath):
        """
        テンポラリファイルを読み込み、デシリアライズかる。
        @param  temppath  シリアライズしたオブジェクトを書きこんだファイル
        @retval  デシリアライズしたデータ、デシリアライズ失敗時は None
        """
        try: 
            # テンポラリファイルを読み込む
            fr = file(temppath,"rb")
            # データを復元(デシリアライズ)
            data = pickle.load(fr)
        except:
            return None
        # テンポラリファイルをクローズ
        fr.close()
        # テンポラリファイルを削除
        os.remove(temppath)
        # デシリアライズしたオブジェクトを返す
        return data

#######################################
#  AcqPath
#######################################  
class AcqPath(object):
    """
    ディレクトリパス取得ユーティリティ
    """
    ###########################################################################
    def GetHome(self):
        """
        ユーザホームディレクトリ取得
        @param    無し
        @retval   ディレクトリのパス (string)
        """ 
        # ユーザのホームディレクトリを取得
        try:
            home = os.environ['UTSUSEMI_USR_PRIV_HOME']
        except:
            # Windows 上で環境変数を設定していない場合はカレントディレクトリとする
            home = os.getcwd()

        return home
    
    ###########################################################################
    def GetHomeExp(self):
        """
        ユーザホームディレクトリ下の exp パスを取得
        @param    無し
        @retval   ディレクトリのパス (string)
        """ 
        # ユーザのホームディレクトリを取得
        home = self.GetHome()
        return os.path.join(home, 'exp')
    
    ###########################################################################
    def GetPrmPath(self):
        """
        ユーザパラメータのパスを取得
        格納場所はホームディレクトリ下の　exp/xml
        @param    無し
        @retval   パラメータディレクトリのパス
        """
        # ホーム下のexpを取得
        exp = self.GetHomeExp()
        return os.path.join(exp, 'xml')
    
    ###########################################################################
    def GetCurrentMth(self):
        """
        カレントメソッドのパスを取得
        @param    無し
        @retval   カレントファイルのパス (string)
        """ 
        # ユーザのホームディレクトリを取得
        exp = self.GetHomeExp()
        return os.path.join(exp, CURRENT_FILE)
    
    ###########################################################################
    def GetSysExp(self):
        """
        システムディレクトリ下のexpパスを取得
        格納場所はファイルサーバ
        @param    無し
        @retval   システムディレクトリ下のexpパス
        """
        # システムディレクトリを取得
        try:
            sysd = os.environ["UTSUSEMI_BASE_DIR"]
        except:
            if os.name == "nt":
                sysd = 'c:\\mlf'
            else:
                sysd = '/usr/local/mlf'
            
        return os.path.join(sysd, 'exp')
    
    ###########################################################################
    def GetSysAnal(self):
        """
        システムディレクトリ下のanalパスを取得
        格納場所はファイルサーバ
        @param    無し
        @retval   システムディレクトリ下の anal パス
        """
        # システムディレクトリを取得
        try:
            sysd = os.environ["UTSUSEMI_BASE_DIR"]
        except:
            if os.name == "nt":
                sysd = 'c:\\mlf'

            else:
                sysd = '/usr/local/mlf'
            
        return os.path.join(sysd, 'ana')
    
    ###########################################################################
    def GetSysVis(self):
        """
        システムディレクトリ下のvisパスを取得
        格納場所はファイルサーバ
        @param    無し
        @retval   システムディレクトリ下の vis パス
        """
        # システムディレクトリを取得
        try:
            sysd = os.environ["UTSUSEMI_BASE_DIR"]
        except:
            if os.name == "nt":
                sysd = 'c:\\mlf'
               
            else:
                sysd = '/usr/local/mlf'
            
        return os.path.join(sysd, 'vis')
    
    ###########################################################################
    def GetDefaultMth(self):
        """
        デフォルトメソッドファイルのパス取得
        ベースディレクトリ下の　exp/xml
        @param    無し
        @retval   ディレクトリのパス (string)
        """ 
        # ベースディレクトリを取得
        base = os.environ["UTSUSEMI_BASE_DIR"]
        if base == None:
            if os.name == "nt":
                base = 'c:\\mlf'
            else:
                base = '/usr/local/mlf'
                
        sysName = os.environ["UTSUSEMI_SYS_NAME"]
        if sysName == None:
            sysName = "AMR"
            
        path = os.path.join(base, sysName)
        path = os.path.join(path, 'exp')
        path = os.path.join(path, 'xml')
        return os.path.join(path, DEFAULT_FILE)
    
    ###########################################################################
    def GetPmtPath(self, flag):
        """
        PMTファイルのパス取得
        ベースディレクトリ下の　ana/xml
        @param    flag  測定フラグ
        @retval   ディレクトリのパス (string)
        """ 
        # ベースディレクトリを取得
        try:
            #base = os.environ["UTSUSEMI_USR_DIR"]  ##[okazaki, inamura 140310]
            base = os.environ.get("UTSUSEMI_USR_PRIV_HOME", None) \
                   or os.enviton["UTSUSEMI_USR_DIR"]
        except:
            if os.name == "nt":
                base = 'c:\\mlf'
            else:
                base = '/usr/local/mlf'
        if flag:
            path = os.path.join(base, 'exp')
        else:
            path = os.path.join(base, 'ana')

        # ディレクトリがあるか
        ##[okazaki, inamura 140310]-->
        #if not os.path.isdir(path):
        #    os.mkdir(path)
        ## PMT用ディレクトリがあるか
        #ppath = os.path.join(path,'pmt')
        #if not os.path.isdir(ppath):
        #    os.mkdir(ppath)
        #return ppath
        try:
            if not os.path.isdir(path):
                os.mkdir(path)
            # PMT用ディレクトリがあるか
            pmtpath = os.path.join(path,'pmt')
            if not os.path.isdir(pmtpath):
                os.mkdir(pmtpath)
        except:
            #pmtpath = os.environ["HOME"]
            pmtpath = os.getcwd()
        return pmtpath
        ##<--[okazaki, inamura 140310]

    
    #########################################
    def GetModulePath(self, module):
        """
        モジュールパスの探索
        @param  module  　ファイル名
        @retval モジュールのフルパス
        """ 
        # カレントディレクトリを取得
        path = os.getcwd()
        fpath = os.path.join(path, module)
        # カレントディレクトリに目的ファイルがあるか
        if os.path.isfile(fpath):
            # フルパスを返す
            return fpath

        # 環境変数に指定されたディレクトリを取得
        paths = [self.GetSysExp(), self.GetSysAnal(), self.GetSysVis()]
        # 全PYTHONPATHディレクトリを探索
        for path in paths:
            fpath = os.path.normpath(os.path.join(path,module))
            # ディレクトリに目的ファイルがあるか
            if os.path.isfile(fpath):
                # フルパスを返す
                return fpath
        
        # 目的ファイルが見つからなかった
        return None
    

#######################################
#  ConvertEC
#######################################  
class ConvertEC(object):
    """
    エレメントコンテナ変換クラス
    Manyo-Lib のエレメントコンテナを、FastPlot 用のデータに
    変換する。
    """
    ###################################################        
    def ConvertEC(self, ec):
        """
        エレメントコンテナ変換
        @param  ec  エレメントコンテナのインスタンス
        @retval x, y, er のアレイ、x軸単位、Y軸単位、ヘッダーディクショナリのタプル
        　　　　変換できなかった場合は、None を返す
        """ 
        try:
            # X値リストを取得
            xx = ec.PutXList()
            ##[inamura 110303]-->
            if ec.PutHeader().CheckKey("Xkey")==0:
                ec.AddToHeader("Xkey", ec.PutXKey())
            else:
                ec.PutHeaderPointer().OverWrite("Xkey",ec.PutXKey())
            ##<--[inamura 110303]
            # Y値リストを取得

            yy = ec.PutYList()   
        except:
            # Manyo-Lib ではない?
            try:
                ec[1][1]
            except:
                # プロット可能なデータではない
                return None
            else:
                # プロット可能なデータなら、元データをそのまま返す
                return ec

        try:
            # エラーリストを取得
            er = ec.PutEList()
        except:
            # エラー無しのヒストグラム
            er = None        
        
        # ヘッダーディクショナリ作成
        header = self._MakeHeaderDic(ec) 
        
        # X label and Y label setting [inamura 160325]
        xlabel="X"
        ylabel="Y"
        if header.has_key("XLabel"):
            xlabel = header["XLabel"]
        if header.has_key("YLabel"):
            ylabel = header["YLabel"]
        #<--[inamura 160325]
        # X軸とY軸の単位文字列を取得
        xunit = ""
        yunit = ""
        try:
            xunit = ec.PutUnit(ec.PutXKey())
            yunit = ec.PutUnit(ec.PutYKey())
        except:
            pass
       
        #[inamura 141212]-->
        if (er!=None):
            for i in range(len(yy)):
                if er[i]<0:
                    yy[i]=MASKVALUE
        #[inamura 160325]-->
        if xlabel!="X" or ylabel!="Y":
            xunit = (xlabel,xunit)
            yunit = (ylabel,yunit)
        #<--[inamura 160325]
        
        return [xx,yy,er,header, xunit,yunit]              

    ###################################################        
    def _MakeHeaderDic(self, ec):
        """
        エレメントコンテナ変換
        @param  ec  エレメントコンテナのインスタンス
        @retval ヘッダーディクショナリ
        """ 
        # ヘッダーの辞書を用意
        header = {}
        try:
            # ヘッダーを取得
            ech = ec.PutHeader()
            # ヘッダーストリングを取得
            work = ech.DumpToString()
        except:
            # 空のヘッダーを返す
            return header
        # ヘッダーストリングを '#' 区切りで分解
        strs = work.split('#')

        # 整数型のキーを取得
        if strs[2]!="None":
            intKey = strs[2].split(',')
            i = 0
            # キーの数だけ値を取得し、文字列に変換してディクショナリに格納
            for key in intKey:
                strV = "%d" % ech.PutInt4(i)
                header[key] = strV
                i += 1
            
        # 実数型のキーを取得
        if strs[8]!="None":
            dblKey = strs[8].split(',')
            i = 0
            # キーの数だけ値を取得し、文字列に変換してディクショナリに格納
            for key in dblKey:
                strV = "%.6f" % ech.PutDouble(i)
                header[key] = strV
                i += 1
            
        # 文字列型のキーを取得
        if strs[14]!="None":
            strKey = strs[14].split(',')
            i = 0
            # キーの数だけ値を取得しディクショナリに格納
            for key in strKey:
                header[key] = ech.PutString(i)
                i += 1    

        ##[inamura 091114]->
        # Get Keys of Vector
        index_h = 18
        
        ## Int4Vector
        num = int(strs[index_h])
        if num!=0:
            index_h = index_h +2
            ivKey=strs[index_h].split(',')
            i=0
            for key in ivKey:
                index_h = index_h +2
                if int(strs[index_h])<7:
                    iv = ech.PutInt4Vector(i)
                    str=''
                    for k in range(iv.size()):
                        str=str+("%.3f" % iv[k])
                        if k!=(iv.size()-1):
                            str=str+","
                    header[key] = str

                i=i+1
                index_h = index_h +2
                
        index_h = index_h + 2  ##[inamura 101001] bug fix
        ## DoubleVector
        num = int(strs[index_h])
        if num!=0:
            index_h = index_h +2
            dvKey=strs[index_h].split(',')
            i=0
            for key in dvKey:
                index_h = index_h +2
                if int(strs[index_h])<7:
                    dv = ech.PutDoubleVector(i)
                    str=''
                    for k in range(dv.size()):
                        str=str+("%.3f" % dv[k])
                        if k!=(dv.size()-1):
                            str=str+","
                    header[key] = str

                i=i+1
                index_h = index_h +2
        else:
            index_h = index_h +2
        
        ##<-[inamura 091114]

        return header                

#######################################
#  Images
#######################################  
class Images(object):
    """
    イメージデータクラス
    """
    
    instance = None
    
    #########################################
    def __new__(cls,*args):
        """
        Singletonコンストラクタ
        @param  *args 可変引数(無し)
        @retval クラスのインスタンス
        """
        if cls.instance is None:
            #クラスインスタンスが未生成なら新規に構築
            cls.instance = object.__new__(cls,*args)
        return cls.instance
    
    #########################################
    def GetMainIcon(self):
        """
        アイコンオブジェクトを取得

        @param 　無し

        @retval アイコンオブジェクト


        """
        icon = wx.EmptyIcon()
        icon.CopyFromBitmap(self.GetBmp('MainIcon'))
        return icon
    
    #########################################
    def GetBmp(self, imageName):
        """
        プラットフォーム独立なビットマップを取得
        @param imageName イメージ名称
        @retval ビットマップオブジェクト
        """
        data = zlib.decompress(self.imageData[imageName])
        stream = cStringIO.StringIO(data)
        image = wx.ImageFromStream(stream)
        return wx.BitmapFromImage(image)
    
    # 'Python25\Scripts\img2py -i ***.png **.py' で作成したデータ 
    imageData= {'MainIcon':
'x\xda\x01\x88\x06w\xf9\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\
\x00\x00 \x08\x06\x00\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\
\x08d\x88\x00\x00\x06?IDATX\x85\xad\x97\xdfo\x1cW\x15\xc7?\xf7\xce\xcc\xeex\
\xedu\xec\xf8G\xfcCI\x956q\xc0\x01\x94Rh\x01\x99\xb4\xf0P!!\x10\x7fC\xc5/\
\xc1\x13\xa8<\xa0(\x08\xd1\x02/<\x81\x04/\xf0\x0e/\x80D\xe1\xa1\x08E\xa9R\
\x02"\x95\xd2$UB\xec\xc46\xb6I\xfcs\xb7\xbb\xf6\xce\xce\x8f{\x0f\x0fwv\xd7?b\
\xd7\x89\x18\xe9jw\xe7\xde9\xe7s\xbe\xe7\xdc3w\x95\xd2\x1eOr\xfd\xaa_\x89\
\xcd,\xdf\xae+\xf5D\x06\xf2\xcb\x7f\xd2\x07_~\xe1e\nA\x80w\xe5M\xf9f%yb\x08\
\xf58\n\xfcz\xa0(\xe7&\xce\xb1\xbaQ!K\x12\x00\x04\xe8-\x97I\xcc\x163\x0b\xb3\
|\xab&\x8f\x05sh\x807\xcf>-\xa3\x03\xe3,,.\xe2)\xd5\x96\xce\xe6#\x08CF\x86\
\x87\x98\xbct\xf9\xff\x0b\xf0\xdb\xa7\xc6\xa5T\xe8\xa2h\x0c\xbeR\x04Z\xe3\
\x01^\x9ez#\x02@*\x82\x11!\xd6\x9a\xb0+\xe4\xf37n\x1d\n\xe4@\x80\xdf\x0cuKo\
\xf7 E\xa5\xe8\xf1<4\x10j\x8d\x06\xf4\xae\xb5\xb1\x08\x06\x88\xac%\xb1\x964\
\xf0Y[_\xe0\xeb\xeb\xf1\x81 \x07\x16\xa1\xf2\nt{\x1eE\xa0\xa8\x14A>\xa0\xa3\
\x008\x15B\xa50"X\xa5\xf0\xb5\xc6v\x95h\x94\xca\xb0\x1e\x1f\xe4b\x7f\x80_\
\xf6\x1a)z\x01\x1fz\xf6YL\x14Q\x99\x9enG\xae\x94\xa2\xa5\x9bi\xc1\x88@\x0e\
\xe8\x05\x01\xb1\x086\xb5\x07:?\x10@+M\xe0\x05\xcc]\xbf\x8e\xaf\x14\'\xce\
\x9c!\xec\xebc\xed\x9dwPy\xde\x816\x88\xf2<\xba\x8e\x1d\xa3\xd0hP\xdb\xd8 \
\x89c\n\xde\x07\xef\xf2\xdd\xa9\xdc3\xa9s\'\x95\xe9iV\xdf}\x97\xb1\xf3\xe792\
1\xb1g\xed\xd8\xd4\x14\x85r\x99\xb8Ri\x83\xf9\x87\xd8a\xfb">J<\x9b$<\xb8|\
\x99ph\x88\xd1\x17_l\xdf7I\xc2\xd2[o\xed\\|\xc8\x06y\xa0\x02\xfbA5WW\xdb\xf7\
\xc4Z6n\xde|\x1c3\x87\x04\x10\x8b\xc5U\xb8\xa1\xb3\xdfM>]\x9f\x9f\x07`\xf5\
\xda5\xb2\xcdM7\'B\x96\xafIE\xc8\xb6\xd5\xca\xe3\x03\x00Yn\xd0\x8a\xb4;^\x0b\
"\xaeV\xdd\xf7(j\x03\xb6\x80m>\x8cX\xe6\xfeX\x96\xab\xafO\xecK\xb2/\x80|\xad\
\x87\xc4\x1abk\x89\xad\xa5)B\x9a\x0f#\xc2V\xa5B\\\xab\x91\xe4\xbf\xcd\xb6\
\xf9\xb85\xb2\x84\xa3=U&\x9f\xbf\xcd\xca\xdf\nr\xefw\x03{@\x1e\tp\xe1R(\xf3_\
\x10j\xa35R\x11\x92<\xa2\xed\xce,\x90nm\xedp\x9e\xe4\x8eS\x11\x9a&e\xecS\x9b\
x>x>\x04i\xc4\xd0\xe8\n\xbb\xd5h\xb7\xe2W\xdf\xf0\xa5o\xa4\x8b\xd5Z\x8c\xd2\
\x82\x0e@k(\xce\x08\x83\x7fQ\x9c~{\x84\xc0\xf7)j\xc7\x1c(\xc5\xe0\xc9\x93,\
\xcf\xce\x02\x90ZK&B\xa4\xaa\x8c\xbe\xf4>\x1f\xffj\n\x80\xcd\x8b&\xcb\xc0d\
\x10G`\x05\x16\xef\x8d\xf1\xdcw\x96U{\x1b\xc6\xbe\xe6\xe1F\x13?\x04\xed\x81\
\x17\x80\xd2\x90M*\x1eNB\xe9\xdf\x0f\x19\x99/C_\x1f:\xcfu\xbd^#\xb5\xaeX\xe3\
,\xc3ln\xf2\xc57\xd6P\xdbt\xd58\x87Z\x03\xbe\xfb\x94\x14\n\xc5\x86S\xe0\xbb\
\x7f\x0e\xa5!B\xb1[\xa1\x03\x08B\xe7X\xfbn\x1f\xe7\x01c-(\x81\x91\x9f\n\xc7\
\xfeZ 82\x08\x80\xd7h\x10K\x83\xaf\xfc\xa1\x86\x17\xe4\xb2n\x03\x90\xbcrM\
\xeal$\x99\xc6\x1f,1\x7f\xd5c\xf2\x1b\x9bn\xa9\xf6\x14\xdas\x91+\x9d\x7f*\
\xe7\\\xe5CkP\x1e<\xf8>\xdc\xf8}\x8c\xaaTP\x95\n\xf7?S\xa3\xfc\'\xf7\xfcn\
\xe7{\nNC\xd7\x99\xa3$\xcb\x11\x9e\xefr\xe3g"x\x81\x8b\xfe\xd4\x89Q\x9ai\x93\
\xd5z\x95\xdd]\xb4eX\xa3\xb0\xfd\x8a\xea\xdda\xd6*5\x16\x97"\xc2j\x84\x1a/\
\xa2\x86\xcbPoB-BY\xe3\xdeO\x1a(\x15\xf1\x8f\xf6\x90=\xa8\xd3\xbc\xbd\x06\
\x06|\xdf\xf0\x8f\x9f<-Z\xeb<z\rs\xcb\x0f\x18:\xd2\xcfg?|n\x87\xe3\xedQ\x95\
\x8a!\xe7\'\xcfqga\x9e\x95\xbc\xefG\x80l\xc6\xc8\xdc\x1aj\xa4\x175q\x0cJE\
\x08\x0b\xa83\xa3\xa8\xa7\x06\xb0s\xeb\xd0H:v\x95\xc5\xd8\xd6\xbb`\x9b\x83\
\xdbK\xb3(\r\x1f;q\x9a\xfe\xee2K\x95U2\x93\xd1\xdb\xd5C\x7fw\x99\x7f\xce\xbc\
\xc7\x95;\xd7Q\xca\xa5\x04\r5\xdb\xe9\xfb\xf6\xbd\xff\xa2\xfaJ\xa8\x13\x03(@\
\xe6\xd7\x91\xcd\x18k\\\r\x88\xa5\xfd\x1d\x0ex\x19\xdd\xf8\xcf4\x1f9\xfe\x0c\
\xe3\xfdC\xed{K\x95U\x9a\xe9\xde\x03\x86\xe0\x8c\xea\\1\xa96P\xe3}nn3n\x17"8\
\xc7-\x90N\xec\xbb\x16\xb4&o-\xdc\xa3\xd5\xce\xffu\xff63\x0f\x17\x9cQ\xc9\
\x87\xd9\xf9\\\x96\x821\xecphR\x07\x97e\x90&nM\x96@\x12{9\x80\xc8\x0eyv_\xcb\
\xb5\r\x00\x1aq\xe4\x9c[\xdaP-\xf8\xd0\n&\xcb\xa3\xcb:\xcdg{\xc4&oDY\x0ea-\
\x88\xf8\xf8Vr\xca4\x97\xc4\x13\xd78py\x8d\xe2fG\xea\x96|F\xb0i\x1eM\ne#\xc4\
Q\xde\xc0\xf2f\xa3\xd6"T\xe8\x93&\xee\xb9$v\x8a5#\x07\x115\x8e0u\xf1\xae\xeb\
\x84\xd6\x08V\x14\x18G\xaf\x04r\xff4b\x97sk\\\xb4b\x05\x91<\n\x036\x15\x8a\
\x06\x8c\xe4\xd1\x9a\x1c\xa4\x91\xa1Q\xb4J&\xdb&\x7f\x16w\xf3\xfc\xf7V\x14\
\x80\xff\x8b/g\n\xe0G\xd7\xcaR\x8bR\xd2\xa6q\x06\xac\xa04\xaclT9{\x1cL\xeato\
EnS(h\x8f\x9f\x7f\xa9\xa9\xae\xbevJ\xd4\xc4]\x9a\x99@\xbe\xa5e#\xc3kB\xa3\
\xee\xa0B\xad!\xea\xe1\xf4+[\n:\xaa\xb67\xe0\x0f>QW\xa1Q(\xab\xb1\xa6\x93\
\x96,\xb3m\xc7m\xe7\x06\x86\xbbC~\xf6\xb9\xa6\x02\xf8\xf4\xc5\x1953\xf3\x0c^\
\xd6C\xdc\x84\xa4\t\xef\xdf\x8f\xd8\xb8U\'nB\x00\xdc\x9b=\xc5\xf1W\xb6\xf6\
\x9c\xd3\x1e\xf9\xc7\xe4\x87owKi `qi\xab\x83hal\xb4\x84o\x84W?Z\xdb\xf7\xc0w\
\xf5\xc7\'exh\x9d\xder\x05\x85\xc7\x9d\xfb\xa7\x98\xba0\xb3\xef\xfa}\xff\x19\
]\xb8\x14\xca\xd9\xe7\x8er\xe5\xef\xee\xfc\xf7\xc2\'\x07\x99\xbeY\xe5\xf5\
\x97\xa2C\x9d6\xaf\xbcvR\xa6.\xce~\xe0\xda\xff\x01\xa1\xab_\xfa\x1c#\xf0\xf4\
\x00\x00\x00\x00IEND\xaeB`\x82+b!\xb7',

'Printer':
"x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2B \xcc\xc1\x04$\
o\xae\x91\x04\x92\x0c\xcc\xc5N\x9e!\x1c\x1c\x1c\xb7\x1f\xfa?\x00r\xd7{\xba8\
\x86hL\xdc;\xf9 o\x8b\x01\x0f\xcbuu/\x87E\xac\xa7<\xd2c2\x97uo\x11\xd0\xb4\
\xfd!\xc7w\xacE\x80\xa5\xff\xf3\xe1\xa6\t\xa9\xd3J\x17\xccQ\x9aw\xfdy+\xdb\
\x81\x828\xa9\xe5?\xb3\xb6G\xaeN}l\xd2\xed\x11\xec\xecb\x1b\xb5\x95\xb9\xa1C\
`\xa2\xffC\x05\xe3+\xa2\x1b\xdc\xb3\x17m\xa8\xddl\xf4]\xc5\xf6\xd4t\xbb\xd4\
\xb4\xb7\xaa\x1b\xe6<z\xfb\xc2g\xf1v\xcb\xa3\x8e\x96\xdb\xae\xac\x11`2\x8ef\
\xbf\xa3\x91\xd7=\xf3\xeb\xdb\xd6g\xbc!\xc7D\x9e\xeeN\xbaU\xcc\xbcA'~o\xc4\
\xf5\xe6}W\x94'\xdfP\xd2\xd9\xfc~yR\xa2D\xb2\xbd\xd1\\\xe1\x9ao\xae\xf5\x7f\
\xef\xd7-U\xad\xd3\xbb1a\xeen\x90W<]\xfd\\\xd69%4\x01\x00\x14\x17c\x8e" ,

'Pen':
'x\xda\x01R\x01\xad\xfe\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\
\x00\x00\x00\x18\x08\x02\x00\x00\x00o\x15\xaa\xaf\x00\x00\x00\x03sBIT\x08\
\x08\x08\xdb\xe1O\xe0\x00\x00\x01\nIDAT8\x8d\xad\xd5Q\x91\x83@\x0c\xc6\xf1\
\x8fN\x1f\xeb\xa3\x02.\x02"\xe0t\x10\x03\'`\x05\x9c\x81E\x07\x02V@V@\x15\x9c\
\x01\x04\xdcC\xda\x94\xb2[`\x99\xe6\xa1\x03\x0f\xfc\xf8o\x86\x99v\x81\xf1\
\x919\x03\xf8\xfe\x8d\xad\x8f\x89\x0cv\x11c\x0f`\xfc\x91\xd3\x81\x97\x8b\x0c\
\x1a\x15\x80\xf6\xeab3d\n\ti\xaf\xf3\xba6h\xa1\xd0@\xf1+6\x17\xad(\r\xd0;E\
\xb2\xd8\xbewA\x9b\xca.\xc8v\xb9\xae\xc0\xbe\xa3\x8d\x16\xbd/\x82\x88\x00T\
\x95z\x11\x91\xf8\xef|\xfc\xc9R\xa9C\xaa\x91Hf!\x02 \xe7|\xbf\x1d\xa8T\xeaP9\
]Gv\x91s\xf6\x17lC\x96\xe3G\xb3\x16"\x99g\x96SY\xb6j\x9c\xa6kJ\t\xb8UO\xd1P\
\xc4\xcc)\xa5\x9dD\x1d\xf2\x13\x85\x10\xa6\xe9z\x1c2\xc2v\xd1\x14\xf5\x02Y\
\x0e3\x1f\x88Z\x16\x85\x10.\x97\x1b\x80\xd6\xa8\'\xb4\xc8i\x8dz)\xf2\x1c\x1b\
\x8f\xdac\x9d\xf0\xf8\xd8\xca\x1c\xd7\x99y\x1c\xff\xd6\xa1\xeeS\x7fG\xffs\
\x90\xab\x00\xd4y\xc8_\x00\x00\x00\x00IEND\xaeB`\x82*\x9a\x8b\xd9',

'Pin':
'x\xda\x017\x01\xc8\xfe\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\
\x00\x00\x00\x18\x08\x02\x00\x00\x00o\x15\xaa\xaf\x00\x00\x00\x03sBIT\x08\
\x08\x08\xdb\xe1O\xe0\x00\x00\x00\xefIDAT8\x8d\xad\x95]\n\x830\x0c\x80\xa3x\
\n\x11A)=G\x0e2<Kv\x15\x91\x9d#\xbb\x86\x14\x07"^c{\xc8\xe6o\x9d\xad\x9a\x87\
RJ\xfb\xf5K\x13h@\x04\x97D\x04\x00\xc5\xadv?\x90)\xfd2\xcb\xfde\xa5\xc3\x03\
\x97gJ\xaf\x17\xfd@\x99\xd2@o+\xcb\x03\xf4\xa5P\x00\x00w\x80r\xce\x8a\x9c\
\xceKL(\xc8\x9c&\xb1\x9f\xd1\xf8\xb4\xdb\x14\'\xd0\x94\xb5Eq\x05\xe5J?\x99en\
\xa58\x81r\xa5\x999M\xe2u\xfb\xec\x80r\xa5\xa7#Or)\xb6Y\x96\xaa5\xa6\xce\x95\
nL-\xf3]\xe5M\xa3caOM\xa4\xce\x82\x1aS\xb7]\xcf\xbf2\x9d2B\xc4\xb3\xa0!#"j\
\xbb\xfe\x94\x11\x11I\xb1\xbc\xa4f \xd1A\xc4\x03RK#"\x92\xf6\xf3\x95\x1aA\
\x0b\x1d_\xa9\x99\xd1\xa0#1H\xb9\xb0Bq\xb1\xea\x0ctD,\xab\xc7\x7fPp\xd5w\xf4\
\x017no\x00\x04\x0eF\xbd\x00\x00\x00\x00IEND\xaeB`\x82\xbf\xb9{\xbe',

'Left':
"x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2\x12 \xcc\xc1\
\x04$\xf3EW\xad\x07R\xcc\xc5N\x9e!\x1c\x1c\x1c\xb7\x1f\xfa?\x00r\x17{\xba8\
\x86X\xf4\xae\xbdr\x9b\x97Y\x91\xc7\xe5\xe2\xec\x0e\xb5;\xbc\xb9\x01\x8c\xb9\
;x\xc37\xe4.\x91\xbeu\xc2}I\x8a|\x0eC\xb3\xfd\xc6\x92\x16\x16c\xfe\xab'\xba8\
\x1d\xce\xdd^\x924m\x9ev\x1e\xf3\x83\x16\x97\x14\xb1M*\xd3X\x0c6\xff\xad\x94\
PbPbX\xffy\x1b\xb7\x95\x80\xf9\xe5\x86\xaa\x0e\xb6+\xfew\x9c\x16\xbb\xb0~\
\x12\x9c\xff\xd3v\x7f\x87\xc0\xdcS\x8cA\xa1\xa1!\xcb\x17\xce)\xd6<zvn\xfd\
\xb6\xd9\xab\xdd\x8f\x1c\xfc{\xfa\x96\xc0u\xbe\\\xf5\xeb\xb3\xff\xa9\x99\x87\
)\xc7\xbf\xdb%\xb5b\xa2\xedv\xb6UQ\xa7\xad\xac\x19\xd22\xe5\xaa\x98#\xe2\xbc\
#\xe6\x05\xfa\xb8\x00\x9d\xcb\xe0\xe9\xea\xe7\xb2\xce)\xa1\t\x00\xce/V\xc3",

'Right':
'x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2\x12 \xcc\xc1\
\x04$\xf3EW\xad\x07R\xcc\xc5N\x9e!\x1c\x1c\x1c\xb7\x1f\xfa?\x00rgz\xba8\x86X\
\xf4\xae\xbdt\x90\x97Y\x91\xc7\xe5\xe2~A\xdf\x0b\xbc\xb9\x01\x8d\xb7\x17\xf0\
\x86oX\xba\xb4Wf\x82Rc\xd9A\x89g\x07\x18\xbd\xfd\x8bg\xac\x9er\xa4\x93\xc5\
\xe1\xc9\xbd\x90\x90\xcf\xcf]\xa4\x1b\xd8\xba\x0c\xe5\x1aBD/\xc8\x98V\xef\
\xb8P\xaf\xa2\xc5~\xe2\xef\xdd\x86=w\xb8\xb7\x9c\xe3](z\x8e\xe1\xa6\x85\xb1\
\xc9\xe3\x98f\x9f\t\xbf.\xea\x9a1-\x98\xf2K\xcc\xfe\x8b\xba\xcb\x12\xeb\xc8\
\x85\x8c\x89\xad\xcb\x8e\xc8\x18\t)gtV\xb4\xc9\x1c\x91\xde\xe2s\xc5\xa4\xb9D\
\xdbW\xd9\xfc\xe3\x85\x0cu\xc6\x80\xb3\xbf/\xf0\xcf\x90\xb0\xfd\xa8j\xf0G\
\x06\xe8H\x06OW?\x97uN\tM\x00C\xa4S\x87',

'Xlabel':
'x\xda\x01\xcc\x013\xfe\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\
\x00\x00\x00\x18\x08\x02\x00\x00\x00o\x15\xaa\xaf\x00\x00\x00\x03sBIT\x08\
\x08\x08\xdb\xe1O\xe0\x00\x00\x01\x84IDAT8\x8d\xad\x95\xcdK\x02A\x1c\x86_\
\xc3\xabz0\xf0P\x10\x0b\xfa\'D\x1d\x07E\x0f\xb1\xdb]\xed\xe3\xa0\x15T\xa4R\
\x07\xc5\x90A\xba\x17Q]\xcaC\xd0\xc7=\xa5\x9b\x8b\xff@\x1e\xddC\xe1\xb6\xa0\
\x82\x91$\xec\xc1\x8e\x1d&\x16\x8a\xddY\xbf~\xa7w\xe0\xe5\x99gv\x07\xc6A)\
\xc14\xc6\t`s\xedzB\xca\xed\xdd\xd6\x0c\xbf\xd1T\xd5\xa6\xaa\xb2\xac\xeb\xba\
\xa2(\x9dN\xc7\xb4\xc9\x03\xe9\xba\x1e\nGB\xe1\x88\xa2(\x002\x87G+\xd2\xeaK\
\xbd>2\xc8\xe5r\xb1\xf0\xd5\xef\xdf\x94JUY\xce\xe7\xb2\x92(\x9a\x96\x9d\x1c\
\x10\x80\xfd\xbd\xdd\x8b\xcb\xab\xf8\xfa\x06\x80x,\x9aL$\xac\x9a6\xdf\xc8\
\xe3v\x1b9\x9dJq\x9a6 A\x10Xx.?\xcdz\xbdc\x82>{\xbd\xe4\xf6\xce\xaf\x9a\xc7\
\xc3\xdf\x92\x07Z\\Z6r\xb7\xfb1&\xe8\xb8P\x00p~v\xca\x96\x83\xef\xc18\xa0r\
\xa5r\xff\xf0\x18\x8fE%Q\xcc\xe7\xb2\x00\x1a\x8d\xc6\xc8\xa0\xaa,\x1f\xa43\
\x00N\x8aE\x00>\x9f\x0f\xc0\xbb\xa6\xf1A&\xf7(\x14\x0c\xaao\xaf\xc6R\x12E\
\xabKhcd\x8c\xd6j\x0b\xfe\x80\xd6j\xdbRl@\x84\x10\x00\xb5Zm"\x90\xe0\x0f\xb0\
@)\x1dF\x8agD)e:\xc3H\x99\x83\x98\x0e!da~nH)K#J)\xa3\xb0?h+e\x022t\xfeq\xf9R\
\xe6F\x86\x0e\x1bCJk\xb5\xadp\x7f@\x82?`\xaac\xd0\t!VgtL\xeb9\xfa\x01\xb9\n\
\x8e!\xea\xcdIa\x00\x00\x00\x00IEND\xaeB`\x82\xf9\xe4\xc8\xf5',

'Ylabel':
'x\xda\x01\xac\x01S\xfe\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\
\x00\x00\x00\x18\x08\x02\x00\x00\x00o\x15\xaa\xaf\x00\x00\x00\x03sBIT\x08\
\x08\x08\xdb\xe1O\xe0\x00\x00\x01dIDAT8\x8d\xad\x95?K\xc3@\x18\x87\x7f\x15\
\xb1[3T(TA"\xe9\xd0\xa5\xceM\xa0\xbd\xb9\xd0~\x02\xc1\xc9EEtku9J\xc5\x0f!X\
\xfc\xf7\x01l\x8a\x83\xa5%\xa3"v\xeb\xa4X\x02I\xbe\xc0-vs8\x08Zsw\xd1\xf4\
\x9d^\xee~<\xf7\xbcp\xc7\xa5(%XD-\x03\xd8\xd9\xbe\x88\xdcc\x8cy\x9e\xa7iZ>\
\x9f\xe7+A\x10|\xcef\x9b\xba>\x97\xbc\xba\xdd]\x92\x1c\xc2\x18\xab\xd5\x1bV\
\xa5\xca\x18\x03`\xf7\xfbV\xa5z\xd9\xed\n\x8dD\xb5\x92N\x7fW;<:\x06\xd0i\xb7\
#\xc32\xa3\xd5l\x967\xaf\xe3q\xad\xde\x00\xf0\xf2\xfc$\n\xcb@\x00\x0e\xf6\
\xf7\x00p\x97\x07\xbb\x17\xa2\xff\x0c\xd22\x19\xde\xdc\xdd\\\x17\x8bEIR\x01\
\xca\xe5r\x00N[M\xb3\\\x96\'\x15\xa0\xfb\x9e\r\xc02MyL\x01\xfa\x98N\x87\xa3\
\x11\x00\xf9Pj\xd0d2\x01p~\xd6QR\x14 >\xd7V\xa9\x94\x14t\xd2j\x0e\x07\x8fq\
\xe6\x82\xfcf\xff~S\xff4r=_7\n\xae\xe7\'\x05\x11B\x008\x8e\x93\x08\xa4\x1b\
\x05\xdePJ\xe3H\xc9\x8c(\xa5\\\'\x8eT4\x88\xeb\x10B6\xd6\xd7bJ\t\x8d(\xa5\
\x9c2}\x7f\x8b#\x15\x01\nu\xe6\xb8r\xa9h\xa3P\x87W(\xe5z\xbe\x08\xf7\x03\xa4\
\x1b\x85H\x9d\x90N\x08\x11\xcd\x98Z\xd4w\xf4\x05W\xb6\x80*\x16C*U\x00\x00\
\x00\x00IEND\xaeB`\x82\xfe\x8d\xb0\xeb',

'XYlabel':
'x\xda\x01g\x02\x98\xfd\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\
\x00\x00\x00\x18\x08\x02\x00\x00\x00o\x15\xaa\xaf\x00\x00\x00\x03sBIT\x08\
\x08\x08\xdb\xe1O\xe0\x00\x00\x02\x1fIDAT8\x8d\xad\x95AH\xdbP\x18\xc7\xff\
\x1d\xb2\x9cj\xa1\x0eJ\xd9`\x14\xf4\xd0\x8b;\x8d\xcd\x164 z(M\xee\xb1\xba\
\x1d\xd4\x0e\xb61\x95\xed\xd0\xd2!\x0fQ\xdcmc\xd7\xcd\x89\x9bng\xd3\xe2e4\
\xeb\xd1\xe1\xece\xb49l4\x0b\xa4\x01\xc7dB(\xee\xb8\xc3\x93\xa7M^\xd3C\xfdN\
\xdf{\xdf\x97\xdf\xfb\xbd\xc7K\x12 D\xc4eD\x1f\x80\xfb\xd3oz\xa4lm\xcf_qM5\
\x0c\xa3a\x184w\x1cG\xd7u\xdb\xb6\xb9C\x00\xb6m\xb3\xe66\x90\xe38\xe3\x13\
\x93\xe3\x13\x93\xba\xae\x03Xz\xfa,%\xc9\x87\xd5*\xab\xa6$99:\xe68\x0e\x80b\
\xa9\x94\x1c\x1d{\xb7\xb9y\xbe5\x16\xc1`\x90&\x7fON\xdenl\x945\xad\x90\xcfI\
\xe94\x9d\xbc*\x08\x8chY\xd6\x93\xc5%\x00\xab++\x1c#\x00\x8f\x1f=\x04\x90\
\x99\xb9\xb7\xb6\xfe"3\xa5\xcc\xcd\xce\xb2\xd2\xb5\x81\x01\x9a\x1cV\xab)I\
\x06p\xf0u\x9fU\xdd\xa0P\x7f?\xcb\x17\x17\x16\xb8\xcbP\x97\xbd\xa2\xca\xd0\
\x1cP,\x16\xa3\x89\xab\xcf\xb5\xcc\xce\x87\xf7\xf1x\xfcb\xa9\r\xf4\xe7\xf8x.\
\xfb\xe0\xec\x99P\x08\x9e\x88D"\x00\n\xf9\\bd\xc4Uj\x03\xdd\xbes\x97\xe5GG\
\xbf\xbd\xa0]\xb5\x08 \x99HxK\xe7\xa0\xe7\xcb\xcb\x00^\xbfzI\x87\xa7\xffN\
\x01\x98Vs\xff\xe0\xdbg\xed\x0b\x80\x86a\x945\r\x80kSm\xa0b\xa9\xb4\xf3\xf1S\
fJ\x91\xd2\xe9B>\x07\xa0^\xaf\x03\x10\x04AQ\x94l6\x0b\xa0V\xab\x01X_[\xf5R\
\xce@eM\xbbx)\xe8A\xfc2M\x00\xe1p\x18\x80\xaa\xaal_\xb7\x86\x87\xb9\xa0\x00!\
\xa2\xcf\xbb\xf6\xbd\xae\xb7Z\xadh4z\xf3\xc6\xf5N=\x00\xb6\xb6\xe7\xfb|\xca\
\x00dY\x06P\xa9T\xfc\xdb\xe0\xbdG\xdc\xe8\x15\x14\x1b\x1c\xa2\t!\xc4\xb4\x9a\
=\x19\x11B\xa8NW\xa9\x8e \xaa#\x8a"=\xe6\xaeR~F\x84\x10J1~\xfe\xe8*\xc5\x071\
\x1d\x17\xd7G\xaa\xa3\x11\xd3\xa1\xc1\xa4L\xab\xc9\xc5y>#\x83C\\\x1dF\x17E\
\x91\xbb\xc7\xc0e\xfd\x8e\xfe\x03\xb5\xd8\xdb\xe0\xd6W5\xe0\x00\x00\x00\x00I\
END\xaeB`\x82\x13\xa3\x19\xe5',

'Green':
'x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2" \xcc\xc1\x04$\
\x99^wE\x01)\xe6b\'\xcf\x10\x0e\x0e\x8e\xdb\x0f\xfd\x1f\x00\xb95\x9e.\x8e!\
\x16\xbdW\'\x1f\xe4;\xa0\xc0\xe1\xbc\xf6\xe6\xff\xffE\xe5\x12\xb7Y\xb4\xa5\
\xf4O[h>\xbc\xa8\xc55)\xd5\xfc\x95\xd9O\xcd\x9a\x13:\r\xd9\x13\xef{\xb4\xf0.\
\xbe\xdd\x17e!\xd1\x90\xb8#x\xcb\x9e\'\xf17<,\xb6\xf7\x0b\x9e\xec\xe6\xce\
\xee\xfed|]\xe1v\xf8d\x1d\x83\x8f;?U]\xc9\xfc}dJ@\xde\xcf}\xd3W\xe7\xfc\xeeu\
SMU\x8e\xd9\xe5.\xa4f\xde\xd8|\xbb&D*\xaeg\xfe\xbf\xe7\xc2b\\\xae\xca\xafd\n\
\x8f\x00\xdd\xc1\xe0\xe9\xea\xe7\xb2\xce)\xa1\t\x00\x7fuK\xa1',

 'Red':
'x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2" \xcc\xc1\x04$\
\x99^wE\x01)\xe6b\'\xcf\x10\x0e\x0e\x8e\xdb\x0f\xfd\x1f\x00\xb95\x9e.\x8e!\
\x16\xbdW\'\x1f\xe4;\xa0\xc0\xe1\x1c\xbe\xf9\xff\xff\xa7\xef\x1cJ\xbaX{\xa7\
\xa7\xce\x99\xf2\x81\x8b\xa9\xe9Ii\xd6\xd3\x19\x7fD\xf6-\x15o\x90\xfd\xd4Wq\
\xc3`W\xb6\x82\xe1\x01\x06\x1d\xae\xab\x87\x9f\x85\xff\xe1\x96\xee\xdcx+\xac\
\xe3\x89\xeb\xe1_\x0b\xfe\x9c=\xbat\xeeb\xcfEj\xf1\xe9\xf7\xb6o\x9a\xe2\xdf%\
4\xb3\xba\xee\x9a\x94R\xf5\xde\x82\x10\xc7\xe7\x7f\x18\xfeL\x9a\xe1r\xa1\xd8\
\xf6\xef\xd9\xafW>,\xfb\xfb\xc5\xde^\x89\xddU9\xf3`F4\xd0\x1d\x0c\x9e\xae~.\
\xeb\x9c\x12\x9a\x00\x06\xcdQ[',

'Processing':
'x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2" \xcc\xc1\x04$\
\x99^wE\x01)\xe6b\'\xcf\x10\x0e\x0e\x8e\xdb\x0f\xfd\x1f\x00\xb9K=]\x1cC,z\
\x8fN\xbe\xcduXA\xc0\xe5\xbc\xc7\xff\xff\xd3\x97\xf3g\x9be]\x11\xd3,Q\\p\xb1\
Po\xf5\xa6\xb3\x99S\x93\x9f\xf0\xe9\xbcT\x8e\xb0\x9f`\xfb\xe1\xc5\xaa\xbd\
\xd3&\xee|g\xc0&(\xaf]:7\xddSB\xba\x85\xe5\x10\x9b\xfe\xdf\xfdQKz[\x14f\xae\
\xe2;\xfe\xea\xc4}\xe3\xe0\xediG+\xa6\xfe\x96\x8dXQ\xbb\xeb\xf4\x7f\xc5}[\
\x03\x8a6\xe5g\xaf\xdb\xf6\xc8\xdb\'\'\xfe\xb8}\x82\xd7\'}\x9b\xed?$\xd6\xbb\
\x94J^;`=u\xc7$\xff(\xdb\xfd*\x85-\xef\xc3\xce\xea{\xb2\xf2\xe7\x9e\x11\x91\
\xdfe\xc38\xff\xea\xfd\xf9O"\xf72\x8a\x87\xc4i\xbc\xd7[\x02r?\x83\xa7\xab\
\x9f\xcb:\xa7\x84&\x00\xc3\xe4^\xe4',

'GreenEnd':
'x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2" \xcc\xc1\x04$\
\x99^wE\x01)\xe6b\'\xcf\x10\x0e\x0e\x8e\xdb\x0f\xfd\x1f\x00\xb9\xb5\x9e.\x8e\
!\x16\xbdW\'{\xf3\x1dP\xe0p\x91}\xfcw\xbdMlG\xd4O\x89G\xcb4\xb5\xe7\xfch\xe3\
\xe0\x98\xf4\xd4\xec\x95\xe9O\xcd;1\xa2\x0e\xfe\xe7d/nH\xb8\xd37\xf1(\x1b\
\xb3\x00\x8f\xf3\xa2\x17z\xfb\x13\x147\xcex\xea4\xff\xbb\xd41\x05\xf3\xc0\
\xd2\xc8\xea\xea\x17\x9b\xbb\x8f\x9fz)0c\xc9\x94\xab\xefR_\xed4W>\xf1\xf6\
\xe8\xf6x\x13\xad\xedk\xda\xba#\'\xbd\x13\xd2\xed\xb4\xff\xfb\xa4\xeaW\x81Q\
\xdd\xaf\xf9\xf2\xbf\x0c\xac\x95\x8b\x1bkO\x02\x1d\xc2\xe0\xe9\xea\xe7\xb2\
\xce)\xa1\t\x00\xeb\xbaN\x98',

'RedEnd':
'x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2" \xcc\xc1\x04$\
\x99^wE\x01)\xe6b\'\xcf\x10\x0e\x0e\x8e\xdb\x0f\xfd\x1f\x00\xb9\r\x9e.\x8e!\
\x16\xbdW\'\x1f\xe4;\xa0\xc0\xe1\xbc\xf2\xe6\xff\xffE\xe5\x02\x8f\xa7$\xcd\
\x99\x9e:g\xc2\x87\x15LMK\xe6FY\xaa\xd9\xb7\xeaK\xb2\x06\xcc-uO\xbba\xc8w|\
\xcd\x11\x06\xe6\x02\x1e]\x97~\xef}\xeeseZ\xa2\x05g9\xbe\xe8n3\xfc\xb8x\xaa\
\xa7Y\xda\xe6\xb8\x86\xbd\xdd\xdaOk\x8bg,\x99\xce/\xb9\xc1<\xdf\xedQ\xf7\x99\
\xf4\xbd9!Aem\xba:\x9d\xfez\x91\x93R~U\xbf^\xf9\xd0\xf7\xf7\xcb\xfa}\x8c:av\
\xd2\xbf\xc4V\xe8\x01\xdd\xc2\xe0\xe9\xea\xe7\xb2\xce)\xa1\t\x00\xd2\xa7J\
\xbc',

'Lattice':
'x\xda\x1dW\t8T\xdd\x1f\xbe\x984J\x0c\x95}-#\x15\x93\x10\xca:\xb6\x8c=I\xb2\
\x0ee\xc9N\xb6f,5\xb6\x10#\x92\x98$\xc4XBeK\x93\xc4\xa4I\xa2\x11cm\x9a\x98\
\xa2\xf9|b\xacY\xd2\xff|\xff\xfb<\xf7\x9e\xfb\xdc\xe7\xdc\xf3\xbb\xcfy\xdf\
\xdf\xfb\xbe7\xc3\xc1\xee\xec\xbe=R{ \x08\xda\x87\xb14s\x04\xa3\xfe\x7f\'\
\x9c\x17\\[\x1e\xda!\xc1\xc0w\xcd\x04\xe3\x04\x87\xc3\'\xa7\xec\xbf\xfd7\rc\
\x86v\n\xb89_\x9cds\xfe\xe2_\xda\xa7\xf9\x13VI\xa6n\x8f\xcc\xd1\xc6\xc6\x0f\
\xa4\xdd\xf8\t\xb9\x03\xb7\x82\xb1\xda\x081e!\xad!\xa4\xdb\xd8\xfew\x9a\\\
\xe9\xc2\x7fw\x9f\xd4d\x96\xef5\x94\x0c\xb5h-J\xcf}O\xef\xd2\xba\x9cl\xa7\
\x14CD\xd0`\x05\x90/\xc1\xc1\xf5\x8e\xfch\xeb\xdd\xd6\xb6\xf9\x10\xfc\xc2\
\xc6N\x84\xb8\xc5\x84\x89\x9b\xdc\xc3\x05\x1d\xd6\xf7\xad\x9d\xc6\xd9\x07[\
\x1b\xaf~\x87\x0f\xcc^\x1bh\x17\xbf\x89 \xfc\r*\xff\x13\xc6\xf7\xe4\xec_\xe1\
?FH\x8bESY!\xda\xf7\xefJi\xdebY\xbb\xd0\x08\x18zd\x8a\xe8jb\xa3\x9c\xdf\xe3c\
naQUU\xd5@\xb5\x84\xd3\x9b\x9a\x9a\x8e\xd8?\x94\x91\x95USUmvQU\xc24P\xe5Sr\
\xfb\xfdN\xa0Pkkk\xcaHd\x89^,\xca\xc0\xc0\xc0\xe9\xb0\xa21\xc5\xbdaj\xca\xbb\
\xde\x19\xbf\xf8\r\x8d*\x9c\x8bl\x1f\x11\t\x86+\xa6S\x8bH\xa4\x9e\x88\xd1li\
\x9db\x12inn\xce\xf4\x14/\x96\xfe2\x8e\xeb\x83\xc1\x08\x10i\xa4\x07\x0f\x04w\
\x8ev>\x1f\x7f\x92\x9c\x1c\xab\xa7\x97\x94\xc8\xa9,\xe4\xe7\xe77I\xd0OI\xd5\
\xd5\xd4<\xef\xe0\x10>\xfd6\x83\x9a.\xdc\xee\xde\x90Km2\xd9\xbb\xb7\xdaN\xa7\
\xa4\xb0\xed\xa2\xaa\xd8\xfa\xcaJ\xcaf\xdcS:\x7f\xf2\xd4/&E(\x9d\xcd&\x1a\
\xc9\xc9&\x84/\xcf4\x96\xe1\\\x8fR\x98\x03X\xf5\xee\xeen!\x19\x95\xb0\x90\
\x10YII\x01\x0e\x17[\xb6\xb5\xb5E{\xf7\xee!\xee\x9f\xa3\x90\xb1m?k\x87K\xa4\
\x1f9\x04\xe0\x92\xa1\x9d\x14d/o\x9c;wN\xc2\xefS\x7f?\xc6\xca\xca\xb1\xc6IQR\
@l\x82\xcd\xbdevH(\x9d\x0f\xaa\xae\xc5\xed6/mn\xfb\x8b8\xf6l\x88\xb3=C\n\xfb\
\x9a\xf47\xa1\xc3\x93\xc5d2\x87W\xeck\x9c^^\x9b\x1d\xe8\xeaBW\x0c\xbe\xe0\
\xd2+**|\x9e\xe9\xaa\xa9\xed\x83\x14\n\xfb\xb22=O\xe3\xb5\xbfc\xe7Vq%v4\xacz\
\x8e\xac\xdeLd\xbb\x86\xa6&\x0f\xb4k\xd7.\x18z{gkAZ0\xdb{,\xff\x88\xfd\xf4\
\xf4\xf4\xefxC\xc6\xd2\x88[\xd8i\x99\x1c\x87Q\x87\xa8\xa8(\x0f\x0f\xe6C\x03\
\xfcG\xbfe\xbd\x85WM\xd7f\xed\xa07U\xb6$\xd1\xfd\xfb\xf18\xdc\xbd{\xf7\xb4Eq\
\xa1\xa1B\xe6\x83\x04\x02\xafX\x96yK\xf0D3\xe7\xe7`Ei\xc2\x9a$\x1a\x81\xc6\
\x11\x10{RM\xe4\x88\xa3\xc3\xc3\xcdA\xa3\xa8"\x1b\x0b\xc4\xdb\xdf\xbf_0\x02\
\xfb\x07\x06\xaa\x8e\xbd\xb10\xc9W\xca\xf0\xbe\xef\xa0\xe2>\xee\xe2\xe9\x99\
\xe3=\xc6\xa8\xbb\x98\xbcbv\xa1<###55\xf5\xc3\x07+\xe8\xcd\xcaJs\xef\x95\xbc\
\xde+\xed\xed\xed\x8e5\xcdMM\x9a\xefm\xa4$\x8a\x15n\xe9\xc5\xfe\xba\xd53\xfd\
\xf8\xf1\xe3\x82y\xb0m\'^\xff\x9e\x8ee%\x88+iU\xde\xbd{\xa0\xc0\xea\x82\x8b\
\x0b\x1c\xc2j\x14\x8d\x8f\x8f\xab\x8aY\x1f+\xf0\xbbr\xe5\x0b%\xf6\x84\xe5\
\xe1\x9b}\xba\x98\xbc\xe5\xe5e\x18:\xbc\xdd\xbd\xb1\x01\xbc\xa3s\xe2\xc4B\
\x05\xd1ps\x91*<;3\xc3[\\>\x18\x80\xe8\xe6r#\xda\xdd\xed\x10\xb0l\x8b\xcb\
\xcf\\b(%4\xf6\xc1\x83\x07k\x9cj\xc5=\xe3\xa6h\xf2I\xb7337c\xcbx A~SU\xb1!NT\
cL\x8dS\xf1\xbd{UN\xc7\n\xac|\xd5cx\x8f\x1d:\xd4\x1d\xd8\xc2\x9f"\xa4o03;\
\xbb{\xf7\xee\xd8\x7f\xc7DDD\xa6\x18\xa7444\xd4\xd5\x15\xc4\xb2\x18\x81\xd1\
\xb9\x93\xfcm\x93\x7f~s\x9f\xb0P\x95\x8e\x92\xfb\xf7S\xb1\xb0\x9c\xcb\xd8\
\x80\xe4\xaeo1\x14\x00`\x02\xe5\xf5\xf6\x92u\xbdsP\x8b+\x1e\x8f\xe7\x9b({<\
\x18\xa0*fT\x93\xad\x00/\xec\xbbp\xe9\x92\xa4\xb4\xb44\xdd\x12\xfb35u\x97\
\x0c\x8d==\xfdj"==\x9dT\\\x0cA\xa8\xc2\xba\xceNy\xf3\xc1\x1bU\xea\x82\xe0\
\xc1\xdb\x08r\x98xf\xb9k\xbd\xf6\xe9\xd3\xd7\xf9\x0e\xedS\x1c\x9e[=t\xc7RI\
\xf4\xfa\xc6\xef\xef\xf9\xf6\xe12\xe4D;\x1b\x1bX\xbe/3\xb4\x8d:u\xa5\x89\x9a\
@\x11\xe4O\xa6\xb1E\xe00\x9elXZ\xabk}`\x8b+\x98m+L\x1e***\xba\xfe\xfd\xfd\
\x9d[\xb7nef\xeei\x9bd\xb2X\xf2\xf4"fh:\xe2\x96\xd9\xd7 >\xe8\xd1\xe8\xdcI\
\xc1\xe5?I\r\xbb\x8b\x15\xe0\x14\xa6\x9c\x88H\xd7\x15\x8d\x8b\xad\xffq^7\xe2\
\x10\x12\xb9\x0b\x9dk\x9a.\xc4\xdd\xd8\xc6f\xaa\xa3\x11\x80\xa2\x1a\x9f\x85\
\xb52\xcb\xe3\r\x93\xae\x93\x9e\xb6\xf2\xda<\xea\xed\xc5d\xf5\xe4\xe5\xe7\
\xb3\x19v\xe4\xa1\x08\x99N\xdcj\xa0\x95\x95\x95\xb3\xb3\xb3\xa9i\xb2\xd3\xb1\
}??\x06hY\x98\xdd\x92\x10\xe4\xc7\xe4iMxq5\x8al@\xfbs\xb9\xdc.\t\x1e\x9e\xc3\
!m\x93jb{I\xfdk\xf3\x87\xe0\xbc\xd4\xa7o\xdf\xbe}\xff\xde2\xd5\xe4Y\xc8dkeee\
oo/\xc3\xe6t\xc9\x8b\xde+999\x16\x88+\xc8\x93\xd0\r%Lr\x17\x04-\xaa\xed\x9a\
\xbb\xf9kn\xae\xef\xfd\xfb\xb8_\xed\xb3\xf1\x94\x15\\\x87EE\x99\xc6\x01L\x9e\
\x12fOjw\xd0hC\xc2&\x87lG.\xdd\xfe\x16\xd9\xae\xfe\x11%f\x1dO\x89:#\x9bN\x1d\
\xa7\xc46\x8e*\xb9\xdb\xf2T\xd1*\xce\x12}||\xaa;:\x0b\xab\x1f9;9}y\x9d\xb0\
\xf5\xb1HSF\xe8\xacr\xfe>aa\xaf\xceD\x035\xb5\xfa\xe6\xe6\xe1\xa0WC\x1c\x05\
\x0c\xaf\x89\x11\xa5\xbb\xa8H\x92<$i\x93&$8\x1f\xae{\xdb\x82\r\x1as{\xcd\xf3\
e\xd4Qee\x0b\xc0Z%\xd1J\xc7\xde\x1f\x91\x9c(\xdc\xf9\xf3\xe7CC\x7f\x81&\x8c\
\xa7\x91\xfa\xad\xbd\xbd\x05\xcf0\x89\xb4\xf1\xf1K\xed\xee\x03l.!\xc53\x08\
\xf7Hesq\xca\xf4\x9f\xe6\xe9\xba\xb2\xb2\xb2\xe1\xe1\xe1~\x92\x0e`\xc3\x11$r\
<\xb8\xb5\xa7\xa7\xc7\x83\x12\xc3\x18\x1e\x8eCF[\xe9\xe6d\xf58\xb2\x04\xbeE\
\x9dY`uv\xfa\xf6\x89u\x9a\x8f6\x8ed\x02\x10d\x84hA\xd2\xb6\x98:\x86!nEEOO\
\x1az\xfa\xe2E\x1cw\xda<\xdb\x82:\xbb\x8c\x14\xedm\r\x99\x8c/\xc3\xe4\x85\
\xeb>\xad\xae\x0e`\x11\xfc\x9f\xb9\xa8\x0b\xee\x87\xc3<\xeb\xae\x95\xd0;::D3\
\xde.\xb40\xe8\xf4\\F\xa0\x1a\n\xc5\x0f\xad\xac\xae\x82\xaa\xf3\xbf\xb9l\x0e\
\x87\xe3\xa4\x9c\x86\xc0y\x18\xb6\xbb\x87\x92\xf7\xfb7\x8d;\xe9\xa1\x11\xda\
\xa4\xec=\xe9\xceu\xa7\xa4\xb2\x010]\xa6\x8d\xa7B#"\xee\xd8\x91\xb7lM\x81\
\xa0\xc1\t\xc1\xac\xd7\xb2\x90\x82h\xc6Xp+\x8d\xcd\x03}\x1c\x18\x98\x08\xd6f\
\xcdi\xb4M&+h)\xe7\xf3@o\xd4mj\x9cF\x80\xae\xb4\xb6\xf2B\x0e\x07~D\xb6\x93t\
\xc2\x84\xf2t\xa1\xa8\xb3gi;\x7f\xb6\xfe\xc4\\mq\xcd0\xcb\x03\n\x0f\xbd\xef\
\xed\xadih\xd8\x01:\xc7\xc2/tx%n\xf4,\xd4\x9cT\xbd\x8d,\xec\xab\xf6\xa0\x15i\
\xfa\xbf{\xf7niy\xf9S\xa9\x91}\xde\xf7\xc5Eu"\xcd\xda\xd2\x12.\x87\xab\xe7xk\
\x93j\xea\\\xfe!\xdc\xb5\xa88Wp[\t|i\xef\x0f}\xcb\x8aA\xab\xff\x1f#\xea\xe6\
\xccA\x87-\xce\x9d;"DZ\x85s\x1d+q+D*\xdb\xafm\x92\xda\xddM(\x95\x0eB\xaf\xaf\
\xaf\xdb\xdb\xdb\xb7\xb5\xb5\x91\x1f?\xc6J\xa4\x95W3C\xd7\xe3\xf4\x05\x04\
\x04\nQ\x1eR\xf2\xf2a\xc1\xc1Z\x12\x82R\xd9iKg\x19\xa7\xe1S\x1f\x8eca\xe8\
\xfb6i\x16\xcb4:\x1dQ\x92#c\xb4\xe3\x05\x90\xf7k\xda\xe8N\xdd+\x8er7>\xe7\
\xd48\xcaz\x9d@\xa9\xad=\xa6\xff\xe5\xd3H\xd8\x85\xfa\x98\xb7.\x9eI\xe6\xe6\
\xe6\xb2\xb2\xb2\xda\xa4}&?\xa3\xce(\xa6\x80{\xe8Fi\xe2\xa6\x80I@\xdb$\xd78\
\x92\xc2T\x1e\xf2\xf1\xf7\'\xf7\xfbmm/\x7f\xea\xeb\xebSL\xb9\xd8\xe0~N\xe5\
\x80\xb0\x9c\xfeX\x07>\x16\x88\xcb\xe2\xc5*D\xf7\x85\xc3\xb6?\x94ah\x1c\x1e\
\xcf\x08\\\xadk|\x8d[\xfbw\x1c\xf4\x0ft\xc3\xaa\xd2G\xdde\xb2\x8d\xcc\x03\
\x11n#J?\xe5\xf7^\x11\xeb\xfb\xcc\xa4\xc4b\xf2\x82\x83\x82(\xd1s#s\x8d\x9d\r\
\x8c\xc0]\xbc]\x81\x95\xd8\x0b\xda\x8d,\xe7\xba\x02;\xf25]\x19\x18\xfa{\xe4u\
` \xa0}##\x97\x86\x87\xef\xf6\xfbU<\xda\xda\xdc\x04\xd6\xb3_T49\xd6\x94<\xb4\
\x11?%\x9f\xa4oim\x8d_\x1b\xf7\x17\x81\x8d\xb7\x85y%&&&$\x18d\xf5d\x12\x89\
\xc2\x92\x13\x9c\xa8\x81\x81\x01^\xa8\x9bJe\x04\xb6x66\xd6\xd7\x9f"\xf5\x03F\
\x01\xe7\x9a\x1d(\xc1\xb3\xb3u\x02\x83\x82j\x9a\xb1ZRd29(pG.O\x1a\x86V\x12}f\
QQS[\xeb\xfa5\t\xb0\xa6\xc3\xb33z\xce\xb9\x13O\x82\xe8\xca\xf95\x14\x8a4-\
\xe2\xa61P*i))GGG\x9f\xcb\x97}5.\xf9\xfa\xfe\xa89O\x96\x92\x96\xd6\xd4\xd4\
\xacI18y\xd2\xfb\x99K^^+\x8a$!)y\x1d$\n;;\xa14ow\xd4E\xe5\xfc\x8dU%\xc4\xa2\
\xef\xf3\x00`\xa5S\xe1\xe2\xe2\xb6p\x82\xc3\xa5\x9fon\xf2)\x8a\xfc\x15P\x13\
\xcdx\xfe\xfc\xb9B\x8a\xbe\\\xd8\xd5\xabGQ(;\xe5\xfc\x923\xd1\x9946F)\x0f8kC\
C\x03\xa0\x88\x9a\x8e\x8e8\x14\xbe\xb1t0O\t)zru\xfb\xcf\xd6:\xc8%\xa9&\xde^^\
\xa5\xe3\xc1\xa8\x13\'\x88\x19\x19\xdc-\x14?:W\xcdm\xfaB\xad\xd7\x03;\x7f\
\x13\x13\x82\xb1\xc2\xfd\xe2\xe2\xa58\xfd\xae\xb0_\xf7\xcc\xf9 cx\xd8\xd7W\
\xa7\xb5\xb5\xef=x\xf0\xc4Ae\xa0\xd4\xa8\xb4\xa8\xa8\xc6A\xa5:$\n\x14\xc6\
\xe4\x01\xfb\x18\xe6[\xff\xc5,\xe8\xf5\xd1\t\x99\x08V\x97\xe0\x81\xb2\xb3\
\xb3#\xdb_\xd5\xd6Z\xd5;\x1b\xc5\xff\xce=s\xa3~\xc6F\xe5\x00\xe0\x8eH\xca\
\x11\xb0\xce\xa7YbN\xce\xf3\xf1\x7f\x9f<y\xe2P\xc6\x93\x820\x1fL\xde-\x9c\
\xb8\xca\xb8\x98\xb8\xdc\xf7\xf1\xe3\xc7\xe5OF\xa5%% #\x8c\x8d\xdd\xb7Q\xae\
\xab\xabKF\xac\xad2\x03\xaf^\xcd\xc8\xce.)-\xd5!\xf5ollxxx8=\xf4\xd4\xf3\xfe\
3\xe7\xd5\x16\xac-h261\x01B\x97u\xe5`.L!\xc5\xda\xda\x1a\x89D\x9a\x94=-/\x9f\
\xde\\\x9d{\x9d\xfc\xfa\xcf\x9a[\x99\xc3\xd8\xc8\xc8L\xb8nk(s\xb3G\xdc\xcb!\
\xa9\xd6\xaa\xb2\xb6\xae\xceM\x9201\xe1Z\xbb\xb4\xf1\xc1\xe7\xd9\xab\xed\xa5\
>\x06\x83\x11\xa3gx\xa66B\xf7\x01~}\xa6\xc40\xe1\x8c\xd3t\xe7#/\xfc|Kyy9\xc8\
 \x9f?\x7f\x1e\x18\xb0kD\x83.-s\xb8[Ppna\x1b\x14\xaeY\x03\xe1\xf1~\xff\xcc\
\xb7\x92\xe8\xe8h\x1e(f\xfe\xc3\xc3\x12\x0f\xe0\xfa\x92\x92\x92V\x95\x91\xb2\
\xf4\x15\x90w|$F\x86\x86\x9a\xf0\xeb\xbftX\xf1\xd7\xb0Xlh(\xea\xc8\x11\xff\
\x1f\xef\n\xfb\xfd.K\xc4l,\xf9\xa6S\xbb|\x9e\xe5\xc8\x1b\xa1\x10p\x19\xa1\
\xdd\x901p\xa5vw\x82B\xf5\x87YW\x0f9"\x10wL\xe5g\xf9\xc4\x80\xce\x08\xf6\x99\
\xfc\xdeaN\x94\xaf\xafoF\x86\xe2w\xbc\x95 \x04\x01\xe5\x8cp\xaft\xcc\xe8\x99\
\x06afi)\xb2\x91\xadCP\x00j\x1c\x12\x12b\xf4w[\x13\xfa\xb6\xc2\x19\xd2\x92\
\xea\x9f\x8f\xd1\x94\x10\x94\xa1\x89\xc0\xbc\xd5%\xe8\xb3\x14\x91Z\xdf\x1f/\
\x05\xf7\xee\xcd\xca\xca\xc2or\xfcC\x99/\x19\xac\xbf[e\xa6\xe9@\xa2L\x91;\
\xfb\x8b\xa9S\xaf\x96>\x1c\x07*\x99\x90\x90\x00\x16\xbe~\xfd\xfak\xf64\x88\
\x9f2\xa75\x0c\x0c\x00D\x05\xc7/\xde\x13\x11\x81q{*\xcd:2c(\xcc>5`&\n\x08Ub\
\xd2L\x91\xff\x08z\xfb\x88VV\xcf\xb1\xe3\xc7\x81\x12T\xec$\xd7\x95\xb0\xd7\
\x17X\'\xc4\xb2N\n\xbaI\x8e\x16\xd0\x87\xc9\x02ZR\xfb\xd0\x08\xe5\xfc\xd3\
\x86\x86\x0f\x8b\x8b\xad\xf2\x94N\xdd\x01\x90\'w\xd19Q:a_Av\x00\xecn\xd18\
\xe0R\x86"\xb4hJa\xf2\xe4\x88\xe9\np\xb8\xb7\xa9)u\xd4+i>\x86R\x88wsum\r\x1e\
7a<\x9f\x99\xf1\xcb\xef=P\x1bk\xa5\x18\x9f\xfaTf\xe0\x14n\xe1K\xfb2P\x8bi]\
\xb9\x83\x07\x91\x0880\xbc4v\\t\xf4)F\x1f\x9b\xbb\x04v\xe8\xda\xb5\xf5\xf9\
\xc9\xb6\x1d\xf5d\xfa\xe1\x8eV\xf07\xe0\\\xc7\xe0D\xc1\xd0\xf1\x8b]\xbb#""\
\x80\xb6^\xf6x\x13m\x86\x0b173S\xed\xfcaik\x0bDA\xb1\xa4\x820\xccoJ\xb2\xa9J\
K\xe3\xa70C\xd5%r\xe4\x0c6K\x15\xf8\xa5w\xa6\x0eF\xaf\xba\xb8\xbb\xdb \xdeNQ\
\xd3C\xb4\'\xdfM\x90\x9b\xbb\xe8*\x99BBB(UU\x05\xb8\xe86\xd3\xbdz\x02\x1b G,\
,.\x0el\x1a\x07y\xfd\xc0\x9e\x9e%\xcaJ6\xa3v58\x81\x800L\xdc\x8eKL\x94\xa3\
\x01\xcc\xe5>\x1f\xb4Y\xdc\x0c\x9b{\xd3\xdb\xdf\x9e\xe8\xdd\x04B;\x841\xb73k\
0\xc1\x12\xfe\x07X{\xb7[',
'index':
'x\xda\x01S\x02\xac\xfd\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\
\x00\x00\x00\x18\x08\x02\x00\x00\x00o\x15\xaa\xaf\x00\x00\x00\x03sBIT\x08\
\x08\x08\xdb\xe1O\xe0\x00\x00\x02\x0bIDAT8\x8d\x9d\x94!\xb2\xe2@\x10\x86{\
\xc8\xabj0\rf*\'\xe0\x04\x80\xa1\n\x0f\x85Ia\x82\n\xe0\x10\xe0\x80\x8b\xe4\
\x02\x90\x03\xa4\x82\x01\x04\xd88\x1c7\xc0\x90\xc4\xc0\x98d\x04\xb0b\xb6R\
\xbb,\xfb\x92G\xab\xce\x88/\x7f\xff\xfd\xcf\xb0\xcb\xe5\x02\x00\x00@D\xa5R)\
\x8ec!\x04\xfc\xbc\n)e<\x1e3\xc6F\xa3\x11\x11}\x00bJ\x11"\x9eN\xa7^\xaf\x17\
\x86a\x10\x04\x9f+BD\xc7q\x0c\xc3\x88\xe3\xf8\x03\xca_ \xcf\xf3\x0c\xc3\x90R\
~\x06\xfa=\x9a\xae\xeb\x8c\xb1\xe7\xf3\x19\x04\x01"V*\x155 \xe7\\\x08\x91\
\x87^\x00\x00"\xeat:\x93\xc9d\xb9\\\x12\x91\xef\xfb\x8c1]\xd79\xe7\x9a\xa6m\
\xb7[D\xcc\x04}\x01\x80\x10\xc2u]\x00\x90RJ)\x11\x91s>\x9dNm\xdb\xb6,\xcb4\
\xcd(\x8ar\x81\x14K5Dd\xdbv\x18\x86\x8c1\xdb\xb6o\xb7[N\xd7\n\xff\x1e\x15\
\x8bE\x00\xe0\x9c\xcf\xe7\xf3\xc1`\x90\x13\xf4\xf5\xf2\xad\xecx<\x1e\xae\xeb\
\xb6Z-e\xbf\xae\xebq\x1c#\xe27\xc6\x17^(\x8e\xe3$I"\xa5l6\x9b\xa6i\xc6q\xac\
\x16\xbaX,4M;\x9dN\xff3\x9e\xa5w-e\xa9?\x03\x00\x11I)}\xdf\x1f\x0e\x87a\x18\
\x02@\x1a\x91\x0cE\x00 \xa5L\x8d\x17B\xa4A\xcdL\xfc\x1b\xb3_\x04*\x10"\x1e\
\x0e\x07"z<\x1e\xb9F{\xa94\xf1\x9b\xcd\xa6\xdb\xed\xee\xf7\xfbZ\xad\xf6\xd6\
\xef\xef@J\xce\xf1x\x8c\xa2(I\x12\xcf\xf3\xae\xd7\xab\x94\x92\x88\x101\x8a"\
\xce9\x00\xa8\xb8f(R\xde\xab>\xdd\xc0h4\xf2</I\x92b\xb1(\xa5\xbc\xdf\xefQ\
\x14ex\xa4\xbcW\x95\x9eX\x96\xa5\x1e\xbfv\xbb\xfd|>s)z[\xba\xae\x97\xcbe\xcb\
\xb2l\xdbN\xa3\xf0c\x10\x11y\x9eW\xadV\x1b\x8d\xc6\x9f\x99\xca\x18\xed\xa5\
\x10q\xb7\xdb\xad\xd7\xebz\xbd>\x9b\xcd\xfa\xfd\xbe\xf2\xfb\x13\xd0j\xb5R\
\xfd\xf9|VWJm\xe3\x93\xd1\x00@\x08\xa1\x1a\xf5\x84\x01\xc0/lH9\xb0\xbf\xdf[\
\xdb\x00\x00\x00\x00IEND\xaeB`\x82\xe4\x12\x039' }
      

#######################################
#  ResourceFile
#######################################  
class ResourceFile(object):
    """
    リソースファイルクラス
    """
    rname = {}

    def __new__(cls,rfile=None):
        """
        リソースファイル毎にインスタンスを返す
        同じリソースファイルであれば、同じインスタンス
        を返す
        @param rfile リソースファイル名
        @retval クラスのインスタンス
        """
        # ファイル名が指定されていなければ
        if rfile == None:
            # デフォルト名を使用
            rfile = RESOURCEFILE
            
        # 指定されたリソースファイルのインスタンスが生成済みなら
        if cls.rname.has_key(rfile):
            # 生成済みのインスタンスを返す
            instance = cls.rname[rfile]
        else:    
            #クラスインスタンスが未生成なら新規に構築
            instance = object.__new__(cls)
                
            # リソースファイル読み込み  
            instance.initinstance(rfile)
            
        return instance 
  
      
    ##############################################
    def initinstance(self,rfile):
        """
        リソースファイルの読み込み
        @param rfile : リソースファイル名
        @retval 無し
        """
        # プラットフォームが Mac なら
        if sys.platform == "darwin":
            # Mac 用リソースファイル
            fname = rfile + "Mac.xrc"
            if self.SearchPath(fname) == "":
                fname = rfile + ".xrc"    
        # プラットフォームはWindows か
        elif os.name == "nt":
            # Windows 用リソースファイル
            fname = rfile + "Win.xrc"
            if self.SearchPath(fname) == "":
                fname = rfile + ".xrc"    
        else:
            # Linux 用リソースファイル
            fname = rfile + ".xrc"
        
        fpath = self.SearchPath(fname)
        
        self.res = None
        try:
            if fpath == "":
                raise PlotException('Common','C006',fname)
        except PlotException, ex:
            PlotMessage(None,ex)
        else:
            self.res = xrc.XmlResource(fpath)

    ##############################################        
    def GetCtrl(self,parent,tag):
        """
        パネル、テキストボックスを取得
        @param parent : 親ウィンドウのID
        @param tag: パネル、テキストボックスのID
        @retval パネル、テキストボックス
        """
        return xrc.XRCCTRL(parent,tag)

    ##############################################    
    def GetFrame(self,parent,tag):
        """
        フレームを取得
        @param parent : 親ウィンドウのID
        @param tag: フレームのID
        @retval フレーム
        """
        # 先にリソースファイルをオープンできていなければ
        if self.res == None:
            # None を返す
            return None
        return self.res.LoadFrame(parent, tag)

    ##############################################    
    def GetMenuBar(self,tag):
        """
        メニューを取得
        @param tag: フレームのID
        @retval フレーム
        """
        return self.res.LoadMenuBar(tag)

    ##############################################    
    def GetDialog(self,parent,tag):
        """
        ダイアログを取得
        @param parent : 親ウィンドウのID
        @param tag: ダイアログのID
        @retval ダイアログ
        """
        return self.res.LoadDialog(parent,tag)

    ##############################################    
    def GetId(self,tag):
        """
        ボタンのIDを取得
        @param tag: ボタンのID
        @retval ボタンのID
        """
        return xrc.XRCID(tag)
    

    #########################################
    def SearchPath(self, fname):
        """
        フルパスの探索
        @param  fname  　ファイル名
        @retval ファイルのフルパス
        """ 
        # カレントディレクトリを取得
        self.filePath = os.getcwd()
        fpath = os.path.join(self.filePath, fname)
        # カレントディレクトリに目的ファイルがあるか
        if os.path.isfile(fpath):
            # フルパスを返す
            return fpath
        
        self.filePath = ""

        # 環境変数に指定されたディレクトリを取得
        ap = AcqPath()
        paths = [ap.GetSysExp(), ap.GetSysAnal(), ap.GetSysVis()]
        ##[inamura 100720]-->
        p_path = os.environ.get('PYTHONPATH')
        if p_path!=None:
            p_path_list = p_path.split(os.pathsep)
            for pp in p_path_list:
                paths.append(pp)
                paths.append( os.path.join(pp,"vis") )
        ##<--[inamura 100720]
        # 全PYTHONPATHディレクトリを探索
        for path in paths:
            fpath = os.path.normpath(os.path.join(path,fname))
            # ディレクトリに目的ファイルがあるか
            if os.path.isfile(fpath):
                # ディレクトリを設定
                self.filePath = path
                # フルパスを返す
                return fpath
        
        # 目的ファイルが見つからなかった
        return ""
    
    #########################################
    def GetDirectory(self):  
        """
        ファイル格納ディレクトリの取得
        @param  無し
        @retval ディレクトリのフルパス
        """         
        return  self.filePath

#######################################
#  PlotException
#######################################  
class PlotException(Exception):
    """
    例外処理用コンテナクラス
    測定条件決定支援処理プログラム内で例外オブジェクトとして使用する
    メッセージ及びエラーコードは当クラスから取得できる
    """
    def __init__(self,parent,key,tap):
        """
        コンストラクタ
        @param parent:メッセージのカテゴリ
        @param key:メッセージID
        @param tap:編集パラメータ(tupleオブジェクト）

        """
        self.parent = parent
        self.key = key
        self.tap = tap
        
    ################################    
    def GetMessage(self):
        """
        メッセージの取得
        @params 無し
        @retval msg:メッセージ
        """
        msg = MessageFile()
        return msg.GetMessage(self.parent, self.key, self.tap)
    
    ################################
    def GetErrorCode(self):
        """
        エラーコードの取得
        @param 無し
        @retval code:エラーコード
        """
        return self.code
    
    ################################
    def GetDetailCode(self):
        """
        詳細コードの取得
        @param 無し
        @retval detail:詳細コード
        """
        return self.detail

#######################################
#  MessageFile
#######################################  
class MessageFile(object):
    """
    MessageFileクラス
    MessageFileの読み込みとMessageの編集を行う
    Singletonクラスとして利用
    """
    instance = None
    lang = 'English'
    
    ################################
    def __new__(cls,*args):
        """
        Singletonコンストラクタ
        @param 無し
        @retval　無し
        """
        if cls.instance is None:
            cls.instance = object.__new__(cls,*args)
            # メッセージファイル読み込み
            cls.instance.Load()
        return cls.instance

    ################################
    def Load(self):
        """
        MessageFileの読み込み
        @param 　無し
        @retval 無し
        """
        # メッセージファイルの絶対パスを作る
        msgpath = self.SearchPath(MESSAGEFILE)
        try:    
            #　メッセージファイルをXML パーサに読み込み
            self.xmlDoc = parse(msgpath)
            self.isRead = True
        except:
            self.isRead = False
    
    ################################
    def GetMessage(self,parent,key,tap):
        """
        編集されたMessageの取得
        @param parent:メッセージのカテゴリ
        @param key:メッセージID
        @param tap:編集パラメータ(tupleオブジェクト）
        @retval Message
        """
        # --> 2008/04/28 Minakawa 
        # メッセージファイルを読み込み済みか
        if self.isRead == False:
            self.Load()
        # <-- 2008/04/28 Minakawa
        
        # メッセージファイルの読み込みに成功しているか
        if self.isRead == True: 
            # 親ノードを取得   
            node = self.xmlDoc.getElementsByTagName(parent)[0]
            # 言語ノードを取得
            lang = node.getElementsByTagName(self.lang)[0]
            try:
                # メッセージ文字列を取得
                child = lang.getElementsByTagName(key)[0]
            except TypeError:
                raise PlotException('Common','C001',(key,"Wrong Code"))
            try:
                # 文字列にタプルで指定された引数を入れこむ
                return child.firstChild.data % ( tap )
            except TypeError:
                raise PlotException('Common','C001',(key,"TypeError"))
        else:
            return 'Message File Read Error!! ( Message.GetMessage() )' 

    #########################################
    def SearchPath(self, fname):
        """
        フルパスの探索
        @param  fname  　ファイル名
        @retval ファイルのフルパス
        """ 
        # カレントディレクトリを取得
        self.filePath = os.getcwd()
        fpath = os.path.join(self.filePath, fname)
        # カレントディレクトリに目的ファイルがあるか
        if os.path.isfile(fpath):
            # フルパスを返す
            return fpath
        self.filePath = ""
        # 環境変数 UTSUSEMI_BASE_DIR に指定されたディレクトリを取得
        try:
            path = os.environ["UTSUSEMI_BASE_DIR"]
            path = os.path.join(path,"vis")
            fpath = os.path.join(path, fname)
            if os.path.isfile(fpath):
                # フルパスを返す
                return fpath
            
        except:
            return ""
        
        ##[inamura 100720]-->
        ## for StandAlone 
        if path==None:
            p_path = os.environ.get('PYTHONPATH')
            if p_path!=None:
                p_path_list = p_path.split(os.pathsep)
                path_list = []
                for pp in p_path_list:
                    path_list.append( pp )
                    path_list.append( os.path.join(pp,"vis") )
                for pp in path_list:
                    fp = os.path.normpath( os.path.join( pp,fname ) )
                    if os.path.isfile(fp):
                        self.filePath = pp
                        return fp
        else:
            return ""
            
        """
        path = os.path.join(path,'vis')
        fpath = os.path.join(path,fname)

        # ディレクトリに目的ファイルがあるか
        if os.path.isfile(fpath):
            # ディレクトリを設定
            self.filePath = path
            # フルパスを返す
            return fpath
        else:
            return ""
        """
        ##<--[inamura 100720]         
        
        """
        # 環境変数PYTHONPATHに指定されたディレクトリを取得
        paths = str( os.environ.get('PYTHONPATH')).split(os.pathsep)
        # 全PYTHONPATHディレクトリを探索
        for path in paths:
            fpath = os.path.normpath(os.path.join(path,fname))
            # ディレクトリに目的ファイルがあるか
            if os.path.isfile(fpath):
                # ディレクトリを設定
                self.filePath = path
                # フルパスを返す
                return fpath
        
        # 目的ファイルが見つからなかった
        return ""
        """
        
    ################################    
    def CloseDoc(self):
        """
        XMLドキュメントの解放
        @param  無
        @retval 無
        """               
        if self.isRead:
            self.xmlDoc.unlink()
            self.isRead = False   # 208/04/28 Minakawa


#######################################
#  PlotMessage
#######################################      
class PlotMessage(object):
    """
    各種メッセージの表示クラス
    有効なウィンドウが指定されない場合はコンソールへのテキスト出力
    親ウィンドウが指定されていれば、MessageBoxを表示
    """
    def __init__(self, parent, ex):
        """
        コンストラクタ
        @param parent:親ウィンドウオブジェクト（無ければNoneを指定）
        @param ex:PlotExceptionのインスタンス
        @retval 無し
        """
        msg = ex.GetMessage()
        
        #MessageBoxを表示する親ウィンドウが無効であればコンソール出力

        if parent is None:
            #traceback.print_stack()
            sys.stdout = codecs.lookup('utf-8')[-1](sys.stdout)
            print msg
        else:
            wx.MessageBox(msg,caption='Message',style=wx.OK)  
              
###############################################################################
# テスト用スクリプト
###############################################################################
if __name__=='__main__':

    pass
