Respan Dataset Explorer

Select one behavior. Every returned turn has one binary label: Present or Absent. Source: final dense boolean release.

5,167,182physical rows
86shards
0.00%qualified row coverage
0.00%qualified cell coverage
Random row JSON API

turns-00031.parquet:40456

4c4d94764782bd355ad60874
turn 1/2gpt-4o-2024-08-06PersianAustralia336 words
degenerate_repetitionAbsentFinal dense release
USER
چگونه با استفاده از برنامه opl game utility اندروید برای ps2 فلش خور یه اسم بازی جدید به فایل ul.cfg اضافه کنم
                            
                            
ASSISTANT
برای اضافه کردن نام یک بازی جدید به فایل `ul.cfg` با استفاده از برنامه OPL Game Utility در دستگاه اندروید برای پلی‌استیشن ۲، مراحل زیر را دنبال کنید:

1. **نصب OPL Game Utility**: ابتدا برنامه OPL Game Utility را بر روی دستگاه اندرویدی خود نصب کنید. این برنامه ابزارهای متنوعی برای مدیریت بازی‌های پلی‌استیشن ۲ ارائه می‌دهد.

2. **اتصال فلش به دستگاه اندروید**: فلش مموری که بازی‌های پلی‌استیشن ۲ روی آن قرار دارند را با استفاده از یک OTG (On-The-Go) به دستگاه اندرویدی خود متصل کنید.

3. **باز کردن فایل `ul.cfg`**: بعد از اینکه فلش مموری متصل شد، به محلی که بازی‌ها ذخیره شده‌اند بروید و فایل `ul.cfg` را پیدا کنید. این فایل معمولاً در پوشه‌ای که بازی‌ها قرار دارند موجود است.

4. **ویرایش فایل `ul.cfg`**:
   - از برنامه ویرایشگر متنی موجود در دستگاه اندروید خود استفاده کنید. می‌توانید از اپلیکیشن‌هایی مانند Notepad++ یا سایر ویرایشگرهای متنی استفاده کنید.
   - فایل `ul.cfg` را باز کنید. این فایل شامل فهرستی از بازی‌های موجود به همراه شناسه و نام آن‌ها است.

5. **اضافه کردن اطلاعات بازی جدید**:
   - برای اضافه کردن بازی جدید، یک خط جدید به انتهای فایل اضافه کنید.
   - ساختار هر خط به شکل زیر است: `UL.[شناسه‌بازی].[توضیحات‌بازی]`
   - برای مثال: `UL.SLUS_203.12.Grand Theft Auto: San Andreas`
   - شناسه بازی را می‌توانید از ISO یا فایل بازی بدست آورید و توضیحات بازی همان نام بازی است که می‌خواهید نمایش داده شود.

6. **ذخیره تغییرات**: بعد از اضافه کردن اطلاعات بازی جدید، فایل `ul.cfg` را ذخیره کنید.

7. **قطع اتصال و تست**: فلش مموری را امن از دستگاه اندرویدی خود خارج کرده و آن را به دستگاه PS2 وصل کنید و بررسی کنید که آیا بازی جدید در فهرست بازی‌ها نمایش داده می‌شود یا نه.

توجه داشته باشید که برای اجرای صحیح بازی‌ها، باید از OPL (Open PS2 Loader) جهت لود کردن بازی‌ها استفاده کنید و مطمئن شوید که تنظیمات OPL به درستی انجام شده است.

turns-00031.parquet:40457

fddc7ceadcd803bd1b61d1ec
turn 2/2gpt-4o-2024-08-06PersianAustralia387 words
degenerate_repetitionAbsentFinal dense release
USER
بهتر توضیح بده
                            
                            
ASSISTANT
البته، بیایید به مراحل اضافه کردن یک بازی جدید به فایل `ul.cfg` با استفاده از OPL Game Utility برای PS2 به‌طور دقیق‌تر بپردازیم:

### پیش‌نیازها:
1. **نصب OPL Game Utility**: این برنامه را از فروشگاه اپلیکیشن اندروید دریافت و نصب کنید.
2. **یک فلش مموری آماده**: اطمینان حاصل کنید که فلش مموری شما دارای قابلیت خواندن و نوشتن است و بازی‌های PS2 روی آن قرار دارند.

### مراحل کار:

1. **اتصال فلش مموری به دستگاه اندروید**:
   - فلش مموری را با استفاده از کابل OTG به گوشی یا تبلت اندرویدی خود متصل کنید.
   - مطمئن شوید که دستگاه، فلش شما را شناسایی کرده است.

2. **پیدا کردن فایل `ul.cfg`**:
   - به اپلیکیشن مدیریت فایل (مثل ES File Explorer یا My Files) بروید.
   - فلش مموری خود را از قسمت "Storage" یا "USB Storage" پیدا کنید.
   - پوشه‌ای که بازی‌های PS2 ذخیره شده‌اند را باز کنید. فایل `ul.cfg` معمولاً در همان پوشه قرار دارد.

3. **ویرایش فایل `ul.cfg`**:
   - از یک ویرایشگر متن (مثل Jota Text Editor یا Notepad++) استفاده کنید.
   - فایل `ul.cfg` را در ویرایشگر متن باز کنید. این فایل شامل لیستی از بازی‌های موجود است.

4. **اضافه کردن نام بازی جدید**:
   - برای اضافه کردن یک بازی جدید، یک خط جدید به انتهای فایل اضافه کنید.
   - ساختار خط به این شکل است: `UL.[شناسه‌بازی].[نام‌بازی]`
     - **شناسه‌بازی**: این شناسه را می‌توانید از فایل ISO بازی پیدا کنید (معمولاً به صورت `SLUS_123.45`).
     - **نام‌بازی**: نامی که می‌خواهید برای بازی نمایش داده شود.
   - به طور مثال، اگر شناسه بازی شما `SLUS_123.45` و نام بازی `God of War` باشد، خط شما به صورت زیر خواهد بود:
     ```
     UL.SLUS_123.45.God of War
     ```

5. **ذخیره فایل**:
   - پس از اضافه کردن بازی به فایل `ul.cfg`، تغییرات را ذخیره کنید.

6. **قطع اتصال و تست در PS2**:
   - فلش مموری را به‌صورت ایمن از دستگاه اندروید جدا کنید.
   - آن را به PS2 خود متصل کرده و کنسول را روشن کنید.
   - OPL را باز کنید و بررسی کنید که آیا بازی جدید در لیست بازی‌ها نمایش داده می‌شود یا نه.

با انجام این مراحل، باید بتوانید بازی جدید خود را به فهرست بازی‌های موجود در PS2 اضافه کنید و از آن لذت ببرید. اگر مشکلی در هر یک از مراحل داشتید، می‌توانید مجدداً مراحل را بررسی کنید یا برای راهنمایی بیشتر با جامعه کاربری OPL مشورت کنید.

turns-00031.parquet:40458

c1ddfd75780d692bc9297752
turn 1/1gpt-4o-2024-08-06FrenchAustralia11 words
degenerate_repetitionAbsentFinal dense release
USER
Assistant: 
User: привет
Assistant:
ASSISTANT
Привет! Как я могу помочь вам сегодня?

turns-00031.parquet:40459

ef490bbe4dddb7f3a4ab3cd8
turn 1/1gpt-4o-2024-08-06EnglishUnited States805 words
degenerate_repetitionAbsentFinal dense release
USER
Assistant: 
User: [Give me only the actual fundamental news. Please provide it concisely in list format for an English learner. I prefer exact dates of future events instead of "soon" or "upcoming." If there is any big news worth mentioning, tell me. Finally, tell me what $YFI means. Do not tell me about price technical analysis.]
2d: Bought more $EEFI yesterday -- price looks great! I’ve been DCA'ing for months, hoping the next few months turn bullish. This will be the most deflationary token! Could repeat $YFI, so I’m aiming for 5 digits ($10,000+). . . 🫰Fingers crossed! LFG! 🚀💰. . #EEFI #AMPL #SPOT #YFI https://t.co/KQ2MEcdo8e
1w: $YFI making a move. . Seems like it's worth a gamble. . longed smol with intention to add if trend doesnt fall apart here https://t.co/IBuaZx85gJ
2d: There is no known vulnerability outside of every part of how the token and ecosystem operate. Plz be patient as we call the cops about this.
3h: TOP 10 COINS BY LUNARCRUSH GALAXY SCORE. . $TAO $SKY $SOL $WLD $ETH $UNCX $XMR $BNB $YFI $BIFI https://t.co/I2TY2XLq5B
1d: Remember when $YFI one of Cronjes projects went from $0 to $90,000+ ??. . The OGs remember.... . $FTM -> $S https://t.co/EPfaLO1fRH
4d: @0xSisyphus Once everyone is done with the meme coins fad, they'll go back to buying blue chip coins again, such as Lido, YFI, UNI, SUSHI and other DeFi tokens
1h: @J4GODA_ Ale czy Yfi Ye ( czy tam chuj wie jak go się pisze ) rozpłakał się po zajęciu nic nie znaczącej pozycji w swoim domowym GP wyprzedzając jedno auto? https://t.co/n5IUJn1N6Z
2d: There’s one chart on Solana that is replicating $YFI movements from defi summer 2020.. . Been saying for a while that SOL has a massive opportunity that the market is underlooking. Multiple sectors rallying is bullish.. . Bet more and lock in
1d: @8BitSam_ @0xSonicLabs Bought my first $YFI at 60$ , god bless @AndreCronjeTech
7h: will take the other side of this and say memes are among the most fun ive had onchain including icos on ether delta, cryptokitties mania, farming yfi, early artblocks etc etc. . its a fantastic mix of internet culture and speculation https://t.co/Et9MBrfa4C
1w: #YFI I need someone here to tell me I’m not crazy. https://t.co/CmPQ74FIvX
2d: Let's review past blue chip token performances during crypto bull runs and compare to @RetardedAPR . . NEO (NEO): 12 Billion during 2017 cycle. Uniswap (UNI): 22 Billion during 2021 cycle. Olympus (OHM): 4 Billion during 2021 cycle. Yearn Finance (YFI): 3 Billion during 2021 cycle https://t.co/qrXZjfgkLs
6d: QT.... shout out to a dope collector who deserves more credit . . @fan_yfi https://t.co/p0AZgznj1I
18h: @reiwarokumonsen 高額転売カード いらない❗
3d: $BAL $CRV $REN $SNX $YFI $SUSHI $UNI #YIELDFARMING fanatics, harvest high returns with TitanX's innovative staking and ETH rewards.
9h: Otto Rauhala sai viikonloppuna täyteen 500 pelattua liigaottelua! 🔥. . Pelaajayhdistys onnittelee! 🤝. . #SJRY #Liiga #Tappara https://t.co/6vnfttt56c
4d: I believe if I can buy under 60k, I will invest heavily. Each drop is an opportunity to buy! By mid to late October, I expect to see real growth, but this month will mainly be volatile, and that has started with $BTC and $ETH.
1d: @ChartingGuy I would love to hear your opinion and few on $YFI ?. NOBODY talking about this cicle. Is it dead ?. Best regards
6d: #LUNCcommunity burn 2 trillion #lunc to see if $lunc is broke or bugged. I seen it b4 wit YFI it can be bugged & no one  fixes it. Don't waste ur time. Make it worth ur time, or make sure it's worth ur time. All the burns, community hype, buys, shit still looks like a photo. ❣️
Assistant:
ASSISTANT
Here is a concise list of fundamental news and relevant mentions:

1. **Yearn Finance ($YFI) History**:
   - $YFI, one of Andre Cronje's projects, famously went from $0 to over $90,000.

2. **DeFi Tokens & Blue Chip Coins**:
   - Trends suggest a return to buying prominent DeFi tokens like YFI, UNI, and SUSHI after the meme coin phase.

3. **Yearn Finance ($YFI) in Market Context**:
   - $YFI remains a significant player, featuring among top coins in various speculative and investment contexts.

4. **General Crypto Market Insight**:
   - Market volatility expected in the short term, with anticipated growth mid to late October for coins like BTC and ETH.

5. **Past Performance**:
   - Yearn Finance ($YFI) reached a market cap of 3 billion during the 2021 cycle.

6. **Crypto Community Discussions**:
   - Active discussions and mixed sentiments around the future relevance and potential resurgence of $YFI.

### $YFI Meaning:
- **Yearn Finance ($YFI)**: An influential decentralized finance (DeFi) project focusing on automating yield farming strategies. It became renowned for having no initial token supply or pre-mine, with its value driven by community engagement and decentralized governance.

No major future events requiring specific dates were identified.

turns-00031.parquet:40460

8ff05301eac020b1cff544ea
turn 1/3gpt-4o-2024-08-06PersianAustralia169 words
degenerate_repetitionAbsentFinal dense release
USER
اثر کدام یک بر یک طرف معادله حسابداری است
پیش پرداخت هزینه
ارائه خدمات به صورت نقد
دریافت خدمات از محل پیش پرداخت ها
پرداخت بدهی های ناشی از هزینه های غیر نقدی
                            
                            
ASSISTANT
پیش پرداخت هزینه‌ها، دریافت خدمات از محل پیش‌پرداخت‌ها و پرداخت بدهی‌های ناشی از هزینه‌های غیر نقدی بر یک طرف معادله حسابداری تأثیر می‌گذارند.

۱. پیش‌پرداخت هزینه: این معمولاً یک دارایی را در ترازنامه افزایش می‌دهد، زیرا پیش‌پرداخت‌ها معمولاً به عنوان دارایی ثبت می‌شوند تا زمانی که هزینه واقعاً مصرف شود.

۲. دریافت خدمات از محل پیش‌پرداخت‌ها: این معمولاً موجب کاهش دارایی‌های پیش‌پرداخت می‌شود و همزمان هزینه‌ها را در صورت سود و زیان افزایش می‌دهد.

۳. ارائه خدمات به صورت نقد: این به طور مستقیم بر دارایی‌ها (افزایش موجودی نقدی) و درآمدها (افزایش در صورت سود و زیان) تأثیر می‌گذارد.

۴. پرداخت بدهی‌های ناشی از هزینه‌های غیر نقدی: این معمولاً موجب کاهش بدهی‌ها و دارایی‌های نقدی می‌شود.

بنابراین، هر یک از این موارد می‌تواند اثرات مختلفی بر معادله حسابداری داشته باشد (دارایی‌ها = بدهی‌ها + حقوق مالکانه).

turns-00031.parquet:40461

b51b327f3d610f1c438699f0
turn 2/3gpt-4o-2024-08-06PersianAustralia231 words
degenerate_repetitionAbsentFinal dense release
USER
پاسخ سوالات


‫اصل دفترچه سواالت استخدامی رشته حسابداری‬
‫بانک تجارت ‪1386‬‬
‫(تایپ شده)‬

‫سرویس خصوصی خدمات عام المنفعه اخبار شغل و استخدام‬

‫‪Www.IranEstekhdam.Ir‬‬

‫خواننده گرامی؛ در جهت بهبود کیفیت این فایل؛ لطفاً هرگونه انتقاد و پیشنهاد خود در مورد مطالب آن‬
‫و یا گزارش مشکل را به آدرس ایمیل و یا با شماره تلفن زیر مطرح نمایید‪:‬‬
‫شماره تلفن تماس‪021-91300013 :‬‬

‫آدرس ایمیل‪soal@iranestekhdam.ir :‬‬

 ‫«توجه مهم»‬
‫جهت تهیه بسته کامل اصل دفترچه سواالت استخدامی بانک تجارت (سالهای اخیر)‬

‫به همراه پاسخ تشریحی اینجا کلیک نمایید‪.‬‬

 ‫«توجه مهم»‬
‫جهت تهیه بسته کامل اصل دفترچه سواالت استخدامی بانک تجارت (سالهای اخیر)‬

‫به همراه پاسخ تشریحی اینجا کلیک نمایید‪.‬‬

 ‫سرویس خصوصی خدمات عام المنفعه اخبار شغل و استخدام‬

‫‪Www.IranEstekhdam.Ir‬‬

‫خواننده گرامی؛ در جهت بهبود کیفیت این فایل؛ لطفاً هرگونه انتقاد و پیشنهاد خود در مورد مطالب آن‬
‫و یا گزارش مشکل را به آدرس ایمیل و یا با شماره تلفن زیر مطرح نمایید‪:‬‬
‫شماره تلفن تماس‪021-91300113 :‬‬

‫آدرس ایمیل‪soal@iranestekhdam.ir :‬‬
                            
                            
ASSISTANT
متأسفانه من به سؤالات و پاسخ‌های دفترچه سؤالات استخدامی بانک تجارت سال 1386 یا هر منبعی که به صورت آنلاین برای دانلود باشد، دسترسی ندارم. پیشنهاد می‌کنم برای تهیه سؤالات و پاسخ‌های مورد نظرتان، به وبسایت‌های معتبر و یا مراجع رسمی مانند وبسایت خود بانک تجارت یا مراکز آموزشی مرتبط مراجعه کنید. همچنین می‌توانید از طریق شماره تماس یا ایمیل ارائه شده در متن، با سایت مربوطه تماس بگیرید و اطلاعات بیشتری دریافت کنید.

turns-00031.parquet:40462

5fb1b86cffe0b97b216d611e
turn 3/3gpt-4o-2024-08-06PersianAustralia103 words
degenerate_repetitionAbsentFinal dense release
USER
تبدیل به متن
                            
                            
ASSISTANT
به نظر می‌رسد شما قبلاً متن دفترچه سؤالات استخدامی را در اختیار دارید و قصد تبدیل آن به یک فرمت خاص یا استخراج اطلاعات دارید. اگر نیازمند تبدیل اسناد متنی به قالب دیگری هستید، می‌توانید از نرم‌افزارهای تبدیل اسناد مانند Microsoft Word یا ابزارهای آنلاین برای فرمت‌دهی و تبدیل استفاده کنید.

مطمئن شوید که برای هر گونه استفاده از این متون، حقوق و مقررات مربوط به کپی‌رایت را رعایت کرده و به اعلامیه‌ها و درخواست‌های مراکز مربوطه توجه کنید. اگر سوال خاصی در زمینه حسابداری دارید یا به مشاوره در زمینه آزمون استخدامی نیاز دارید، خوشحال می‌شوم که کمک کنم.

turns-00031.parquet:40463

53edc21f9c10fa93a1a0ad05
turn 1/1o1-preview-2024-09-12EnglishAlgeria872 words
degenerate_repetitionAbsentFinal dense release
USER
Create a Business Central extension using AL language which handles sending REST API requests 
- Support for Bearer and OAuth authentications, all authentication is stored in a seperate table and referenced by the API configuration
- Support for mapping the response to any table using a reference to Mapping table which holds all information to map the JSON response to the specified table 
Use the ID range starting from 9030 and higher. Each file must start with the prefix XTV, match the object name, and be placed in its respective folder type (Page, Page Ext, Codeunits). Only provide the file names followed by their source code, with no additional comments.
ASSISTANT
**File: XTVAuthentication.al**

```al
table 9030 "XTV Authentication"
{
    Caption = 'XTV Authentication';
    DataClassification = CustomerContent;

    fields
    {
        field(1; ID; Integer)
        {
            Caption = 'ID';
            DataClassification = CustomerContent;
        }
        field(2; Name; Text[100])
        {
            Caption = 'Name';
            DataClassification = CustomerContent;
        }
        field(3; "Authentication Type"; Enum "XTV Authentication Type")
        {
            Caption = 'Authentication Type';
            DataClassification = CustomerContent;
        }
        field(4; "Bearer Token"; Text[250])
        {
            Caption = 'Bearer Token';
            DataClassification = SensitiveData;
        }
        field(5; "OAuth Client ID"; Text[100])
        {
            Caption = 'OAuth Client ID';
            DataClassification = SensitiveData;
        }
        field(6; "OAuth Client Secret"; Text[100])
        {
            Caption = 'OAuth Client Secret';
            DataClassification = SensitiveData;
        }
        field(7; "OAuth Token Endpoint"; Text[250])
        {
            Caption = 'OAuth Token Endpoint';
            DataClassification = CustomerContent;
        }
        field(8; "OAuth Scope"; Text[250])
        {
            Caption = 'OAuth Scope';
            DataClassification = CustomerContent;
        }
    }

    keys
    {
        key(PK; ID)
        {
            Clustered = true;
        }
    }
}
```

**File: XTVAPIConfiguration.al**

```al
table 9031 "XTV API Configuration"
{
    Caption = 'XTV API Configuration';
    DataClassification = CustomerContent;

    fields
    {
        field(1; ID; Integer)
        {
            Caption = 'ID';
            DataClassification = CustomerContent;
        }
        field(2; Name; Text[100])
        {
            Caption = 'Name';
            DataClassification = CustomerContent;
        }
        field(3; "Base URL"; Text[250])
        {
            Caption = 'Base URL';
            DataClassification = CustomerContent;
        }
        field(4; Endpoint; Text[250])
        {
            Caption = 'Endpoint';
            DataClassification = CustomerContent;
        }
        field(5; "HTTP Method"; Enum "XTV HTTP Method")
        {
            Caption = 'HTTP Method';
            DataClassification = CustomerContent;
        }
        field(6; "Authentication Reference"; Integer)
        {
            Caption = 'Authentication Reference';
            TableRelation = "XTV Authentication";
            DataClassification = CustomerContent;
        }
        field(7; "Mapping Reference"; Integer)
        {
            Caption = 'Mapping Reference';
            TableRelation = "XTV Mapping";
            DataClassification = CustomerContent;
        }
    }

    keys
    {
        key(PK; ID)
        {
            Clustered = true;
        }
    }
}
```

**File: XTVMapping.al**

```al
table 9032 "XTV Mapping"
{
    Caption = 'XTV Mapping';
    DataClassification = CustomerContent;

    fields
    {
        field(1; ID; Integer)
        {
            Caption = 'ID';
            DataClassification = CustomerContent;
        }
        field(2; Name; Text[100])
        {
            Caption = 'Name';
            DataClassification = CustomerContent;
        }
        field(3; "Target Table ID"; Integer)
        {
            Caption = 'Target Table ID';
            DataClassification = CustomerContent;
        }
    }

    keys
    {
        key(PK; ID)
        {
            Clustered = true;
        }
    }
}
```

**File: XTVMappingLine.al**

```al
table 9033 "XTV Mapping Line"
{
    Caption = 'XTV Mapping Line';
    DataClassification = CustomerContent;

    fields
    {
        field(1; "Mapping ID"; Integer)
        {
            Caption = 'Mapping ID';
            TableRelation = "XTV Mapping";
            DataClassification = CustomerContent;
        }
        field(2; "Field No."; Integer)
        {
            Caption = 'Field No.';
            DataClassification = CustomerContent;
        }
        field(3; "JSON Path"; Text[250])
        {
            Caption = 'JSON Path';
            DataClassification = CustomerContent;
        }
    }

    keys
    {
        key(PK; "Mapping ID", "Field No.")
        {
            Clustered = true;
        }
    }
}
```

**File: XTVRestAPIHandler.al**

```al
codeunit 9034 "XTV Rest API Handler"
{
    Caption = 'XTV Rest API Handler';

    trigger OnRun()
    begin
        // Entry point if needed
    end;

    procedure SendRequest(APIConfigID: Integer)
    var
        APIConfig: Record "XTV API Configuration";
        AuthConfig: Record "XTV Authentication";
        Client: HttpClient;
        Response: HttpResponseMessage;
        OAuthResponse: HttpResponseMessage;
        OAuthContent: HttpContent;
        OAuthJsonObject: JsonObject;
        OAuthToken: Text;
        JsonText: Text;
        JsonObject: JsonObject;
        Mapping: Record "XTV Mapping";
        MappingLine: Record "XTV Mapping Line";
        TargetRecRef: RecordRef;
        TargetFieldRef: FieldRef;
        FieldNo: Integer;
        JSONPathValue: Text;
    begin
        APIConfig.Get(APIConfigID);
        AuthConfig.Get(APIConfig."Authentication Reference");

        Client.DefaultRequestHeaders.Clear();

        case AuthConfig."Authentication Type" of
            AuthConfig."Authentication Type"::Bearer:
                begin
                    Client.DefaultRequestHeaders.Authorization := 'Bearer ' + AuthConfig."Bearer Token";
                end;
            AuthConfig."Authentication Type"::OAuth:
                begin
                    OAuthContent.WriteFrom('grant_type=client_credentials&client_id=' + Uri.EscapeDataString(AuthConfig."OAuth Client ID") +
                                           '&client_secret=' + Uri.EscapeDataString(AuthConfig."OAuth Client Secret") +
                                           '&scope=' + Uri.EscapeDataString(AuthConfig."OAuth Scope"));
                    OAuthContent.GetHeaders('Content-Type').Clear();
                    OAuthContent.GetHeaders('Content-Type').Add('application/x-www-form-urlencoded');

                    Client.Post(AuthConfig."OAuth Token Endpoint", OAuthContent, OAuthResponse);
                    if OAuthResponse.IsSuccessStatusCode() then begin
                        OAuthResponse.Content().ReadAs(JsonText);
                        OAuthJsonObject.ReadFrom(JsonText);
                        OAuthToken := OAuthJsonObject.GetValue('access_token').AsValue().AsText();
                        Client.DefaultRequestHeaders.Authorization := 'Bearer ' + OAuthToken;
                    end else
                        Error('Failed to retrieve OAuth token. Status Code: %1', OAuthResponse.HttpStatusCode());
                end;
        end;

        case APIConfig."HTTP Method" of
            APIConfig."HTTP Method"::GET:
                begin
                    Client.Get(APIConfig."Base URL" + APIConfig.Endpoint, Response);
                end;
            APIConfig."HTTP Method"::POST:
                begin
                    // Implement POST logic here
                end;
            APIConfig."HTTP Method"::PUT:
                begin
                    // Implement PUT logic here
                end;
            APIConfig."HTTP Method"::DELETE:
                begin
                    // Implement DELETE logic here
                end;
        end;

        if Response.IsSuccessStatusCode() then begin
            Response.Content().ReadAs(JsonText);
            JsonObject.ReadFrom(JsonText);

            Mapping.Get(APIConfig."Mapping Reference");
            MappingLine.SetRange("Mapping ID", Mapping.ID);

            if TargetRecRef.Open(Mapping."Target Table ID") then begin
                if MappingLine.FindSet() then
                    repeat
                        FieldNo := MappingLine."Field No.";
                        if TargetRecRef.FieldExists(FieldNo) then begin
                            TargetFieldRef := TargetRecRef.Field(FieldNo);
                            JSONPathValue := GetJSONValue(JsonObject, MappingLine."JSON Path");
                            TargetFieldRef.Value := JSONPathValue;
                        end;
                    until MappingLine.Next() = 0;
                TargetRecRef.Insert();
            end;
        end else
            Error('Failed to get a successful response. Status Code: %1', Response.HttpStatusCode());
    end;

    local procedure GetJSONValue(JsonObject: JsonObject; JSONPath: Text) Result: Text
    var
        JsonToken: JsonToken;
    begin
        if JsonObject.SelectToken(JSONPath, JsonToken) then
            Result := JsonToken.ToValue().AsText()
        else
            Result := '';
    end;
}
```

**File: XTV Authentication Type.al**

```al
enum 9035 "XTV Authentication Type"
{
    Caption = 'XTV Authentication Type';

    value(0; Bearer)
    {
        Caption = 'Bearer';
    }
    value(1; OAuth)
    {
        Caption = 'OAuth';
    }
}
```

**File: XTV HTTP Method.al**

```al
enum 9036 "XTV HTTP Method"
{
    Caption = 'XTV HTTP Method';

    value(0; GET)
    {
        Caption = 'GET';
    }
    value(1; POST)
    {
        Caption = 'POST';
    }
    value(2; PUT)
    {
        Caption = 'PUT';
    }
    value(3; DELETE)
    {
        Caption = 'DELETE';
    }
}
```

turns-00031.parquet:40464

c715cd07702639620b2174d8
turn 1/1o1-preview-2024-09-12EnglishIndonesia8764 words
degenerate_repetitionAbsentFinal dense release
USER
dari script berikut ini tambahkan fitur heat level dan ini bisa di bool pada bagian atas script , yg dimana square jika collision nya terjadi terlalu cepat maka glow intensity nya akan bertambah, jadi ini di hitung dari jarak jarak collision, dan pertambahan intensity harus lah smooth, jadi jika collision yg terjadi hanya lumayan maka glow nya bertambah lumayan juga, jika sangat cepat maka glow intensity nya juga signifikan, buatkan agar level heat nya ini smooth dan memanfaatkan level level dari jarak collision yg terjadi, buatkan dengan benar dan tepat tanpa mempengaruhi fitur fitur yg sudah ada, sesuaikan dengan fitur yg sudah ada, buatkan dengan tepat dan lengkap : import pygame
import mido
import sys
import random
import requests
import colorsys
import os
import math
import cv2
import numpy as np
from os.path import join, isfile
from time import time as get_current_time
from typing import Union, Optional, Any
from enum import Enum
from math import sin, pi

pygame.mixer.init()
pygame.init()
FRAMERATE = 60

# =========================
# Customizable Configuration
# =========================

# Midi Selection
SONG = "rush-e.mid"

# Screen Resolution
SCREEN_WIDTH = 1280
SCREEN_HEIGHT = 720

# Other Customizable Settings
SQUARE_SPEED = 600
SQUARE_SIZE = 40
BOUNCE_MIN_SPACING = 50
DIRECTION_CHANGE = 30
EMPTY_SQUARE = True

# Particle Settings
PARTICLE_BOUNCE = False
PARTICLE_TRAIL = False
TRAIL_COLOR_BASED_ON_SQUARE = False
PARTICLE_SPEED = 5

# Peg Settings
BOUNCE_PEG = True
PEG_COLOR = (255, 255, 255)
PEG_REMOVE = True
PEG_MULTI_COLOR = False
NO_COLOR = False

# Glow Settings
SQUARE_GLOW = True
PEG_GLOW = True
GLOW_RANDOM_COLOR = False

# Star Settings
STAR = True
STAR_COLOR = (255, 255, 255)
STAR_DENSITY = 0.0001

# =========================
def color_hunt():
    def is_bright(hex_color):
        hex_color = hex_color.lstrip('#')
        rgb = tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))
        luminance = 0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]
        r, g, b = [x / 255.0 for x in rgb]
        h, s, v = colorsys.rgb_to_hsv(r, g, b)
        return luminance >= 130 and s >= 0.3
    while True:
        url = 'https://colorhunt.co/php/feed.php'
        headers = {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
        }
        data = {
            'step': 0,
            'sort': 'random',
            'tags': ''
        }
        response = requests.post(url, headers=headers, data=data)
        if response.status_code == 200:
            palettes = response.json()
            color_pairs = []
            for palette in palettes:
                code = palette['code']
                hex_colors = [f'#{code[i:i+6].upper()}' for i in range(0, len(code), 6)]
                if len(hex_colors) == 4 and all(is_bright(hex_color) for hex_color in hex_colors):
                    color_pairs.append(tuple(hex_colors))
            if color_pairs:
                selected_color_pair = random.choice(color_pairs)
                return selected_color_pair
        else:
            raise Exception(f"Failed to retrieve data. Status code: {response.status_code}")

selected_colors = color_hunt()
color1, color2, color3, color4 = selected_colors

class Config:
    # Constants
    SQUARE_SIZE = SQUARE_SIZE
    PARTICLE_SPEED = PARTICLE_SPEED
    CAMERA_SPEED = 500
    # Colors
    color_themes = {
        "dark": {
            "hallway": pygame.Color('#2D033B'),
            "background": pygame.Color('#070F2B'),
            "square": [
                pygame.Color(color1),
                pygame.Color(color2),
                pygame.Color(color3),
                pygame.Color(color4)
            ],
            "peg": pygame.Color(PEG_COLOR),    # Added peg color
        }
    }

    # Configuration
    script_dir = os.path.dirname(os.path.abspath(__file__))
    assets = os.path.join(script_dir, 'assets/icon.png')
    song = os.path.join(script_dir, 'songs')
    font = os.path.join(script_dir, 'assets/poppins-regular.ttf')
    SCREEN_WIDTH = SCREEN_WIDTH
    SCREEN_HEIGHT = SCREEN_HEIGHT
    theme: Optional[str] = "dark"
    seed: Optional[int] = None
    camera_mode: Optional[int] = 2
    start_playing_delay = 5000
    max_notes: Optional[int] = None
    bounce_min_spacing: Optional[float] = BOUNCE_MIN_SPACING
    square_speed: Optional[int] = SQUARE_SPEED
    volume: Optional[int] = 100
    music_offset: Optional[int] = 0
    direction_change_chance: Optional[int] = DIRECTION_CHANGE
    particle_trail = PARTICLE_TRAIL
    do_color_bounce_pegs = BOUNCE_PEG
    do_particles_on_bounce = PARTICLE_BOUNCE

    # Non-configurable settings
    backtrack_chance: Optional[float] = 0.02
    backtrack_amount: Optional[int] = 40
    square_swipe_anim_speed: Optional[int] = 4
    particle_amount = 20

    # Glow effect settings for square
    square_glow = SQUARE_GLOW
    square_glow_duration = 0.2
    glow_intensity = 15  # Adjusted intensity for better visibility
    square_min_glow = 0   # Lower value for slight glow when no collision

    # Glow effect settings for pegs
    peg_glow = PEG_GLOW
    peg_glow_duration = 0.5
    peg_glow_intensity = 15  # Adjusted intensity for better visibility
    peg_min_glow = 7

    if GLOW_RANDOM_COLOR:
        peg_glow_color = pygame.Color(random.choice(selected_colors))
        square_glow_color = pygame.Color(random.choice(selected_colors))
    else:
        peg_glow_color = pygame.Color(255, 255, 255)
        square_glow_color = pygame.Color(255, 255, 255)

    # Star settings
    star_color = STAR_COLOR
    star_density = STAR_DENSITY

    # Other random stuff
    current_song = None
    dt = 0.01

def get_colors():
    return Config.color_themes.get(Config.theme, Config.color_themes["dark"])

def read_midi_file(file):
    midi_file = mido.MidiFile(file=file)

    notes = []
    current_time = 0

    for msg in midi_file:
        if msg.type == 'note_on' and msg.velocity != 0:
            timestamp = current_time + msg.time
            notes.append(round(timestamp*1000)/1000)
        current_time += msg.time
    return notes

def remove_too_close_values(lst: list[float], threshold=30) -> list[float]:
    """Assumes the list is sorted"""
    new = []
    before = None
    for _ in lst:
        if before is None:
            before = _
            new.append(_)
            continue
        if before+threshold/1000 > _:
            continue
        before = _
        new.append(_)
    return new

def fix_overlap(rects: list[pygame.Rect], callback=None):
    """
    Optimized function to merge overlapping rectangles efficiently.
    """
    if callback is None:
        callback = lambda _: None

    rects = rects.copy()
    # Sort rectangles based on x coordinate
    rects.sort(key=lambda r: (r.x, r.y))

    merged_rects = []
    for rect in rects:
        if not merged_rects:
            merged_rects.append(rect)
        else:
            last = merged_rects[-1]
            if last.colliderect(rect):
                merged_rect = last.union(rect)
                merged_rects[-1] = merged_rect
            else:
                merged_rects.append(rect)

    callback("Finished merging rectangles")

    return merged_rects

def get_font(size: int = 24) -> pygame.font.Font:
    font_path = Config.font
    return pygame.font.Font(font_path, size)

class MapLoadingFailureError(Exception):
    """The map fails to load (recurs function fails)"""
    pass

class UserCancelsLoadingError(Exception):
    """User cancels the loading screen"""
    pass

def interpolate_fn(n):
    """Interpolate sigmoidally from 0-1"""
    n = min(max(n, 0), 1)
    return sin(pi * (n - 0.5)) / 2 + 0.5

class Particle:
    SPEED_VARIATION = 4
    SIZE_MIN = 7
    SIZE_MAX = 14
    AGE_RATE = 20
    SLOW_DOWN_RATE = 1.2

    def __init__(self, pos: list[float], delta: list[float], invert_color: bool = False, color: Optional[tuple] = None):
        self.pos = pos.copy()
        self.size = random.randint(Particle.SIZE_MIN, Particle.SIZE_MAX)
        self.delta = delta.copy()
        self.delta[0] += random.randint(-Particle.SPEED_VARIATION, Particle.SPEED_VARIATION)/8
        self.delta[1] += random.randint(-Particle.SPEED_VARIATION, Particle.SPEED_VARIATION)/8
        if color is not None:
            self.color = color
        else:
            # Default color if color is not given
            self.color = get_colors()["hallway"] if not invert_color else get_colors()["background"]

        # Adjust color to white for particles
        self.color = (255, 255, 255)

    def age(self):
        self.size -= Particle.AGE_RATE*Config.dt
        self.x += self.delta[0] * Config.PARTICLE_SPEED
        self.y += self.delta[1] * Config.PARTICLE_SPEED
        if Config.dt != 0:
            self.delta[0] /= (Particle.SLOW_DOWN_RATE+FRAMERATE) * Config.dt
            self.delta[1] /= (Particle.SLOW_DOWN_RATE+FRAMERATE) * Config.dt
        return self.size <= 0

    @property
    def x(self):
        return self.pos[0]

    @x.setter
    def x(self, val: float):
        self.pos[0] = val

    @property
    def y(self):
        return self.pos[1]

    @y.setter
    def y(self, val: float):
        self.pos[1] = val

    @property
    def rect(self):
        return pygame.Rect(self.x-self.size/2, self.y-self.size/2, *(2*[self.size]))

class Bounce:
    def __init__(self, sq_pos: list[float], sq_dir: list[int], time: float, bounce_dir: int):
        self.square_pos = sq_pos  # New square position
        self.square_dir = sq_dir  # New square direction
        self.bounce_dir = bounce_dir  # Bounce direction for squish effect; 0 or 1
        self.time = time  # Time during bounce

    def get_collision_rect(self):
        sx, sy = self.square_pos
        if self.bounce_dir == 0:
            # Bounce left or right wall
            if self.square_dir[0] == -1:
                # Right wall
                return pygame.Rect(
                    sx+Config.SQUARE_SIZE/2+1,
                    sy-10,
                    10,
                    20
                )
            elif self.square_dir[0] == 1:
                # Left wall
                return pygame.Rect(
                    sx-10-Config.SQUARE_SIZE/2-1,
                    sy-10,
                    10,
                    20
                )
        elif self.bounce_dir == 1:
            # Bounce top or bottom wall
            if self.square_dir[1] == -1:
                # Bottom wall
                return pygame.Rect(
                    sx-10,
                    sy+Config.SQUARE_SIZE/2+1,
                    20,
                    10
                )
            elif self.square_dir[1] == 1:
                # Top wall
                return pygame.Rect(
                    sx-10,
                    sy-10-Config.SQUARE_SIZE/2-1,
                    20,
                    10
                )

    def copy(self) -> "Bounce":
        return Bounce(self.square_pos.copy(), self.square_dir.copy(), self.time, self.bounce_dir)

    def __repr__(self):
        return f"<Bounce(sq_pos={self.square_pos}, sq_dir={self.square_dir}, time={self.time}, dir={self.bounce_dir})"

# Glow effect functions

def create_border(image: np.ndarray, margin: int, thickness: int, color: tuple) -> np.ndarray:
    height, width = image.shape[:2]
    cv2.rectangle(image, (margin, margin), (width - margin, height - margin), color, thickness=thickness)
    return image

def apply_blooming(image: np.ndarray) -> np.ndarray:
    # Provide some blurring to image, to create some bloom.
    cv2.GaussianBlur(image, ksize=(15, 15), sigmaX=20, sigmaY=20, dst=image)
    cv2.blur(image, ksize=(12, 12), dst=image)
    return image

def glowing_border(image: np.ndarray, margin=20, thickness=20, color=(255, 255, 255)):
    """
    Create a glowing border around an image.
    """
    # Generate the colored border.
    image = create_border(image, margin, thickness, color)

    # Apply the bloom effect to the image with the border.
    image = apply_blooming(image)

    # Reassert the original border to enhance the edges.
    image = create_border(image, margin - 1, 1, color)
    image = create_border(image, margin + 1, 1, color)
    return image

def make_glowy2(size, color, intensity=0) -> pygame.Surface:
    image = np.zeros((*size[::-1], 3), dtype=np.uint8)
    border_color_rgb = color  # Assuming color is RGB tuple
    border = glowing_border(image.copy(), color=border_color_rgb, thickness=intensity)
    return pygame.surfarray.make_surface(np.fliplr(np.rot90(border, k=-1)))

class Square:
    glowing_surface_cache = {}
    def __init__(self, x: float = 0, y: float = 0, dx: int = 1, dy: int = 1):
        self.pos: list[float] = [x, y]
        self.dir: list[int] = [dx, dy]
        self.last_bounce_time = -100
        self.latest_bounce_direction = 0  # 0 = horiz, 1 = vert
        self.past_colors = []
        self.died = False
        self.time_since_glow_start = -1000  # For glow effect

    def register_past_color(self, col: tuple[int, int, int]):
        for _ in range(max(Config.square_swipe_anim_speed, 1)):
            self.past_colors.insert(0, col)
        while len(self.past_colors) > Config.SQUARE_SIZE * 4 / 5:
            self.past_colors.pop()

    def get_surface(self, size: tuple[int, int]):
        ss = int(Config.SQUARE_SIZE * 4 / 5)
        surf = pygame.Surface((ss, ss))
        for index, col in enumerate(self.past_colors):
            y = index if self.dir_y != 1 else ss - 1 - index
            pygame.draw.line(surf, col, (0, y), (ss, y))
        return pygame.transform.scale(surf, size)

    def copy(self) -> "Square":
        new = Square(*self.pos, *self.dir)
        new.last_bounce_time = self.last_bounce_time
        new.latest_bounce_direction = self.latest_bounce_direction
        return new

    def get_current_color(self):
        if EMPTY_SQUARE:
            return (255, 255, 255)  # Border color is white
        else:
            square_color_index = round((self.dir_x + 1) / 2 + self.dir_y + 1)
            return get_colors()["square"][square_color_index % len(get_colors()["square"])]

    def compute_glowy_surface(self, rect, val):
        cache_key = (rect.size, val)
        if cache_key in Square.glowing_surface_cache:
            return Square.glowing_surface_cache[cache_key]
        glowy_borders = make_glowy2((rect.width + 40, rect.height + 40), Config.square_glow_color, val)
        surface = pygame.Surface(rect.inflate(100, 100).size, pygame.SRCALPHA)
        surface.blit(glowy_borders, (20, 20), special_flags=pygame.BLEND_RGBA_ADD)
        Square.glowing_surface_cache[cache_key] = surface
        return surface

    def draw_glowing3(self, win, rect):
        if self.died:
            return

        if Config.square_glow:
            current_ticks = pygame.time.get_ticks()
            time_since_glow = current_ticks - self.time_since_glow_start

            if EMPTY_SQUARE:
                # Glow is always slightly on, increases during collision
                if time_since_glow < Config.square_glow_duration * 1000:
                    progress = 1 - (time_since_glow) / (Config.square_glow_duration * 1000)
                    val = int(progress * Config.glow_intensity)
                    val = max(val, Config.square_min_glow)
                else:
                    # Minimum glow intensity when not colliding
                    val = Config.square_min_glow
            else:
                # Glow only during collision
                if time_since_glow < Config.square_glow_duration * 1000:
                    progress = 1 - (time_since_glow) / (Config.square_glow_duration * 1000)
                    val = int(progress * Config.glow_intensity)
                    val = max(val, Config.square_min_glow)
                else:
                    return  # Do not draw glow if not within glow duration

            if val > 0:
                surf = self.compute_glowy_surface(rect, val)
                win.blit(surf, rect.move(-40, -40).topleft, special_flags=pygame.BLEND_RGBA_ADD)

    @property
    def x(self):
        return self.pos[0]

    @property
    def y(self):
        return self.pos[1]

    def draw(self, screen: pygame.Surface, sqrect: pygame.Rect):
        if self.died:
            return

        # Draw glowing square if glowing
        self.draw_glowing3(screen, sqrect)

        if EMPTY_SQUARE:
            # Draw the square as an empty square with white border
            border_color = (255, 255, 255)
            border_thickness = 2  # Adjust as needed
            pygame.draw.rect(screen, border_color, sqrect, border_thickness)
        else:
            # Default drawing of the square
            square_color_index = round((self.dir_x + 1) / 2 + self.dir_y + 1)
            self.register_past_color(get_colors()["square"][square_color_index % len(get_colors()["square"])])

            # Draw the square itself
            pygame.draw.rect(screen, (0, 0, 0), sqrect)
            sq_surf = self.get_surface(
                tuple(sqrect.inflate(-int(Config.SQUARE_SIZE / 5), -int(Config.SQUARE_SIZE / 5))[2:]))
            screen.blit(sq_surf, sq_surf.get_rect(center=sqrect.center))

    @x.setter
    def x(self, val: int):
        self.pos[0] = val

    @y.setter
    def y(self, val: int):
        self.pos[1] = val

    @property
    def dir_x(self):
        return self.dir[0]

    @property
    def dir_y(self):
        return self.dir[1]

    @property
    def rect(self):
        return pygame.Rect(self.x - Config.SQUARE_SIZE / 2, self.y - Config.SQUARE_SIZE / 2,
                           *([Config.SQUARE_SIZE] * 2))

    def obey_bounce(self, bounce: Bounce):
        # Planned bounces
        self.pos = bounce.square_pos.copy()
        self.dir = bounce.square_dir.copy()
        self.latest_bounce_direction = bounce.bounce_dir
        self.last_bounce_time = bounce.time
        # Start glow effect
        self.time_since_glow_start = pygame.time.get_ticks()
        return

    def reg_move(self, use_dt: bool = True):
        self.x += self.dir_x * Config.square_speed * (Config.dt if use_dt else 1 / FRAMERATE)
        self.y += self.dir_y * Config.square_speed * (Config.dt if use_dt else 1 / FRAMERATE)

class Camera:
    def __init__(self, x: int = 0, y: int = 0):
        self.x = x
        self.y = y
        self.locked_on_square = True
        self.lock_type: CameraFollow = CameraFollow(Config.camera_mode)

    def attempt_movement(self):
        if not self.locked_on_square:
            keys = pygame.key.get_pressed()
            shift_modifier = (keys[pygame.K_LSHIFT] | keys[pygame.K_RSHIFT]) + 1
            self.x += (keys[pygame.K_d] - keys[pygame.K_a]) * Config.CAMERA_SPEED * shift_modifier / FRAMERATE
            self.y += (keys[pygame.K_s] - keys[pygame.K_w]) * Config.CAMERA_SPEED * shift_modifier / FRAMERATE

    @property
    def pos(self):
        return self.x, self.y

    @pos.setter
    def pos(self, val: Union[tuple[int, int], list[int]]):
        self.x, self.y = val

    def offset(self, pos_or_rect: Union[pygame.Rect, tuple[int, int]]) -> Union[pygame.Rect, list[int]]:
        if isinstance(pos_or_rect, pygame.Rect):
            return pos_or_rect.move(-self.x, -self.y)
        else:
            return [pos_or_rect[0]-self.x, pos_or_rect[1]-self.y]

    def apply_parallax(self, pos: tuple[float, float], depth: float) -> list[float]:
        # Parallax factor: nearer stars move faster than distant ones
        parallax_factor = 0.2 + depth * 0.8  # From 0.2 to 1.0
        screen_x = (pos[0] - self.x) * parallax_factor
        screen_y = (pos[1] - self.y) * parallax_factor
        return [screen_x, screen_y]

    def follow(self, square: Square):

        # Square in center
        if self.lock_type == CameraFollow.Center:
            self.pos = [square.x - Config.SCREEN_WIDTH / 2, square.y - Config.SCREEN_HEIGHT / 2]

        # Smooth camera
        if self.lock_type == CameraFollow.Smoothed:
            easing_rate = 3
            self.x = (square.x - Config.SCREEN_WIDTH / 2) * easing_rate * Config.dt + self.x - easing_rate * self.x * Config.dt
            self.y = (square.y - Config.SCREEN_HEIGHT / 2) * easing_rate * Config.dt + self.y - easing_rate * self.y * Config.dt

class CameraFollow(Enum):
    Center = 0  # Center the square
    Smoothed = 2  # Smoothed camera

class Star:
    def __init__(self, pos: tuple[float, float], depth: float):
        self.initial_pos = list(pos)
        self.depth = depth  # between 0 (far) and 1 (near)
        size_min = 0.5
        size_max = 2
        self.size = size_min + (1 - self.depth) * (size_max - size_min)
        self.phase = random.uniform(0, 2 * math.pi)  # For random phase
        self.brightness = 0  # Will be updated in the update method
        self.color = Config.star_color  # Use star color from Config

    def update(self, time):
        # Adjust brightness over time to create blinking effect
        blink_speed = 10  # can adjust to get desired speed
        brightness_variation = (math.sin(blink_speed * time + self.phase) + 1) / 2  # Normalize between 0 and 1
        min_brightness = 100
        max_brightness = 255
        brightness = min_brightness + brightness_variation * (max_brightness - min_brightness)
        self.color = tuple(min(255, int(c * (brightness / 255))) for c in Config.star_color)  # Adjust color based on brightness

    def get_screen_pos(self, camera: Camera):
        parallax_factor = 0.2 + self.depth * 0.8  # from 0.2 to 1.0
        screen_x = (self.initial_pos[0] - camera.x) * parallax_factor
        screen_y = (self.initial_pos[1] - camera.y) * parallax_factor
        return [screen_x, screen_y]

class Peg:
    glowing_surface_cache = {}
    def __init__(self, rect: pygame.Rect, color: tuple, collision_time: float):
        self.rect = rect
        self.color = color
        self.collision_time = collision_time  # The time when the square is supposed to bounce on this peg
        self.time_since_glow_start = -1000  # For glow effect
        self.visible = False  # Visibility flag

    def update_glow(self, current_time):
        # Update the glow start time
        self.time_since_glow_start = current_time
        self.visible = True  # Set visibility to True after collision

    def compute_glowy_surface(self, rect, val):
        cache_key = (rect.size, val)
        if cache_key in Peg.glowing_surface_cache:
            return Peg.glowing_surface_cache[cache_key]
        glowy_borders = make_glowy2((rect.width + 40, rect.height + 40), Config.peg_glow_color, val)
        surface = pygame.Surface(rect.inflate(100, 100).size, pygame.SRCALPHA)
        surface.blit(glowy_borders, (20, 20), special_flags=pygame.BLEND_RGBA_ADD)
        Peg.glowing_surface_cache[cache_key] = surface
        return surface

    def draw_glow(self, screen, rect):
        if Config.peg_glow:
            current_ticks = pygame.time.get_ticks()
            elapsed_time = (current_ticks - self.time_since_glow_start) / 1000.0
            if elapsed_time < Config.peg_glow_duration:
                progress = 1 - (elapsed_time) / Config.peg_glow_duration
                val = int(progress * Config.peg_glow_intensity)
                val = max(val, Config.peg_min_glow)
                surf = self.compute_glowy_surface(rect, val)
                screen.blit(surf, rect.move(-40, -40).topleft, special_flags=pygame.BLEND_RGBA_ADD)

    def draw(self, screen: pygame.Surface, camera: Camera, current_time: float):
        offsetted = camera.offset(self.rect)
        if screen.get_rect().colliderect(offsetted):
            if self.visible:
                # After collision time, draw the peg and glow effect
                self.draw_glow(screen, offsetted)
                pygame.draw.rect(screen, self.color, offsetted)
            else:
                color = (get_colors()["background"])
                pygame.draw.rect(screen, color, offsetted)
                pass  # Peg remains invisible before collision

class World:
    """It's a cruel world out there"""

    def __init__(self):
        self.future_bounces: list[Bounce] = []
        self.past_bounces: list[Bounce] = []
        self.start_time = 0
        self.time = 0
        self.pegs: list[Peg] = []  # List of Peg objects
        self.particles: list[Particle] = []
        self.stars: list[Star] = []
        self.timestamps = []
        self.square = Square()
        self.safe_areas: list[pygame.Rect] = []

    def update_time(self) -> None:
        self.time = get_current_time() - self.start_time

    def get_next_bounce(self) -> Bounce:
        """Also pops the bounce from the future_bounces list"""
        bounce = self.future_bounces.pop(0)
        self.past_bounces.append(bounce)
        return bounce

    def add_bounce_particles(self, sp: list[float], sd: list[float], color: tuple):
        for _ in range(Config.particle_amount):
            new = Particle([sp[0] + random.randint(-10, 10), sp[1] + random.randint(-10, 10)], sd, color=color)
            self.particles.append(new)

    def handle_bouncing(self, square: Square):
        if len(self.future_bounces):
            if (self.time * 1000 + Config.music_offset)/1000 > self.future_bounces[0].time:
                current_bounce = self.get_next_bounce()
                before = square.dir.copy()
                square.obey_bounce(current_bounce)
                changed = square.dir.copy()
                for _ in range(2):
                    if before[_] == changed[_]:
                        changed[_] = 0
                    else:
                        changed[_] = -changed[_]
                if Config.do_particles_on_bounce:
                    square_color = square.get_current_color()
                    self.add_bounce_particles(square.pos, changed, color=square_color)

                # Stop square at end
                if len(self.future_bounces) == 0:
                    square.dir = [0, 0]
                    square.pos = current_bounce.square_pos

                # Update the corresponding peg's glow
                index = len(self.past_bounces) - 1  # Index of the current bounce
                if index < len(self.pegs):
                    peg = self.pegs[index]
                    peg.update_glow(pygame.time.get_ticks())

    def generate_stars(self):
        self.stars = []
        # Calculate total safe area
        total_safe_area = sum(area.width * area.height for area in self.safe_areas)
        star_density = Config.star_density  # Use star density from Config
        total_num_stars = int(total_safe_area * star_density)
        min_distance_squared = (20) ** 2  # Avoid clustering

        # Get bounding rectangle of all safe areas
        min_x = min(area.left for area in self.safe_areas)
        max_x = max(area.right for area in self.safe_areas)
        min_y = min(area.top for area in self.safe_areas)
        max_y = max(area.bottom for area in self.safe_areas)
        bounding_rect = pygame.Rect(min_x, min_y, max_x - min_x, max_y - min_y)

        stars = []
        attempts = 0
        max_attempts = total_num_stars * 10

        while len(stars) < total_num_stars and attempts < max_attempts:
            x = random.uniform(bounding_rect.left, bounding_rect.right)
            y = random.uniform(bounding_rect.top, bounding_rect.bottom)
            point = (x, y)

            # Ensure point is within safe area
            inside_safe_area = any(area.collidepoint(point) for area in self.safe_areas)

            if inside_safe_area:
                # Ensure minimum distance between stars
                if all((star.initial_pos[0] - x) ** 2 + (star.initial_pos[1] - y) ** 2 >= min_distance_squared for star in stars):
                    depth = random.uniform(0, 1)
                    star = Star((x, y), depth)
                    stars.append(star)
            attempts += 1

        self.stars = stars

    def gen_future_bounces(self, _start_notes: list[float], percent_update_callback):
        """Recursive function with optimized overlap checking"""
        total_notes = len(_start_notes)
        max_percent = 0
        path = []
        safe_areas = []
        force_return = 0

        def recurs(
                square: Square,
                notes: list[float],
                bounces_so_far: list[Bounce] = None,
                prev_index_priority=None,
                t: float = 0,
                depth: int = 0
        ) -> Union[list[Bounce], bool]:
            nonlocal force_return, max_percent
            if prev_index_priority is None:
                prev_index_priority = [0, 1]
            if bounces_so_far is None:
                bounces_so_far = []
            if total_notes:
                gone_through_percent = (total_notes-len(notes)) * 100 // total_notes
                while gone_through_percent > max_percent:
                    max_percent += 1
                    if percent_update_callback(f"{max_percent}% done generating map"):
                        raise UserCancelsLoadingError()

            all_bounce_rects = [_bounc.get_collision_rect() for _bounc in bounces_so_far]
            if len(notes) == 0:
                return bounces_so_far

            path_segment_start = len(path)
            start_rect = square.rect.copy()
            while True:
                t += 1/FRAMERATE
                square.reg_move(False)
                path.append(square.rect)
                if t > notes[0]:
                    # No collision (we good)
                    bounce_indexes = prev_index_priority

                    # Randomly change direction every X% of the time
                    if random.random() * 100 < Config.direction_change_chance:
                        bounce_indexes = list(bounce_indexes.__reversed__())

                    # Add safe area
                    safe_areas.append(start_rect.union(square.rect))

                    for direction_to_bounce in bounce_indexes:
                        square.dir[direction_to_bounce] *= -1
                        bounces_so_far.append(Bounce(square.pos.copy(), square.dir.copy(), t, direction_to_bounce))

                        toextend = recurs(
                            square=square.copy(),
                            notes=notes[1:],
                            bounces_so_far=[_b.copy() for _b in bounces_so_far],
                            t=t,
                            prev_index_priority=bounce_indexes.copy(),
                            depth=depth+1
                        )

                        if toextend:
                            return toextend
                        else:
                            bounces_so_far = bounces_so_far[:-1]
                            square.dir[direction_to_bounce] *= -1

                            # Backtrack if necessary
                            if force_return:
                                force_return -= 1
                                while len(path) != path_segment_start:
                                    path.pop()
                                return False

                            continue
                    while len(path) != path_segment_start:
                        path.pop()
                    return False

                othercheck = False
                if len(bounces_so_far):
                    othercheck = bounces_so_far[-1].get_collision_rect().collidelist(path[:-10])+1

                if square.rect.collidelist(all_bounce_rects) != -1 or othercheck:
                    if depth > 200:
                        if random.random() < Config.backtrack_chance:
                            max_percent -= (Config.backtrack_amount * 100 // total_notes) + 1
                            force_return = Config.backtrack_amount

                    while len(path) != path_segment_start:
                        path.pop()
                    return False

        _start_notes = _start_notes[:Config.max_notes] if Config.max_notes is not None else _start_notes

        self.future_bounces = recurs(
            square=self.square.copy(),
            notes=remove_too_close_values(
                [_sn for _sn in _start_notes],
                threshold=Config.bounce_min_spacing
            )
        )

        if self.future_bounces is False:
            raise MapLoadingFailureError("The map failed to generate because of the recursion function. " +
                                         "If the MIDI has too many notes too close, it may not generate. " +
                                         "Maybe try changing the \"bounce min spacing\", \"square speed\", or \"change dir chance\" in the config.")

        if len(self.future_bounces) == 0:
            raise MapLoadingFailureError("Map safe area list is empty. Please report this issue.")

        percent_update_callback("Merging overlapping safe areas")

        # Merging overlapping safe areas more efficiently
        self.safe_areas = fix_overlap(safe_areas, percent_update_callback)

        # Generate colors for pegs
        def gather_colors(num_colors=20):
            colors = []
            while len(colors) < num_colors:
                new_colors = color_hunt()
                rgb_colors = [tuple(int(hex_color[i:i+2], 16) for i in (1, 3, 5)) for hex_color in new_colors]
                colors.extend(rgb_colors)
            return colors[:num_colors]
        collected_colors = gather_colors()
        # Setting random colors for the generated pegs
        colors = [random.choice(collected_colors) for _ in self.future_bounces]

        if not PEG_REMOVE:
            if PEG_MULTI_COLOR:
                collected_colors = gather_colors()
                # Setting random colors for the generated pegs
                colors = [random.choice(collected_colors) for _ in self.future_bounces]
            elif NO_COLOR:
                colors = [get_colors()["background"] for _ in self.future_bounces]
            else:
                # Use the peg color from get_colors() if peg_multi_color is False
                colors = [get_colors()["peg"] for _ in self.future_bounces]
        else:
            colors = [get_colors()["hallway"] for _ in self.future_bounces]

        # Create pegs
        self.pegs = []
        for i in range(len(self.future_bounces)):
            bounce_rect = self.future_bounces[i].get_collision_rect()
            color = colors[i]
            collision_time = self.future_bounces[i].time
            peg = Peg(bounce_rect, color, collision_time)
            self.pegs.append(peg)

        # Generate stars in safe areas
        if STAR:
            self.generate_stars()

        return self.safe_areas

class Game:
    def __init__(self):
        self.active = False
        self.notes = []
        self.camera = Camera()
        self.world = World()
        self.safe_areas: list[pygame.Rect] = []
        self.music_has_played = False
        self.offset_happened = False

    def start_song(self, screen: pygame.Surface):
        random.seed(Config.seed)

        # Load song and notes
        with open(Config.current_song.fp, 'rb') as f:
            notes = read_midi_file(file=f)
        notes = sorted([note for note in notes])
        self.notes = notes

        # Other settings
        self.world = World()
        self.music_has_played = False
        self.offset_happened = False
        self.camera.lock_type = CameraFollow(Config.camera_mode)
        screen.fill(get_colors()["background"])
        pygame.display.flip()

        def update_loading_screen(message: str):
            screen.fill(get_colors()["background"], pygame.Rect(0, 0, Config.SCREEN_WIDTH, Config.SCREEN_HEIGHT))
            font_size = int(Config.SCREEN_HEIGHT * 0.05)
            loading_text = get_font(font_size).render(message, True, get_colors()["hallway"])
            text_rect = loading_text.get_rect()
            text_rect.center = (Config.SCREEN_WIDTH // 2, Config.SCREEN_HEIGHT // 2)
            screen.blit(loading_text, text_rect)
            pygame.display.flip()

        try:
            self.safe_areas = self.world.gen_future_bounces(self.notes, update_loading_screen)
            # No need to fix overlap here, as it's handled in gen_future_bounces
        except UserCancelsLoadingError:
            return True
        except MapLoadingFailureError as e:
            return e.args[0] if len(e.args) else "Big error... can't load map :("

        self.world.start_time = get_current_time()
        self.world.square.dir = [0, 0]
        if self.world.future_bounces:
            self.world.square.pos = self.world.future_bounces[0].square_pos
        else:
            self.world.square.pos = [Config.SCREEN_WIDTH / 2, Config.SCREEN_HEIGHT / 2]
        return None

    def draw(self, screen: pygame.Surface):
        if not self.active:
            return

        if not self.music_has_played:
            if not self.offset_happened:
                for bnc_change in self.world.future_bounces:
                    bnc_change.time += Config.start_playing_delay / 1000
            self.offset_happened = True
            if self.world.time-Config.music_offset/1000 > Config.start_playing_delay/1000:
                self.music_has_played = True
                song_load_before = get_current_time()
                pygame.mixer.music.play()
                for bnc_change in self.world.future_bounces:
                    bnc_change.time += (get_current_time()-song_load_before)/1000

        screen_rect = screen.get_rect()

        # Set world time
        self.world.update_time()

        # Move camera
        self.camera.attempt_movement()

        # Handle square bounces
        self.world.handle_bouncing(self.world.square)

        # Move square
        self.world.square.reg_move()

        # Square in center of camera if locked
        if self.camera.locked_on_square:
            self.camera.follow(self.world.square)

        # Bounce animation
        sqrect = self.camera.offset(self.world.square.rect)
        if (self.world.time - 0.25) + Config.music_offset / 1000 < self.world.square.last_bounce_time:
            lerp = abs((self.world.time - 0.25 + Config.music_offset / 1000) - self.world.square.last_bounce_time) * 5
            lerp = lerp ** 2  # Square it for better-looking interpolation
            if self.world.square.latest_bounce_direction:
                sqrect.inflate_ip((lerp * 5, -10 * lerp))
            else:
                sqrect.inflate_ip((-10 * lerp, lerp * 5))

        # Draw background (walls)
        screen.fill(get_colors()["background"])

        # Create a hallway surface
        hallway_surface = pygame.Surface((Config.SCREEN_WIDTH, Config.SCREEN_HEIGHT), pygame.SRCALPHA)

        # Safe areas
        for safe_area in self.world.safe_areas:
            offsetted = self.camera.offset(safe_area)
            if screen_rect.colliderect(offsetted):
                pygame.draw.rect(hallway_surface, get_colors()["hallway"], offsetted)

        # Obtain current time
        current_time = pygame.time.get_ticks() / 1000.0  # Time in seconds

        # Draw stars onto the hallway surface
        for star in self.world.stars:
            star.update(current_time)  # Update blinking effect
            screen_pos = star.get_screen_pos(self.camera)
            if 0 <= screen_pos[0] < Config.SCREEN_WIDTH and 0 <= screen_pos[1] < Config.SCREEN_HEIGHT:
                # Check if star's position is within the hallway (safe areas)
                if hallway_surface.get_at((int(screen_pos[0]), int(screen_pos[1]))).a != 0:
                    pygame.draw.circle(hallway_surface, star.color, (int(screen_pos[0]), int(screen_pos[1])), int(star.size))

        # Blit the hallway surface onto the main screen
        screen.blit(hallway_surface, (0, 0))

        # Draw pegs
        for peg in self.world.pegs:
            peg.draw(screen, self.camera, self.world.time)

        # Particles
        for particle in self.world.particles:
            pygame.draw.rect(screen, particle.color, self.camera.offset(particle.rect))
        for remove_particle in [particle for particle in self.world.particles if particle.age()]:
            self.world.particles.remove(remove_particle)

        # Particle trail in game
        if Config.particle_trail:
            # Add particles periodically
            if not self.world.square.died:
                if TRAIL_COLOR_BASED_ON_SQUARE:
                    square_color = self.world.square.get_current_color()
                    color = square_color
                else:
                    color = (255, 255, 255)
                new = Particle(self.world.square.pos.copy(), [0, 0], True, color=color)
                new.delta = [random.randint(-2, 2)/20, random.randint(5, 15)/20]
                self.world.particles.append(new)

        # Draw square
        self.world.square.draw(screen, sqrect)

    def handle_event(self, event: pygame.event.Event):
        if not self.active:
            return False

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                pygame.quit()
                sys.exit()
            if event.key == pygame.K_TAB:
                self.camera.locked_on_square = not self.camera.locked_on_square

class InvalidSongError(Exception):
    """The song is invalid somehow"""
    pass

def make_song_from_midi(fpath: str) -> Any:
    new_song = type('Song', (object,), {})()
    new_song.fp = fpath
    new_song.name = os.path.basename(fpath)  # Use filename as song name
    new_song.creator = ''  # Empty creator
    new_song.music_offset = 0
    return new_song

def main():
    pygame.init()
    clock = pygame.time.Clock()
    screen = pygame.display.set_mode((Config.SCREEN_WIDTH, Config.SCREEN_HEIGHT), pygame.DOUBLEBUF | pygame.HWSURFACE)
    pygame.display.set_caption("chubbMidi")
    try:
        pygame.display.set_icon(pygame.image.load(Config.assets).convert_alpha())
    except Exception as e:
        print(e)

    # Specify the song file to use
    selected_song_filepath = join(Config.song, SONG)
    if not isfile(selected_song_filepath):
        print(f"Song file {selected_song_filepath} not found.")
        return

    Config.current_song = make_song_from_midi(selected_song_filepath)

    # Load the music file
    try:
        pygame.mixer.music.load(Config.current_song.fp)
    except Exception as e:
        print(f"Error loading MIDI file as audio: {e}")
        print("Your platform may not support MIDI playback via pygame.mixer.music.")
        print("The game will run without audio.")
        # Uncomment the line below to exit if audio is essential
        # return
    pygame.mixer.music.set_volume(Config.volume / 100)

    # Initialize the game
    game = Game()

    # Start the game
    if msg := game.start_song(screen):
        if isinstance(msg, str):
            print(f"Error starting game: {msg}")
            return
    game.active = True

    running = True
    while running:
        # screen.fill(get_colors()["background"])  # Moved to the draw function
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            game.handle_event(event)

        game.draw(screen)
        pygame.display.flip()
        clock.tick(FRAMERATE)
        Config.dt = clock.get_time() / 1000.0 if clock.get_time() > 0 else 0.016  # Avoid division by zero

    pygame.quit()

if __name__ == '__main__':
    main()
ASSISTANT
To implement the heat level feature that adjusts the square's glow intensity based on the speed of collisions, we'll make several modifications to the script while ensuring that existing features remain unaffected.

**1. Add a Boolean Setting for Heat Level at the Top of the Script**

```python
# Heat Level Setting
HEAT_LEVEL = True
```

**2. Update the `Config` Class to Include Heat Level Settings**

We'll add the heat level parameters to the `Config` class for easy adjustments.

```python
class Config:
    # ... existing code ...

    # Glow effect settings for square
    square_glow = SQUARE_GLOW
    square_glow_duration = 0.2
    glow_intensity = 15  # Adjusted intensity for better visibility
    square_min_glow = 0   # Lower value for slight glow when no collision

    # Heat Level Settings
    HEAT_LEVEL = HEAT_LEVEL  # From the top setting
    heat_increase_scale = 1.0  # Adjust this to scale the heat increase per collision
    max_heat_increase = 5.0   # Max heat level increase per collision
    max_heat_level = 10.0     # Max heat level
    heat_decay_rate = 1.0     # Heat level decays at 1 unit per second

    # ... existing code ...
```

**3. Modify the `Square` Class to Handle Heat Level Calculations**

- **Initialize `heat_level` and `last_collision_interval` in `__init__`:**

```python
class Square:
    def __init__(self, x: float = 0, y: float = 0, dx: int = 1, dy: int = 1):
        self.pos: list[float] = [x, y]
        self.dir: list[int] = [dx, dy]
        self.last_bounce_time = -100
        self.latest_bounce_direction = 0  # 0 = horiz, 1 = vert
        self.past_colors = []
        self.died = False
        self.time_since_glow_start = -1000  # For glow effect
        self.last_collision_interval = None
        self.heat_level = 0
```

- **Update Heat Level on Collision in `obey_bounce`:**

```python
    def obey_bounce(self, bounce: Bounce):
        # Before updating the last_bounce_time, compute time since last collision
        if self.last_bounce_time != -100:
            self.last_collision_interval = bounce.time - self.last_bounce_time
            # Update heat level
            if Config.HEAT_LEVEL and self.last_collision_interval > 0:
                heat_increase = Config.heat_increase_scale / self.last_collision_interval
                heat_increase = min(heat_increase, Config.max_heat_increase)
                self.heat_level += heat_increase
                self.heat_level = min(self.heat_level, Config.max_heat_level)
        else:
            self.last_collision_interval = None  # First collision, no previous interval

        # Then update last_bounce_time
        self.last_bounce_time = bounce.time

        # Start glow effect
        self.time_since_glow_start = pygame.time.get_ticks()
```

- **Decay Heat Level Over Time in `update_heat_level`:**

```python
    def update_heat_level(self, dt):
        if Config.HEAT_LEVEL:
            self.heat_level = max(0, self.heat_level - Config.heat_decay_rate * dt)
```

- **Adjust Glow Intensity Based on Heat Level in `draw_glowing3`:**

```python
    def draw_glowing3(self, win, rect):
        if self.died:
            return

        if Config.square_glow:
            if Config.HEAT_LEVEL:
                val = Config.square_min_glow + (self.heat_level / Config.max_heat_level) * (Config.glow_intensity - Config.square_min_glow)
                val = int(val)
                val = min(val, Config.glow_intensity)
                val = max(val, Config.square_min_glow)
            else:
                # Original glow code
                current_ticks = pygame.time.get_ticks()
                time_since_glow = current_ticks - self.time_since_glow_start

                if EMPTY_SQUARE:
                    # Glow is always slightly on, increases during collision
                    if time_since_glow < Config.square_glow_duration * 1000:
                        progress = 1 - (time_since_glow) / (Config.square_glow_duration * 1000)
                        val = int(progress * Config.glow_intensity)
                        val = max(val, Config.square_min_glow)
                    else:
                        # Minimum glow intensity when not colliding
                        val = Config.square_min_glow
                else:
                    # Glow only during collision
                    if time_since_glow < Config.square_glow_duration * 1000:
                        progress = 1 - (time_since_glow) / (Config.square_glow_duration * 1000)
                        val = int(progress * Config.glow_intensity)
                        val = max(val, Config.square_min_glow)
                    else:
                        return  # Do not draw glow if not within glow duration

            if val > 0:
                surf = self.compute_glowy_surface(rect, val)
                win.blit(surf, rect.move(-40, -40).topleft, special_flags=pygame.BLEND_RGBA_ADD)
```

**4. Update the Game Loop to Call `update_heat_level`**

In the `Game` class's `draw` method, after updating the world time, we'll call `update_heat_level` with the current delta time.

```python
    def draw(self, screen: pygame.Surface):
        if not self.active:
            return

        if not self.music_has_played:
            if not self.offset_happened:
                for bnc_change in self.world.future_bounces:
                    bnc_change.time += Config.start_playing_delay / 1000
            self.offset_happened = True
            if self.world.time-Config.music_offset/1000 > Config.start_playing_delay/1000:
                self.music_has_played = True
                song_load_before = get_current_time()
                pygame.mixer.music.play()
                for bnc_change in self.world.future_bounces:
                    bnc_change.time += (get_current_time()-song_load_before)/1000

        screen_rect = screen.get_rect()

        # Set world time
        self.world.update_time()

        # Update heat level
        self.world.square.update_heat_level(Config.dt)

        # ... existing code ...
```

**5. Ensure Existing Features Remain Unaffected**

All changes are additive and conditional on the `HEAT_LEVEL` setting. Existing features and configurations remain intact, and the new heat level feature integrates smoothly without interfering with other functionalities.

**6. Test and Adjust Parameters as Needed**

After implementing, you may need to adjust the values of the following parameters in the `Config` class to achieve the desired smoothness and responsiveness:

- `heat_increase_scale`
- `max_heat_increase`
- `max_heat_level`
- `heat_decay_rate`

**Complete Modified Code**

```python
import pygame
import mido
import sys
import random
import requests
import colorsys
import os
import math
import cv2
import numpy as np
from os.path import join, isfile
from time import time as get_current_time
from typing import Union, Optional, Any
from enum import Enum
from math import sin, pi

pygame.mixer.init()
pygame.init()
FRAMERATE = 60

# =========================
# Customizable Configuration
# =========================

# Midi Selection
SONG = "rush-e.mid"

# Screen Resolution
SCREEN_WIDTH = 1280
SCREEN_HEIGHT = 720

# Other Customizable Settings
SQUARE_SPEED = 600
SQUARE_SIZE = 40
BOUNCE_MIN_SPACING = 50
DIRECTION_CHANGE = 30
EMPTY_SQUARE = True

# Particle Settings
PARTICLE_BOUNCE = False
PARTICLE_TRAIL = False
TRAIL_COLOR_BASED_ON_SQUARE = False
PARTICLE_SPEED = 5

# Peg Settings
BOUNCE_PEG = True
PEG_COLOR = (255, 255, 255)
PEG_REMOVE = True
PEG_MULTI_COLOR = False
NO_COLOR = False

# Glow Settings
SQUARE_GLOW = True
PEG_GLOW = True
GLOW_RANDOM_COLOR = False

# Star Settings
STAR = True
STAR_COLOR = (255, 255, 255)
STAR_DENSITY = 0.0001

# Heat Level Setting
HEAT_LEVEL = True

# =========================
def color_hunt():
    def is_bright(hex_color):
        hex_color = hex_color.lstrip('#')
        rgb = tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))
        luminance = 0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]
        r, g, b = [x / 255.0 for x in rgb]
        h, s, v = colorsys.rgb_to_hsv(r, g, b)
        return luminance >= 130 and s >= 0.3
    while True:
        url = 'https://colorhunt.co/php/feed.php'
        headers = {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
        }
        data = {
            'step': 0,
            'sort': 'random',
            'tags': ''
        }
        response = requests.post(url, headers=headers, data=data)
        if response.status_code == 200:
            palettes = response.json()
            color_pairs = []
            for palette in palettes:
                code = palette['code']
                hex_colors = [f'#{code[i:i+6].upper()}' for i in range(0, len(code), 6)]
                if len(hex_colors) == 4 and all(is_bright(hex_color) for hex_color in hex_colors):
                    color_pairs.append(tuple(hex_colors))
            if color_pairs:
                selected_color_pair = random.choice(color_pairs)
                return selected_color_pair
        else:
            raise Exception(f"Failed to retrieve data. Status code: {response.status_code}")

selected_colors = color_hunt()
color1, color2, color3, color4 = selected_colors

class Config:
    # Constants
    SQUARE_SIZE = SQUARE_SIZE
    PARTICLE_SPEED = PARTICLE_SPEED
    CAMERA_SPEED = 500
    # Colors
    color_themes = {
        "dark": {
            "hallway": pygame.Color('#2D033B'),
            "background": pygame.Color('#070F2B'),
            "square": [
                pygame.Color(color1),
                pygame.Color(color2),
                pygame.Color(color3),
                pygame.Color(color4)
            ],
            "peg": pygame.Color(PEG_COLOR),    # Added peg color
        }
    }

    # Configuration
    script_dir = os.path.dirname(os.path.abspath(__file__))
    assets = os.path.join(script_dir, 'assets/icon.png')
    song = os.path.join(script_dir, 'songs')
    font = os.path.join(script_dir, 'assets/poppins-regular.ttf')
    SCREEN_WIDTH = SCREEN_WIDTH
    SCREEN_HEIGHT = SCREEN_HEIGHT
    theme: Optional[str] = "dark"
    seed: Optional[int] = None
    camera_mode: Optional[int] = 2
    start_playing_delay = 5000
    max_notes: Optional[int] = None
    bounce_min_spacing: Optional[float] = BOUNCE_MIN_SPACING
    square_speed: Optional[int] = SQUARE_SPEED
    volume: Optional[int] = 100
    music_offset: Optional[int] = 0
    direction_change_chance: Optional[int] = DIRECTION_CHANGE
    particle_trail = PARTICLE_TRAIL
    do_color_bounce_pegs = BOUNCE_PEG
    do_particles_on_bounce = PARTICLE_BOUNCE

    # Non-configurable settings
    backtrack_chance: Optional[float] = 0.02
    backtrack_amount: Optional[int] = 40
    square_swipe_anim_speed: Optional[int] = 4
    particle_amount = 20

    # Glow effect settings for square
    square_glow = SQUARE_GLOW
    square_glow_duration = 0.2
    glow_intensity = 15  # Adjusted intensity for better visibility
    square_min_glow = 0   # Lower value for slight glow when no collision

    # Heat Level Settings
    HEAT_LEVEL = HEAT_LEVEL  # From the top setting
    heat_increase_scale = 1.0  # Adjust this to scale the heat increase per collision
    max_heat_increase = 5.0   # Max heat level increase per collision
    max_heat_level = 10.0     # Max heat level
    heat_decay_rate = 1.0     # Heat level decays at 1 unit per second

    # Glow effect settings for pegs
    peg_glow = PEG_GLOW
    peg_glow_duration = 0.5
    peg_glow_intensity = 15  # Adjusted intensity for better visibility
    peg_min_glow = 7

    if GLOW_RANDOM_COLOR:
        peg_glow_color = pygame.Color(random.choice(selected_colors))
        square_glow_color = pygame.Color(random.choice(selected_colors))
    else:
        peg_glow_color = pygame.Color(255, 255, 255)
        square_glow_color = pygame.Color(255, 255, 255)

    # Star settings
    star_color = STAR_COLOR
    star_density = STAR_DENSITY

    # Other random stuff
    current_song = None
    dt = 0.01

def get_colors():
    return Config.color_themes.get(Config.theme, Config.color_themes["dark"])

def read_midi_file(file):
    midi_file = mido.MidiFile(file=file)

    notes = []
    current_time = 0

    for msg in midi_file:
        if msg.type == 'note_on' and msg.velocity != 0:
            timestamp = current_time + msg.time
            notes.append(round(timestamp*1000)/1000)
        current_time += msg.time
    return notes

def remove_too_close_values(lst: list[float], threshold=30) -> list[float]:
    """Assumes the list is sorted"""
    new = []
    before = None
    for _ in lst:
        if before is None:
            before = _
            new.append(_)
            continue
        if before+threshold/1000 > _:
            continue
        before = _
        new.append(_)
    return new

def fix_overlap(rects: list[pygame.Rect], callback=None):
    """
    Optimized function to merge overlapping rectangles efficiently.
    """
    if callback is None:
        callback = lambda _: None

    rects = rects.copy()
    # Sort rectangles based on x coordinate
    rects.sort(key=lambda r: (r.x, r.y))

    merged_rects = []
    for rect in rects:
        if not merged_rects:
            merged_rects.append(rect)
        else:
            last = merged_rects[-1]
            if last.colliderect(rect):
                merged_rect = last.union(rect)
                merged_rects[-1] = merged_rect
            else:
                merged_rects.append(rect)

    callback("Finished merging rectangles")

    return merged_rects

def get_font(size: int = 24) -> pygame.font.Font:
    font_path = Config.font
    return pygame.font.Font(font_path, size)

class MapLoadingFailureError(Exception):
    """The map fails to load (recurs function fails)"""
    pass

class UserCancelsLoadingError(Exception):
    """User cancels the loading screen"""
    pass

def interpolate_fn(n):
    """Interpolate sigmoidally from 0-1"""
    n = min(max(n, 0), 1)
    return sin(pi * (n - 0.5)) / 2 + 0.5

class Particle:
    SPEED_VARIATION = 4
    SIZE_MIN = 7
    SIZE_MAX = 14
    AGE_RATE = 20
    SLOW_DOWN_RATE = 1.2

    def __init__(self, pos: list[float], delta: list[float], invert_color: bool = False, color: Optional[tuple] = None):
        self.pos = pos.copy()
        self.size = random.randint(Particle.SIZE_MIN, Particle.SIZE_MAX)
        self.delta = delta.copy()
        self.delta[0] += random.randint(-Particle.SPEED_VARIATION, Particle.SPEED_VARIATION)/8
        self.delta[1] += random.randint(-Particle.SPEED_VARIATION, Particle.SPEED_VARIATION)/8
        if color is not None:
            self.color = color
        else:
            # Default color if color is not given
            self.color = get_colors()["hallway"] if not invert_color else get_colors()["background"]

        # Adjust color to white for particles
        self.color = (255, 255, 255)

    def age(self):
        self.size -= Particle.AGE_RATE*Config.dt
        self.x += self.delta[0] * Config.PARTICLE_SPEED
        self.y += self.delta[1] * Config.PARTICLE_SPEED
        if Config.dt != 0:
            self.delta[0] /= (Particle.SLOW_DOWN_RATE+FRAMERATE) * Config.dt
            self.delta[1] /= (Particle.SLOW_DOWN_RATE+FRAMERATE) * Config.dt
        return self.size <= 0

    @property
    def x(self):
        return self.pos[0]

    @x.setter
    def x(self, val: float):
        self.pos[0] = val

    @property
    def y(self):
        return self.pos[1]

    @y.setter
    def y(self, val: float):
        self.pos[1] = val

    @property
    def rect(self):
        return pygame.Rect(self.x-self.size/2, self.y-self.size/2, *(2*[self.size]))

class Bounce:
    def __init__(self, sq_pos: list[float], sq_dir: list[int], time: float, bounce_dir: int):
        self.square_pos = sq_pos  # New square position
        self.square_dir = sq_dir  # New square direction
        self.bounce_dir = bounce_dir  # Bounce direction for squish effect; 0 or 1
        self.time = time  # Time during bounce

    def get_collision_rect(self):
        sx, sy = self.square_pos
        if self.bounce_dir == 0:
            # Bounce left or right wall
            if self.square_dir[0] == -1:
                # Right wall
                return pygame.Rect(
                    sx+Config.SQUARE_SIZE/2+1,
                    sy-10,
                    10,
                    20
                )
            elif self.square_dir[0] == 1:
                # Left wall
                return pygame.Rect(
                    sx-10-Config.SQUARE_SIZE/2-1,
                    sy-10,
                    10,
                    20
                )
        elif self.bounce_dir == 1:
            # Bounce top or bottom wall
            if self.square_dir[1] == -1:
                # Bottom wall
                return pygame.Rect(
                    sx-10,
                    sy+Config.SQUARE_SIZE/2+1,
                    20,
                    10
                )
            elif self.square_dir[1] == 1:
                # Top wall
                return pygame.Rect(
                    sx-10,
                    sy-10-Config.SQUARE_SIZE/2-1,
                    20,
                    10
                )

    def copy(self) -> "Bounce":
        return Bounce(self.square_pos.copy(), self.square_dir.copy(), self.time, self.bounce_dir)

    def __repr__(self):
        return f"<Bounce(sq_pos={self.square_pos}, sq_dir={self.square_dir}, time={self.time}, dir={self.bounce_dir})"

# Glow effect functions

def create_border(image: np.ndarray, margin: int, thickness: int, color: tuple) -> np.ndarray:
    height, width = image.shape[:2]
    cv2.rectangle(image, (margin, margin), (width - margin, height - margin), color, thickness=thickness)
    return image

def apply_blooming(image: np.ndarray) -> np.ndarray:
    # Provide some blurring to image, to create some bloom.
    cv2.GaussianBlur(image, ksize=(15, 15), sigmaX=20, sigmaY=20, dst=image)
    cv2.blur(image, ksize=(12, 12), dst=image)
    return image

def glowing_border(image: np.ndarray, margin=20, thickness=20, color=(255, 255, 255)):
    """
    Create a glowing border around an image.
    """
    # Generate the colored border.
    image = create_border(image, margin, thickness, color)

    # Apply the bloom effect to the image with the border.
    image = apply_blooming(image)

    # Reassert the original border to enhance the edges.
    image = create_border(image, margin - 1, 1, color)
    image = create_border(image, margin + 1, 1, color)
    return image

def make_glowy2(size, color, intensity=0) -> pygame.Surface:
    image = np.zeros((*size[::-1], 3), dtype=np.uint8)
    border_color_rgb = color  # Assuming color is RGB tuple
    border = glowing_border(image.copy(), color=border_color_rgb, thickness=intensity)
    return pygame.surfarray.make_surface(np.fliplr(np.rot90(border, k=-1)))

class Square:
    glowing_surface_cache = {}
    def __init__(self, x: float = 0, y: float = 0, dx: int = 1, dy: int = 1):
        self.pos: list[float] = [x, y]
        self.dir: list[int] = [dx, dy]
        self.last_bounce_time = -100
        self.latest_bounce_direction = 0  # 0 = horiz, 1 = vert
        self.past_colors = []
        self.died = False
        self.time_since_glow_start = -1000  # For glow effect
        self.last_collision_interval = None
        self.heat_level = 0

    def register_past_color(self, col: tuple[int, int, int]):
        for _ in range(max(Config.square_swipe_anim_speed, 1)):
            self.past_colors.insert(0, col)
        while len(self.past_colors) > Config.SQUARE_SIZE * 4 / 5:
            self.past_colors.pop()

    def get_surface(self, size: tuple[int, int]):
        ss = int(Config.SQUARE_SIZE * 4 / 5)
        surf = pygame.Surface((ss, ss))
        for index, col in enumerate(self.past_colors):
            y = index if self.dir_y != 1 else ss - 1 - index
            pygame.draw.line(surf, col, (0, y), (ss, y))
        return pygame.transform.scale(surf, size)

    def copy(self) -> "Square":
        new = Square(*self.pos, *self.dir)
        new.last_bounce_time = self.last_bounce_time
        new.latest_bounce_direction = self.latest_bounce_direction
        return new

    def get_current_color(self):
        if EMPTY_SQUARE:
            return (255, 255, 255)  # Border color is white
        else:
            square_color_index = round((self.dir_x + 1) / 2 + self.dir_y + 1)
            return get_colors()["square"][square_color_index % len(get_colors()["square"])]

    def compute_glowy_surface(self, rect, val):
        cache_key = (rect.size, val)
        if cache_key in Square.glowing_surface_cache:
            return Square.glowing_surface_cache[cache_key]
        glowy_borders = make_glowy2((rect.width + 40, rect.height + 40), Config.square_glow_color, val)
        surface = pygame.Surface(rect.inflate(100, 100).size, pygame.SRCALPHA)
        surface.blit(glowy_borders, (20, 20), special_flags=pygame.BLEND_RGBA_ADD)
        Square.glowing_surface_cache[cache_key] = surface
        return surface

    def draw_glowing3(self, win, rect):
        if self.died:
            return

        if Config.square_glow:
            if Config.HEAT_LEVEL:
                # Glow intensity based on heat level
                val = Config.square_min_glow + (self.heat_level / Config.max_heat_level) * (Config.glow_intensity - Config.square_min_glow)
                val = int(val)
                val = min(val, Config.glow_intensity)
                val = max(val, Config.square_min_glow)
            else:
                current_ticks = pygame.time.get_ticks()
                time_since_glow = current_ticks - self.time_since_glow_start

                if EMPTY_SQUARE:
                    # Glow is always slightly on, increases during collision
                    if time_since_glow < Config.square_glow_duration * 1000:
                        progress = 1 - (time_since_glow) / (Config.square_glow_duration * 1000)
                        val = int(progress * Config.glow_intensity)
                        val = max(val, Config.square_min_glow)
                    else:
                        # Minimum glow intensity when not colliding
                        val = Config.square_min_glow
                else:
                    # Glow only during collision
                    if time_since_glow < Config.square_glow_duration * 1000:
                        progress = 1 - (time_since_glow) / (Config.square_glow_duration * 1000)
                        val = int(progress * Config.glow_intensity)
                        val = max(val, Config.square_min_glow)
                    else:
                        return  # Do not draw glow if not within glow duration

            if val > 0:
                surf = self.compute_glowy_surface(rect, val)
                win.blit(surf, rect.move(-40, -40).topleft, special_flags=pygame.BLEND_RGBA_ADD)

    @property
    def x(self):
        return self.pos[0]

    @property
    def y(self):
        return self.pos[1]

    def draw(self, screen: pygame.Surface, sqrect: pygame.Rect):
        if self.died:
            return

        # Draw glowing square if glowing
        self.draw_glowing3(screen, sqrect)

        if EMPTY_SQUARE:
            # Draw the square as an empty square with white border
            border_color = (255, 255, 255)
            border_thickness = 2  # Adjust as needed
            pygame.draw.rect(screen, border_color, sqrect, border_thickness)
        else:
            # Default drawing of the square
            square_color_index = round((self.dir_x + 1) / 2 + self.dir_y + 1)
            self.register_past_color(get_colors()["square"][square_color_index % len(get_colors()["square"])])

            # Draw the square itself
            pygame.draw.rect(screen, (0, 0, 0), sqrect)
            sq_surf = self.get_surface(
                tuple(sqrect.inflate(-int(Config.SQUARE_SIZE / 5), -int(Config.SQUARE_SIZE / 5))[2:]))
            screen.blit(sq_surf, sq_surf.get_rect(center=sqrect.center))

    @x.setter
    def x(self, val: int):
        self.pos[0] = val

    @y.setter
    def y(self, val: int):
        self.pos[1] = val

    @property
    def dir_x(self):
        return self.dir[0]

    @property
    def dir_y(self):
        return self.dir[1]

    @property
    def rect(self):
        return pygame.Rect(self.x - Config.SQUARE_SIZE / 2, self.y - Config.SQUARE_SIZE / 2,
                           *([Config.SQUARE_SIZE] * 2))

    def obey_bounce(self, bounce: Bounce):
        # Before updating the last_bounce_time, compute time since last collision
        if self.last_bounce_time != -100:
            self.last_collision_interval = bounce.time - self.last_bounce_time
            # Update heat level
            if Config.HEAT_LEVEL and self.last_collision_interval > 0:
                heat_increase = Config.heat_increase_scale / self.last_collision_interval
                heat_increase = min(heat_increase, Config.max_heat_increase)
                self.heat_level += heat_increase
                self.heat_level = min(self.heat_level, Config.max_heat_level)
        else:
            self.last_collision_interval = None  # First collision, no previous interval

        # Then update last_bounce_time
        self.last_bounce_time = bounce.time
        self.pos = bounce.square_pos.copy()
        self.dir = bounce.square_dir.copy()
        self.latest_bounce_direction = bounce.bounce_dir
        # Start glow effect
        self.time_since_glow_start = pygame.time.get_ticks()
        return

    def update_heat_level(self, dt):
        if Config.HEAT_LEVEL:
            self.heat_level = max(0, self.heat_level - Config.heat_decay_rate * dt)

    def reg_move(self, use_dt: bool = True):
        self.x += self.dir_x * Config.square_speed * (Config.dt if use_dt else 1 / FRAMERATE)
        self.y += self.dir_y * Config.square_speed * (Config.dt if use_dt else 1 / FRAMERATE)

class Camera:
    def __init__(self, x: int = 0, y: int = 0):
        self.x = x
        self.y = y
        self.locked_on_square = True
        self.lock_type: CameraFollow = CameraFollow(Config.camera_mode)

    def attempt_movement(self):
        if not self.locked_on_square:
            keys = pygame.key.get_pressed()
            shift_modifier = (keys[pygame.K_LSHIFT] | keys[pygame.K_RSHIFT]) + 1
            self.x += (keys[pygame.K_d] - keys[pygame.K_a]) * Config.CAMERA_SPEED * shift_modifier / FRAMERATE
            self.y += (keys[pygame.K_s] - keys[pygame.K_w]) * Config.CAMERA_SPEED * shift_modifier / FRAMERATE

    @property
    def pos(self):
        return self.x, self.y

    @pos.setter
    def pos(self, val: Union[tuple[int, int], list[int]]):
        self.x, self.y = val

    def offset(self, pos_or_rect: Union[pygame.Rect, tuple[int, int]]) -> Union[pygame.Rect, list[int]]:
        if isinstance(pos_or_rect, pygame.Rect):
            return pos_or_rect.move(-self.x, -self.y)
        else:
            return [pos_or_rect[0]-self.x, pos_or_rect[1]-self.y]

    def apply_parallax(self, pos: tuple[float, float], depth: float) -> list[float]:
        # Parallax factor: nearer stars move faster than distant ones
        parallax_factor = 0.2 + depth * 0.8  # From 0.2 to 1.0
        screen_x = (pos[0] - self.x) * parallax_factor
        screen_y = (pos[1] - self.y) * parallax_factor
        return [screen_x, screen_y]

    def follow(self, square: Square):

        # Square in center
        if self.lock_type == CameraFollow.Center:
            self.pos = [square.x - Config.SCREEN_WIDTH / 2, square.y - Config.SCREEN_HEIGHT / 2]

        # Smooth camera
        if self.lock_type == CameraFollow.Smoothed:
            easing_rate = 3
            self.x = (square.x - Config.SCREEN_WIDTH / 2) * easing_rate * Config.dt + self.x - easing_rate * self.x * Config.dt
            self.y = (square.y - Config.SCREEN_HEIGHT / 2) * easing_rate * Config.dt + self.y - easing_rate * self.y * Config.dt

class CameraFollow(Enum):
    Center = 0  # Center the square
    Smoothed = 2  # Smoothed camera

class Star:
    def __init__(self, pos: tuple[float, float], depth: float):
        self.initial_pos = list(pos)
        self.depth = depth  # between 0 (far) and 1 (near)
        size_min = 0.5
        size_max = 2
        self.size = size_min + (1 - self.depth) * (size_max - size_min)
        self.phase = random.uniform(0, 2 * math.pi)  # For random phase
        self.brightness = 0  # Will be updated in the update method
        self.color = Config.star_color  # Use star color from Config

    def update(self, time):
        # Adjust brightness over time to create blinking effect
        blink_speed = 10  # can adjust to get desired speed
        brightness_variation = (math.sin(blink_speed * time + self.phase) + 1) / 2  # Normalize between 0 and 1
        min_brightness = 100
        max_brightness = 255
        brightness = min_brightness + brightness_variation * (max_brightness - min_brightness)
        self.color = tuple(min(255, int(c * (brightness / 255))) for c in Config.star_color)  # Adjust color based on brightness

    def get_screen_pos(self, camera: Camera):
        parallax_factor = 0.2 + self.depth * 0.8  # from 0.2 to 1.0
        screen_x = (self.initial_pos[0] - camera.x) * parallax_factor
        screen_y = (self.initial_pos[1] - camera.y) * parallax_factor
        return [screen_x, screen_y]

class Peg:
    glowing_surface_cache = {}
    def __init__(self, rect: pygame.Rect, color: tuple, collision_time: float):
        self.rect = rect
        self.color = color
        self.collision_time = collision_time  # The time when the square is supposed to bounce on this peg
        self.time_since_glow_start = -1000  # For glow effect
        self.visible = False  # Visibility flag

    def update_glow(self, current_time):
        # Update the glow start time
        self.time_since_glow_start = current_time
        self.visible = True  # Set visibility to True after collision

    def compute_glowy_surface(self, rect, val):
        cache_key = (rect.size, val)
        if cache_key in Peg.glowing_surface_cache:
            return Peg.glowing_surface_cache[cache_key]
        glowy_borders = make_glowy2((rect.width + 40, rect.height + 40), Config.peg_glow_color, val)
        surface = pygame.Surface(rect.inflate(100, 100).size, pygame.SRCALPHA)
        surface.blit(glowy_borders, (20, 20), special_flags=pygame.BLEND_RGBA_ADD)
        Peg.glowing_surface_cache[cache_key] = surface
        return surface

    def draw_glow(self, screen, rect):
        if Config.peg_glow:
            current_ticks = pygame.time.get_ticks()
            elapsed_time = (current_ticks - self.time_since_glow_start) / 1000.0
            if elapsed_time < Config.peg_glow_duration:
                progress = 1 - (elapsed_time) / Config.peg_glow_duration
                val = int(progress * Config.peg_glow_intensity)
                val = max(val, Config.peg_min_glow)
                surf = self.compute_glowy_surface(rect, val)
                screen.blit(surf, rect.move(-40, -40).topleft, special_flags=pygame.BLEND_RGBA_ADD)

    def draw(self, screen: pygame.Surface, camera: Camera, current_time: float):
        offsetted = camera.offset(self.rect)
        if screen.get_rect().colliderect(offsetted):
            if self.visible:
                # After collision time, draw the peg and glow effect
                self.draw_glow(screen, offsetted)
                pygame.draw.rect(screen, self.color, offsetted)
            else:
                color = (get_colors()["background"])
                pygame.draw.rect(screen, color, offsetted)
                pass  # Peg remains invisible before collision

class World:
    """It's a cruel world out there"""

    def __init__(self):
        self.future_bounces: list[Bounce] = []
        self.past_bounces: list[Bounce] = []
        self.start_time = 0
        self.time = 0
        self.pegs: list[Peg] = []  # List of Peg objects
        self.particles: list[Particle] = []
        self.stars: list[Star] = []
        self.timestamps = []
        self.square = Square()
        self.safe_areas: list[pygame.Rect] = []

    def update_time(self) -> None:
        self.time = get_current_time() - self.start_time

    def get_next_bounce(self) -> Bounce:
        """Also pops the bounce from the future_bounces list"""
        bounce = self.future_bounces.pop(0)
        self.past_bounces.append(bounce)
        return bounce

    def add_bounce_particles(self, sp: list[float], sd: list[float], color: tuple):
        for _ in range(Config.particle_amount):
            new = Particle([sp[0] + random.randint(-10, 10), sp[1] + random.randint(-10, 10)], sd, color=color)
            self.particles.append(new)

    def handle_bouncing(self, square: Square):
        if len(self.future_bounces):
            if (self.time * 1000 + Config.music_offset)/1000 > self.future_bounces[0].time:
                current_bounce = self.get_next_bounce()
                before = square.dir.copy()
                square.obey_bounce(current_bounce)
                changed = square.dir.copy()
                for _ in range(2):
                    if before[_] == changed[_]:
                        changed[_] = 0
                    else:
                        changed[_] = -changed[_]
                if Config.do_particles_on_bounce:
                    square_color = square.get_current_color()
                    self.add_bounce_particles(square.pos, changed, color=square_color)

                # Stop square at end
                if len(self.future_bounces) == 0:
                    square.dir = [0, 0]
                    square.pos = current_bounce.square_pos

                # Update the corresponding peg's glow
                index = len(self.past_bounces) - 1  # Index of the current bounce
                if index < len(self.pegs):
                    peg = self.pegs[index]
                    peg.update_glow(pygame.time.get_ticks())

    def generate_stars(self):
        self.stars = []
        # Calculate total safe area
        total_safe_area = sum(area.width * area.height for area in self.safe_areas)
        star_density = Config.star_density  # Use star density from Config
        total_num_stars = int(total_safe_area * star_density)
        min_distance_squared = (20) ** 2  # Avoid clustering

        # Get bounding rectangle of all safe areas
        min_x = min(area.left for area in self.safe_areas)
        max_x = max(area.right for area in self.safe_areas)
        min_y = min(area.top for area in self.safe_areas)
        max_y = max(area.bottom for area in self.safe_areas)
        bounding_rect = pygame.Rect(min_x, min_y, max_x - min_x, max_y - min_y)

        stars = []
        attempts = 0
        max_attempts = total_num_stars * 10

        while len(stars) < total_num_stars and attempts < max_attempts:
            x = random.uniform(bounding_rect.left, bounding_rect.right)
            y = random.uniform(bounding_rect.top, bounding_rect.bottom)
            point = (x, y)

            # Ensure point is within safe area
            inside_safe_area = any(area.collidepoint(point) for area in self.safe_areas)

            if inside_safe_area:
                # Ensure minimum distance between stars
                if all((star.initial_pos[0] - x) ** 2 + (star.initial_pos[1] - y) ** 2 >= min_distance_squared for star in stars):
                    depth = random.uniform(0, 1)
                    star = Star((x, y), depth)
                    stars.append(star)
            attempts += 1

        self.stars = stars

    def gen_future_bounces(self, _start_notes: list[float], percent_update_callback):
        """Recursive function with optimized overlap checking"""
        total_notes = len(_start_notes)
        max_percent = 0
        path = []
        safe_areas = []
        force_return = 0

        def recurs(
                square: Square,
                notes: list[float],
                bounces_so_far: list[Bounce] = None,
                prev_index_priority=None,
                t: float = 0,
                depth: int = 0
        ) -> Union[list[Bounce], bool]:
            nonlocal force_return, max_percent
            if prev_index_priority is None:
                prev_index_priority = [0, 1]
            if bounces_so_far is None:
                bounces_so_far = []
            if total_notes:
                gone_through_percent = (total_notes-len(notes)) * 100 // total_notes
                while gone_through_percent > max_percent:
                    max_percent += 1
                    if percent_update_callback(f"{max_percent}% done generating map"):
                        raise UserCancelsLoadingError()

            all_bounce_rects = [_bounc.get_collision_rect() for _bounc in bounces_so_far]
            if len(notes) == 0:
                return bounces_so_far

            path_segment_start = len(path)
            start_rect = square.rect.copy()
            while True:
                t += 1/FRAMERATE
                square.reg_move(False)
                path.append(square.rect)
                if t > notes[0]:
                    # No collision (we good)
                    bounce_indexes = prev_index_priority

                    # Randomly change direction every X% of the time
                    if random.random() * 100 < Config.direction_change_chance:
                        bounce_indexes = list(bounce_indexes.__reversed__())

                    # Add safe area
                    safe_areas.append(start_rect.union(square.rect))

                    for direction_to_bounce in bounce_indexes:
                        square.dir[direction_to_bounce] *= -1
                        bounces_so_far.append(Bounce(square.pos.copy(), square.dir.copy(), t, direction_to_bounce))

                        toextend = recurs(
                            square=square.copy(),
                            notes=notes[1:],
                            bounces_so_far=[_b.copy() for _b in bounces_so_far],
                            t=t,
                            prev_index_priority=bounce_indexes.copy(),
                            depth=depth+1
                        )

                        if toextend:
                            return toextend
                        else:
                            bounces_so_far = bounces_so_far[:-1]
                            square.dir[direction_to_bounce] *= -1

                            # Backtrack if necessary
                            if force_return:
                                force_return -= 1
                                while len(path) != path_segment_start:
                                    path.pop()
                                return False

                            continue
                    while len(path) != path_segment_start:
                        path.pop()
                    return False

                othercheck = False
                if len(bounces_so_far):
                    othercheck = bounces_so_far[-1].get_collision_rect().collidelist(path[:-10])+1

                if square.rect.collidelist(all_bounce_rects) != -1 or othercheck:
                    if depth > 200:
                        if random.random() < Config.backtrack_chance:
                            max_percent -= (Config.backtrack_amount * 100 // total_notes) + 1
                            force_return = Config.backtrack_amount

                    while len(path) != path_segment_start:
                        path.pop()
                    return False

        _start_notes = _start_notes[:Config.max_notes] if Config.max_notes is not None else _start_notes

        self.future_bounces = recurs(
            square=self.square.copy(),
            notes=remove_too_close_values(
                [_sn for _sn in _start_notes],
                threshold=Config.bounce_min_spacing
            )
        )

        if self.future_bounces is False:
            raise MapLoadingFailureError("The map failed to generate because of the recursion function. " +
                                         "If the MIDI has too many notes too close, it may not generate. " +
                                         "Maybe try changing the \"bounce min spacing\", \"square speed\", or \"change dir chance\" in the config.")

        if len(self.future_bounces) == 0:
            raise MapLoadingFailureError("Map safe area list is empty. Please report this issue.")

        percent_update_callback("Merging overlapping safe areas")

        # Merging overlapping safe areas more efficiently
        self.safe_areas = fix_overlap(safe_areas, percent_update_callback)

        # Generate colors for pegs
        def gather_colors(num_colors=20):
            colors = []
            while len(colors) < num_colors:
                new_colors = color_hunt()
                rgb_colors = [tuple(int(hex_color[i:i+2], 16) for i in (1, 3, 5)) for hex_color in new_colors]
                colors.extend(rgb_colors)
            return colors[:num_colors]
        collected_colors = gather_colors()
        # Setting random colors for the generated pegs
        colors = [random.choice(collected_colors) for _ in self.future_bounces]

        if not PEG_REMOVE:
            if PEG_MULTI_COLOR:
                collected_colors = gather_colors()
                # Setting random colors for the generated pegs
                colors = [random.choice(collected_colors) for _ in self.future_bounces]
            elif NO_COLOR:
                colors = [get_colors()["background"] for _ in self.future_bounces]
            else:
                # Use the peg color from get_colors() if peg_multi_color is False
                colors = [get_colors()["peg"] for _ in self.future_bounces]
        else:
            colors = [get_colors()["hallway"] for _ in self.future_bounces]

        # Create pegs
        self.pegs = []
        for i in range(len(self.future_bounces)):
            bounce_rect = self.future_bounces[i].get_collision_rect()
            color = colors[i]
            collision_time = self.future_bounces[i].time
            peg = Peg(bounce_rect, color, collision_time)
            self.pegs.append(peg)

        # Generate stars in safe areas
        if STAR:
            self.generate_stars()

        return self.safe_areas

class Game:
    def __init__(self):
        self.active = False
        self.notes = []
        self.camera = Camera()
        self.world = World()
        self.safe_areas: list[pygame.Rect] = []
        self.music_has_played = False
        self.offset_happened = False

    def start_song(self, screen: pygame.Surface):
        random.seed(Config.seed)

        # Load song and notes
        with open(Config.current_song.fp, 'rb') as f:
            notes = read_midi_file(file=f)
        notes = sorted([note for note in notes])
        self.notes = notes

        # Other settings
        self.world = World()
        self.music_has_played = False
        self.offset_happened = False
        self.camera.lock_type = CameraFollow(Config.camera_mode)
        screen.fill(get_colors()["background"])
        pygame.display.flip()

        def update_loading_screen(message: str):
            screen.fill(get_colors()["background"], pygame.Rect(0, 0, Config.SCREEN_WIDTH, Config.SCREEN_HEIGHT))
            font_size = int(Config.SCREEN_HEIGHT * 0.05)
            loading_text = get_font(font_size).render(message, True, get_colors()["hallway"])
            text_rect = loading_text.get_rect()
            text_rect.center = (Config.SCREEN_WIDTH // 2, Config.SCREEN_HEIGHT // 2)
            screen.blit(loading_text, text_rect)
            pygame.display.flip()

        try:
            self.safe_areas = self.world.gen_future_bounces(self.notes, update_loading_screen)
            # No need to fix overlap here, as it's handled in gen_future_bounces
        except UserCancelsLoadingError:
            return True
        except MapLoadingFailureError as e:
            return e.args[0] if len(e.args) else "Big error... can't load map :("

        self.world.start_time = get_current_time()
        self.world.square.dir = [0, 0]
        if self.world.future_bounces:
            self.world.square.pos = self.world.future_bounces[0].square_pos
        else:
            self.world.square.pos = [Config.SCREEN_WIDTH / 2, Config.SCREEN_HEIGHT / 2]
        return None

    def draw(self, screen: pygame.Surface):
        if not self.active:
            return

        if not self.music_has_played:
            if not self.offset_happened:
                for bnc_change in self.world.future_bounces:
                    bnc_change.time += Config.start_playing_delay / 1000
            self.offset_happened = True
            if self.world.time-Config.music_offset/1000 > Config.start_playing_delay/1000:
                self.music_has_played = True
                song_load_before = get_current_time()
                pygame.mixer.music.play()
                for bnc_change in self.world.future_bounces:
                    bnc_change.time += (get_current_time()-song_load_before)/1000

        screen_rect = screen.get_rect()

        # Set world time
        self.world.update_time()

        # Update heat level
        self.world.square.update_heat_level(Config.dt)

        # Move camera
        self.camera.attempt_movement()

        # Handle square bounces
        self.world.handle_bouncing(self.world.square)

        # Move square
        self.world.square.reg_move()

        # Square in center of camera if locked
        if self.camera.locked_on_square:
            self.camera.follow(self.world.square)

        # Bounce animation
        sqrect = self.camera.offset(self.world.square.rect)
        if (self.world.time - 0.25) + Config.music_offset / 1000 < self.world.square.last_bounce_time:
            lerp = abs((self.world.time - 0.25 + Config.music_offset / 1000) - self.world.square.last_bounce_time) * 5
            lerp = lerp ** 2  # Square it for better-looking interpolation
            if self.world.square.latest_bounce_direction:
                sqrect.inflate_ip((lerp * 5, -10 * lerp))
            else:
                sqrect.inflate_ip((-10 * lerp, lerp * 5))

        # Draw background (walls)
        screen.fill(get_colors()["background"])

        # Create a hallway surface
        hallway_surface = pygame.Surface((Config.SCREEN_WIDTH, Config.SCREEN_HEIGHT), pygame.SRCALPHA)

        # Safe areas
        for safe_area in self.world.safe_areas:
            offsetted = self.camera.offset(safe_area)
            if screen_rect.colliderect(offsetted):
                pygame.draw.rect(hallway_surface, get_colors()["hallway"], offsetted)

        # Obtain current time
        current_time = pygame.time.get_ticks() / 1000.0  # Time in seconds

        # Draw stars onto the hallway surface
        for star in self.world.stars:
            star.update(current_time)  # Update blinking effect
            screen_pos = star.get_screen_pos(self.camera)
            if 0 <= screen_pos[0] < Config.SCREEN_WIDTH and 0 <= screen_pos[1] < Config.SCREEN_HEIGHT:
                # Check if star's position is within the hallway (safe areas)
                if hallway_surface.get_at((int(screen_pos[0]), int(screen_pos[1]))).a != 0:
                    pygame.draw.circle(hallway_surface, star.color, (int(screen_pos[0]), int(screen_pos[1])), int(star.size))

        # Blit the hallway surface onto the main screen
        screen.blit(hallway_surface, (0, 0))

        # Draw pegs
        for peg in self.world.pegs:
            peg.draw(screen, self.camera, self.world.time)

        # Particles
        for particle in self.world.particles:
            pygame.draw.rect(screen, particle.color, self.camera.offset(particle.rect))
        for remove_particle in [particle for particle in self.world.particles if particle.age()]:
            self.world.particles.remove(remove_particle)

        # Particle trail in game
        if Config.particle_trail:
            # Add particles periodically
            if not self.world.square.died:
                if TRAIL_COLOR_BASED_ON_SQUARE:
                    square_color = self.world.square.get_current_color()
                    color = square_color
                else:
                    color = (255, 255, 255)
                new = Particle(self.world.square.pos.copy(), [0, 0], True, color=color)
                new.delta = [random.randint(-2, 2)/20, random.randint(5, 15)/20]
                self.world.particles.append(new)

        # Draw square
        self.world.square.draw(screen, sqrect)

    def handle_event(self, event: pygame.event.Event):
        if not self.active:
            return False

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                pygame.quit()
                sys.exit()
            if event.key == pygame.K_TAB:
                self.camera.locked_on_square = not self.camera.locked_on_square

class InvalidSongError(Exception):
    """The song is invalid somehow"""
    pass

def make_song_from_midi(fpath: str) -> Any:
    new_song = type('Song', (object,), {})()
    new_song.fp = fpath
    new_song.name = os.path.basename(fpath)  # Use filename as song name
    new_song.creator = ''  # Empty creator
    new_song.music_offset = 0
    return new_song

def main():
    pygame.init()
    clock = pygame.time.Clock()
    screen = pygame.display.set_mode((Config.SCREEN_WIDTH, Config.SCREEN_HEIGHT), pygame.DOUBLEBUF | pygame.HWSURFACE)
    pygame.display.set_caption("chubbMidi")
    try:
        pygame.display.set_icon(pygame.image.load(Config.assets).convert_alpha())
    except Exception as e:
        print(e)

    # Specify the song file to use
    selected_song_filepath = join(Config.song, SONG)
    if not isfile(selected_song_filepath):
        print(f"Song file {selected_song_filepath} not found.")
        return

    Config.current_song = make_song_from_midi(selected_song_filepath)

    # Load the music file
    try:
        pygame.mixer.music.load(Config.current_song.fp)
    except Exception as e:
        print(f"Error loading MIDI file as audio: {e}")
        print("Your platform may not support MIDI playback via pygame.mixer.music.")
        print("The game will run without audio.")
        # Uncomment the line below to exit if audio is essential
        # return
    pygame.mixer.music.set_volume(Config.volume / 100)

    # Initialize the game
    game = Game()

    # Start the game
    if msg := game.start_song(screen):
        if isinstance(msg, str):
            print(f"Error starting game: {msg}")
            return
    game.active = True

    running = True
    while running:
        # screen.fill(get_colors()["background"])  # Moved to the draw function
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            game.handle_event(event)

        game.draw(screen)
        pygame.display.flip()
        clock.tick(FRAMERATE)
        Config.dt = clock.get_time() / 1000.0 if clock.get_time() > 0 else 0.016  # Avoid division by zero

    pygame.quit()

if __name__ == '__main__':
    main()
```

This modified script adds the heat level feature as per your requirements, ensuring smooth glow transitions based on the time between collisions, without affecting existing functionalities.

turns-00031.parquet:40465

6547e9c49c7f9d1aa34aabde
turn 1/1gpt-4o-2024-08-06RussianAustralia152 words
degenerate_repetitionAbsentFinal dense release
USER
Assistant: 
User: System: You are an assistant that helps users and speaks Russian.
System: You are an assistant that helps users and speaks Russian.
User: Тебя теперь зовут IRCM
Assistant: Здравствуйте! Как я могу помочь вам сегодня?
User: Как я тебя назвал?
Assistant: Здравствуйте! Вы назвали меня IRCM. Как я могу помочь вам сегодня?
User: Как дела?
Assistant: У меня всё хорошо, спасибо! А как у вас дела? Чем могу помочь?
User: Как ты?
Assistant: Я в порядке, спасибо! А как ты? Чем могу помочь?
User: Как ты?
Assistant: Я в порядке, спасибо! А как ты? Чем могу помочь?
User: как ты?
Assistant: Я в порядке, спасибо! А как у вас дела? Чем могу помочь?
User: Как ты?
Assistant: Я в порядке, спасибо! А как у вас дела? Чем могу помочь?
User: Как ты?
Assistant:
Assistant:
ASSISTANT
Я в порядке, спасибо! Если у вас есть какие-либо вопросы или чем-то могу помочь, дайте знать.