§
    Çz¿jé8  ã                   ó"  — d Z ddlZddlZddlZddlmZ ddlZddlmZ  ee	¦  «         
                    ¦   «         j        j        j        Zedz  dz  Zedz  Zedz  d	z  Zedz  d
z  Z G d„ d¦  «        Z G d„ d¦  «        Z G d„ d¦  «        ZdS )a®  
Empirical Challenger Test Suite: Milestone 3 Remediation.
Adversarial stress-testing of Client Script Integration & Leader Aura Ground Decals.

Verifies:
1. client/webapp/index.html script tags, attributes, and ordering.
2. Node.js evaluation of wilderness_zone_packs.js, monster_pack_system.js, and ambush_trigger_system.js.
3. Window global bridge exports.
4. Canvas 2D renderLeaderAuraDecal across 5 aura types with mock context.
5. Adversarial edge cases: dead mobs, non-leaders, negative coords, undefined time, NaN guards.
6. High-frequency 10,000-frame render stress loop (zero NaN, zero throw, budget <= 0.05ms/call).
7. Safe haven firewall on pack spawning & ambush triggers.
é    N)ÚPath)ÚBeautifulSoupÚclientÚwebappz
index.htmlÚjsÚdataÚenginec                   ó*   — e Zd ZdZdd„Zdd„Zdd„ZdS )ÚTestIndexHtmlScriptIntegrationz6Adversarial DOM parsing and script order verification.ÚreturnNc                 ó   — t                                ¦   «         sJ dt           › �¦   «         ‚t                                d¬¦  «                             ¦   «         }t	          |¦  «        }|dk    sJ d|› �¦   «         ‚|dk    sJ d|› �¦   «         ‚d S )Nzindex.html missing at úutf-8©ÚencodingéÈ   z$index.html exceeded soft cap (200): i�  z$index.html exceeded hard cap (400): )Ú
INDEX_HTMLÚexistsÚ	read_textÚ
splitlinesÚlen)ÚselfÚlinesÚ
line_counts      úMC:\Projects\FreeExile\tests\unit\test_challenger_m3_script_and_aura_stress.pyÚ&test_index_html_line_cap_and_existencezETestIndexHtmlScriptIntegration.test_index_html_line_cap_and_existence    s¢   € Ý× Ò Ñ"Ô"ÐIÐIÐ$I½ZÐ$IÐ$IÑIÔIÐ"Ý×$Ò$¨gÐ$Ñ6Ô6×AÒAÑCÔCˆÝ˜‘Z”Zˆ
Ø˜SÒ Ð Ð Ð"UÈÐ"UÐ"UÑ Ô Ð Ø˜SÒ Ð Ð Ð"UÈÐ"UÐ"UÑ Ô Ð Ð Ð ó    c                 ó„  — t                                d¬¦  «        }t          |d¦  «        }|                     d¦  «        }g d¢}d„ |D ¦   «         }|D ]l}||v sJ d|› �¦   «         ‚|                     dd|i¬	¦  «        }|€J ‚|                     d
¦  «        dk    s#J d|› d|                     d
¦  «        › �¦   «         ‚Œmd S )Nr   r   úhtml.parserÚscript)ú js/data/wilderness_zone_packs.jsú js/engine/monster_pack_system.jsú"js/engine/ambush_trigger_system.jsc                 ób   — g | ],}|                      d ¦  «        ¯|                      d ¦  «        ‘Œ-S ©Úsrc©Úget©Ú.0Úss     r   ú
<listcomp>z[TestIndexHtmlScriptIntegration.test_script_tags_presence_and_attributes.<locals>.<listcomp>1   s1   € ÐEÐEÐE¨¸¿º¸e¹¼ÐE�q—u’u˜U‘|”|ÐEÐEÐEr   zExpected script tag missing: r%   )ÚattrsÚtypeÚmodulezScript z must be type='module', got )r   r   r   Úfind_allÚfindr'   )r   Úhtml_contentÚsoupÚscriptsÚexpected_scriptsÚscript_srcsÚexpectedÚtags           r   Ú(test_script_tags_presence_and_attributeszGTestIndexHtmlScriptIntegration.test_script_tags_presence_and_attributes'   s	  € Ý!×+Ò+°WÐ+Ñ=Ô=ˆÝ˜\¨=Ñ9Ô9ˆØ—-’- Ñ)Ô)ˆð
ð 
ð 
Ðð
 FÐE¨WÐEÑEÔEˆà(ð 	rð 	rˆHØ˜{Ð*Ð*Ð*Ð,VÈHÐ,VÐ,VÑ*Ô*Ð*Ø—)’)˜H¨U°HÐ,=�)Ñ>Ô>ˆCØ�?�?�?Ø—7’7˜6‘?”? hÒ.Ð.Ð.Ð0q¸(Ð0qÐ0qÐ`c×`gÒ`gÐhnÑ`oÔ`oÐ0qÐ0qÑ.Ô.Ð.Ð.ð		rð 	rr   c                 ó6  — t                                d¬¦  «        }t          |d¦  «        }d„ |                     d¦  «        D ¦   «         }|                     d¦  «        }|                     d¦  «        }|                     d¦  «        }|                     d	¦  «        }|                     d
¦  «        }|                     d¦  «        }	||k     s
J d¦   «         ‚||k     s
J d¦   «         ‚||k     s
J d¦   «         ‚||k     s
J d¦   «         ‚||	k     s
J d¦   «         ‚d S )Nr   r   r   c                 ób   — g | ],}|                      d ¦  «        ¯|                      d ¦  «        ‘Œ-S r$   r&   r(   s     r   r+   zLTestIndexHtmlScriptIntegration.test_script_tags_ordering.<locals>.<listcomp><   s1   € ÐUÐUÐU¨ÈÏÊÈeÉÌÐU�q—u’u˜U‘|”|ÐUÐUÐUr   r   r    r!   r"   zjs/engine/monster_system.jszjs/engine/entity_renderer.jsz
js/main.jsz9monster_system.js should precede wilderness_zone_packs.jsz<wilderness_zone_packs.js must precede monster_pack_system.jsz<monster_pack_system.js must precede ambush_trigger_system.jsz8ambush_trigger_system.js must precede entity_renderer.jsz'entity_renderer.js must precede main.js)r   r   r   r/   Úindex)
r   r1   r2   r5   Úidx_dataÚidx_packÚ
idx_ambushÚidx_monsterÚ
idx_entityÚidx_mains
             r   Útest_script_tags_orderingz8TestIndexHtmlScriptIntegration.test_script_tags_ordering9   sE  € Ý!×+Ò+°WÐ+Ñ=Ô=ˆÝ˜\¨=Ñ9Ô9ˆØUÐU¨T¯]ª]¸8Ñ-DÔ-DÐUÑUÔUˆà×$Ò$Ð%GÑHÔHˆØ×$Ò$Ð%GÑHÔHˆØ ×&Ò&Ð'KÑLÔLˆ
Ø!×'Ò'Ð(EÑFÔFˆØ ×&Ò&Ð'EÑFÔFˆ
Ø×$Ò$ \Ñ2Ô2ˆà˜XÒ%Ð%Ð%Ð'bÑ%Ô%Ð%Ø˜(Ò"Ð"Ð"Ð$bÑ"Ô"Ð"Ø˜*Ò$Ð$Ð$Ð&dÑ$Ô$Ð$Ø˜JÒ&Ð&Ð&Ð(bÑ&Ô&Ð&Ø˜HÒ$Ð$Ð$Ð&OÑ$Ô$Ð$Ð$Ð$r   ©r   N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r8   rB   © r   r   r   r      sd   € € € € € Ø@Ð@ðVð Vð Vð Vðrð rð rð rð$Pð Pð Pð Pð Pð Pr   r   c                   ó   — e Zd ZdZdZdd„ZdS )Ú&TestNodeJsSimulationAndAuraDecalStresszDNode.js runtime simulation of module execution and Canvas 2D decals.a’  
    import { isSafeHavenZone, getWildernessPacks, getZoneAmbushTriggers, SAFE_HAVEN_ZONES } from './client/webapp/js/data/wilderness_zone_packs.js';
    import { populateZonePacks, updateMonsterPackAI, renderLeaderAuraDecal } from './client/webapp/js/engine/monster_pack_system.js';
    import { activeAmbushTriggers, initZoneAmbushTriggers, updateAmbushTriggers } from './client/webapp/js/engine/ambush_trigger_system.js';

    // Mock Window environment
    globalThis.window = globalThis;
    window.SAFE_HAVEN_ZONES = SAFE_HAVEN_ZONES;
    window.isSafeHavenZone = isSafeHavenZone;
    window.getWildernessPacks = getWildernessPacks;
    window.getZoneAmbushTriggers = getZoneAmbushTriggers;
    window.populateZonePacks = populateZonePacks;
    window.updateMonsterPackAI = updateMonsterPackAI;
    window.renderLeaderAuraDecal = renderLeaderAuraDecal;
    window.getWildernessZoneMonsters = (z, fn) => populateZonePacks(z, fn);
    window.activeAmbushTriggers = activeAmbushTriggers;
    window.initZoneAmbushTriggers = initZoneAmbushTriggers;
    window.updateAmbushTriggers = updateAmbushTriggers;

    const results = {
      globalsDefined: {},
      auraStress: [],
      adversarialEdgeCases: [],
      highFreqStress: null,
      safeHavenAudit: null
    };

    const requiredGlobals = [
      'getWildernessZoneMonsters',
      'initZoneAmbushTriggers',
      'updateMonsterPackAI',
      'updateAmbushTriggers',
      'renderLeaderAuraDecal'
    ];
    for (const g of requiredGlobals) results.globalsDefined[g] = typeof window[g] === 'function';

    class MockCanvasContext {
      constructor() {
        this.saveCount = 0;
        this.restoreCount = 0;
        this.strokeStyle = '';
        this.fillStyle = '';
        this.globalAlpha = 1.0;
        this.ellipses = [];
      }
      save() { this.saveCount++; }
      restore() { this.restoreCount++; }
      beginPath() {}
      stroke() {}
      fill() {}
      ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle) {
        for (const arg of [x, y, radiusX, radiusY, rotation, startAngle, endAngle]) {
          if (typeof arg !== 'number' || Number.isNaN(arg) || !Number.isFinite(arg)) {
            throw new Error(`NaN/Non-finite argument in ellipse: ${arg}`);
          }
        }
        this.ellipses.push({ x, y, radiusX, radiusY, rotation, startAngle, endAngle });
      }
      createRadialGradient() { return { addColorStop() {} }; }
    }

    const canonicalAuras = [
      { type: 'HASTE', expectedColor: '#a855f7' },
      { type: 'DAMAGE_RESISTANCE', expectedColor: '#38bdf8' },
      { type: 'ELEMENTAL_EMPOWERMENT', expectedColor: '#f59e0b' },
      { type: 'VAMPIRIC', expectedColor: '#ef4444' },
      { type: 'MORTAL_MIGHT', expectedColor: '#ec4899' }
    ];

    for (const aura of canonicalAuras) {
      const ctx = new MockCanvasContext();
      const mob = { isPackLeader: true, hp: 5000, leaderAura: aura.type };
      let threw = false, errorMsg = null;
      try {
        renderLeaderAuraDecal(ctx, mob, 450.5, 320.25, 12.345);
      } catch (err) { threw = true; errorMsg = err.message; }

      results.auraStress.push({
        aura: aura.type, threw, errorMsg,
        saveBalanced: ctx.saveCount === 1 && ctx.restoreCount === 1,
        ellipseCount: ctx.ellipses.length,
        colorMatches: ctx.strokeStyle === aura.expectedColor && ctx.fillStyle === aura.expectedColor,
        allRadiiPositive: ctx.ellipses.every(e => e.radiusX > 0 && e.radiusY > 0),
        yOffsetApplied: ctx.ellipses.every(e => Math.abs(e.y - 324.25) < 0.001)
      });
    }

    const edgeCases = [
      { name: 'dead_mob', mob: { isPackLeader: true, hp: 0, leaderAura: 'HASTE' }, x: 100, y: 100, t: 1.0, expectRender: false },
      { name: 'negative_hp', mob: { isPackLeader: true, hp: -250, leaderAura: 'HASTE' }, x: 100, y: 100, t: 1.0, expectRender: false },
      { name: 'non_leader', mob: { isPackLeader: false, hp: 1000, leaderAura: 'HASTE' }, x: 100, y: 100, t: 1.0, expectRender: false },
      { name: 'undef_aura', mob: { isPackLeader: true, hp: 1000, leaderAura: undefined }, x: 100, y: 100, t: 1.0, expectRender: true, expectColor: '#a855f7' },
      { name: 'unknown_aura', mob: { isPackLeader: true, hp: 1000, leaderAura: 'CHAOS' }, x: 100, y: 100, t: 1.0, expectRender: true, expectColor: '#a855f7' },
      { name: 'negative_coords', mob: { isPackLeader: true, hp: 1000, leaderAura: 'VAMPIRIC' }, x: -999.5, y: -450.2, t: 2.5, expectRender: true },
      { name: 'large_coords', mob: { isPackLeader: true, hp: 1000, leaderAura: 'DAMAGE_RESISTANCE' }, x: 1e6, y: 2e6, t: 3.0, expectRender: true },
      { name: 'undef_time', mob: { isPackLeader: true, hp: 1000, leaderAura: 'HASTE' }, x: 50, y: 50, t: undefined, expectRender: true },
      { name: 'zero_time', mob: { isPackLeader: true, hp: 1000, leaderAura: 'HASTE' }, x: 50, y: 50, t: 0, expectRender: true },
      { name: 'negative_time', mob: { isPackLeader: true, hp: 1000, leaderAura: 'MORTAL_MIGHT' }, x: 50, y: 50, t: -543.21, expectRender: true }
    ];

    for (const ec of edgeCases) {
      const ctx = new MockCanvasContext();
      let threw = false, errorMsg = null;
      try {
        renderLeaderAuraDecal(ctx, ec.mob, ec.x, ec.y, ec.t);
      } catch (err) { threw = true; errorMsg = err.message; }

      results.adversarialEdgeCases.push({
        name: ec.name, threw, errorMsg,
        saveBalanced: ec.expectRender ? (ctx.saveCount === 1 && ctx.restoreCount === 1) : (ctx.saveCount === 0 && ctx.restoreCount === 0),
        renderedMatchesExpectation: (ctx.ellipses.length === 2) === ec.expectRender,
        colorMatches: ec.expectColor ? ctx.strokeStyle === ec.expectColor : true
      });
    }

    // High Frequency 10,000 frames stress loop
    const hfCtx = new MockCanvasContext();
    const hfMob = { isPackLeader: true, hp: 5000, leaderAura: 'MORTAL_MIGHT' };
    const t0 = performance.now();
    let hfThrew = false, hfErrMsg = null;
    try {
      for (let f = 0; f < 10000; f++) {
        renderLeaderAuraDecal(hfCtx, hfMob, 100 + (f % 50), 200 + (f % 50), f * 0.016);
      }
    } catch (e) { hfThrew = true; hfErrMsg = e.message; }
    const durationMs = performance.now() - t0;
    results.highFreqStress = {
      iterations: 10000,
      threw: hfThrew,
      errorMsg: hfErrMsg,
      durationMs,
      avgMsPerFrame: durationMs / 10000,
      totalEllipses: hfCtx.ellipses.length
    };

    // Safe Haven Zone Audit
    const dummyCreator = (cfg) => ({ ...cfg });
    const hideoutMobs = populateZonePacks('zone_player_hideout', dummyCreator);
    const sanctuaryMobs = populateZonePacks('zone_boundless_sanctuary', dummyCreator);
    const wildernessMobs = populateZonePacks('zone_tang_kiem_nhai', dummyCreator);
    results.safeHavenAudit = {
      hideoutMobCount: hideoutMobs.length,
      sanctuaryMobCount: sanctuaryMobs.length,
      wildernessMobCount: wildernessMobs.length,
      wildernessHasLeader: wildernessMobs.some(m => m.isPackLeader && m.leaderAura)
    };

    console.log(JSON.stringify(results, null, 2));
    r   Nc                 ó\  — ddd| j         g}t          j        |t          t          ¦  «        dd¬¦  «        }|j        dk    sJ d|j        › �¦   «         ‚t          j        |j	        ¦  «        }|d          
                    ¦   «         D ]\  }}|du sJ d	|› d
�¦   «         ‚Œt          |d         ¦  «        dk    sJ ‚|d         D ]¢}|d         }|d         rJ d|› d|d         › �¦   «         ‚|d         sJ d|› d�¦   «         ‚|d         dk    sJ d|› d|d         › �¦   «         ‚|d         sJ d|› d�¦   «         ‚|d         sJ d|› d�¦   «         ‚|d         sJ d|› d�¦   «         ‚Œ£|d         D ]j}|d         }	|d         rJ d|	› d|d         › �¦   «         ‚|d         sJ d|	› d �¦   «         ‚|d!         sJ d|	› d"�¦   «         ‚|d         sJ d|	› d#�¦   «         ‚Œk|d$         }
|
d         rJ d%|
d         › �¦   «         ‚|
d&         d'k    sJ d(|
d&         › �¦   «         ‚|
d)         d*k     sJ d+|
d)         d,›d-�¦   «         ‚|d.         }|d/         dk    sJ d0|d/         › d1�¦   «         ‚|d2         dk    sJ d3|d2         › d1�¦   «         ‚|d4         dk    s
J d5¦   «         ‚|d6         du s
J d7¦   «         ‚d S )8NÚnodez--input-type=modulez-eT)ÚcwdÚcapture_outputÚtextr   z#Node.js script failed with stderr: ÚglobalsDefinedzGlobal window.z was not defined!Ú
auraStressé   ÚauraÚthrewzAura z threw: ÚerrorMsgÚsaveBalancedz save/restore unbalanced!ÚellipseCounté   z expected 2 ellipses, got ÚcolorMatchesz color mismatch!ÚallRadiiPositivez non-positive radius detected!ÚyOffsetAppliedz% y-offset (+4) not applied correctly!ÚadversarialEdgeCasesÚnamez
Edge case z save/restore state unbalanced!ÚrenderedMatchesExpectationz render expectation mismatch!z fallback color mismatch!ÚhighFreqStressz10k stress threw: ÚtotalEllipsesi N  zExpected 20,000 ellipses, got ÚavgMsPerFramegš™™™™™©?zRender decal too slow: z.4fzms/frameÚsafeHavenAuditÚhideoutMobCountzSafe Haven hideout spawned z mobs!ÚsanctuaryMobCountzSafe Haven sanctuary spawned ÚwildernessMobCountzWilderness zone spawned 0 mobs!ÚwildernessHasLeaderz3Wilderness zone missing rare pack leader with aura!)ÚNODE_TEST_SCRIPTÚ
subprocessÚrunÚstrÚPROJECT_ROOTÚ
returncodeÚstderrÚjsonÚloadsÚstdoutÚitemsr   )r   ÚcmdÚresr   r]   Úis_defÚaura_resÚ	aura_nameÚec_resÚec_nameÚhfÚshs               r   Ú#test_run_node_simulation_and_verifyzJTestNodeJsSimulationAndAuraDecalStress.test_run_node_simulation_and_verifyå   sü  € ØÐ,¨d°DÔ4IÐJˆÝŒn˜S¥c­,Ñ&7Ô&7ÈÐSWÐXÑXÔXˆØŒ~ Ò"Ð"Ð"Ð$VÈ#Ì*Ð$VÐ$VÑ"Ô"Ð"åŒz˜#œ*Ñ%Ô%ˆð !Ð!1Ô2×8Ò8Ñ:Ô:ð 	Lð 	L‰LˆD�&Ø˜T�>�>�>Ð#K°DÐ#KÐ#KÐ#K‘>”>�>�>õ �4˜Ô%Ñ&Ô&¨!Ò+Ð+Ð+Ð+Ø˜\Ô*ð 	hð 	hˆHØ  Ô(ˆIØ Ô(Ð[Ð[Ð*[°)Ð*[Ð*[ÀXÈjÔEYÐ*[Ð*[Ñ[Ô[Ð(Ø˜NÔ+ÐYÐYÐ-Y°YÐ-YÐ-YÐ-YÑYÔYÐ+Ø˜NÔ+¨qÒ0Ð0Ð0Ð2y¸)Ð2yÐ2yÐ_gÐhvÔ_wÐ2yÐ2yÑ0Ô0Ð0Ø˜NÔ+ÐPÐPÐ-P°YÐ-PÐ-PÐ-PÑPÔPÐ+ØÐ.Ô/ÐbÐbÐ1b¸Ð1bÐ1bÐ1bÑbÔbÐ/ØÐ,Ô-ÐgÐgÐ/g°yÐ/gÐ/gÐ/gÑgÔgÐ-Ðgð Ð1Ô2ð 	[ð 	[ˆFØ˜V”nˆGØ˜g”ÐZÐZÐ(Z°WÐ(ZÐ(ZÀfÈZÔFXÐ(ZÐ(ZÑZÔZÐ&Ø˜.Ô)Ð`Ð`Ð+`¸Ð+`Ð+`Ð+`Ñ`Ô`Ð)ØÐ6Ô7ÐlÐlÐ9lÀgÐ9lÐ9lÐ9lÑlÔlÐ7Ø˜.Ô)ÐZÐZÐ+Z¸Ð+ZÐ+ZÐ+ZÑZÔZÐ)ÐZð Ð"Ô#ˆØ�g”;ÐEÐEÐ E°R¸
´^Ð EÐ EÑEÔEˆØ�/Ô" eÒ+Ð+Ð+Ð-cÈbÐQ`ÔNaÐ-cÐ-cÑ+Ô+Ð+Ø�/Ô" TÒ)Ð)Ð)Ð+fÀRÈÔEXÐ+fÐ+fÐ+fÐ+fÑ)Ô)Ð)ð Ð"Ô#ˆØÐ#Ô$¨Ò)Ð)Ð)Ð+fÈÐL]ÔI^Ð+fÐ+fÐ+fÑ)Ô)Ð)ØÐ%Ô&¨!Ò+Ð+Ð+Ð-lÈRÐPcÔMdÐ-lÐ-lÐ-lÑ+Ô+Ð+ØÐ&Ô'¨!Ò+Ð+Ð+Ð-NÑ+Ô+Ð+ØÐ'Ô(¨DÐ0Ð0Ð0Ð2gÑ0Ô0Ð0Ð0Ð0r   rC   )rD   rE   rF   rG   rg   r{   rH   r   r   rJ   rJ   L   s>   € € € € € ØNÐNðTÐðl)hð )hð )hð )hð )hð )hr   rJ   c                   ó   — e Zd ZdZdd„ZdS )ÚTestEntityRendererDecalCallSitezWVerifies entity_renderer.js has valid call site and layering for renderLeaderAuraDecal.r   Nc                 óÎ  — t           dz  }|                     ¦   «         sJ ‚|                     d¬¦  «        }d|v s
J d¦   «         ‚d|v s
J d¦   «         ‚|                     d¦  «        }|                     d¦  «        }|                     d	¦  «        }|d
k    s
J d¦   «         ‚|d
k    s
J d¦   «         ‚|d
k    s
J d¦   «         ‚||cxk     r|k     sn J d|› d|› d|› d�¦   «         ‚d S )Nzentity_renderer.jsr   r   zwindow.renderLeaderAuraDecalz=Missing renderLeaderAuraDecal call site in entity_renderer.jszm.isPackLeaderz0Missing isPackLeader guard in entity_renderer.jszctx.ellipse(mPos.x, mPos.y + 4zAnimationEngine.drawEntityFrameéÿÿÿÿz6Monster shadow ellipse not found in entity_renderer.jsz6Leader aura decal call not found in entity_renderer.jsz?AnimationEngine.drawEntityFrame not found in entity_renderer.jsz*Invalid visual layering! Expected shadow (z) < decal (z) < sprite (ú))Ú
ENGINE_DIRr   r   r0   )r   Úrenderer_pathÚcontentÚ
shadow_idxÚ	decal_idxÚ
sprite_idxs         r   Ú test_callsite_in_entity_rendererz@TestEntityRendererDecalCallSite.test_callsite_in_entity_renderer  s@  € Ý"Ð%9Ñ9ˆØ×#Ò#Ñ%Ô%Ð%Ð%Ð%Ø×)Ò)°7Ð)Ñ;Ô;ˆà-°Ð8Ð8Ð8Ð:yÑ8Ô8Ð8Ø 7Ð*Ð*Ð*Ð,^Ñ*Ô*Ð*à—\’\Ð"BÑCÔCˆ
Ø—L’LÐ!?Ñ@Ô@ˆ	Ø—\’\Ð"CÑDÔDˆ
à˜RÒÐÐÐ!YÑÔÐØ˜BŠˆˆÐ X‰ŒˆØ˜RÒÐÐÐ!bÑÔÐØ˜IÐ2Ð2Ò2Ð2¨
Ò2Ð2Ð2Ð2Ð2Øt¸ÐtÐtÐPYÐtÐtÐgqÐtÐtÐtñ 3Ô2Ð2Ð2Ð2r   rC   )rD   rE   rF   rG   r‡   rH   r   r   r}   r}     s.   € € € € € ØaÐað
ð 
ð 
ð 
ð 
ð 
r   r}   )rG   rn   Úosrh   Úpathlibr   ÚpytestÚbs4r   Ú__file__ÚresolveÚparentrk   Ú
WEBAPP_DIRr   ÚDATA_DIRr�   r   rJ   r}   rH   r   r   ú<module>r‘      sQ  ððð ð €€€Ø 	€	€	€	Ø Ð Ð Ð Ø Ð Ð Ð Ð Ð Ø €€€Ø Ð Ð Ð Ð Ð àˆt�H‰~Œ~×%Ò%Ñ'Ô'Ô.Ô5Ô<€Ø˜HÑ$ xÑ/€
Ø˜,Ñ&€
Ø˜Ñ˜vÑ%€Ø˜$Ñ Ñ)€
ð,Pð ,Pð ,Pð ,Pð ,Pñ ,Pô ,Pð ,Pð^Bhð Bhð Bhð Bhð Bhñ Bhô Bhð BhðJ
ð 
ð 
ð 
ð 
ñ 
ô 
ð 
ð 
ð 
r   