#!/usr/bin/python  
 | 
# -*- coding: GBK -*-  
 | 
#-------------------------------------------------------------------------------  
 | 
#  
 | 
#-------------------------------------------------------------------------------  
 | 
#  
 | 
##@package Player.PlayerGoldInvest  
 | 
#  
 | 
# @todo:Àí²ÆÍ¶×Ê  
 | 
# @author xdh  
 | 
# @date 2018-04-02  
 | 
# @version 1.0  
 | 
#  
 | 
#  
 | 
# ÏêϸÃèÊö: Àí²ÆÍ¶×Ê  
 | 
#  
 | 
#---------------------------------------------------------------------  
 | 
#"""Version = 2018-04-02 10:30"""  
 | 
#---------------------------------------------------------------------  
 | 
  
 | 
import IpyGameDataPY  
 | 
import NetPackCommon  
 | 
import ChPyNetSendPack  
 | 
import IPY_GameWorld  
 | 
import PlayerControl  
 | 
import GameWorld  
 | 
import ChConfig  
 | 
import ItemControler  
 | 
import DataRecordPack  
 | 
import PlayerFamilyRedPacket  
 | 
  
 | 
import time  
 | 
  
 | 
  
 | 
## »ñȡͶ×ÊÀí²ÆÍæ¼ÒÊý¾Ý¿â×ÖµäÐÅÏ¢Öµ  
 | 
#  @param curPlayer Íæ¼ÒʵÀý  
 | 
#  @param key ×Öµäkey  
 | 
#  @param defaultValue Ä¬ÈÏÖµ  
 | 
#  @return  
 | 
def __GetPDictValue(curPlayer, key, defaultValue=0):  
 | 
    return curPlayer.NomalDictGetProperty(key, defaultValue, ChConfig.Def_PDictType_GoldInvest)  
 | 
  
 | 
  
 | 
## ÉèÖÃͶ×ÊÀí²ÆÍæ¼ÒÊý¾Ý¿â×ÖµäÐÅÏ¢Öµ  
 | 
#  @param curPlayer Íæ¼ÒʵÀý  
 | 
#  @param key ×Öµäkey  
 | 
#  @param value ÉèÖõÄÖµ  
 | 
#  @return  
 | 
def __SetPDictValue(curPlayer, key, value):  
 | 
    PlayerControl.NomalDictSetProperty(curPlayer, key, value, ChConfig.Def_PDictType_GoldInvest)  
 | 
    return  
 | 
  
 | 
  
 | 
## Í¶×ÊÀí²ÆÍæ¼ÒµÇ¼´¦Àí  
 | 
#  @param curPlayer Íæ¼Ò  
 | 
#  @return  
 | 
def OnLogin(curPlayer):  
 | 
    __CheckOldInvest(curPlayer)  
 | 
    for iType in ChConfig.GoldInvestTypeList:  
 | 
        Sync_GoldInvestInfo(curPlayer, iType)  
 | 
    return  
 | 
  
 | 
  
 | 
## Í¶×ÊÀí²ÆÍæ¼Ò¹ýÌì´¦Àí  
 | 
#  @param curPlayer Íæ¼Ò  
 | 
#  @return  
 | 
def OnDay(curPlayer):  
 | 
    __CheckOldInvest(curPlayer)  
 | 
    #vipͶ×ʹýÁËÕû¸öÖÜÆÚÔòÖØÖà  
 | 
    __CheckInvestReset(curPlayer)  
 | 
      
 | 
      
 | 
    for iType in ChConfig.GoldInvestTypeList:  
 | 
        Sync_GoldInvestInfo(curPlayer, iType)  
 | 
      
 | 
    awardData = __GetInvestLVData(curPlayer)  
 | 
    __SetPDictValue(curPlayer, ChConfig.Def_PDict_GoldInvest_AwardData % ChConfig.GoldInvestType_VIP, awardData)  
 | 
    return  
 | 
  
 | 
def __CheckInvestReset(curPlayer):  
 | 
    ##¼ì²évipͶ×ÊÖØÖ೬¹ý28Ìì»ò28Ìì½±ÀøÒÑÁìÈ¡¿ÉÖØÖà  
 | 
    investType = ChConfig.GoldInvestType_VIP  
 | 
    investGoldRecord = __GetPDictValue(curPlayer, ChConfig.Def_PDict_GoldInvest_Gold % investType)  
 | 
    if not investGoldRecord:  
 | 
        return  
 | 
    curDay = __GetInvestCurDay(curPlayer, investType)  
 | 
    investMaxDayDict = IpyGameDataPY.GetFuncEvalCfg('InvestMaxDay')  
 | 
    maxDay = investMaxDayDict.get(str(investType), 0)  
 | 
    if curDay > maxDay or __GetPDictValue(curPlayer, ChConfig.Def_PDict_GoldInvest_GotRewardValue % (investType, maxDay)):  
 | 
        __SetPDictValue(curPlayer, ChConfig.Def_PDict_GoldInvest_Time % investType, 0)  
 | 
        __SetPDictValue(curPlayer, ChConfig.Def_PDict_GoldInvest_Gold % investType, 0)  
 | 
        for i in xrange(1, maxDay+1):  
 | 
            __SetPDictValue(curPlayer, ChConfig.Def_PDict_GoldInvest_GotRewardValue % (investType, i), 0)  
 | 
    Sync_GoldInvestInfo(curPlayer, investType, isForce=True)  
 | 
    return  
 | 
  
 | 
def __CheckOldInvest(curPlayer):  
 | 
    #¾É°æ±¾Í¶×ʲ¹³¥  
 | 
    investType = ChConfig.GoldInvestType_VIP  
 | 
    investGoldRecord = __GetPDictValue(curPlayer, ChConfig.Def_PDict_GoldInvest_Gold % investType)  
 | 
    if investGoldRecord != 300:  
 | 
        return  
 | 
    maxDay = 28  
 | 
    curDay = __GetInvestCurDay(curPlayer, investType)  
 | 
    if curDay > maxDay:  
 | 
        return  
 | 
    if __GetPDictValue(curPlayer, ChConfig.Def_PDict_GoldInvest_GotRewardValue % (investType, curDay)):  
 | 
        sendDayList = range(curDay+1,maxDay+1)  
 | 
    else:  
 | 
        sendDayList = range(curDay, maxDay+1)  
 | 
    if sendDayList:  
 | 
        sendItemDict = {}  
 | 
        for day in sendDayList:  
 | 
            index = day%7  
 | 
            if index == 0:  
 | 
                index = 7  
 | 
            ipyData = IpyGameDataPY.GetIpyGameData('Invest', investType*100+index)  
 | 
            if not ipyData:  
 | 
                continue  
 | 
            itemList = ipyData.GetReward()['1']  
 | 
            for itemID, itemCnt, isBind in itemList:  
 | 
                sendItemDict[itemID] = sendItemDict.get(itemID, 0) + itemCnt  
 | 
      
 | 
        sendItemList = [(itemID, itemCnt, 1) for itemID, itemCnt in sendItemDict.items()]  
 | 
        PlayerControl.SendMailByKey('VIPInvest', [curPlayer.GetID()], sendItemList, [len(sendDayList)])  
 | 
        GameWorld.Log('    ¾É°æ±¾Í¶×ʲ¹³¥ sendDay=%s, sendItemList=%s'%(len(sendDayList), sendItemList), curPlayer.GetID())  
 | 
          
 | 
    __SetPDictValue(curPlayer, ChConfig.Def_PDict_GoldInvest_Time % investType, 0)  
 | 
    __SetPDictValue(curPlayer, ChConfig.Def_PDict_GoldInvest_Gold % investType, 0)  
 | 
    for i in xrange(1, maxDay+1):  
 | 
        __SetPDictValue(curPlayer, ChConfig.Def_PDict_GoldInvest_GotRewardValue % (investType, i), 0)  
 | 
    return  
 | 
#// A5 40 Í¶×ÊÀí²Æ #tagCMGoldInvest  
 | 
#  
 | 
#struct    tagCMGoldInvest  
 | 
#{  
 | 
#    tagHead        Head;  
 | 
#    BYTE        InvestType; // Í¶×ÊÀàÐÍ  
 | 
#    DWORD        InvestGold; // Í¶×ʶî¶È  
 | 
#};  
 | 
## Í¶×ÊÀí²Æ  
 | 
#  @param   
 | 
#  @return  
 | 
def OnGoldInvest(index, clientData, tick):  
 | 
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)  
 | 
    investType = clientData.InvestType  
 | 
    investGold = clientData.InvestGold  
 | 
      
 | 
    GameWorld.DebugLog("Ͷ×ÊÀí²Æ£ºinvestType=%s,investGold=%s" % (investType, investGold))  
 | 
    investCostDict = IpyGameDataPY.GetFuncEvalCfg('InvestCost')  
 | 
    if str(investType) not in investCostDict:  
 | 
        return  
 | 
    costList = investCostDict[str(investType)]  
 | 
    if investGold not in costList:  
 | 
        GameWorld.DebugLog('    Í¶×ÊÀí²Æ Í¶×ʶî¶È²»´æÔÚ investGold=%s£¬ investType=%s'%(investGold, investType))  
 | 
        return  
 | 
      
 | 
    awardData = costList.index(investGold) + 1  
 | 
    if investType == ChConfig.GoldInvestType_VIP:  
 | 
        awardData = __GetInvestLVData(curPlayer)  
 | 
        needVIPLV = IpyGameDataPY.GetFuncCfg('VIPInvest', 2)  
 | 
        if curPlayer.GetVIPLv() < needVIPLV:  
 | 
            GameWorld.DebugLog('    Í¶×ÊÀí²Æ ÐèÒªVIP%s'%(needVIPLV))  
 | 
            return  
 | 
      
 | 
          
 | 
    deductGold = investGold  
 | 
    investGoldRecord = __GetPDictValue(curPlayer, ChConfig.Def_PDict_GoldInvest_Gold % investType)  
 | 
    if investGoldRecord:  
 | 
        curDay = __GetInvestCurDay(curPlayer, investType)  
 | 
        #¿ÉÑ»·Í¶×Ê  
 | 
        if investType in ChConfig.CanRepeatInvestType:  
 | 
            # ÒÑͶ×ʹý£¬¼ì²éÌìÊýÊÇ·ñÒѽáÊø  
 | 
            investMaxDayDict = IpyGameDataPY.GetFuncEvalCfg('InvestMaxDay')  
 | 
            maxDay = investMaxDayDict.get(str(investType), 0)  
 | 
            if curDay < maxDay:  
 | 
                GameWorld.DebugLog('    »¹ÓÐͶ×ÊÌìÊýδÁìÈ¡£¡curDay=%s,maxDay=%s'%(curDay,maxDay))  
 | 
                return  
 | 
            if curDay == maxDay:  
 | 
                rewardRecord = __GetPDictValue(curPlayer, ChConfig.Def_PDict_GoldInvest_GotRewardValue % (investType, maxDay))  
 | 
                if not rewardRecord:  
 | 
                    GameWorld.DebugLog("    »¹ÓÐδÁìÈ¡µÄͶ×ʻر¨£¬²»¿ÉͶ×Ê£¡investType=%s,rewardRecord=%s"   
 | 
                                       % (investType, rewardRecord))  
 | 
                    return  
 | 
                  
 | 
                  
 | 
        # ²»¿ÉÑ»·Í¶×Ê£¬µ«¿É×·¼ÓͶ×Ê  
 | 
        elif investType in ChConfig.InvestGoldTypeList:  
 | 
            if investGoldRecord >= investGold:  
 | 
                GameWorld.DebugLog("    ÒÑͶ×ʵµ´Î=%s >= ×·¼ÓͶ×ʵµ´Î=%s ,²»¿É×·¼ÓͶ×Ê£¡"   
 | 
                                   % (investGoldRecord, investGold))  
 | 
                return  
 | 
              
 | 
            deductGold = investGold - investGoldRecord # ×·¼ÓͶ×ÊÐèÒª¿Û³ýµÄ×êʯ  
 | 
            GameWorld.DebugLog("    ÒÑͶ×Ê=%s£¬×·¼ÓͶ×ÊÐè¿Û³ý=%s" % (investGoldRecord, deductGold))  
 | 
        else:  
 | 
            GameWorld.DebugLog("    investType = %s ÒÑͶ×ʹý£¬²»¿ÉÖØ¸´Í¶×Ê" % investType)  
 | 
            return  
 | 
#    elif investType in ChConfig.InvestGoldTypeList:  
 | 
#        goldInvestLVLimit = IpyGameDataPY.GetFuncEvalCfg('GoldInvestLVLimit', 1, {}).get(investType, 0)  
 | 
#        if goldInvestLVLimit and curPlayer.GetLV() > goldInvestLVLimit:  
 | 
#            GameWorld.DebugLog('    ÏÉÓñͶ×ÊÀí²Æ µÈ¼¶²»ÄܸßÓÚ%s'%(goldInvestLVLimit))  
 | 
#            return  
 | 
          
 | 
    __DoGoldInvest(curPlayer, investType, investGold, deductGold, awardData)  
 | 
    return  
 | 
  
 | 
def __GetInvestCurDay(curPlayer, investType):  
 | 
    ## »ñȡͶ×ʵ±Ç°µÚ¼¸Ìì  
 | 
    investTime = __GetPDictValue(curPlayer, ChConfig.Def_PDict_GoldInvest_Time % investType)  
 | 
    curTime = GameWorld.ChangeTimeStrToNum(GameWorld.GetCurrentDataTimeStr())  
 | 
    passTick = max(0, curTime - investTime)  
 | 
    return passTick / 3600 / 24 + 1  
 | 
  
 | 
def __GetInvestLVData(curPlayer):  
 | 
    #vipͶ×Ê µ±Ç°ËùÊôµÈ¼¶·¶Î§  
 | 
    investLVDataDict = IpyGameDataPY.GetFuncEvalCfg('VIPInvest')  
 | 
    lv = curPlayer.GetLV()  
 | 
    for keyData, lvRange in investLVDataDict.items():  
 | 
        if lvRange[0] <=lv <= lvRange[1]:  
 | 
            return int(keyData)  
 | 
    return 0  
 | 
  
 | 
## Ö´ÐÐͶ×ÊÀí²Æ  
 | 
#  @param   
 | 
#  @return  
 | 
def __DoGoldInvest(curPlayer, investType, investGold, deductGold, awardData):  
 | 
    #¿Û×êʯ      
 | 
    infoDict = {"InvestType":investType, "DeductGold":deductGold, "InvestGold":investGold,  
 | 
                ChConfig.Def_Cost_Reason_SonKey:investType}  
 | 
    if not PlayerControl.PayMoney(curPlayer, IPY_GameWorld.TYPE_Price_Gold_Money, deductGold,  
 | 
                                  ChConfig.Def_Cost_GoldInvest, infoDict):  
 | 
        return  
 | 
    #ºì°ü½±Àø  
 | 
    if investGold == deductGold:  
 | 
        redPacketID = IpyGameDataPY.GetFuncEvalCfg('InvestRedPackAward', 1, {}).get(investType, 0)  
 | 
        if redPacketID:  
 | 
            PlayerFamilyRedPacket.CreatRedPacketByID(curPlayer, redPacketID)  
 | 
    if investType == ChConfig.GoldInvestType_VIP:  
 | 
        PlayerControl.WorldNotify(0, 'VIPInvestmentRadio', [curPlayer.GetName()])  
 | 
    elif investType in ChConfig.InvestGoldTypeList:  
 | 
        PlayerControl.WorldNotify(0, 'JadeInvestmentRadio', [curPlayer.GetName(), investGold])  
 | 
  
 | 
    # ¸üÐÂͶ×Êʱʱ¼ä£¬Í¶×ʽð¶î£¬ÖØÖûر¨¼Ç¼  
 | 
    curTime = GameWorld.GetCurrentTime()  
 | 
    curTimeNum = GameWorld.ChangeTimeStrToNum(str(curTime)[:10], ChConfig.TYPE_Time_Format_Day)  
 | 
    __SetPDictValue(curPlayer, ChConfig.Def_PDict_GoldInvest_Time % investType, curTimeNum)  
 | 
    __SetPDictValue(curPlayer, ChConfig.Def_PDict_GoldInvest_Gold % investType, investGold)  
 | 
    __SetPDictValue(curPlayer, ChConfig.Def_PDict_GoldInvest_AwardData % investType, awardData)  
 | 
      
 | 
    if investType in ChConfig.CanRepeatInvestType:  
 | 
        investMaxDayDict = IpyGameDataPY.GetFuncEvalCfg('InvestMaxDay')  
 | 
        maxDay = investMaxDayDict.get(str(investType), 0)  
 | 
        for i in xrange(1, maxDay+1):  
 | 
            __SetPDictValue(curPlayer, ChConfig.Def_PDict_GoldInvest_GotRewardValue % (investType, i), 0)  
 | 
      
 | 
      
 | 
    #EventShell.EventRespons_OnGoldInvest(curPlayer, investType)  
 | 
    # Í¬²½Í¶×ÊÐÅÏ¢  
 | 
    Sync_GoldInvestInfo(curPlayer, investType)  
 | 
      
 | 
    # Í¶×ÊÈ«·þ¹ã²¥  
 | 
      
 | 
    GameWorld.DebugLog("    Í¶×ʳɹ¦£¡¿Û³ý×êʯ=%s" % deductGold)  
 | 
    return  
 | 
  
 | 
  
 | 
  
 | 
#// A5 41 ÁìȡͶ×ÊÀí²Æ»Ø±¨ #tagCMGetInvestReward  
 | 
#  
 | 
#struct    tagCMGetInvestReward  
 | 
#{  
 | 
#    tagHead        Head;  
 | 
#    BYTE        InvestType; // Í¶×ÊÀàÐÍ  
 | 
#    BYTE        RewardIndex; // »Ø±¨Ë÷Òý  
 | 
#};  
 | 
## ÁìȡͶ×ÊÀí²Æ»Ø±¨  
 | 
#  @param   
 | 
#  @return  
 | 
def OnGetGoldInvestReward(index, clientData, tick):  
 | 
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)  
 | 
    investType = clientData.InvestType  
 | 
    rewardIndex = clientData.RewardIndex  
 | 
    ipyData = IpyGameDataPY.GetIpyGameData('Invest', investType*100+rewardIndex)  
 | 
    if not ipyData:  
 | 
        return  
 | 
      
 | 
    investGold = __GetPDictValue(curPlayer, ChConfig.Def_PDict_GoldInvest_Gold % investType)  
 | 
      
 | 
    GameWorld.DebugLog("ÁìȡͶ×ÊÀí²Æ»Ø±¨£ºinvestType=%s,investGold=%s,rewardIndex=%s"   
 | 
                       % (investType, investGold, rewardIndex))  
 | 
      
 | 
    if not investGold:  
 | 
        GameWorld.DebugLog("    ¸ÃÀàÐÍûÓÐͶ×ʹý£¬ÎÞ·¨ÁìÈ¡»Ø±¨£¡investType=%s" % investType)  
 | 
        return  
 | 
    needLV = ipyData.GetNeedLV()  
 | 
    if curPlayer.GetLV() < needLV:  
 | 
        GameWorld.DebugLog("    µÈ¼¶²»¹»%s£¬ÎÞ·¨ÁìÈ¡»Ø±¨£¡investType=%s" % (needLV, investType))  
 | 
        return  
 | 
      
 | 
    needDay = ipyData.GetNeedDay()  
 | 
    if needDay:  
 | 
        curDay = __GetInvestCurDay(curPlayer, investType)  
 | 
        if needDay != curDay:  
 | 
            GameWorld.DebugLog("    ÎÞ·¨ÁìÈ¡»Ø±¨£¡ Ö»ÄÜÁìÈ¡µ±ÌìµÄ£¬curDay=%s£¬needDay=%s" % (curDay, needDay))  
 | 
            return  
 | 
      
 | 
    rewardDict = ipyData.GetReward()  
 | 
    awardData = __GetPDictValue(curPlayer, ChConfig.Def_PDict_GoldInvest_AwardData % investType, 1)  
 | 
    if str(awardData) not in rewardDict:  
 | 
        GameWorld.DebugLog('    ÁìȡͶ×ÊÀí²Æ»Ø±¨, rewardDict=%s, Ã»ÓÐkey=%s'%(rewardDict, awardData))  
 | 
        return  
 | 
    rewardList = rewardDict[str(awardData)]  
 | 
  
 | 
    rewardItemList = rewardList # »Ø±¨ÎïÆ·ÁÐ±í  
 | 
    rewardValueKey = ChConfig.Def_PDict_GoldInvest_GotRewardValue % (investType, rewardIndex)  
 | 
    lastDayGotData = __GetPDictValue(curPlayer, rewardValueKey) # ÒÑÁìÈ¡Êý¾Ý  
 | 
  
 | 
    if lastDayGotData:  
 | 
        if investType in ChConfig.InvestGoldTypeList:  
 | 
            if awardData > lastDayGotData:  
 | 
                lastGotAwardList = rewardDict[str(lastDayGotData)]  
 | 
                rewardItemList = []  
 | 
                for itemID, itemCnt, isBind in rewardList:  
 | 
                    newCnt = itemCnt  
 | 
                    for itemInfo in lastGotAwardList:  
 | 
                        if itemID == itemInfo[0]:  
 | 
                            newCnt = max(1,itemCnt - itemInfo[1])  
 | 
                            break  
 | 
                    rewardItemList.append([itemID, newCnt, isBind])  
 | 
            else:  
 | 
                GameWorld.DebugLog('    11ÁìȡͶ×ÊÀí²Æ»Ø±¨, ÒÑÁìÈ¡¹ý£¡ investType=%s, rewardIndex=%s'%(investType, rewardIndex))  
 | 
                return  
 | 
        else:  
 | 
            GameWorld.DebugLog('    ÁìȡͶ×ÊÀí²Æ»Ø±¨, ÒÑÁìÈ¡¹ý£¡ investType=%s, rewardIndex=%s'%(investType, rewardIndex))  
 | 
            return  
 | 
              
 | 
          
 | 
    __SetPDictValue(curPlayer, rewardValueKey, awardData)  
 | 
                  
 | 
    GameWorld.DebugLog("    ÁìȡͶ×ÊÀí²Æ»Ø±¨ rewardItemList=%s" % (rewardItemList))  
 | 
    if rewardItemList:  
 | 
        for itemID, itemCnt, isBind in rewardItemList:  
 | 
            ItemControler.GivePlayerItem(curPlayer, itemID, itemCnt, isBind, [IPY_GameWorld.rptItem, IPY_GameWorld.rptAnyWhere], True, showSysInfo=True)  
 | 
      
 | 
    __CheckInvestReset(curPlayer)  
 | 
    # ¼Ç¼Áìȡʼþ  
 | 
    DataRecordPack.DR_GetGoldInvestReward(curPlayer, investType, rewardIndex, rewardItemList)  
 | 
          
 | 
    Sync_GoldInvestInfo(curPlayer, investType, rewardIndex)  
 | 
    return  
 | 
  
 | 
## Í¬²½Í¶×ÊÀí²ÆÐÅÏ¢  
 | 
#  @param   
 | 
#  @return  
 | 
def Sync_GoldInvestInfo(curPlayer, investType, index=-1, isForce=False):  
 | 
    investGold = __GetPDictValue(curPlayer, ChConfig.Def_PDict_GoldInvest_Gold % investType)  
 | 
    if not isForce and not investGold:  
 | 
        return  
 | 
    investInfoPack = ChPyNetSendPack.tagMCGoldInvestInfo()  
 | 
    investInfoPack.Clear()  
 | 
    investInfoPack.InvestType = investType  
 | 
    investInfoPack.CurDay = __GetInvestCurDay(curPlayer, investType)  
 | 
    investInfoPack.InvestGold = investGold  
 | 
    investInfoPack.InvestRewardList = []  
 | 
    ipyGameDataList = IpyGameDataPY.GetIpyGameDataByCondition('Invest', {'Type':investType}, True)  
 | 
      
 | 
    if not ipyGameDataList:  
 | 
        return  
 | 
    for ipyData in ipyGameDataList:  
 | 
        rewardIndex = ipyData.GetID() % 100  
 | 
        if index !=-1 and rewardIndex != index:  
 | 
            continue  
 | 
        investReward = ChPyNetSendPack.tagMCInvestReward()  
 | 
        investReward.RewardIndex = rewardIndex  
 | 
        investReward.RewardValue = __GetPDictValue(curPlayer, ChConfig.Def_PDict_GoldInvest_GotRewardValue % (investType, rewardIndex))  
 | 
        investInfoPack.InvestRewardList.append(investReward)  
 | 
    investInfoPack.RewardRecordCnt = len(investInfoPack.InvestRewardList)  
 | 
    NetPackCommon.SendFakePack(curPlayer, investInfoPack)  
 | 
    return  
 | 
  
 | 
  
 | 
  
 | 
  
 |