Page 1 of 1

Parent removed, but some offspring remains

Posted: Thu Oct 13, 2016 7:49 am
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?

Re: Parent removed, but some offspring remains

Posted: Thu Oct 13, 2016 8:27 am
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).

Re: Parent removed, but some offspring remains

Posted: Thu Oct 13, 2016 8:45 am
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).

Re: Parent removed, but some offspring remains

Posted: Thu Oct 13, 2016 9:21 am
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.

Re: Parent removed, but some offspring remains

Posted: Thu Oct 13, 2016 10:33 am
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

Re: Parent removed, but some offspring remains

Posted: Thu Oct 13, 2016 11:43 am
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.

Re: Parent removed, but some offspring remains

Posted: Fri Oct 14, 2016 3:41 am
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.