Parent removed, but some offspring remains

All topics about ZGameEditor goes here.

Moderator: Moderators

Post Reply
User avatar
rrTea
Posts: 475
Joined: Sat Feb 15, 2014 9:54 am

Parent removed, but some offspring remains

Post by rrTea »

I have a model that spawns a few smaller models with "SpawnerIsParent" turned on. When the Parent is removed, all the kids are removed too. But one particular model often leaves one of its kids around and when I try to remove that orphan kid, ZGE crashes reporting only "ZArrayList bad index" or "Access Violation".


Crashes disappear as soon as the "SpawnerIsParent" is turned off. It also works in a simple isolated case, but even when I started adding features from the project to it, still no crashes so it must be something in the main project... I tried everything I can think of (peppering everything with "trace"s, clamping all array-related operations, changing various parameters, conditions) but no luck.


Here are two test cases, as mentioned they both work perfectly but I'm pasting them in case somebody can spot anything suspicious:

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" Camera="Camera1" ViewportRatio="3" FileVersion="2">
  <OnLoaded>
    <Repeat Count="20">
      <OnIteration>
        <ZExpression>
          <Expression>
<![CDATA[Model1.Position.X = sin(rnd()*Pi*2) *16*0.5;
Model1.Position.Y = sin(rnd()*Pi*2) *9*0.5;]]>
          </Expression>
        </ZExpression>
        <SpawnModel Model="Model1"/>
      </OnIteration>
    </Repeat>
  </OnLoaded>
  <Content>
    <Model Name="Model1" BaseModel="baseMdl" Position="-5.038 3.1623 0" Category="1">
      <OnUpdate>
        <Timer Comment="Spawn kids" Interval="0.05" RepeatCount="20">
          <OnTimer>
            <ZExpression>
              <Expression>
<![CDATA[Model2.Position.X = CurrentModel.Position.X + sin(rnd()*Pi*2) *16*0.1;
Model2.Position.Y = CurrentModel.Position.Y + sin(rnd()*Pi*2) *9*0.1;]]>
              </Expression>
            </ZExpression>
            <SpawnModel Model="Model2" SpawnerIsParent="255"/>
          </OnTimer>
        </Timer>
        <Timer Comment="Expire" Interval="2">
          <OnTimer>
            <RemoveModel/>
          </OnTimer>
        </Timer>
      </OnUpdate>
      <OnRender>
        <UseMaterial Material="Material1"/>
        <RenderSetColor Color="1 0 0.502 1"/>
        <RenderNet/>
      </OnRender>
    </Model>
    <Model Name="Model2" BaseModel="baseMdl" Position="-5.2244 2.5007 0" Scale="0.5 0.5 1" Category="2">
      <OnSpawn>
        <ZExpression>
          <Expression>
<![CDATA[//In the project this model changes category
//under certain conditions
CurrentModel.Category = 0;]]>
          </Expression>
        </ZExpression>
      </OnSpawn>
      <OnRender>
        <UseMaterial Material="Material1"/>
        <RenderSetColor Color="0 1 1 1"/>
        <RenderNet/>
      </OnRender>
    </Model>
    <Material Name="Material1" Shading="1" Light="0"/>
    <Camera Name="Camera1" Kind="1" Position="0 0 10" OrthoZoom="9"/>
    <Model Name="baseMdl"/>
  </Content>
</ZApplication>
And here is the next one with features simulating the events from the main game. The only difference is that the spawned models in the game do not overlap when spawned but here I just let them (I thought maybe it's related to collisions / positioning, but no - I left it in anyway for now):

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" Camera="Camera1" ViewportRatio="3" FileVersion="2">
  <OnLoaded>
    <DefineCollision Cat1="1" Cat2="2"/>
    <DefineCollision Cat1="1" Cat2="11"/>
    <Variable Name="current_Smalls" Type="1"/>
    <Variable Name="current_Bigs" Type="1"/>
    <ZExpression>
      <Expression>
<![CDATA[current_Bigs = 0;
current_Smalls = 0;

arr_Smalls.SizeDim1 = 16*2;
arr_Smalls.SizeDim2 = 9*2;

int c,x,y;
int l = arr_Smalls.SizeDim1*arr_Smalls.SizeDim2;
while (c<l)
      {x=c%arr_Smalls.SizeDim1;
       y=c/arr_Smalls.SizeDim1;
       arr_Smalls[x,y]=0;
       c++;}]]>
      </Expression>
    </ZExpression>
    <Repeat Count="10">
      <OnIteration>
        <ZExpression>
          <Expression>
<![CDATA[m_Big.Position.X = round(sin(rnd()*Pi*2) *16*0.5);
m_Big.Position.Y = round(sin(rnd()*Pi*2) *9*0.5);]]>
          </Expression>
        </ZExpression>
        <SpawnModel Model="m_Big"/>
      </OnIteration>
    </Repeat>
  </OnLoaded>
  <OnUpdate>
    <Timer Interval="6">
      <OnTimer>
        <Repeat Count="10">
          <OnIteration>
            <ZExpression>
              <Expression>
<![CDATA[m_Big.Position.X = round(sin(rnd()*Pi*2) *16*0.5);
m_Big.Position.Y = round(sin(rnd()*Pi*2) *9*0.5);]]>
              </Expression>
            </ZExpression>
            <SpawnModel Model="m_Big"/>
            <ZExpression>
              <Expression>
<![CDATA[m_Big1.Position.X = round(sin(rnd()*Pi*2) *16*0.5);
m_Big1.Position.Y = round(sin(rnd()*Pi*2) *9*0.5);]]>
              </Expression>
            </ZExpression>
            <SpawnModel Model="m_Big1"/>
          </OnIteration>
        </Repeat>
      </OnTimer>
    </Timer>
    <ZExpression>
      <Expression>
<![CDATA[txt_Array.Text = "";

int c,x,y;
int l = arr_Smalls.SizeDim1*arr_Smalls.SizeDim2;
while (c<l)
      {x=c%arr_Smalls.SizeDim1;
       y=c/arr_Smalls.SizeDim1;
       switch(arr_Smalls[x,y])
             {case 0: txt_Array.Text += " ";break;
              case 1:
              case 2:
              case 3:
              case 4:
              case 5:
              case 6:
              case 7:
              case 8:
              case 9: txt_Array.Text += intToStr(arr_Smalls[x,y]);break;
              default: txt_Array.Text += "+";}
       c++;}]]>
      </Expression>
    </ZExpression>
  </OnUpdate>
  <OnRender>
    <Group>
      <Children>
        <UseMaterial Material="mat_Wireframe"/>
        <RenderSetColor Color="0 0.251 0.502 1"/>
        <RenderNet XCount="31" YCount="17">
          <RenderVertexExpression>
<![CDATA[//Update each vertex.
//Vertex : current vertex
//TexCoord : current texture coordinate
//Color : current vertex color

Vertex.X *= 16*2;
Vertex.Y *= 9*2;]]>
          </RenderVertexExpression>
        </RenderNet>
      </Children>
    </Group>
    <Group>
      <Children>
        <UseMaterial Material="matFnt_Weiba"/>
        <RenderText TextFloatRef="current_Smalls" X="-12" Y="7" Scale="10" Align="1" UseModelSpace="255"/>
        <RenderText TextFloatRef="current_Bigs" X="-12" Y="5" Scale="10" Align="1" UseModelSpace="255"/>
        <RenderText Name="txt_Array" Text="                                  1         2   1       1   1                                                  1           1                                            1       1    1  1     11                                                                         1     1       1           1 1       1    2                                   1                              1                  1           1          1         1            11                                                                                                            1         1                 " X="-16" Y="-9" Scale="4" Align="1" UseModelSpace="255">
          <RenderCharExpression>
<![CDATA[//Modify current character before render.
//CharX,CharY : current coordinate
//CharI : current character index (read only)
//CharRotate : current character rotation in radians
//CharScale : current character scale

CharX = 0+(CharI%arr_Smalls.SizeDim1)*2.5;
CharY = 0+(CharI/arr_Smalls.SizeDim1)*2.5;]]>
          </RenderCharExpression>
        </RenderText>
      </Children>
    </Group>
  </OnRender>
  <Content>
    <Material Name="mat_Clean" Shading="1" Light="0"/>
    <Material Name="mat_Wireframe" Shading="2" Light="0" ZBuffer="0"/>
    <Camera Name="Camera1" Kind="1" Position="0 0 10" OrthoZoom="9"/>
    <Array Name="arr_Smalls" Type="1" Dimensions="1" SizeDim1="32" SizeDim2="18"/>
    <Group Comment="Font">
      <Children>
        <Bitmap Name="bmp_FontWeiba" Comment="by Ray" Width="256" Height="256">
          <Producers>
            <BitmapFromFile Comment="Imported from weiba 01.png" Transparency="2" HasAlphaLayer="1" DataWidth="256" DataHeight="256">
              <BitmapFile>
<![CDATA[78DAED5D3BAF655791E617183B9E9180CE8684474406389809DD4633A901939B470E861FE0478E78B8B3412DEC8E86C46008C8FC92092D0C9E1419D172DEA3AFA562CAABABD6AA5AAB6AED7DEEA992B66EF7B9E7EEC7DAABDE555F3D78F0FFF4CE3BEF3C78F7DD771F64D1DB6FBFFDF058A5DFFDEE770F9E7FFEF987C78F7EF4A3073FF9C94F1E7E164538DF8F7FFCE387075D830E7C869FF8FC873FFCE13F7F8FCFE9FFF43BFA5EFBF791F75A5414C59B9FFEF4A71F3CFEF8E3293280CE8F635506808F3EF5A94F7DE2009F45D137BFF9CD47CE1F79E0FE8B8ACEC4FB4F3CF1C43FF7276440849EE6E77FECB1C7FE797EC88037DF7CF3B4FCFFE73FFFB9F8BFE86A781FFCDEEE51F0EB5B6FBDB57C7ED812E0F7F6FC9037B37686C4FFD13CF5AD6F7DABF8BFE8C6137C7EAEFBF9B16A07407E68E7C6E7B3E786AE6FCF077F3B92326D80E2FFA233FAFE917C0ADD9EC1FB20C4D032ED7FA2EF7EF7BBE2FDC336A018218FEDE11E280E8803DFE1B141FACE1B6FBC519BAEE854F4DE7BEFA932C06B07683E05F9FEABB1855DFCFFF7BFFF5D7C8EDBB76FD78629BA9A5880876FDB586294CF3FF2FF21133248BA168ECAE1155D9B2F30920123DE8FCA2948FE7F16FFC306909EE9EB5FFF7A6D96A21B493DDF1D3240CA0BE0B39EDC88C825F4F83F33A6A6D900BFFDED6F6BB3145D9D2F00D9C0F3F73DBD1F5D4BA0F17F74FCDF62037CED6B5FAB8D527495BE00F1F56EDE07ED8AFF71827CA93840D1B511EC76CD0EC0E71AEFA37E2883F7357B3C9BFF419FFBDCE7CA06282A3B607044E4F8CEA6FF41BFF8C52FC4E7FDE52F7F599BA4A86440608ECFEBFF67C5FF5BFAEC673FFBC8B5611714155D830CD07C814C7FBFBD07C9E788CC2F960D5054F428F5F2823BF87F247F706F9179468D6EDDBAF5C8B561171415DD64DDDFE3FD6C1E1CF1FE8EB823D1CF7FFEF3B2018A8AF73B32209207B51EE2A3E28F20D4FFB5D7FDCC673E539BA5E86A781FFA38AA6748A35E5D21EEAB979BCC9401C8FB576F6FD14DA65EEE9F747CAF6F70D50EE8D9FCBCFEA8F79DCC780072FF92ED817AC1A2A24B26D8DC23DEB7D808B3B6B8A5F6D023273208F5FFD23577E5228B8A76DBFC9A4E8FECFD1BD9FCDEEB67619AF66C80FBF7EFD7462ABA48DEB7EA7D0FDF5AF5700F336C64CFCFC88D55FAFDEF7F2F5E2FB31FA9A828CBDF5FEDE5415FE06C1FF0A8D7C02A3FB263922D3DF5D453650314DD58BD3F83FF15E93F78AFDFAB53D26C08E871C2EAA3B91FC0EFA3791EFCE07341F06F6D5EC0F7BEF7BDDA584517C1FB1C9F3F0AFFB3670700773853677B314D358C8FD50338C2454567A54C9CDE515E003220133FC09397C8E2FF6F7FFBDBB5C98A2E4EF747D5D0697E05D5096BBFDF717D7E7EA9A730EAF8F0C30F6BA3159D5A06703D195D3FDB9EBFE53DD8019C47A37B88DBB8A6F47C59FA9FE60514155D820CC8CA93919FA1D9F4E4AF67F50F513C42936D7CA6703BB3B79DFB4B3F797C9062823C7EC8670417155D820CC8EEDF1DD50F645E1FB949F4EFEFC009D09E3F1B1BA5A868954817725DF6FAEBAF9FE2DE104FE7B93AD2C7B8E751AC9D6C9C5E5C11E786CEA667C7B923E675CDCE57C7334166D1FBA0E726DB83CF1623BB04FDC9997907D43DB7B64F260EEA5FFEF29787CFC49F9F6C2BBE07E8C87E7EF477E079C113D81B38566A3D70BF3B7512AEF5B39FFD4CFDFD8EF9BADEF78F597C12F69684C585BCFB071F7C3015E390E280ABF67B1B83B4CC43C09E926A8B3D07FE3E6346C12EFC35DCFBCA1AE06F33E492341B7A25C683F5DC819DC5F9A0C7CFD2FB85BCDF4D1F7DF4D1D21C6EE4DE20ABB53CA0B4E6D1FCAFE51F7AEF1BF22B32FE08D9194912FE6A74BDB3367B75E6F8FEF7BF1F765FC8E568D7819E5A59CF6C0C3B5E13D3DBD347E1EB727AEDB5D74C783F162C124F1D9084F33FBBB7676A2AA3793FA316315BFF47F27EF4F343A768D778F6D967A7CE09DD9A5DA3DEEEC5DEFBDA3D5FAB25E06865E5E24675C051B26FA6A652C314893AA26CE1CCF90BF07BB29E7FD517424C21A3DEB3E537EC4D3E5F2B22EEDDEAC0B3F2FF9D3B77866BFCC52F7EF161CD3DC59EE023E0330FEF6B3256E27FAF6E9BAD69D47C5DE08A417FF11C248F7DD13A408FC0D695E69444CE2A91D6286A7F7CF5AB5F15EF1DB11FD8051477A4585FDBA3D18B133DF9E493E17E7F7B605F46C8D3ECFAB7DEFBDA395F9BD3ABAFBEDA5D5BD857EFBFFF7ED737EBD967161F6B55F6CDF620235E19593BA4EDD588B878967ED0F4EBCC1A443FBF45F7CFC60124799A8D9FD5B3D78E98AF81389D76AFD0EDD635EDF51093FEEDE173AD3C3BEA1867FB98244CE1D5B922921E8CC028E6FE6AA4FD2FCD5658C15597EC205C23DAEF5FB5017AB5E7B3F18011567F6F4F1FA1FFB51E5AC8712B9E9E1523BCA74F666D5B6FBFA1650FACC6EDE10B64E86929461A715E69ED7FF0831F843EFFCC3EEED9259A9DE1B10146BD275E1C4BCBACAE5E3E6FB7FEC75A49F7F8A52F7DC9CCFB3DBBDB6307CEE4B6227A18259E5ACDB966F9E959FC1FED5744ED634D37610F69B2C1D3F769E93DB3FA0256ACFEDE3AECCEFF69392FAB0C1D61854A9F6B7AC5CB332B7869239B7A55E64AEB1A21C7B3E44A74ED45844CD57413B7217BF26136FE37B39F3C737A7BEBBA7BBEB6E4A759F3B516FC6FC946D36675787450247601725314C3C61EC53557F35592FF3FEBFF1EC5FF2BF22AE27C16DED66484D506F0F49E6BFB0A393E4FBD4CCFA6DD99FFD3EAA92CB2D38A17A8BD1FE91AD667F7E0A31F419A5FDAD645CF50567D78B4FE97CEE7A9E5D26C7B29BEB7926F90E42930257BB83C3C1E30D2814F3FFDB46B5DA5FB415E96F7C448FF26FD051D63B57DA49A17C4FB57F57ECB7F8825B4DF937A9AA46747DE9CF700E3E8F9582FBDF452282F530F10BF7EDB8F0C9B019FC16ECACEFF67C587A3EDCE559F4A8BF94B7EA9C54FF0CA530B8EE6880F309FC76B074561E160BFA19FCE2BFB2C7594782ECF1C70493E4BBA40CBC57A0FCC075CED99846C94E60C1E5DFF97651F46F3FF8AFD3FC3CF9A0DD0AB59193DF708C3CE62837A6BDAA278C092C75AD94BADECEBF9DCD69EA6E8679FED3D91725767E901CACA0F49FA3A3AFE6F8DFF697E7F8F97676D80117F5AF3DA1A1F78E3351958585A3C6FD597245C9F51BCCDEA5B663CFB73CF3DE7DAB7D1FD2FD1FD7F59FC1FDD773AAB5B56EA1067EA012CEB698DEF49D8795E1ECBC2C2937C01E9D99F79E619D77BC6F38EE26DD27B91D6200B07D46A7B47F600216693D1FF2FE5D522F243D1F1BF59DDB252D3E389197A9F7B94DFD374A0370E22DD0FFC50C2B26BFB2F782CAA177FC27E6C49EAF7FAC217BE10BE67A5FE208937B4F81FC538799C93F274BCF70479C595DE13AD0708B93CAC2DEF7FE1F7C3DF016A7C677BD1CFE6FFAFE8FF993C65440F82577E78FC9E193C09AF5C8D90C3D6D8A9B6DE91F84DABF93FAF6DEB891B5BEE73A6A72C93227A24ADE78D8EFF8DCE17D137A4E5B4B5F7E8ADA76C65C04C4FDB0EFC0F49174AFD27B76EDD4AC5AB403EC1DA5712E5DBCEF4DE48FD2FB33D402D8623744C942F90850F156DFF7B6BB9BD7CDB23F8B0D13527AD0C206C9B91EFEBF583A2F85F8A6349FB04B5B833799315DDAFC99728DB56AABD1DD59E48EB3E1BBBCBACE1CAAAFF89EE2BF0DA299AEE9F99DFE28903CCE63DC1F796BE20EF5E8892C3D6FE2B8D47E1B35BFB7F24C2DF4A753F3D7B2EAAB645927DA3358CACABC9EAD1CD942D3BE27FDAF9A06BA267B758FB02B2FBEDBC7190A8F720C501D1E7EE592BAC3F704067785F93E73D7B2EAA0645F27DB467EFADFBAC1F24D91F51FC9FD5FF176D5778DEA516B359894359E339D9FCEF3D7FC47B907CEEDE7A8EF03F3C75EBB8868607866BF4E449440DCA6CFC4FF2FFB53EA519F913D1FB136DA7649E579253D2F9227187AC7A8DEF850CCCF911FFF77C51C95E40FE8FE7BADAFA7FFA09BDA3E5C0A4FC1FA711FE17CEDDE321FC4E5B6F3AEEDEBDEBB695A8F7A1ADBD6F6BF07BF93F4BED7D940D9AA1CB326CA4ECBC82F57C995869969AC0EC791BDE75CDAAFFB1C49F251DA8E17F920CC25A6A7EBE17FB2AEBD9ADF53F5AFE1FBE14E44B2B7F3816287E2FE552ACF207F7C83135F94C213EE350C2E82419C9E722F2FA043A576F1DA2F5BF258E1D81DF312B8FC9A6CD9EB7E1B56925BB69670D2C6613455FDF8A7B175DFFEFF5E1B330C02DF2277306BA655F4BFCBF3257C4C2FF9A9F1A593F358A031C61FF7BF13F76D6BF932F1031FF03E7C02C9195B5DA3D7722BAFEDFDA83B483FFBD71E7E8FE1F7EBEC87CFF887AF50059F5D491FEFF11F3D77A317CCB31933B88EC7D5E79F62819E0913F59BECF517327A47DCCED0F6D7F65CC0E95640DCDA7CBC6DBF5C66BB06F69AEAC14EF239F90CF5EE07EA207FFC36A3FF57CDBB6AE0FFA6ED67E231F98D7D8538F037E624DF8BC5DF2BDE9BBF033A29E1DF7A2CDC3B0C81FEFDCE20CDF6795FFA3E3FF92FF81BD427220D2EFD77201B816DF9FD9789B59F5DA4710788B7894CFC1466F61E6CCE7A39F1932B5ED37C2FFDBCF56642FC97D2EFFDA38603B73886421C948FE4EB80C2559D9B389F87BA59F2B36143D8F754E39D66DA6D6C463CF4A35AD5CDFD21A46CC9C2742DC9DEF111CD23AE07B6D8FDB4ACD38AE8167E2FA33028386B032F9BECC9C3F4FEF8EE6DEF33CE0AF7FFDEB50AC3FBE1788BF579F8DFA45BCB884B41F78AE81FFE47CCDFB21F95EA3DF919C909E859E99E71D22DFE71FFEF0874766A749E7870E69E556E47DA05677B50603320AB852DC06C77DE25DADEABF1DFD9767AC13E9F13CB0FC2CB305D18701BB6E5516443F9B072369473C40B26BB3EBDFACFDEF99FB8AFA7566CE87D8017A64B4B9866DBD18FCDF8839A4ABF9979D75E291F512E07B5CC3324741F3BD67E30F91BCA0CD23B3CA800CFE97F653B4DE99DD2FD1FB9FEB7D92C19E77897DE8993B26E5313CFD333BF01723E21A99F309C01716396B395E7EF9E5C3D6AC871583B9E447F1BF95EF8E887F67F435B4EFC1FA2EA3F2DFD061F7EEDD3B0DFF47C8D3ACFE13F4E7786688590E6F3C39E21D40DFF43063ADF67F463EC08AB91AA9FFAD767D74CF2430FBDAF760916BC8211D51FF163DD7656696DE51F6BFA5E6107601E632500C0C39C92F7FF9CBC3BFB3E09947C9CC1E562C781F7B72E55E681602C5F32866DDE62128864971CC5E9C363B3F65DD2F91FB1FF8F4D27B183D97A5FE1DF878D02BB4D6D85F96FA77ECF19DFA3AABAF21FABC88E18FF8B7A733E163E1BDF6E205563DB21283B2CC8B388B9FB5339E635DD3A87DD5B3BF7AEF72D4FF067FBE87458298DF285E80BDBE2B5E9F25D7A3FD450D2704FADE33C303E7817DB052836FED59F5F0FEEC0CF95D73A0A371FF2DE797FC8B08FD37C2E8D5D60F7B47FB3BE49F3CF17CC49E61236836A016138C96F797821325C900ACF96C2D8856B30C5F6186E746F3DF4736FF6C4E72D71CC8ECEBACC4FF3D71080B46BFC64FDA9E59C1BFD17A0E347F7447FFE599F37F5867F0FD2AEE18485BFB11FE80D67FA0D9EF3D7DD3CE893C539E65B44F22AF637D8ED55954967CB1743EAD073902FF4EAB5D91F2D3D1FC9A15FFCFEC97C49AADF23EC912298F78FBF66DB7ADAACD7619E9FD15DECFB4DF2CD7B1EC139A7F99E9FF5BF4FFC8E61FAD9F867F9B893F826B66CBE12CFF31BA4F3C8BB4586ECF9E1BF51F920CF0CE3F3E93FD16711D3C1FEA182CFE8D35AF3763FF5BF57EEFBA929E88C4BF97628212FEFD0EFE3F63FC3F9324BD8038EF8CFEE732203AD677E43A7BF9BFE5B9D1335BE3D0DED82BFC7D4DEFE39E60EB8DF849D3CF3398E3BDBC80E51ABD7C6FDBFB25CD006B31F2A4D9D5117A3A3B5E1C4912BE4CD6ECF548DEDF19FFF7F0BF66F7401EA0DE7985FF3DF10E4BCCD5E2A74A784FF0D9A349CA07B4F9A81DF80F59FAFFACFDCC92ACEAD504CED6DCADC4F98FD6FF56BB7B646B6BF26FA5FE47DA573DDEE7715ACB73496B9C813F24F900EDB3EDC07FC88AFF47D68B469224DF7B589C920D0A3B7266EEEB25F37F7B1DAB9F2DC9412BBE9685FF1153EDD9FCFCDA16BB263BF7E1B1E576F0FF19E7449F89FF355EE8EDFF0CDD9F19BFF15E87F7CF598EB6BFC9BA5F467AC55B5F69F127B27B1F6E22FF67F5FFECE27FC4453C3A97D62CA3C6EF0CFCDFD381A3FA068B2EB6EAD81EFFCFD45859EC27E99A1173475A92E662B46B20DD0BE1BA73FC3B291E487D203C3E2861D765D9FF67CCFF818029E3D1FFA33D339201AB39FF197F384B3759F46DCF36201960F51735D9ABE1288C6C2F8BDC91F403EA50A349AA036A31C6AC38292BFE63049FEEAA4B3BC2FEB7C43647BE80A7C72F322F17791DC43CACFAB657778B75927A32ACF1FF5EEC65545F69E97FD572733BE60FB4F545B3BD27BBEDC74BD2FF5EFEF7C4A0AD71A8B3C7593C394F3C33AF81B4AC87350EEDF17F2DFD9456FC61694EEEECDC77ABED8F6B66BFEFACF8F12EBF348280CBE89983E8C9B98FEC63894FA2FCF2EC3C83F64C3DDBA6D7776BD92FD6B957D678ABD5FE055E5F960DA0CD9494E44B34BF66C5362F29FF1FE1FFF7786E6407ACF80247D6FFCFDA34BD38DD68BF58F4FF2A7EAAA7FF07353B2BBD28A833D7FA80A5DE8268797F49F83F5904FC008FFE9F790759B9C15D799691DEF5FA33165F407A8E51EDB5772D3DF2539B5B4D3382BC84BFD1CE89DE54EB7B888EFF65F5FF9F55FF47C4FF2C6B96D10FB4ABCEAAC777B3F73EAA19F0DAFF33B694E75D825F35198ED8BDC717806ED7FA7EF11C5AFF59F4FBCE8A1FED8A4B67F9FF19FC3F9201337680357E9515FF5BED61EED901D23ED4E4D0AC0CF2DA7223FC2FF404F6E4007EB782FFB563FE5A16FF67C5FFB1A6ED3C40DEE3443358785D04CDEDC1BF251BACC7FFD21E8CC2FFF46200EEEAFFD1308F22F298DA7A48724C5AFB19DCC495389505FB17BA1D3542B427B1C7343FDF83011CAD57B3E2743BFBFF24FF7DF5E8F9FF113E53140EE851F9FF159EB3CA008BFF8F3AE21519345B3F65C1A2CEC0FF8EAEFFC9CA1FEDECFF97FCF788D9E0D93993081CF023FA7F5679AE170FE0BE80F41CFC79237A2A56D60F767AC4FC0F3CC76BAFBD76085F65D5E9ED8CFF9F41FFCFAE99660758FDD95DFA9F9E39AB8F9188CFE3E8F9FF99F8493BE77F79B143577DCF5DF6FFCEFE3F297EB77AF4FA7FA26B1B09278BF33E66539C699D71CEAC1E462D26A8D5FF46FA1E51EB87783E6A8430DBD332A306D87E33B54334279C7A79F013F52BB384FE02EA1DA2F38DE6AF5B729D749F3CDE66C1D6872CF4AE0BBECFE7B2F3381FBF073E5BBA9D11CEE734E333CC19EBAD199FA5BD3A839D6C5FBEFF3DBE0FC776C2B1B21F34C27A64D8FCBDF590FC61DC4764FF14AD1F9F83BE3A4F1C3C42F3D2790F1E3E8BC00B3D82C063847FEE9D97E7218AC5E31ADA5AD10CF8761E3D8FFDF359F23C1F8003F3C22367C6F7F601C90A92D9245F251907BEEFF118640C3D0F3D532BEBB84CE2CFAC5D73C6D76AAFD5AE3BC9573E678CFF9EE769785F2AFDBF27BF88AFE83AF8D9F6C89D855F4807F2BD886793F6359EABEDD75DD52911047D2CCD3DC89063520F94545B158581001B33DA56C6BAC0B6B3DA81A8F1B6AE6504F61B7A4A707FB3EF6F05FBD07A78B117CF525706AC4EF80052AF90F4EE512B40EFE1ACCFA5D53D67D8005A2D64BB57A33110D1CBBDEA4F424669F361A2E6C04763BF7867CFEFE2FF9E4C3E635D19D650C290F5C400A107CE2AD7B4F86664FFB32667A439481918488829CDEAC4A83C10EEA1873B9E81FD3ABAE68E7B58E5FF23FBCAB176D1F3E8CFC6FF1A6F4662A06A3246E2490BFEFECCF1E4934FBAEFDB320B3AAA0E2493F72CB52767D5FF47F13F629167C7E1DB6D9BCF90D6FFACF91812FF235FC767DBB7F12F1E1FD7FA2E70F4E2FE33BC0FDF82E6C0E3BE61CFF4AE4F07CE6DE13DD429F17A661E13A535C0F52DD7B43CBBB4F6347F82E281F4B3CDABF09C497BB471F2B3DBFF96778F3507DFD073C1CE97665867E27067C6E6A2701035BF59F32F226225D86352DD8D75AEC3A80FA497BFA0F5D43025347E5CADD5C4FD6872DC32F7485BFB9D7AEA0C736550AB378AABF4DE3DE28488FD5D8AFD3FB2D1DB1C502BD35BBDDCEA67AF6F118579F9CA2BAF88D7B6C47B347F1F3D1E1173E0A5FAB6A85A6DEC3FCD1EE8CD9E071D8DEBBC0B8B7BC7BBEFF5009F91FF351B20E3804FB0430749B19B516D8066AF4066CDCE81E77A59ABB38BECFDE8E52B7AB2F7E83CD5D1B832BD359BC500D1F4EA19F13256F21C9E7CC82E1B54C23FEFD55D683270750E3CC5587A78B5D1B637EE57EB49F5F85ED7A2FFB577BF8A010692F08FCF382F6B870D30CA2B46C680A418404FFF6B3E7BD42CD8DEB36760FD6BEF539B6D7D34AEE391F68794A38FCA83EF9AE390990B88AA491951540FA496BFE99154DB857ABAA3F67E44ECCD8A3D7D06FBFF483E41CD5E7BEDE79E7BEED4EF368324BC5C1CA879E53D0FBCD69BC7001143D26A242DBD2B921FEC5D2B2DFEDF9BEB021D9F9503B590147B8BC87D7BE65B1C3DD7F528FF43B393FEFAD7BFDE88B846940D60B185566B8A25FD8F1C34F56FF11E14DED347398A5ECCB5570723E18CC0F7BB09BA4F8A03487110AD0681CB7A2EE779EE9FF2FFBCFFC7DB8725AD01D57E68BD9CBC0FA9ED07B55E7FF5DDE3EFDB7BE4EB8067B814FB7F95873DB57E56FD9F8DF9A3EDBDCC5EC89DB6B724CFADF3B776D6B845D71F5A75ACF4DC9EDA9799FB3EB3FEEFE5427A7C1CD14F94C1FFC8B98DE4CF1963DF51FC6F952DD1FCE7E57FEBFC9FE8EBAFE61D66D6EDCCFABFC7CB3DB918D14B9451078F9A8E19FEDF19A3C9C4FAB39E3B5AF67AF7F851F6C7EABB9FB9EFB3CECB9C8D0344F51267F5C18CEC7F690F48FD8997A8FF25B92CEDEFE8DE4BAFFC8A7EF7D6F593DEBDA7FF6D466E9E5DFF7B6D00AD76C89B3F95DE05EA785ACC9FB6D6983EEFC5FFA4BE9B5EDEE3E8F85F94FE97D6448A8D49F637F5FFF083E310B5F83F3C0EE6C5EE91D680DE3D7FEF7CBE03E10471BC248A0F5AB1D2248C496BAF08ED1D1EFBA47B9262A2F43303C76DA70DC0EDE9C81EE2CCFE9F1E3F5B67B4EFB4FF23726FC861596B9A8EEEBF3DCA07F3E448AF8D3EF8E083A10DA0C50A67EAE6A26AD066EA7F245CAFC839F05E1B3282F724F98D5A97CCB53FA30D3422A9FE47AB93BC36EAF5F06A7A73163F24127F5FEAE5EAE58451EB976903F4CE639D551FA1D73499168D7D7E161BC8425AED77940D70A9D8C023FB7E264F986DFF13C177F5F4FF68CF095F70A6F7AFD5C33D8CFDE8592DE859D16221DABBC99A177976FB7FF4EE237ABFB267AB1C650344E38644F6A07BF57FEF3931B37D661FDCBF7FFF13F1776DBE45A4DCC335B5B84DEFDD9C3107BAD3FFD0F2D7886DFFE31FFF709FEFE38F3FFEC47BC07E8C9C6F70061BC0DBDFBFCBFED7E6B85A7847C38040FF80C71EC43A48985056FC8F19B987F7A4F5FDE2BA3D197634FF65C5403C369336B7157680675F23F625BDFB5D73968EB2015631C322EA609077F2F6FF7002E6EF680EFCA80E12BD631E4CCE55DD0BB934EADD1CCDA1CC9A177B84EF374B23EC37C44E7A7D41342BCC8BFF780964C10758D1FDDA1EA01E14DE8742B95ECAA7529EB537873D1AFF93E6C0532E1CFC67C1E294FA9034EC4D3E0B479AB9639D3D6FD973DADAF3D93F7CCE5A8BBF4A3D5A1CA3B4EDCFE9F95F92ECE7FD3FED5C287EEEB63F89F6488B4767C9BB7BDE3D9D1FFF9E7DF797443D1D13D12F7354FD9F441973E0353E8CAE7D3F2BFE772F9E9F31FB61D69EC9C07E0726E5A5532F0E10912BC9D883F00566EF2D6AFE07CED1B3BF33F81FBEA667FEC70EFEEFF9723BE68F78FC89A8F91F78F777EFDE7D705348B201A2E68544EF01D86411F3BF56E7C08F7207D1CF6DB9E611FC77B4FEF7C6135AFCD619CC2BC4946F12C106E03AD1D25F67A5A83D807B8A8E1DC18640ECCF320312DF41ACC86A7744E85ED42F22EE386BEB5C03FFCFC63311CFC7DA4A7582527D256280975CF363910114EB897CCE765672DB5BC2E33F7CC634C57E5E7CF1C52DBD15E031BAD776BECD4C0C1475496D1C8D7A59DA585B8B351335FF9B6690F36BB6383FEDBC8776E6773BB7BCC508EAD55FF1F56CDF750F774E9A07DF620559E28FDE77DFC66567DFFD88CF10876A67B26BEB4F07E21751B58B78A63B77EE88F3B6F87EA4B5469C1D7D03974C348B9ED618EB7993E579919DFEF77F3F7CF0C73FFEF1E13153176421E830CCAC8C887BCFEA43C86AA986D67A207773297D8E565B143504113AA4E832E94F7FFAD383CF7FFEDF1EFCEBBFFECBC3E33FFEE3DFC365C0A87E60E6F0F6B1596698590F3CCFA5D108D301F5C045D747FFF55FFFF94FDEA7E385175E083BBF368720E2B0F63366C89F4BEBA5B4C4C22267A41715FF4B38C4D1C7C876CDBC874BF205ACB1F0B3E3B81645FB85CF3FC2FFBFF9CDFF849C5BF3B5914B82FE6CF1AF38263EFF1D6C082D4F8198428FA499793C9FD5C61FDBF82C6C07094763B6064F23D4D2502C12353AD184D8079D1FCFD4CBFB786A6C8A6E860C801D80E357BFFAEF90736AB5F52BFD345E3CDE19CC5F8D2CB86133847A0CA9AF0AB265B54F7BF699765DBFE8E692D4AFAAE1347948AA55413E5122A9DE7DE51E243B60B5F7A9D7EBE2C16C9CA55E3DA8B5BFB0A8E8519BE2C7293133298EAFD56049F7B012BB97AEBD529337EACBB5F4B8AE90E5FAE50BDC6C42CEBFF5FF23280B7BCD33DB247A0645349E8CA54636B35FDC12133CEB5CD7A273F3BFB4B722F4BF94CBD3786407FFAFE0395AEAC333F1622CD7BF84B90E45B1FC8F7AC05592FA8DE13FAF9214B7D67030A8069DD772AFD4BA4562F981EEDDBB37E4BF8C5CC059AE5F744EFE8FC80144CED0208AC6E68DD0FFABFAB187B1B2635ECFD1D72F3A9650EBDBF2FF57BEF295901A602DFF0F1D8EDE438E6BC4FBAAF83C247CD6EB511DE5FF2542BE10F909DE87A6CD61E7BD48D2F3ACFAC71AAE75044EB385D0CB2DE51F71FD9BD6E75DA4FBD4AD0C401F006C83157AFDF5D70FAFFFE384EFA287E70CFDD72D21CE4EB2E6089B1BBE00C9BE8AF95F17C1DF6FF9BF9505A80D429D90572644F6DDACC413B3EEA3E2E3453781E0F3F764003F200BD0376825C9BE5C3D3CB5299932A8F8BFE826C900DE0BDC3BF03D8B0CC8ECBFE961AFECB87E24FFC3E6A7B8C311F637F51F1CE57F149DC717403CC02207F09D51AEB0D70384F994ED2C761E7F433CAE17FBB3F4DFF46290B83EC5F8782CB0C563A7FB91620759F1BF5DF5F7B88654838CBEA98AFF5D37112610FA81A51821F9021A45F60069BD2A3D4CB0E81EA48C79CE67CEFFEDE83F28BA1C6AB182E8D0FC00A90768A50648AAFDD17A7F40520DD24AFF4FF43C29D8DC47D6DF5BEAFFCB17286A6D022B5E48740DB08425D4E33FA95E67E5FA47D4FF67CE8BB7D4FF57FD6F514BA80FE2FCAFF5D44998732BF6B2A47F7BFB53E2AF33F5FF8C30F9B2F1782CD72FFE2F6AA9C50CD36200D2FE42CC6D96A4DE9F9E7E94F49B173794933403F7A6F7FF96FD7F3DFC1A7D3EF4E5B4FBE9D6AD5BA1FE7F6F06EE25E07FF4E26F3BF0377AF82355FF7F3308FE79EBB3CFD6F74BFD029AFFAFC5DF9F7DF659F77535ECAF5EEF0F667644C5FFB37A8F8EAEFFD7AE0FDE2FFCAF9B41526DDF2C0E8E9407ECF50BF6F2EF88C551BEBF9D6B4439777C47C3AA5CC9FF4397C317E0F38EDA794B38E0AFAC5CDF4ABCFE3FD3E6EFF90254F750F5FF378BA0B3A5BCDD77BEF31D73AF3FBE87EF4B35403D5B22B3FECED2FB038CEE23EB0F8B8ACE403FFDE94FCDF5FD9E03E71D5146FDBD278E9771FD4B9BFF5154A4D5F0CD1E1E1F227206CF0CEF45CA80951C4251D14D900133F103D8EB2BF337F1B72BF85DABF33F57668F16159D8550C327CDFDB2F6FEAEE28210FE0E8FBDB573B76916100EE4D83EFCF0C3B0E7C7F591376C67ACD3FCF3160308F71A357BBCA8E8687AFFFDF71FE67610B7A31E1FCB91311B1C7C0D9D4E7C4F3200D841BB788EAECF7B0123627B382FEF1F6C7F72D9479FF33C48FB5DFE7BFAFFAC3D8275875CE5BD97FCF9F935212B77612CF2B5C37DD0BDE03EDE78E38DB0F3E379F0FC1C6B8EAEC3D703D7471D49E45EA46B4BD7A377CFF36258FF88EBE3BAD44777E40C6B3C4BAFAF579A1598B9FFA43AC108DC6DEBCCCD9DF8039017B31868C05A5CF1BF56D72EA21619727DF6F957FDCF55FF173DD933D787AE97E25FBB653AEE43ABA3B11CF8DB8F3EFA28FCBEA43AE588BD66E9EF593D3C722A2A06BB23F791C1FF5131E019DD19197FF6AEBF5687F7CC33CF6CE37DD497F466CD590F9C23BA265DDA6B11B83E67D2FFD139D0EC1C4834FF473FBF8707A5BED5DDEB3F533F1B45521FC0EA81985C1465E0FAEFE27F8BFECFAAC1CAF405BCBD9E677D7EF81B67C0BED66C00C8854C927A70A43E17D8F614DB428CC282191A2503B2F4BF2457E0FF697140AA3BE63141FE3DFE3B8A0F59E27FBD1A685E838D9F3CF687037A46EA7B227F348B226572AF061DB67C5B73CED71A3D9F5A9C0A718495B5A7FA73BEEE1C070FFF47FDF9CAF539E15CD279900FC8B2F97BFC0B3EEFC535D1BFD39B511F858F13DDD79F1D57F4C6F923E4BE16B7C9CAD144BD136D0E95B7076DE6F923FBCF34FBDDB3FE88BF3DFEF8E38F9CE3F6EDDBE1EF0F713AE95AD45BE6B96FEC61AD4F16D758ED538BC6F53A13FF4B1868D0273324F541DDB973475D53C966215C576EEF48FA57D29BD077ED79473670F6F3F7FABFA3F1E722FACFB599AFD1BE9CA6B7F1F90CBF028B5693812B3305B53589C0DD91F83F13CFCBAA4767E3F792FDA8C9C991DDB62BFE21BDDBD9DCB71443ECF924525E69257722ADBF779F6A7A39B297558B35ACF6B4E36FB5B8C08A1D9AC5FF59E73DCAB7F1F8E4DA1ED8CDFF91B95DEFFB8C8E2B45C544B5B874940DA0E53B22720D9A4FB5225777E6FF76F70D4AF7302B83A4FA81DEB9347B2DF2183D4B641ED1BB4F2479B962FF49F6C7CC3E851E7DE2892796E3891E3F2572DF4BB6E50AAE78F47BCAF2FF66735F6D5E6156CE4B71E8575E79C51D7BDB59FF4075C43CC7315B337DB4FE97D67F167F2E2B0EA0BDF3C838B1665BCE5E234BFF6B6B919D73CD20D48ACDACB9666B22E6DCC6FD280FA6CD5AC767ED9CF65DF5C8337162E9FBB37A45CB3FACF4C549F1CCD53880546B91314746C2AD9CEDD9C9CAFF817AF3CF601351CF13DFD73C0FBCA3FF10EB46D7E73D46F8095F4EC33FB3D88B88DB4AB6E6A876201A3B3E8224FBDBABFFB1667CC65C8B3FD7D68160FD57E6DF79EDD3D5BA1AE99957E3F3561F60D6AF8B9E13D0F25694ADBBDA7FE2B505A3EACF341BA0D7CF97659345FBB53DFB7B765DAD47443FA4245B66F3A33BDF5B646E3D93FF35BD71A6DAFB997DEA89E77CFCF1C762CEA9670364DA6451FA6614D3CEACFF8E8AA769B5F93D5CFDA81C51F49E8DCCEB44DF73740F48643C75669FA22E36E21A9ACF1699B72082BE6CEB7B39DE818401839C8756FF3CF27FB2F83F5AFE4BCF376B0348FCBFCBFE9FD50F59BDE6922F009D77B6FE9BD93E65AFFD29D99ADA8C910C3D126D8F8FD63FBAFF1BF226C3FFD36C8099388084B79D314746AA079E8DFF65D5FF6A847E0BAC6D1BF3E6F11FFA2C33FEC3DF59DB634407EC8CA8FE1FE40AADB666062603D674A7FDA5F57FB598776D4F578B091585FFE38D53CFE4D477E4FFC03F91B99033C69A5A8AE8FF58A1A8F947522E41AA89C8A8C988B2C7ADF5C397B0AF88B41EE9199F4B7AC7913E8B64FB8FFC15D43C69BC92E9FF536E8DE43BF6F06CDC56D2C3A3380DD5BF10A6EA4AFD8F77FEA227E7D4C6D1093B911FABB6EF2AFFC3DEF1D898D2BE5AE9FF926AB922311181EF26E1ED7831B7B458570486AF665F8CEC31AA5F811E6B755666FC3FF2DCD2BA8E7462641CDDD3FFE3F5DD76D4454AFC089E6EB156795F22FE3F8B7F1A5DC3909DA702E66EC40CF8CCFE1FAD0FB867074BF70339407F9319FFCBEEBF199DEBE8EB67DB9AABF79F11E7CDB2FF77E444256CD4191B40F317E1C7CEC8005C1F980D33780ABD3E14F812D2BD46ADABB407667D216FFF8DA68376F4FFEEDA6767CCF3F4AEB782BB2DD97FD1FCAFC9666FEC45C31A213BC013B782EDA5E97DD496F6E4C96C1F6AD4BA22CE1F65EB4AFEFF284713D98324F9FFB3B5A2DA3ECBE4C7DDFDD852BE63A54F2D22FE62A1A79F7E3A44368FF0BF5043D2F3ABF8BC02ED18CDCAEED90D51B8DA33F18A28FCA9915F1A85FBA8BD8795FC83947382CEC8B20176F3BFB6F633F530DAFB473FBC265F39CE12E594DB792312B6A476AD19BB51D27F12FE27D68472E188D569FA7EB6F7D1224BB2F4901457253D4C18902D4616FDECCD49B1E6DF7B3D48B0475B9C51DA27F8377EBF7A7D8DDE7EFBEDAD3680C4FF589BB6E681E394F1D820E71F6BDC5D9B3542D8A3BC0F88F75DD175F0FEB5FEAB5EFD47D6EC899938A896F3593966FB9EAD7220720F4A35513BFB3FB2F0AF2366A166D8151EFE9F3DACFB23EBDD8FEA0FB3F87F06BB14043B5D8B0778E77F8C6C7EAB1CE8CD228AD64191F3CF67E248D13D4851F3E334FF68769F79E3E73BE62E65CCFF18D9E299BD47B3385E88D3ADE042624FAC62FD5AED810CBF304A06CCE60F106F3913EF1369F199E8D934913CE1D50F1AF67ED6FA67F61EAFCA66BC57CFFC4F3C6FF69C22D89BDC1EC88A0B1D397F92AE3F3B8312718CC87AB35E9C0CFB373A0E18A9FF676A91F1EE56FABF3CEF1FDFE3FD04528F23D539D14F9A85DC62D0F0FFD3F723DF7D5BD748B59EBBE793D2FDC01EC8C6E9A619D0B49EF47EDA785316FE0F9F7FCDF789347368C7FC6FE24DAC7DD6B58827781CAF9DC3C4F198DA9E1CCE472B7210EF1273B1DAB83BDD17BF2E7EE23DEDEAF3282A3A82E0D745D487177D32BFF2EEBBEF5EE4BD430740C6927C24B98B1AE559C2DF72FD46F89147D81945459904BE7FECB1C71ED6C7BDF5D65B1771CFF0F75E7EF9E56EEE7FA52EA7D7FF0D8C025C3BB3FE746497F2D95811B9354F4C80DBBFB89715395B742CBDF7DE7B9FC05C45DEEDEC7600F69C84131BD9032ED5C24BF5C4BB71668F9E1328C9C5A3B1768BE66D7EE4C8A5BC397E77463BDF52EBB78BFFB93D10ED1760FDA57760AD4BD5FE7E95A4B8F8EE39A545717B4CD3A3B003CE2403702FF05176F5E578F3BF58C737DF7C33F459257FCCD2D749EF1547F43BCCEE2B2FDACF575AAD5DC6FE9921E43346F580E895423E88F72FCC62FC81E0D3F29C0FEA4E346C3B6E37ADE65EDAF7D1BE8311FF8DFE3E83FFA3F39F147BA51C33729A1577CD8D019C590668737C6936D4CEFBC3B5704DED7E56E61769F618B72D7A58D7F88EE4CF45BEC30CAC6D8B8CA1B5AD58E3DE58C0D1BE80E687634FBFFAEAAB87AD17FA0AB4F59AED07B0D8621A4ECC2E3B6E074EE5A8F62E0323BEE8C18377DE79478D071C6107A0CE235B9F65F84E239C91D9980CD6E21BDFF8C6239FE3B35DEF4D92C7D1FC6F89BD5CE25CD44B8F09EEE6BB175F7C710AC7632769B8252FBDF4524A4CC61B938CCEE5EE98B569ED47A9BC439E0CD062ED3B658034B717BEF7D9E8A9A79E0A9F638CB8FF8A0CC87A4F3B7025A9C609470F5304C7913EE0913A87EAFDEFDDBBB7D5B6DD150FD0E6769CB12E01BC2ADD2B9E21CB163B82F777C5FF24EAF582A34732BAD7FB8CA4615AA3D72FE3F98FCC0D4A38343B70DF6749CA0D7AFA2F79CF251DB0B525DB6274C046E2FD919447A31E869690276DF1A4A8EF93FE963E97FA8109174BEA47A3BFA57EB5959EE49E2C5CB1B7F0FCB4DE749F1C6BABC5FBE7FFE6EBC67BF2F8F7F877579E5FB28733E7E6910CD0E2DC993240B233BD38983B49C2A5B0DAC599F82B965CFDCEEBCFDA0A237CD8155F200BFF2A323774F7EEDDB4E73F634C70479D49244975F1D677EDA935CEE0BFC8599759313B4B4C70360E91897F13C5FF161995C91F231910DD3728EDC933F3BFC4C3D6FBDDA97F251ED9297F22E7AE47ED8F9DEB3FCBFF99CF1FE10B205F10690748CF9B81F39869FF5BDFC74EFD23F1DF4EFB7796FF61DB66D9BF3BF97FD6FEC97C7E0FA1C6B46707A096382BFEB7320F259BA41C9535D683FE7D1E2FA319BC387AB5C6DA817A208AD7D179081745BA27C254E3B12B1EF3E3F13C29FE079C3A1EB7A41820C534796C332BFEB512FFE3F8773C5EC9E376ED2C5D7A2E8AFFF17FB7D8793C1E98F5FCA891DF453B62821AD6F319F37FDA6C8AD59E95D93AA0CCFE6D4957EEF2CBFEF6B7BF89F92FECFD23B0588EC8FF4932607556EE596382D2BB463EEC6C24E5E856F3313D197BA40C907C95CC397C9A2D4CBA36ABFEE5CC845C08D98AC80B1CA9F7B43AC1881A21D4D04AE7C6F39FE95D48F7F8C20B2F4C9FB3D78FE939A263321AFF571DEEF5127A86341980CF57F2025AFFCF59B049341D0DFBE7FEFDFBE17695D6FF03FB43B315A2ED80DD73318BCE4F99F180B3F6FF42EF6B7C3ACB0FBD75243ED6F03F467223AA0F48F2FF77DBFF45E7940159B5C23DCCBF23F03F7A35B9ABF81F1A1E23D951BDFE7B4D0644DA4B92FE8FEEFF29BA793260650F02536BD40783FC1B72F03CDFB23277057FCBEBBE2DF85FB8C70CFC2FEE4349F610D7BFAD0C88B6FF0BFFAF68C517988D07CCF4C2ADD8A5DE9AD8C83A685A43E99C16FC6FD8FAF85BC891284C52CFF58BAE9B689E48743C0AFDB41EFCEF15BBD4C3FFC8F545CFA3D2F0BBADF977BC830CBF68647F1415D1FED37C81D57814F6A02537BEB22F2D35B1B88733CCFFD8790F65FF17ADDAEC1158F9C80D8EE67FADF07FAF261FF566C0269BCDF1AD10CD39E4736957E77C7B08D7E29802BBE78F155D16C1DF6FE78B45DBA53417BC9D53BE1AFFA3D81FD57F037BBAE6CE1615CDD90167C1ED2D2A2ADA2F038AF78B8A8A6E824F43BE77C9B4A2A2EB21292E78665CA2A2A2A21842CE52CB09941D505474B3A987135539F0A2A29B4DBD9AA0E2FFA2A2B2FF8B8A8A6E2EADE0FC1715155D3E110E07E2FEA5F78B8A8A8A8A8A8A8A8A8A6E2EA1CF88FADEA83F6867FF5D5151D17154F8174545D74B857F5B5454FC5FF8B74545C5FF55FB575454FE7F5151D175F27FE9FFA2A2EBA0AAFF2D2ABA5EAAF9574545C5FFA5FF8B8AAE8F6AFE4551D1F552E5FF8B8AAE97A4F87FF17F51D1F5EAFFC2FF2D2ABA5EFD5FFC5F54741D24C5FF2AFE5F5474BDF67FC5FF8B8AAE83A4FC7FF17F51D1F5F23F6A828B8A8A6E3E01EB8BB0BFC0F785FF555454545454E4A3FF03645B97F4]]>
              </BitmapFile>
            </BitmapFromFile>
            <BitmapExpression>
              <Expression>
<![CDATA[//X,Y : current coordinate (0..1)
//Pixel : current color (rgb)
//Sample expression: Pixel.R=abs(sin(X*16));

Pixel.A = 1-(Pixel.R + Pixel.G + Pixel.B)/3;
Pixel.R = 1;
Pixel.G = 1;
Pixel.B = 1;]]>
              </Expression>
            </BitmapExpression>
          </Producers>
        </Bitmap>
        <Font Name="fnt_FontWeiba" Bitmap="bmp_FontWeiba" FirstChar="32" CharPixelWidth="32" CharPixelHeight="32"/>
        <Material Name="matFnt_Weiba" Shading="1" Light="0" Blend="1" Font="fnt_FontWeiba"/>
      </Children>
    </Group>
    <Group Comment="Models">
      <Children>
        <Model Name="baseMdl" Category="2" CollisionBounds="1 1 0 0">
          <OnSpawn>
            <ZExpression>
              <Expression>
<![CDATA[switch(CurrentModel.Category)
      {case 2:current_Bigs++;
              break;

       case 11:current_Smalls++;
               //Convert coordinates to array
               float rX,rY;
               rX = (CurrentModel.Position.X + 16)/32;
               rY = (CurrentModel.Position.Y + 9)/18;
               int aX,aY;
               aX = clamp(rX*arr_Smalls.SizeDim1,0,arr_Smalls.SizeDim1-1);
               aY = clamp(rY*arr_Smalls.SizeDim2,0,arr_Smalls.SizeDim2-1);
               arr_Smalls[aX,aY]++;
               break;}]]>
              </Expression>
            </ZExpression>
          </OnSpawn>
          <OnRemove>
            <ZExpression>
              <Expression>
<![CDATA[switch(CurrentModel.Category)
      {case 2:current_Bigs--;
              break;

       case 11:current_Smalls--;
              //Convert coordinates to array
              float rX,rY;
              rX = (CurrentModel.Position.X + 16)/32;
              rY = (CurrentModel.Position.Y + 9)/18;
              int aX,aY;
              aX = clamp(rX*arr_Smalls.SizeDim1,0,arr_Smalls.SizeDim1-1);
              aY = clamp(rY*arr_Smalls.SizeDim2,0,arr_Smalls.SizeDim2-1);
              arr_Smalls[aX,aY]--;
              break;}]]>
              </Expression>
            </ZExpression>
          </OnRemove>
        </Model>
        <Model Name="m_Big" Comment="Spawns Smalls" BaseModel="baseMdl" Position="1 4 0">
          <OnSpawn>
            <ZExpression>
              <Expression>
<![CDATA[timer_Lifespan.Interval = CurrentModel.Personality*4; //+2
timer_Reproduce.Interval = 0.05+CurrentModel.Personality*0.25;]]>
              </Expression>
            </ZExpression>
          </OnSpawn>
          <OnUpdate>
            <Timer Name="timer_Reproduce" Comment="Spawn kids" Interval="0.05" RepeatCount="5">
              <OnTimer>
                <ZExpression>
                  <Expression>
<![CDATA[m_Small.Position.X = round(CurrentModel.Position.X + sin(rnd()*Pi*2) *16*0.5);
m_Small.Position.Y = round(CurrentModel.Position.Y + sin(rnd()*Pi*2) *9*0.5);

@SpawnModel(Model:m_Small, SpawnerIsParent:1);]]>
                  </Expression>
                </ZExpression>
              </OnTimer>
            </Timer>
            <Timer Name="timer_Lifespan" Comment="Expire" Interval="2">
              <OnTimer>
                <RemoveModel/>
              </OnTimer>
            </Timer>
          </OnUpdate>
          <OnRender>
            <UseMaterial Material="mat_Clean"/>
            <RenderSetColor Color="1 0 0.502 1"/>
            <RenderNet/>
          </OnRender>
        </Model>
        <Model Name="m_Big1" Comment="Tries to confuse ZGE" BaseModel="baseMdl" Position="6 4 0" Category="11">
          <OnSpawn>
            <ZExpression Expression="timer_Lifespan1.Interval = 1+CurrentModel.Personality*4;"/>
          </OnSpawn>
          <OnUpdate>
            <Timer Name="timer_Lifespan1" Comment="Expire" Interval="2">
              <OnTimer>
                <RemoveModel/>
              </OnTimer>
            </Timer>
          </OnUpdate>
          <OnRender>
            <UseMaterial Material="mat_Clean"/>
            <RenderSetColor Color="0 0 0.6275 1"/>
            <RenderNet/>
          </OnRender>
        </Model>
        <Model Name="m_Small" BaseModel="baseMdl" Position="-6 0 0" Category="11">
          <States>
            <ModelState Name="ModelState1">
              <OnStart>
                <ZExpression Expression="CurrentModel.Scale *= 0.5;"/>
              </OnStart>
              <OnUpdate>
                <Timer Interval="0.5">
                  <OnTimer>
                    <SetModelState State="ModelState2"/>
                  </OnTimer>
                </Timer>
              </OnUpdate>
            </ModelState>
            <ModelState Name="ModelState2">
              <OnStart>
                <ZExpression>
                  <Expression>
<![CDATA[CurrentModel.Scale = 1;
CurrentModel.CollisionBounds = 1;]]>
                  </Expression>
                </ZExpression>
              </OnStart>
            </ModelState>
          </States>
          <OnSpawn>
            <ZExpression>
              <Expression>
<![CDATA[timer_LifespanChild.Interval = 1+CurrentModel.Personality*4;
CurrentModel.CollisionBounds = 0;]]>
              </Expression>
            </ZExpression>
            <SetModelState State="ModelState1"/>
          </OnSpawn>
          <OnUpdate>
            <Timer Name="timer_LifespanChild" Interval="1" RepeatCount="0">
              <OnTimer>
                <RemoveModel/>
              </OnTimer>
            </Timer>
          </OnUpdate>
          <OnRender>
            <UseMaterial Material="mat_Clean"/>
            <RenderSetColor Color="0 1 1 1"/>
            <RenderNet/>
          </OnRender>
        </Model>
      </Children>
    </Group>
  </Content>
</ZApplication>
It all started when I moved the models from a particular AppState (used for experiments) to the main Content so might be related to the "ZArrayList bad index" reported previously (here). Just a wild guess. Any suggestions where to look next?
User avatar
VilleK
Site Admin
Posts: 2274
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: Parent removed, but some offspring remains

Post by VilleK »

I found a bug in ZGE here: the idea with "SpawnerIsParent" is that the SpawnModel should execute inside a Model (in Model.OnUpdate etc) and that model then becomes the parent. In your code you SpawnModel from App.OnLoaded and then there is no "current model" that can be the parent. I've added a check for this now so it should not crash anymore (download latest beta for the fix).
User avatar
rrTea
Posts: 475
Joined: Sat Feb 15, 2014 9:54 am

Re: Parent removed, but some offspring remains

Post by rrTea »

But no models in OnLoaded / OnUpdate are spawned with a Parent? The only model that is spawned as a child is m_Small, and that is spawned from m_Big.

Anyway I tried with the latest beta and it's still the same: test cases work fine, ingame crashes.

Edit: if this kind of setup (spawning as a child without a real parent, which I think I'm not doing?) were causing the crashes, wouldn't it crash every time? In my game it crashes very, very irregularly (every 5 rounds approximately, and in each round spawning / deleting of both parents and children can happen a over a hundred times).
User avatar
VilleK
Site Admin
Posts: 2274
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: Parent removed, but some offspring remains

Post by VilleK »

Sorry, I misunderstood, I thought you were talking about setting SpawnAsParent on the SpawnModel in App.OnLoaded. Please look further on how to find a reproduceable test case because otherwise I cannot fix it.
User avatar
rrTea
Posts: 475
Joined: Sat Feb 15, 2014 9:54 am

Re: Parent removed, but some offspring remains

Post by rrTea »

I think I know what's happening. The problem is that the BaseModel of "Big" model (the one that spawns kids) has a condition of expiry (in my game it's if HP == 0, here it's just a timer) but the creation of the kid models is in the "Big" model itself (not in the BaseModel).

So if I'm not mistaken the events in the BaseModel.OnUpdate get executed first (the model is removed) but then the events in the model itself spawn a "child" model. For example if you run this example it won't take long before it crashes:

Sorry there's lot of fluff mixed in here (I just kept adding stuff from the game), will clean it up tomorrow (have to run in a few minutes):

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" Camera="Camera1" ViewportRatio="3" FileVersion="2">
  <OnLoaded>
    <DefineCollision Cat1="1" Cat2="2"/>
    <DefineCollision Cat1="1" Cat2="11"/>
    <Variable Name="current_Smalls" Type="1"/>
    <Variable Name="current_Bigs" Type="1"/>
    <ZExpression>
      <Expression>
<![CDATA[current_Bigs = 0;
current_Smalls = 0;

arr_Smalls.SizeDim1 = 16*2;
arr_Smalls.SizeDim2 = 9*2;

int c,x,y;
int l = arr_Smalls.SizeDim1*arr_Smalls.SizeDim2;
while (c<l)
      {x=c%arr_Smalls.SizeDim1;
       y=c/arr_Smalls.SizeDim1;
       arr_Smalls[x,y]=0;
       c++;}]]>
      </Expression>
    </ZExpression>
    <Repeat Count="10">
      <OnIteration>
        <ZExpression>
          <Expression>
<![CDATA[m_Big.Position.X = round(sin(rnd()*Pi*2) *16*0.5);
m_Big.Position.Y = round(sin(rnd()*Pi*2) *9*0.5);]]>
          </Expression>
        </ZExpression>
        <SpawnModel Model="m_Big"/>
      </OnIteration>
    </Repeat>
    <SpawnModel Model="m_Player" SpawnStyle="1"/>
  </OnLoaded>
  <OnUpdate>
    <Timer Interval="6">
      <OnTimer>
        <Repeat Count="10">
          <OnIteration>
            <ZExpression>
              <Expression>
<![CDATA[m_Big.Position.X = round(sin(rnd()*Pi*2) *16*0.5);
m_Big.Position.Y = round(sin(rnd()*Pi*2) *9*0.5);]]>
              </Expression>
            </ZExpression>
            <SpawnModel Model="m_Big"/>
            <ZExpression>
              <Expression>
<![CDATA[m_Big1.Position.X = round(sin(rnd()*Pi*2) *16*0.5);
m_Big1.Position.Y = round(sin(rnd()*Pi*2) *9*0.5);]]>
              </Expression>
            </ZExpression>
            <SpawnModel Model="m_Big1"/>
          </OnIteration>
        </Repeat>
      </OnTimer>
    </Timer>
    <ZExpression>
      <Expression>
<![CDATA[txt_Array.Text = "";

int c,x,y;
int l = arr_Smalls.SizeDim1*arr_Smalls.SizeDim2;
while (c<l)
      {x=c%arr_Smalls.SizeDim1;
       y=c/arr_Smalls.SizeDim1;
       switch(arr_Smalls[x,y])
             {case 0: txt_Array.Text += " ";break;
              case 1:
              case 2:
              case 3:
              case 4:
              case 5:
              case 6:
              case 7:
              case 8:
              case 9: txt_Array.Text += intToStr(arr_Smalls[x,y]);break;
              default: txt_Array.Text += "+";}
       c++;}]]>
      </Expression>
    </ZExpression>
  </OnUpdate>
  <OnRender>
    <Group>
      <Children>
        <UseMaterial Material="mat_Wireframe"/>
        <RenderSetColor Color="0 0.251 0.502 1"/>
        <RenderNet XCount="31" YCount="17">
          <RenderVertexExpression>
<![CDATA[//Update each vertex.
//Vertex : current vertex
//TexCoord : current texture coordinate
//Color : current vertex color

Vertex.X *= 16*2;
Vertex.Y *= 9*2;]]>
          </RenderVertexExpression>
        </RenderNet>
      </Children>
    </Group>
    <Group>
      <Children>
        <UseMaterial Material="matFnt_Weiba"/>
        <RenderText TextFloatRef="current_Smalls" X="-12" Y="7" Scale="10" Align="1" UseModelSpace="255"/>
        <RenderText TextFloatRef="current_Bigs" X="-12" Y="5" Scale="10" Align="1" UseModelSpace="255"/>
        <RenderText Name="txt_Array" Text="                                       1  1                                               1                           1               1         1                      1 11                             1  111      1 1                     1 1                    1       1                1                      1 1     1                                                1                              1        1        2   1    1                                     1                                                 1                1                                                " X="-16" Y="-9" Scale="4" Align="1" UseModelSpace="255">
          <RenderCharExpression>
<![CDATA[//Modify current character before render.
//CharX,CharY : current coordinate
//CharI : current character index (read only)
//CharRotate : current character rotation in radians
//CharScale : current character scale

CharX = 0+(CharI%arr_Smalls.SizeDim1)*2.5;
CharY = 0+(CharI/arr_Smalls.SizeDim1)*2.5;]]>
          </RenderCharExpression>
        </RenderText>
      </Children>
    </Group>
  </OnRender>
  <Content>
    <Material Name="mat_Clean" Shading="1" Light="0"/>
    <Material Name="mat_Wireframe" Shading="2" Light="0" ZBuffer="0"/>
    <Camera Name="Camera1" Kind="1" Position="0 0 10" OrthoZoom="9"/>
    <Array Name="arr_Smalls" Type="1" Dimensions="1" SizeDim1="32" SizeDim2="18"/>
    <Group Comment="Font">
      <Children>
        <Bitmap Name="bmp_FontWeiba" Comment="by Ray" Width="256" Height="256">
          <Producers>
            <BitmapFromFile Comment="Imported from weiba 01.png" Transparency="2" HasAlphaLayer="1" DataWidth="256" DataHeight="256">
              <BitmapFile>
<![CDATA[78DAED5D3BAF655791E617183B9E9180CE8684474406389809DD4633A901939B470E861FE0478E78B8B3412DEC8E86C46008C8FC92092D0C9E1419D172DEA3AFA562CAABABD6AA5AAB6AED7DEEA992B66EF7B9E7EEC7DAABDE555F3D78F0FFF4CE3BEF3C78F7DD771F64D1DB6FBFFDF058A5DFFDEE770F9E7FFEF987C78F7EF4A3073FF9C94F1E7E164538DF8F7FFCE387075D830E7C869FF8FC873FFCE13F7F8FCFE9FFF43BFA5EFBF791F75A5414C59B9FFEF4A71F3CFEF8E3293280CE8F635506808F3EF5A94F7DE2009F45D137BFF9CD47CE1F79E0FE8B8ACEC4FB4F3CF1C43FF7276440849EE6E77FECB1C7FE797EC88037DF7CF3B4FCFFE73FFFB9F8BFE86A781FFCDEEE51F0EB5B6FBDB57C7ED812E0F7F6FC9037B37686C4FFD13CF5AD6F7DABF8BFE8C6137C7EAEFBF9B16A07407E68E7C6E7B3E786AE6FCF077F3B92326D80E2FFA233FAFE917C0ADD9EC1FB20C4D032ED7FA2EF7EF7BBE2FDC336A018218FEDE11E280E8803DFE1B141FACE1B6FBC519BAEE854F4DE7BEFA932C06B07683E05F9FEABB1855DFCFFF7BFFF5D7C8EDBB76FD78629BA9A5880876FDB586294CF3FF2FF21133248BA168ECAE1155D9B2F30920123DE8FCA2948FE7F16FFC306909EE9EB5FFF7A6D96A21B493DDF1D3240CA0BE0B39EDC88C825F4F83F33A6A6D900BFFDED6F6BB3145D9D2F00D9C0F3F73DBD1F5D4BA0F17F74FCDF62037CED6B5FAB8D527495BE00F1F56EDE07ED8AFF71827CA93840D1B511EC76CD0EC0E71AEFA37E2883F7357B3C9BFF419FFBDCE7CA06282A3B607044E4F8CEA6FF41BFF8C52FC4E7FDE52F7F599BA4A86440608ECFEBFF67C5FF5BFAEC673FFBC8B5611714155D830CD07C814C7FBFBD07C9E788CC2F960D5054F428F5F2823BF87F247F706F9179468D6EDDBAF5C8B561171415DD64DDDFE3FD6C1E1CF1FE8EB823D1CF7FFEF3B2018A8AF73B32209207B51EE2A3E28F20D4FFB5D7FDCC673E539BA5E86A781FFA38AA6748A35E5D21EEAB979BCC9401C8FB576F6FD14DA65EEE9F747CAF6F70D50EE8D9FCBCFEA8F79DCC780072FF92ED817AC1A2A24B26D8DC23DEB7D808B3B6B8A5F6D023273208F5FFD23577E5228B8A76DBFC9A4E8FECFD1BD9FCDEEB67619AF66C80FBF7EFD7462ABA48DEB7EA7D0FDF5AF5700F336C64CFCFC88D55FAFDEF7F2F5E2FB31FA9A828CBDF5FEDE5415FE06C1FF0A8D7C02A3FB263922D3DF5D453650314DD58BD3F83FF15E93F78AFDFAB53D26C08E871C2EAA3B91FC0EFA3791EFCE07341F06F6D5EC0F7BEF7BDDA584517C1FB1C9F3F0AFFB3670700773853677B314D358C8FD50338C2454567A54C9CDE515E003220133FC09397C8E2FF6F7FFBDBB5C98A2E4EF747D5D0697E05D5096BBFDF717D7E7EA9A730EAF8F0C30F6BA3159D5A06703D195D3FDB9EBFE53DD8019C47A37B88DBB8A6F47C59FA9FE60514155D820CC8CA93919FA1D9F4E4AF67F50F513C42936D7CA6703BB3B79DFB4B3F797C9062823C7EC8670417155D820CC8EEDF1DD50F645E1FB949F4EFEFC009D09E3F1B1BA5A868954817725DF6FAEBAF9FE2DE104FE7B93AD2C7B8E751AC9D6C9C5E5C11E786CEA667C7B923E675CDCE57C7334166D1FBA0E726DB83CF1623BB04FDC9997907D43DB7B64F260EEA5FFEF29787CFC49F9F6C2BBE07E8C87E7EF477E079C113D81B38566A3D70BF3B7512AEF5B39FFD4CFDFD8EF9BADEF78F597C12F69684C585BCFB071F7C3015E390E280ABF67B1B83B4CC43C09E926A8B3D07FE3E6346C12EFC35DCFBCA1AE06F33E492341B7A25C683F5DC819DC5F9A0C7CFD2FB85BCDF4D1F7DF4D1D21C6EE4DE20ABB53CA0B4E6D1FCAFE51F7AEF1BF22B32FE08D9194912FE6A74BDB3367B75E6F8FEF7BF1F765FC8E568D7819E5A59CF6C0C3B5E13D3DBD347E1EB727AEDB5D74C783F162C124F1D9084F33FBBB7676A2AA3793FA316315BFF47F27EF4F343A768D778F6D967A7CE09DD9A5DA3DEEEC5DEFBDA3D5FAB25E06865E5E24675C051B26FA6A652C314893AA26CE1CCF90BF07BB29E7FD517424C21A3DEB3E537EC4D3E5F2B22EEDDEAC0B3F2FF9D3B77866BFCC52F7EF161CD3DC59EE023E0330FEF6B3256E27FAF6E9BAD69D47C5DE08A417FF11C248F7DD13A408FC0D695E69444CE2A91D6286A7F7CF5AB5F15EF1DB11FD8051477A4585FDBA3D18B133DF9E493E17E7F7B605F46C8D3ECFAB7DEFBDA395F9BD3ABAFBEDA5D5BD857EFBFFF7ED737EBD967161F6B55F6CDF620235E19593BA4EDD588B878967ED0F4EBCC1A443FBF45F7CFC60124799A8D9FD5B3D78E98AF81389D76AFD0EDD635EDF51093FEEDE173AD3C3BEA1867FB98244CE1D5B922921E8CC028E6FE6AA4FD2FCD5658C15597EC205C23DAEF5FB5017AB5E7B3F18011567F6F4F1FA1FFB51E5AC8712B9E9E1523BCA74F666D5B6FBFA1650FACC6EDE10B64E86929461A715E69ED7FF0831F843EFFCC3EEED9259A9DE1B10146BD275E1C4BCBACAE5E3E6FB7FEC75A49F7F8A52F7DC9CCFB3DBBDB6307CEE4B6227A18259E5ACDB966F9E959FC1FED5744ED634D37610F69B2C1D3F769E93DB3FA0256ACFEDE3AECCEFF69392FAB0C1D61854A9F6B7AC5CB332B7869239B7A55E64AEB1A21C7B3E44A74ED45844CD57413B7217BF26136FE37B39F3C737A7BEBBA7BBEB6E4A759F3B516FC6FC946D36675787450247601725314C3C61EC53557F35592FF3FEBFF1EC5FF2BF22AE27C16DED66484D506F0F49E6BFB0A393E4FBD4CCFA6DD99FFD3EAA92CB2D38A17A8BD1FE91AD667F7E0A31F419A5FDAD645CF50567D78B4FE97CEE7A9E5D26C7B29BEB7926F90E42930257BB83C3C1E30D2814F3FFDB46B5DA5FB415E96F7C448FF26FD051D63B57DA49A17C4FB57F57ECB7F8825B4DF937A9AA46747DE9CF700E3E8F9582FBDF452282F530F10BF7EDB8F0C9B019FC16ECACEFF67C587A3EDCE559F4A8BF94B7EA9C54FF0CA530B8EE6880F309FC76B074561E160BFA19FCE2BFB2C7594782ECF1C70493E4BBA40CBC57A0FCC075CED99846C94E60C1E5DFF97651F46F3FF8AFD3FC3CF9A0DD0AB59193DF708C3CE62837A6BDAA278C092C75AD94BADECEBF9DCD69EA6E8679FED3D91725767E901CACA0F49FA3A3AFE6F8DFF697E7F8F97676D80117F5AF3DA1A1F78E3351958585A3C6FD597245C9F51BCCDEA5B663CFB73CF3DE7DAB7D1FD2FD1FD7F59FC1FDD773AAB5B56EA1067EA012CEB698DEF49D8795E1ECBC2C2937C01E9D99F79E619D77BC6F38EE26DD27B91D6200B07D46A7B47F600216693D1FF2FE5D522F243D1F1BF59DDB252D3E389197A9F7B94DFD374A0370E22DD0FFC50C2B26BFB2F782CAA177FC27E6C49EAF7FAC217BE10BE67A5FE208937B4F81FC538799C93F274BCF70479C595DE13AD0708B93CAC2DEF7FE1F7C3DF016A7C677BD1CFE6FFAFE8FF993C65440F82577E78FC9E193C09AF5C8D90C3D6D8A9B6DE91F84DABF93FAF6DEB891B5BEE73A6A72C93227A24ADE78D8EFF8DCE17D137A4E5B4B5F7E8ADA76C65C04C4FDB0EFC0F49174AFD27B76EDD4AC5AB403EC1DA5712E5DBCEF4DE48FD2FB33D402D8623744C942F90850F156DFF7B6BB9BD7CDB23F8B0D13527AD0C206C9B91EFEBF583A2F85F8A6349FB04B5B833799315DDAFC99728DB56AABD1DD59E48EB3E1BBBCBACE1CAAAFF89EE2BF0DA299AEE9F99DFE28903CCE63DC1F796BE20EF5E8892C3D6FE2B8D47E1B35BFB7F24C2DF4A753F3D7B2EAAB645927DA3358CACABC9EAD1CD942D3BE27FDAF9A06BA267B758FB02B2FBEDBC7190A8F720C501D1E7EE592BAC3F704067785F93E73D7B2EAA0645F27DB467EFADFBAC1F24D91F51FC9FD5FF176D5778DEA516B359894359E339D9FCEF3D7FC47B907CEEDE7A8EF03F3C75EBB8868607866BF4E449440DCA6CFC4FF2FFB53EA519F913D1FB136DA7649E579253D2F9227187AC7A8DEF850CCCF911FFF77C51C95E40FE8FE7BADAFA7FFA09BDA3E5C0A4FC1FA711FE17CEDDE321FC4E5B6F3AEEDEBDEBB695A8F7A1ADBD6F6BF07BF93F4BED7D940D9AA1CB326CA4ECBC82F57C995869969AC0EC791BDE75CDAAFFB1C49F251DA8E17F920CC25A6A7EBE17FB2AEBD9ADF53F5AFE1FBE14E44B2B7F3816287E2FE552ACF207F7C83135F94C213EE350C2E82419C9E722F2FA043A576F1DA2F5BF258E1D81DF312B8FC9A6CD9EB7E1B56925BB69670D2C6613455FDF8A7B175DFFEFF5E1B330C02DF2277306BA655F4BFCBF3257C4C2FF9A9F1A593F358A031C61FF7BF13F76D6BF932F1031FF03E7C02C9195B5DA3D7722BAFEDFDA83B483FFBD71E7E8FE1F7EBEC87CFF887AF50059F5D491FEFF11F3D77A317CCB31933B88EC7D5E79F62819E0913F59BECF517327A47DCCED0F6D7F65CC0E95640DCDA7CBC6DBF5C66BB06F69AEAC14EF239F90CF5EE07EA207FFC36A3FF57CDBB6AE0FFA6ED67E231F98D7D8538F037E624DF8BC5DF2BDE9BBF033A29E1DF7A2CDC3B0C81FEFDCE20CDF6795FFA3E3FF92FF81BD427220D2EFD77201B816DF9FD9789B59F5DA4710788B7894CFC1466F61E6CCE7A39F1932B5ED37C2FFDBCF56642FC97D2EFFDA38603B73886421C948FE4EB80C2559D9B389F87BA59F2B36143D8F754E39D66DA6D6C463CF4A35AD5CDFD21A46CC9C2742DC9DEF111CD23AE07B6D8FDB4ACD38AE8167E2FA33028386B032F9BECC9C3F4FEF8EE6DEF33CE0AF7FFDEB50AC3FBE1788BF579F8DFA45BCB884B41F78AE81FFE47CCDFB21F95EA3DF919C909E859E99E71D22DFE71FFEF0874766A749E7870E69E556E47DA05677B50603320AB852DC06C77DE25DADEABF1DFD9767AC13E9F13CB0FC2CB305D18701BB6E5516443F9B072369473C40B26BB3EBDFACFDEF99FB8AFA7566CE87D8017A64B4B9866DBD18FCDF8839A4ABF9979D75E291F512E07B5CC3324741F3BD67E30F91BCA0CD23B3CA800CFE97F653B4DE99DD2FD1FB9FEB7D92C19E77897DE8993B26E5313CFD333BF01723E21A99F309C01716396B395E7EF9E5C3D6AC871583B9E447F1BF95EF8E887F67F435B4EFC1FA2EA3F2DFD061F7EEDD3B0DFF47C8D3ACFE13F4E7786688590E6F3C39E21D40DFF43063ADF67F463EC08AB91AA9FFAD767D74CF2430FBDAF760916BC8211D51FF163DD7656696DE51F6BFA5E6107601E632500C0C39C92F7FF9CBC3BFB3E09947C9CC1E562C781F7B72E55E681602C5F32866DDE62128864971CC5E9C363B3F65DD2F91FB1FF8F4D27B183D97A5FE1DF878D02BB4D6D85F96FA77ECF19DFA3AABAF21FABC88E18FF8B7A733E163E1BDF6E205563DB21283B2CC8B388B9FB5339E635DD3A87DD5B3BF7AEF72D4FF067FBE87458298DF285E80BDBE2B5E9F25D7A3FD450D2704FADE33C303E7817DB052836FED59F5F0FEEC0CF95D73A0A371FF2DE797FC8B08FD37C2E8D5D60F7B47FB3BE49F3CF17CC49E61236836A016138C96F797821325C900ACF96C2D8856B30C5F6186E746F3DF4736FF6C4E72D71CC8ECEBACC4FF3D71080B46BFC64FDA9E59C1BFD17A0E347F7447FFE599F37F5867F0FD2AEE18485BFB11FE80D67FA0D9EF3D7DD3CE893C539E65B44F22AF637D8ED55954967CB1743EAD073902FF4EAB5D91F2D3D1FC9A15FFCFEC97C49AADF23EC912298F78FBF66DB7ADAACD7619E9FD15DECFB4DF2CD7B1EC139A7F99E9FF5BF4FFC8E61FAD9F867F9B893F826B66CBE12CFF31BA4F3C8BB4586ECF9E1BF51F920CF0CE3F3E93FD16711D3C1FEA182CFE8D35AF3763FF5BF57EEFBA929E88C4BF97628212FEFD0EFE3F63FC3F9324BD8038EF8CFEE732203AD677E43A7BF9BFE5B9D1335BE3D0DED82BFC7D4DEFE39E60EB8DF849D3CF3398E3BDBC80E51ABD7C6FDBFB25CD006B31F2A4D9D5117A3A3B5E1C4912BE4CD6ECF548DEDF19FFF7F0BF66F7401EA0DE7985FF3DF10E4BCCD5E2A74A784FF0D9A349CA07B4F9A81DF80F59FAFFACFDCC92ACEAD504CED6DCADC4F98FD6FF56BB7B646B6BF26FA5FE47DA573DDEE7715ACB73496B9C813F24F900EDB3EDC07FC88AFF47D68B469224DF7B589C920D0A3B7266EEEB25F37F7B1DAB9F2DC9412BBE9685FF1153EDD9FCFCDA16BB263BF7E1B1E576F0FF19E7449F89FF355EE8EDFF0CDD9F19BFF15E87F7CF598EB6BFC9BA5F467AC55B5F69F127B27B1F6E22FF67F5FFECE27FC4453C3A97D62CA3C6EF0CFCDFD381A3FA068B2EB6EAD81EFFCFD45859EC27E99A1173475A92E662B46B20DD0BE1BA73FC3B291E487D203C3E2861D765D9FF67CCFF818029E3D1FFA33D339201AB39FF197F384B3759F46DCF36201960F51735D9ABE1288C6C2F8BDC91F403EA50A349AA036A31C6AC38292BFE63049FEEAA4B3BC2FEB7C43647BE80A7C72F322F17791DC43CACFAB657778B75927A32ACF1FF5EEC65545F69E97FD572733BE60FB4F545B3BD27BBEDC74BD2FF5EFEF7C4A0AD71A8B3C7593C394F3C33AF81B4AC87350EEDF17F2DFD9456FC61694EEEECDC77ABED8F6B66BFEFACF8F12EBF348280CBE89983E8C9B98FEC63894FA2FCF2EC3C83F64C3DDBA6D7776BD92FD6B957D678ABD5FE055E5F960DA0CD9494E44B34BF66C5362F29FF1FE1FFF7786E6407ACF80247D6FFCFDA34BD38DD68BF58F4FF2A7EAAA7FF07353B2BBD28A833D7FA80A5DE8268797F49F83F5904FC008FFE9F790759B9C15D799691DEF5FA33165F407A8E51EDB5772D3DF2539B5B4D3382BC84BFD1CE89DE54EB7B888EFF65F5FF9F55FF47C4FF2C6B96D10FB4ABCEAAC777B3F73EAA19F0DAFF33B694E75D825F35198ED8BDC717806ED7FA7EF11C5AFF59F4FBCE8A1FED8A4B67F9FF19FC3F9201337680357E9515FF5BED61EED901D23ED4E4D0AC0CF2DA7223FC2FF404F6E4007EB782FFB563FE5A16FF67C5FFB1A6ED3C40DEE3443358785D04CDEDC1BF251BACC7FFD21E8CC2FFF46200EEEAFFD1308F22F298DA7A48724C5AFB19DCC495389505FB17BA1D3542B427B1C7343FDF83011CAD57B3E2743BFBFF24FF7DF5E8F9FF113E53140EE851F9FF159EB3CA008BFF8F3AE21519345B3F65C1A2CEC0FF8EAEFFC9CA1FEDECFF97FCF788D9E0D93993081CF023FA7F5679AE170FE0BE80F41CFC79237A2A56D60F767AC4FC0F3CC76BAFBD76085F65D5E9ED8CFF9F41FFCFAE99660758FDD95DFA9F9E39AB8F9188CFE3E8F9FF99F8493BE77F79B143577DCF5DF6FFCEFE3F297EB77AF4FA7FA26B1B09278BF33E66539C699D71CEAC1E462D26A8D5FF46FA1E51EB87783E6A8430DBD332A306D87E33B54334279C7A79F013F52BB384FE02EA1DA2F38DE6AF5B729D749F3CDE66C1D6872CF4AE0BBECFE7B2F3381FBF073E5BBA9D11CEE734E333CC19EBAD199FA5BD3A839D6C5FBEFF3DBE0FC776C2B1B21F34C27A64D8FCBDF590FC61DC4764FF14AD1F9F83BE3A4F1C3C42F3D2790F1E3E8BC00B3D82C063847FEE9D97E7218AC5E31ADA5AD10CF8761E3D8FFDF359F23C1F8003F3C22367C6F7F601C90A92D9245F251907BEEFF118640C3D0F3D532BEBB84CE2CFAC5D73C6D76AAFD5AE3BC9573E678CFF9EE769785F2AFDBF27BF88AFE83AF8D9F6C89D855F4807F2BD886793F6359EABEDD75DD52911047D2CCD3DC89063520F94545B158581001B33DA56C6BAC0B6B3DA81A8F1B6AE6504F61B7A4A707FB3EF6F05FBD07A78B117CF525706AC4EF80052AF90F4EE512B40EFE1ACCFA5D53D67D8005A2D64BB57A33110D1CBBDEA4F424669F361A2E6C04763BF7867CFEFE2FF9E4C3E635D19D650C290F5C400A107CE2AD7B4F86664FFB32667A439481918488829CDEAC4A83C10EEA1873B9E81FD3ABAE68E7B58E5FF23FBCAB176D1F3E8CFC6FF1A6F4662A06A3246E2490BFEFECCF1E4934FBAEFDB320B3AAA0E2493F72CB52767D5FF47F13F629167C7E1DB6D9BCF90D6FFACF91812FF235FC767DBB7F12F1E1FD7FA2E70F4E2FE33BC0FDF82E6C0E3BE61CFF4AE4F07CE6DE13DD429F17A661E13A535C0F52DD7B43CBBB4F6347F82E281F4B3CDABF09C497BB471F2B3DBFF96778F3507DFD073C1CE97665867E27067C6E6A2701035BF59F32F226225D86352DD8D75AEC3A80FA497BFA0F5D43025347E5CADD5C4FD6872DC32F7485BFB9D7AEA0C736550AB378AABF4DE3DE28488FD5D8AFD3FB2D1DB1C502BD35BBDDCEA67AF6F118579F9CA2BAF88D7B6C47B347F1F3D1E1173E0A5FAB6A85A6DEC3FCD1EE8CD9E071D8DEBBC0B8B7BC7BBEFF5009F91FF351B20E3804FB0430749B19B516D8066AF4066CDCE81E77A59ABB38BECFDE8E52B7AB2F7E83CD5D1B832BD359BC500D1F4EA19F13256F21C9E7CC82E1B54C23FEFD55D683270750E3CC5587A78B5D1B637EE57EB49F5F85ED7A2FFB577BF8A010692F08FCF382F6B870D30CA2B46C680A418404FFF6B3E7BD42CD8DEB36760FD6BEF539B6D7D34AEE391F68794A38FCA83EF9AE390990B88AA491951540FA496BFE99154DB857ABAA3F67E44ECCD8A3D7D06FBFF483E41CD5E7BEDE79E7BEED4EF368324BC5C1CA879E53D0FBCD69BC7001143D26A242DBD2B921FEC5D2B2DFEDF9BEB021D9F9503B590147B8BC87D7BE65B1C3DD7F528FF43B393FEFAD7BFDE88B846940D60B185566B8A25FD8F1C34F56FF11E14DED347398A5ECCB5570723E18CC0F7BB09BA4F8A03487110AD0681CB7A2EE779EE9FF2FFBCFFC7DB8725AD01D57E68BD9CBC0FA9ED07B55E7FF5DDE3EFDB7BE4EB8067B814FB7F95873DB57E56FD9F8DF9A3EDBDCC5EC89DB6B724CFADF3B776D6B845D71F5A75ACF4DC9EDA9799FB3EB3FEEFE5427A7C1CD14F94C1FFC8B98DE4CF1963DF51FC6F952DD1FCE7E57FEBFC9FE8EBAFE61D66D6EDCCFABFC7CB3DB918D14B9451078F9A8E19FEDF19A3C9C4FAB39E3B5AF67AF7F851F6C7EABB9FB9EFB3CECB9C8D0344F51267F5C18CEC7F690F48FD8997A8FF25B92CEDEFE8DE4BAFFC8A7EF7D6F593DEBDA7FF6D466E9E5DFF7B6D00AD76C89B3F95DE05EA785ACC9FB6D6983EEFC5FFA4BE9B5EDEE3E8F85F94FE97D6448A8D49F637F5FFF083E310B5F83F3C0EE6C5EE91D680DE3D7FEF7CBE03E10471BC248A0F5AB1D2248C496BAF08ED1D1EFBA47B9262A2F43303C76DA70DC0EDE9C81EE2CCFE9F1E3F5B67B4EFB4FF23726FC861596B9A8EEEBF3DCA07F3E448AF8D3EF8E083A10DA0C50A67EAE6A26AD066EA7F245CAFC839F05E1B3282F724F98D5A97CCB53FA30D3422A9FE47AB93BC36EAF5F06A7A73163F24127F5FEAE5EAE58451EB976903F4CE639D551FA1D73499168D7D7E161BC8425AED77940D70A9D8C023FB7E264F986DFF13C177F5F4FF68CF095F70A6F7AFD5C33D8CFDE8592DE859D16221DABBC99A177976FB7FF4EE237ABFB267AB1C650344E38644F6A07BF57FEF3931B37D661FDCBF7FFF13F1776DBE45A4DCC335B5B84DEFDD9C3107BAD3FFD0F2D7886DFFE31FFF709FEFE38F3FFEC47BC07E8C9C6F70061BC0DBDFBFCBFED7E6B85A7847C38040FF80C71EC43A48985056FC8F19B987F7A4F5FDE2BA3D197634FF65C5403C369336B7157680675F23F625BDFB5D73968EB2015631C322EA609077F2F6FF7002E6EF680EFCA80E12BD631E4CCE55DD0BB934EADD1CCDA1CC9A177B84EF374B23EC37C44E7A7D41342BCC8BFF780964C10758D1FDDA1EA01E14DE8742B95ECAA7529EB537873D1AFF93E6C0532E1CFC67C1E294FA9034EC4D3E0B479AB9639D3D6FD973DADAF3D93F7CCE5A8BBF4A3D5A1CA3B4EDCFE9F95F92ECE7FD3FED5C287EEEB63F89F6488B4767C9BB7BDE3D9D1FFF9E7DF797443D1D13D12F7354FD9F441973E0353E8CAE7D3F2BFE772F9E9F31FB61D69EC9C07E0726E5A5532F0E10912BC9D883F00566EF2D6AFE07CED1B3BF33F81FBEA667FEC70EFEEFF9723BE68F78FC89A8F91F78F777EFDE7D705348B201A2E68544EF01D86411F3BF56E7C08F7207D1CF6DB9E611FC77B4FEF7C6135AFCD619CC2BC4946F12C106E03AD1D25F67A5A83D807B8A8E1DC18640ECCF320312DF41ACC86A7744E85ED42F22EE386BEB5C03FFCFC63311CFC7DA4A7582527D256280975CF363910114EB897CCE765672DB5BC2E33F7CC634C57E5E7CF1C52DBD15E031BAD776BECD4C0C1475496D1C8D7A59DA585B8B351335FF9B6690F36BB6383FEDBC8776E6773BB7BCC508EAD55FF1F56CDF750F774E9A07DF620559E28FDE77DFC66567DFFD88CF10876A67B26BEB4F07E21751B58B78A63B77EE88F3B6F87EA4B5469C1D7D03974C348B9ED618EB7993E579919DFEF77F3F7CF0C73FFEF1E13153176421E830CCAC8C887BCFEA43C86AA986D67A207773297D8E565B143504113AA4E832E94F7FFAD383CF7FFEDF1EFCEBBFFECBC3E33FFEE3DFC365C0A87E60E6F0F6B1596698590F3CCFA5D108D301F5C045D747FFF55FFFF94FDEA7E385175E083BBF368720E2B0F63366C89F4BEBA5B4C4C22267A41715FF4B38C4D1C7C876CDBC874BF205ACB1F0B3E3B81645FB85CF3FC2FFBFF9CDFF849C5BF3B5914B82FE6CF1AF38263EFF1D6C082D4F8198428FA499793C9FD5C61FDBF82C6C07094763B6064F23D4D2502C12353AD184D8079D1FCFD4CBFB786A6C8A6E860C801D80E357BFFAEF90736AB5F52BFD345E3CDE19CC5F8D2CB86133847A0CA9AF0AB265B54F7BF699765DBFE8E692D4AFAAE1347948AA55413E5122A9DE7DE51E243B60B5F7A9D7EBE2C16C9CA55E3DA8B5BFB0A8E8519BE2C7293133298EAFD56049F7B012BB97AEBD529337EACBB5F4B8AE90E5FAE50BDC6C42CEBFF5FF23280B7BCD33DB247A0645349E8CA54636B35FDC12133CEB5CD7A273F3BFB4B722F4BF94CBD3786407FFAFE0395AEAC333F1622CD7BF84B90E45B1FC8F7AC05592FA8DE13FAF9214B7D67030A8069DD772AFD4BA4562F981EEDDBB37E4BF8C5CC059AE5F744EFE8FC80144CED0208AC6E68DD0FFABFAB187B1B2635ECFD1D72F3A9650EBDBF2FF57BEF295901A602DFF0F1D8EDE438E6BC4FBAAF83C247CD6EB511DE5FF2542BE10F909DE87A6CD61E7BD48D2F3ACFAC71AAE75044EB385D0CB2DE51F71FD9BD6E75DA4FBD4AD0C401F006C83157AFDF5D70FAFFFE384EFA287E70CFDD72D21CE4EB2E6089B1BBE00C9BE8AF95F17C1DF6FF9BF9505A80D429D90572644F6DDACC413B3EEA3E2E3453781E0F3F764003F200BD0376825C9BE5C3D3CB5299932A8F8BFE826C900DE0BDC3BF03D8B0CC8ECBFE961AFECB87E24FFC3E6A7B8C311F637F51F1CE57F149DC717403CC02207F09D51AEB0D70384F994ED2C761E7F433CAE17FBB3F4DFF46290B83EC5F8782CB0C563A7FB91620759F1BF5DF5F7B88654838CBEA98AFF5D37112610FA81A51821F9021A45F60069BD2A3D4CB0E81EA48C79CE67CEFFEDE83F28BA1C6AB182E8D0FC00A90768A50648AAFDD17A7F40520DD24AFF4FF43C29D8DC47D6DF5BEAFFCB17286A6D022B5E48740DB08425D4E33FA95E67E5FA47D4FF67CE8BB7D4FF57FD6F514BA80FE2FCAFF5D44998732BF6B2A47F7BFB53E2AF33F5FF8C30F9B2F1782CD72FFE2F6AA9C50CD36200D2FE42CC6D96A4DE9F9E7E94F49B173794933403F7A6F7FF96FD7F3DFC1A7D3EF4E5B4FBE9D6AD5BA1FE7F6F06EE25E07FF4E26F3BF0377AF82355FF7F3308FE79EBB3CFD6F74BFD029AFFAFC5DF9F7DF659F77535ECAF5EEF0F667644C5FFB37A8F8EAEFFD7AE0FDE2FFCAF9B41526DDF2C0E8E9407ECF50BF6F2EF88C551BEBF9D6B4439777C47C3AA5CC9FF4397C317E0F38EDA794B38E0AFAC5CDF4ABCFE3FD3E6EFF90254F750F5FF378BA0B3A5BCDD77BEF31D73AF3FBE87EF4B35403D5B22B3FECED2FB038CEE23EB0F8B8ACE403FFDE94FCDF5FD9E03E71D5146FDBD278E9771FD4B9BFF5154A4D5F0CD1E1E1F227206CF0CEF45CA80951C4251D14D900133F103D8EB2BF337F1B72BF85DABF33F57668F16159D8550C327CDFDB2F6FEAEE28210FE0E8FBDB573B76916100EE4D83EFCF0C3B0E7C7F591376C67ACD3FCF3160308F71A357BBCA8E8687AFFFDF71FE67610B7A31E1FCB91311B1C7C0D9D4E7C4F3200D841BB788EAECF7B0123627B382FEF1F6C7F72D9479FF33C48FB5DFE7BFAFFAC3D8275875CE5BD97FCF9F935212B77612CF2B5C37DD0BDE03EDE78E38DB0F3E379F0FC1C6B8EAEC3D703D7471D49E45EA46B4BD7A377CFF36258FF88EBE3BAD44777E40C6B3C4BAFAF579A1598B9FFA43AC108DC6DEBCCCD9DF8039017B31868C05A5CF1BF56D72EA21619727DF6F957FDCF55FF173DD933D787AE97E25FBB653AEE43ABA3B11CF8DB8F3EFA28FCBEA43AE588BD66E9EF593D3C722A2A06BB23F791C1FF5131E019DD19197FF6AEBF5687F7CC33CF6CE37DD497F466CD590F9C23BA265DDA6B11B83E67D2FFD139D0EC1C4834FF473FBF8707A5BED5DDEB3F533F1B45521FC0EA81985C1465E0FAEFE27F8BFECFAAC1CAF405BCBD9E677D7EF81B67C0BED66C00C8854C927A70A43E17D8F614DB428CC282191A2503B2F4BF2457E0FF697140AA3BE63141FE3DFE3B8A0F59E27FBD1A685E838D9F3CF687037A46EA7B227F348B226572AF061DB67C5B73CED71A3D9F5A9C0A718495B5A7FA73BEEE1C070FFF47FDF9CAF539E15CD279900FC8B2F97BFC0B3EEFC535D1BFD39B511F858F13DDD79F1D57F4C6F923E4BE16B7C9CAD144BD136D0E95B7076DE6F923FBCF34FBDDB3FE88BF3DFEF8E38F9CE3F6EDDBE1EF0F713AE95AD45BE6B96FEC61AD4F16D758ED538BC6F53A13FF4B1868D0273324F541DDB973475D53C966215C576EEF48FA57D29BD077ED79473670F6F3F7FABFA3F1E722FACFB599AFD1BE9CA6B7F1F90CBF028B5693812B3305B53589C0DD91F83F13CFCBAA4767E3F792FDA8C9C991DDB62BFE21BDDBD9DCB71443ECF924525E69257722ADBF779F6A7A39B297558B35ACF6B4E36FB5B8C08A1D9AC5FF59E73DCAB7F1F8E4DA1ED8CDFF91B95DEFFB8C8E2B45C544B5B874940DA0E53B22720D9A4FB5225777E6FF76F70D4AF7302B83A4FA81DEB9347B2DF2183D4B641ED1BB4F2479B962FF49F6C7CC3E851E7DE2892796E3891E3F2572DF4BB6E50AAE78F47BCAF2FF66735F6D5E6156CE4B71E8575E79C51D7BDB59FF4075C43CC7315B337DB4FE97D67F167F2E2B0EA0BDF3C838B1665BCE5E234BFF6B6B919D73CD20D48ACDACB9666B22E6DCC6FD280FA6CD5AC767ED9CF65DF5C8337162E9FBB37A45CB3FACF4C549F1CCD53880546B91314746C2AD9CEDD9C9CAFF817AF3CF601351CF13DFD73C0FBCA3FF10EB46D7E73D46F8095F4EC33FB3D88B88DB4AB6E6A876201A3B3E8224FBDBABFFB1667CC65C8B3FD7D68160FD57E6DF79EDD3D5BA1AE99957E3F3561F60D6AF8B9E13D0F25694ADBBDA7FE2B505A3EACF341BA0D7CF97659345FBB53DFB7B765DAD47443FA4245B66F3A33BDF5B646E3D93FF35BD71A6DAFB997DEA89E77CFCF1C762CEA9670364DA6451FA6614D3CEACFF8E8AA769B5F93D5CFDA81C51F49E8DCCEB44DF73740F48643C75669FA22E36E21A9ACF1699B72082BE6CEB7B39DE818401839C8756FF3CF27FB2F83F5AFE4BCF376B0348FCBFCBFE9FD50F59BDE6922F009D77B6FE9BD93E65AFFD29D99ADA8C910C3D126D8F8FD63FBAFF1BF226C3FFD36C8099388084B79D314746AA079E8DFF65D5FF6A847E0BAC6D1BF3E6F11FFA2C33FEC3DF59DB634407EC8CA8FE1FE40AADB666062603D674A7FDA5F57FB598776D4F578B091585FFE38D53CFE4D477E4FFC03F91B99033C69A5A8AE8FF58A1A8F947522E41AA89C8A8C988B2C7ADF5C397B0AF88B41EE9199F4B7AC7913E8B64FB8FFC15D43C69BC92E9FF536E8DE43BF6F06CDC56D2C3A3380DD5BF10A6EA4AFD8F77FEA227E7D4C6D1093B911FABB6EF2AFFC3DEF1D898D2BE5AE9FF926AB922311181EF26E1ED7831B7B458570486AF665F8CEC31AA5F811E6B755666FC3FF2DCD2BA8E7462641CDDD3FFE3F5DD76D4454AFC089E6EB156795F22FE3F8B7F1A5DC3909DA702E66EC40CF8CCFE1FAD0FB867074BF70339407F9319FFCBEEBF199DEBE8EB67DB9AABF79F11E7CDB2FF77E444256CD4191B40F317E1C7CEC8005C1F980D33780ABD3E14F812D2BD46ADABB407667D216FFF8DA68376F4FFEEDA6767CCF3F4AEB782BB2DD97FD1FCAFC9666FEC45C31A213BC013B782EDA5E97DD496F6E4C96C1F6AD4BA22CE1F65EB4AFEFF284713D98324F9FFB3B5A2DA3ECBE4C7DDFDD852BE63A54F2D22FE62A1A79F7E3A44368FF0BF5043D2F3ABF8BC02ED18CDCAEED90D51B8DA33F18A28FCA9915F1A85FBA8BD8795FC83947382CEC8B20176F3BFB6F633F530DAFB473FBC265F39CE12E594DB792312B6A476AD19BB51D27F12FE27D68472E188D569FA7EB6F7D1224BB2F4901457253D4C18902D4616FDECCD49B1E6DF7B3D48B0475B9C51DA27F8377EBF7A7D8DDE7EFBEDAD3680C4FF589BB6E681E394F1D820E71F6BDC5D9B3542D8A3BC0F88F75DD175F0FEB5FEAB5EFD47D6EC899938A896F3593966FB9EAD7220720F4A35513BFB3FB2F0AF2366A166D8151EFE9F3DACFB23EBDD8FEA0FB3F87F06BB14043B5D8B0778E77F8C6C7EAB1CE8CD228AD64191F3CF67E248D13D4851F3E334FF68769F79E3E73BE62E65CCFF18D9E299BD47B3385E88D3ADE042624FAC62FD5AED810CBF304A06CCE60F106F3913EF1369F199E8D934913CE1D50F1AF67ED6FA67F61EAFCA66BC57CFFC4F3C6FF69C22D89BDC1EC88A0B1D397F92AE3F3B8312718CC87AB35E9C0CFB373A0E18A9FF676A91F1EE56FABF3CEF1FDFE3FD04528F23D539D14F9A85DC62D0F0FFD3F723DF7D5BD748B59EBBE793D2FDC01EC8C6E9A619D0B49EF47EDA785316FE0F9F7FCDF789347368C7FC6FE24DAC7DD6B58827781CAF9DC3C4F198DA9E1CCE472B7210EF1273B1DAB83BDD17BF2E7EE23DEDEAF3282A3A82E0D745D487177D32BFF2EEBBEF5EE4BD430740C6927C24B98B1AE559C2DF72FD46F89147D81945459904BE7FECB1C71ED6C7BDF5D65B1771CFF0F75E7EF9E56EEE7FA52EA7D7FF0D8C025C3BB3FE746497F2D95811B9354F4C80DBBFB89715395B742CBDF7DE7B9FC05C45DEEDEC7600F69C84131BD9032ED5C24BF5C4BB71668F9E1328C9C5A3B1768BE66D7EE4C8A5BC397E77463BDF52EBB78BFFB93D10ED1760FDA57760AD4BD5FE7E95A4B8F8EE39A545717B4CD3A3B003CE2403702FF05176F5E578F3BF58C737DF7C33F459257FCCD2D749EF1547F43BCCEE2B2FDACF575AAD5DC6FE9921E43346F580E895423E88F72FCC62FC81E0D3F29C0FEA4E346C3B6E37ADE65EDAF7D1BE8311FF8DFE3E83FFA3F39F147BA51C33729A1577CD8D019C590668737C6936D4CEFBC3B5704DED7E56E61769F618B72D7A58D7F88EE4CF45BEC30CAC6D8B8CA1B5AD58E3DE58C0D1BE80E687634FBFFAEAAB87AD17FA0AB4F59AED07B0D8621A4ECC2E3B6E074EE5A8F62E0323BEE8C18377DE79478D071C6107A0CE235B9F65F84E239C91D9980CD6E21BDFF8C6239FE3B35DEF4D92C7D1FC6F89BD5CE25CD44B8F09EEE6BB175F7C710AC7632769B8252FBDF4524A4CC61B938CCEE5EE98B569ED47A9BC439E0CD062ED3B658034B717BEF7D9E8A9A79E0A9F638CB8FF8A0CC87A4F3B7025A9C609470F5304C7913EE0913A87EAFDEFDDBBB7D5B6DD150FD0E6769CB12E01BC2ADD2B9E21CB163B82F777C5FF24EAF582A34732BAD7FB8CA4615AA3D72FE3F98FCC0D4A38343B70DF6749CA0D7AFA2F79CF251DB0B525DB6274C046E2FD919447A31E869690276DF1A4A8EF93FE963E97FA8109174BEA47A3BFA57EB5959EE49E2C5CB1B7F0FCB4DE749F1C6BABC5FBE7FFE6EBC67BF2F8F7F877579E5FB28733E7E6910CD0E2DC993240B233BD38983B49C2A5B0DAC599F82B965CFDCEEBCFDA0A237CD8155F200BFF2A323774F7EEDDB4E73F634C70479D49244975F1D677EDA935CEE0BFC8599759313B4B4C70360E91897F13C5FF161995C91F231910DD3728EDC933F3BFC4C3D6FBDDA97F251ED9297F22E7AE47ED8F9DEB3FCBFF99CF1FE10B205F10690748CF9B81F39869FF5BDFC74EFD23F1DF4EFB7796FF61DB66D9BF3BF97FD6FEC97C7E0FA1C6B46707A096382BFEB7320F259BA41C9535D683FE7D1E2FA319BC387AB5C6DA817A208AD7D179081745BA27C254E3B12B1EF3E3F13C29FE079C3A1EB7A41820C534796C332BFEB512FFE3F8773C5EC9E376ED2C5D7A2E8AFFF17FB7D8793C1E98F5FCA891DF453B62821AD6F319F37FDA6C8AD59E95D93AA0CCFE6D4957EEF2CBFEF6B7BF89F92FECFD23B0588EC8FF4932607556EE596382D2BB463EEC6C24E5E856F3313D197BA40C907C95CC397C9A2D4CBA36ABFEE5CC845C08D98AC80B1CA9F7B43AC1881A21D4D04AE7C6F39FE95D48F7F8C20B2F4C9FB3D78FE939A263321AFF571DEEF5127A86341980CF57F2025AFFCF59B049341D0DFBE7FEFDFBE17695D6FF03FB43B315A2ED80DD73318BCE4F99F180B3F6FF42EF6B7C3ACB0FBD75243ED6F03F467223AA0F48F2FF77DBFF45E7940159B5C23DCCBF23F03F7A35B9ABF81F1A1E23D951BDFE7B4D0644DA4B92FE8FEEFF29BA793260650F02536BD40783FC1B72F03CDFB23277057FCBEBBE2DF85FB8C70CFC2FEE4349F610D7BFAD0C88B6FF0BFFAF68C517988D07CCF4C2ADD8A5DE9AD8C83A685A43E99C16FC6FD8FAF85BC891284C52CFF58BAE9B689E48743C0AFDB41EFCEF15BBD4C3FFC8F545CFA3D2F0BBADF977BC830CBF68647F1415D1FED37C81D57814F6A02537BEB22F2D35B1B88733CCFFD8790F65FF17ADDAEC1158F9C80D8EE67FADF07FAF261FF566C0269BCDF1AD10CD39E4736957E77C7B08D7E29802BBE78F155D16C1DF6FE78B45DBA53417BC9D53BE1AFFA3D81FD57F037BBAE6CE1615CDD90167C1ED2D2A2ADA2F038AF78B8A8A6E824F43BE77C9B4A2A2EB21292E78665CA2A2A2A21842CE52CB09941D505474B3A987135539F0A2A29B4DBD9AA0E2FFA2A2B2FF8B8A8A6E2EADE0FC1715155D3E110E07E2FEA5F78B8A8A8A8A8A8A8A8A8A6E2EA1CF88FADEA83F6867FF5D5151D17154F8174545D74B857F5B5454FC5FF8B74545C5FF55FB575454FE7F5151D175F27FE9FFA2A2EBA0AAFF2D2ABA5EAAF9574545C5FFA5FF8B8AAE8F6AFE4551D1F552E5FF8B8AAE97A4F87FF17F51D1F5EAFFC2FF2D2ABA5EFD5FFC5F54741D24C5FF2AFE5F5474BDF67FC5FF8B8AAE83A4FC7FF17F51D1F5F23F6A828B8A8A6E3E01EB8BB0BFC0F785FF555454545454E4A3FF03645B97F4]]>
              </BitmapFile>
            </BitmapFromFile>
            <BitmapExpression>
              <Expression>
<![CDATA[//X,Y : current coordinate (0..1)
//Pixel : current color (rgb)
//Sample expression: Pixel.R=abs(sin(X*16));

Pixel.A = 1-(Pixel.R + Pixel.G + Pixel.B)/3;
Pixel.R = 1;
Pixel.G = 1;
Pixel.B = 1;]]>
              </Expression>
            </BitmapExpression>
          </Producers>
        </Bitmap>
        <Font Name="fnt_FontWeiba" Bitmap="bmp_FontWeiba" FirstChar="32" CharPixelWidth="32" CharPixelHeight="32"/>
        <Material Name="matFnt_Weiba" Shading="1" Light="0" Blend="1" Font="fnt_FontWeiba"/>
      </Children>
    </Group>
    <Group Comment="Models">
      <Children>
        <Model Name="baseMdl" Category="2" CollisionBounds="1 1 0 0">
          <OnSpawn>
            <ZExpression>
              <Expression>
<![CDATA[switch(CurrentModel.Category)
      {case 2:current_Bigs++;
              break;

       case 11:current_Smalls++;
               //Convert coordinates to array
               float rX,rY;
               rX = (CurrentModel.Position.X + 16)/32;
               rY = (CurrentModel.Position.Y + 9)/18;
               int aX,aY;
               aX = clamp(rX*arr_Smalls.SizeDim1,0,arr_Smalls.SizeDim1-1);
               aY = clamp(rY*arr_Smalls.SizeDim2,0,arr_Smalls.SizeDim2-1);
               arr_Smalls[aX,aY]++;
               break;}]]>
              </Expression>
            </ZExpression>
            <ZExpression Expression="timer_Lifespan.Interval = CurrentModel.Personality*4; //+2"/>
          </OnSpawn>
          <OnUpdate>
            <Timer Name="timer_Lifespan" Comment="Expire" Interval="2">
              <OnTimer>
                <RemoveModel/>
              </OnTimer>
            </Timer>
          </OnUpdate>
          <OnRemove>
            <ZExpression>
              <Expression>
<![CDATA[switch(CurrentModel.Category)
      {case 2:current_Bigs--;
              break;

       case 11:current_Smalls--;
              //Convert coordinates to array
              float rX,rY;
              rX = (CurrentModel.Position.X + 16)/32;
              rY = (CurrentModel.Position.Y + 9)/18;
              int aX,aY;
              aX = clamp(rX*arr_Smalls.SizeDim1,0,arr_Smalls.SizeDim1-1);
              aY = clamp(rY*arr_Smalls.SizeDim2,0,arr_Smalls.SizeDim2-1);
              arr_Smalls[aX,aY]--;
              break;}]]>
              </Expression>
            </ZExpression>
          </OnRemove>
        </Model>
        <Model Name="m_Big" Comment="Spawns Smalls" BaseModel="baseMdl" Position="-7 3 0">
          <OnSpawn>
            <ZExpression Expression="timer_Reproduce.Interval = 0.05+CurrentModel.Personality*0.25;"/>
          </OnSpawn>
          <OnUpdate>
            <Timer Name="timer_Reproduce" Comment="Spawn kids" Interval="0.05" RepeatCount="20">
              <OnTimer>
                <ZExpression>
                  <Expression>
<![CDATA[m_Small.Position.X = round(CurrentModel.Position.X + sin(rnd()*Pi*2) *16*0.5);
m_Small.Position.Y = round(CurrentModel.Position.Y + sin(rnd()*Pi*2) *9*0.5);

@SpawnModel(Model:m_Small, SpawnerIsParent:1);]]>
                  </Expression>
                </ZExpression>
              </OnTimer>
            </Timer>
          </OnUpdate>
          <OnRender>
            <UseMaterial Material="mat_Clean"/>
            <RenderSetColor Color="1 0 0.502 1"/>
            <RenderNet/>
          </OnRender>
        </Model>
        <Model Name="m_Big1" Comment="Tries to confuse ZGE" BaseModel="baseMdl" Position="-8 -3 0" Category="11">
          <OnRender>
            <UseMaterial Material="mat_Clean"/>
            <RenderSetColor Color="0 0 0.6275 1"/>
            <RenderNet/>
          </OnRender>
        </Model>
        <Model Name="m_Small" BaseModel="baseMdl" Position="0 3 0" Category="11">
          <States>
            <ModelState Name="ModelState1">
              <OnStart>
                <ZExpression Expression="CurrentModel.Scale *= 0.5;"/>
              </OnStart>
              <OnUpdate>
                <Timer Interval="0.5">
                  <OnTimer>
                    <SetModelState State="ModelState2"/>
                  </OnTimer>
                </Timer>
              </OnUpdate>
            </ModelState>
            <ModelState Name="ModelState2">
              <OnStart>
                <ZExpression>
                  <Expression>
<![CDATA[CurrentModel.Scale = 1;
CurrentModel.CollisionBounds = 1;]]>
                  </Expression>
                </ZExpression>
              </OnStart>
            </ModelState>
          </States>
          <OnSpawn>
            <ZExpression>
              <Expression>
<![CDATA[timer_LifespanChild.Interval = 1+CurrentModel.Personality*4;
CurrentModel.CollisionBounds = 0;]]>
              </Expression>
            </ZExpression>
            <SetModelState State="ModelState1"/>
          </OnSpawn>
          <OnUpdate>
            <Timer Name="timer_LifespanChild" Interval="1" RepeatCount="0">
              <OnTimer>
                <RemoveModel/>
              </OnTimer>
            </Timer>
          </OnUpdate>
          <OnRender>
            <UseMaterial Material="mat_Clean"/>
            <RenderSetColor Color="0 1 1 1"/>
            <RenderNet/>
          </OnRender>
        </Model>
        <Model Name="m_Player" Rotation="0 0 26.0691" RotationVelocity="0 0 0.2" Category="1">
          <OnRender>
            <UseMaterial Material="mat_Clean"/>
            <RenderSetColor Color="1 0.502 1 1"/>
            <RenderNet/>
          </OnRender>
        </Model>
      </Children>
    </Group>
  </Content>
</ZApplication>
Edit: luckily for me this is super easy to fix! Adding a condition for the spawner model to check it's own HP>0 before it spawns anything makes it work. Although... how can it check anything if it's already removed :D
Last edited by rrTea on Fri Oct 14, 2016 3:24 am, edited 1 time in total.
User avatar
VilleK
Site Admin
Posts: 2274
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: Parent removed, but some offspring remains

Post by VilleK »

Good analysis, you are correct, if the spawner adds child models after it has been removed then it would cause error messages. I've protected against this in the engine now so it should not crash.
User avatar
rrTea
Posts: 475
Joined: Sat Feb 15, 2014 9:54 am

Re: Parent removed, but some offspring remains

Post by rrTea »

Excellent, thanks!

btw the reason I have it set up like this is because the BaseModel for the enemies has all the standard events (bumping into walls, sustaining and dealing damage, deletion) but only particular enemy models have things like spawning other enemies (bullets and other independent models), I guess this makes sense? But one of the enemy models was also acting as parent so this is what triggered the problem.

Anyway - I just tested the new build, seems that removing Parent model still sometimes leaves Children behind (but deleting orphan Children doesn't crash anymore). I'll just leave the condition of parent checking whether it still exists (that sounds weird...) before it does anything just in case.
Post Reply