ZH's software thread
Moderator: General Mods
-
- Seen it all
- Posts: 2302
- Joined: Mon Jan 03, 2005 5:04 pm
- Location: Germany
- Contact:
The first line clears the result string.Franky wrote:Also, I don't quite understand that pascal program (never even touched pascal). Could you explain how it works?
Then a "for" loop goes through all characters in HexString, takes the current one and converts it to uppercase. (This becomes the value of c.)
Google an ASCII table; you'll see that 0..9 and A..F are grouped together. If c is not in these two groups, then the user entered an invalid hex. string.
Code: Select all
if (c <= '9') then tmp := Ord(c) - Ord('0')
if (c <= 'F') then tmp := Ord(c) - Ord('A') + 10
vSNES | Delphi 10 BPLs
bsnes launcher with recent files list
bsnes launcher with recent files list
-
- ZSNES Shake Shake Prinny
- Posts: 5632
- Joined: Wed Jul 28, 2004 4:15 pm
- Location: PAL50, dood !
thread hijack lol
So yeah, little polish needed for CLI, but aside from that it's pretty badass.
Credit goes to ardnew for giving me the idea.
Code: Select all
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <math.h>
#define FLAGSIZ uint32_t
#define BITMAX (8*sizeof(FLAGSIZ)+2)
struct pnentry
{
uint32_t val;
uint32_t start;
uint32_t end;
FLAGSIZ flag;
FLAGSIZ used;
struct pnentry *less;
struct pnentry *more;
};
uint32_t c_base = 5, c_digt = 4, c_match = 2;
struct pnentry pnlist;
static void clear_list(struct pnentry *entry)
{
if (entry)
{
clear_list(entry->less);
clear_list(entry->more);
free(entry);
entry = NULL;
}
}
#define ASSIGN(ENTRY) \
if (ENTRY) { add_entry(val, id, ENTRY); } \
else if ((ENTRY = (struct pnentry *)malloc(sizeof(struct pnentry)))) \
{ \
memset(ENTRY, 0, sizeof(struct pnentry)); \
add_entry(val, id, ENTRY); \
} \
else \
{ \
puts("Critical error: couldn't allocate memory for new entry."); \
return (false); \
}
static bool add_entry(const uint32_t val, const uint8_t id, struct pnentry *etr)
{
if (etr->val)
{
if (val < etr->val) { ASSIGN((etr->less)) } // comments are for weenies
else if (val > etr->val) { ASSIGN((etr->more)) }
else { etr->flag |= 1<<id; }
}
else
{
etr->val = val;
etr->start = val/((uint32_t)pow(10,c_digt-c_match));
etr->end = val%((uint32_t)pow(10,c_match));
etr->flag = 1<<id;
etr->used = 0;
etr->less = etr->more = NULL;
}
return (true);
}
static bool build_list(const uint32_t max_base)
{
uint32_t base = 3, num, val;
bool notdone, test = true;
for (; base<=max_base; base++)
{
for (num=0, notdone=true; notdone; num++)
{
val = ((base-2)*num+4-base)*num/2;
if (val>=((uint32_t)pow(10,c_digt))) { notdone = false; }
else if (val>=((uint32_t)pow(10,c_digt-1)))
{ test &= add_entry(val, base-3, &pnlist); }
}
}
return (test);
}
#define DIVE_FURTHER \
test = 1<<(8*sizeof(FLAGSIZ)-1); \
while (test) \
{ \
if ((entry->flag & test) && !((entry->flag & test) & slots)) \
{ \
slots ^= test; \
entry->used = test; \
dive(&pnlist, entry->start, cnt-1); \
if (done) \
{ \
uint8_t mask = 32; \
while (!(entry->used >> --mask)) {} \
printf(">> %u (%u-gon) ", entry->val, mask+3); \
break; \
} \
entry->used = 0; \
slots ^= test; \
} \
test >>= 1; \
}
static bool dive(struct pnentry *entry, const uint32_t cval, const uint32_t cnt)
{
static bool done = false;
static uint32_t last = -1;
static FLAGSIZ slots = 0;
if (cnt)
{
if (!done && entry->less) { dive(entry->less, cval, cnt); }
if (!done && (entry->flag & ~slots) && !entry->used)
{
FLAGSIZ test;
if (!cval)
{
last = entry->end;
DIVE_FURTHER
last = 0;
}
else if (cval == entry->end) { DIVE_FURTHER }
}
if (!done && entry->more) { dive(entry->more, cval, cnt); }
}
else { done = (cval == last); }
return (done);
}
uint32_t set_val(const uint32_t val, const uint32_t min, const uint32_t max)
{
return (((val<min) ? min : (val>max) ? max : val));
}
int main(const int argc, char *argv[])
{
int success = 0;
// TODO: better CL parsing stuff here
if (argc > 1) { c_base = set_val(strtoul(argv[1], NULL, 0), 3, BITMAX); }
if (argc > 2) { c_digt = set_val(strtoul(argv[2], NULL, 0), 2, 9); }
if (argc > 3) { c_match = set_val(strtoul(argv[3], NULL, 0), 1, c_digt-1); }
puts((success = (build_list(c_base) && dive(&pnlist, 0, c_base-2))) ?
"\nSearch ended successfully.\n" : "No cycle found.\n");
clear_list(pnlist.less);
clear_list(pnlist.more);
return (--success);
}
Credit goes to ardnew for giving me the idea.
皆黙って俺について来い!!
Pantheon: Gideon Zhi | CaitSith2 | Nach | kode54
Code: Select all
<jmr> bsnes has the most accurate wiki page but it takes forever to load (or something)
Alright, haven't yet tried using creaothceann's idea of using ASCII numbers to validate my hex input (haven't fully understood it yet, though I've looked at an ASCII table and I'm beginning to understand).
I looked on google and found a function for converting to uppercase (on the following page: http://www.java2s.com/Code/VB/Language- ... erCase.htm). I no longer have, for example, both "Case A" and "Case a"; I just have Case "A". I also don't have "like "[a-f]""; I just have "If hexr like "[A-F]" and hexr like "#""
Here's the new code:
I looked on google and found a function for converting to uppercase (on the following page: http://www.java2s.com/Code/VB/Language- ... erCase.htm). I no longer have, for example, both "Case A" and "Case a"; I just have Case "A". I also don't have "like "[a-f]""; I just have "If hexr like "[A-F]" and hexr like "#""
Here's the new code:
Code: Select all
Module Module1
Private BinaryString, choice, sign, HexString, hexr, bits_string As String
Private digit, bits As Double
Private proceed, inform_4dv As Boolean
Sub Main()
display_options()
Do
digit = 0
BinaryString = ""
Console.Write("?: ")
choice = Console.ReadLine()
Select Case choice
Case "quit"
End
Case "display"
display_options()
Case "hex2dec"
validate_bits()
validate_sign()
validate_HexString()
hex2dec()
Console.WriteLine(digit)
Case "hex2bin"
validate_bits()
validate_HexString()
hex2bin()
Console.WriteLine(BinaryString)
Case ""
Case Else
Console.WriteLine("Invalid option")
End Select
Loop
End Sub
Private Sub validate_bits()
Do
proceed = True
inform_4dv = False
Console.Write("Address space: ")
bits_string = Console.ReadLine()
Try
bits = Convert.ToInt32(bits_string)
Catch ex As Exception
proceed = False
End Try
If proceed = True Then
If bits < 1 Then
ElseIf (bits - (Int(bits))) <> 0 Then
ElseIf ((bits / 4) - Int(bits / 4)) <> 0 Then
inform_4dv = True
Else
Exit Do
End If
End If
Console.WriteLine("Invalid input")
If inform_4dv = True Then
Console.WriteLine("Note: ensure that 4 is a factor of the address space")
End If
Loop
End Sub
Private Sub validate_sign()
Do
Console.Write("Signed or unsigned: ")
sign = Console.ReadLine()
If sign = "signed" Or sign = "unsigned" Then
Exit Do
End If
Console.WriteLine("Invalid input")
Loop
End Sub
Private Sub validate_HexString()
Do
proceed = True
Console.Write("Hex: ")
HexString = Console.ReadLine()
If HexString = "" Then
proceed = False
Else
HexString = HexString.ToUpper()
For pos = 1 To HexString.Length Step 1
hexr = Mid(HexString, pos, 1)
If hexr Like "[A-F]" Or hexr Like "#" Then
Else
proceed = False
Exit For
End If
Next
End If
If proceed = True Then
If (HexString.Length * 4) < (bits + 1) Then
Exit Do
End If
End If
Console.WriteLine("Invalid input")
Loop
End Sub
Private Sub hex2dec()
hex2bin()
For pos = BinaryString.Length To 1 Step -1
If Mid(BinaryString, pos, 1) = "1" Then
digit = ((2 ^ (BinaryString.Length - pos)) + digit)
End If
Next
If sign = "signed" And BinaryString.Length = bits And (Mid(BinaryString, 1, 1)) = "1" Then
digit = (digit - (2 ^ bits))
End If
End Sub
Private Sub hex2bin()
For pos = 1 To HexString.Length Step 1
Select Case Mid(HexString, pos, 1)
Case "0"
BinaryString = BinaryString + "0000"
Case "1"
BinaryString = BinaryString + "0001"
Case "2"
BinaryString = BinaryString + "0010"
Case "3"
BinaryString = BinaryString + "0011"
Case "4"
BinaryString = BinaryString + "0100"
Case "5"
BinaryString = BinaryString + "0101"
Case "6"
BinaryString = BinaryString + "0110"
Case "7"
BinaryString = BinaryString + "0111"
Case "8"
BinaryString = BinaryString + "1000"
Case "9"
BinaryString = BinaryString + "1001"
Case "A"
BinaryString = BinaryString + "1010"
Case "B"
BinaryString = BinaryString + "1011"
Case "C"
BinaryString = BinaryString + "1100"
Case "D"
BinaryString = BinaryString + "1101"
Case "E"
BinaryString = BinaryString + "1110"
Case "F"
BinaryString = BinaryString + "1111"
End Select
Next
End Sub
Private Sub display_options()
Console.WriteLine("hex2dec - Hexadecimal to decimal conversion")
Console.WriteLine("hex2bin - Hexadecimal to binary conversion")
Console.WriteLine("display - display options")
Console.WriteLine("quit - exit this program")
End Sub
End Module
Alright, got bored and decided to write a (somewhat cliche) bubble sorter:

Code: Select all
Module Module1
Private digit(20), mem As Integer
Private proceed As Boolean
Sub Main()
Do
generate_numbers()
Console.WriteLine("numbers generated:")
show_numbers()
Console.ReadLine()
bubble()
Console.Write("sorted")
Console.ReadLine()
For pos = 1 To 5 Step 1
Console.WriteLine()
Next
Loop
End Sub
Private Sub generate_numbers()
Randomize()
For pos = 1 To 20 Step 1
digit(pos - 1) = Int(Rnd() * 75)
Next
End Sub
Private Sub show_numbers()
For pos = 1 To 20 Step 1
If pos = 20 Then
Console.WriteLine(digit(pos - 1).ToString)
Else
Console.Write(digit(pos - 1).ToString + ", ")
End If
Next
End Sub
Private Sub bubble()
Do
proceed = True
For pos = 1 To 19 Step 1
If digit(pos - 1) > digit(pos) Then
mem = digit(pos - 1)
digit(pos - 1) = digit(pos)
digit(pos) = mem
System.Threading.Thread.Sleep(75)
show_numbers()
End If
Next
For pos = 1 To 19 Step 1
If digit(pos - 1) > digit(pos) Then
proceed = False
Exit For
End If
Next
If proceed = True Then
Exit Do
End If
Loop
End Sub
End Module

-
- Seen it all
- Posts: 2302
- Joined: Mon Jan 03, 2005 5:04 pm
- Location: Germany
- Contact:
Why don't you use indices starting at zero?Code: Select all
For pos = 1 To 20 Step 1 digit(pos - 1) = Int(Rnd() * 75) Next
vSNES | Delphi 10 BPLs
bsnes launcher with recent files list
bsnes launcher with recent files list
Umm, well I don't fully understand that question, but rnd() will give something like 0.129, 0.894, etc (betwen 0 and 1). Let's say I do the integer of (rnd() *10), it will be between 0 and 10, or I * it by 75 instead of 10 it'll be between 0 and 75. Just saves time really.creaothceann wrote:Why don't you use indices starting at zero?Code: Select all
For pos = 1 To 20 Step 1 digit(pos - 1) = Int(Rnd() * 75) Next
-
- Seen it all
- Posts: 2302
- Joined: Mon Jan 03, 2005 5:04 pm
- Location: Germany
- Contact:
No, the for-loop indices.
http://en.wikipedia.org/wiki/Index_(inf ... echnology)
You're using 1..20 for pos, then always subtract 1. Would be easier to just use 0..19.
http://en.wikipedia.org/wiki/Index_(inf ... echnology)
You're using 1..20 for pos, then always subtract 1. Would be easier to just use 0..19.
vSNES | Delphi 10 BPLs
bsnes launcher with recent files list
bsnes launcher with recent files list
ok, guys. Had some really great fun; I decided to sit down and create my own (imaginary) programming language syntax. Compare the following to my isbn13-validator:
What do you think?
Not like I can compile that and run it. If I ever go l33t and create a new programming language, the syntax will look somewhat like this
I call this language zzit
Code: Select all
g standard\
g str isbn\
g int digits(13),pos,total,check\
p init()>
out:"ISBN-13 Validation"\
lp
.sp validate_isbn13()\
.sp calculate_check()\
.sp validation_results()\
/re
\p
sp validate_isbn13()>
lp
.outnl:"?: "\
.in:isbn\
.? isbn "quit"
./off /?
isbn "" /?
isbn s "#############"
.\.lp\ ?/
out:"Invalid input"\
\?
/re
\sp
sp calculate_check()>
.total := 0
mv pos 2; 2 up 12
.digits(pos - 2) := int32(p>pos-1,1 .isbn)\
.digits(pos - 1) := int32(p,pos,1 .isbn)\
.digits(pos - 1) := digits(pos-1) * 3\
.total := total + digits(pos-1) + digits(pos-2)\
/n
.digits(12) = int32(p>13,1 .isbn)\
.check = (10 - (total %10)) %10\
\sp
sp validation_results()>
? check ! digits(12)
.out:"Invalid ISBN-13 number"\ ?/
.out:"Valid ISBN-13 number"\
\?
\sp
Not like I can compile that and run it. If I ever go l33t and create a new programming language, the syntax will look somewhat like this

I call this language zzit
-
- ZNES Developer
- Posts: 215
- Joined: Mon Aug 02, 2004 11:22 pm
Wow, that, my friend, is worse than this.
Code: Select all
g standard\
p init()>
.out:"Hello World"\
in::\
\p
Code: Select all
g standard\
g str BinaryString,choice,sign,HexString,hexr,bits_string
g dbl digit,bits
g bool proceed,inform_4dv
p init()>
.sp display_options()\
lp
.digit 0\
.BinaryString ""\
.outnl:"?: "\
.in:choice\
.lowc(choice)\
cs choice
? "quit">
.sp display_options()\
? "display">
.sp validate_bits()\
.sp validate_sign()\
.sp validate_HexString()\
.sp hex2dec()\
.out:digit\
? "hex2bin">
.sp validate_bits()\
.sp validate_HexString()\
.sp hex2bin()
.out:BinaryString\
? ""
/?
.out:"Invalid option"\
\cs
/re
\p
sp validate_bits()
lp
.proceed true\
.inform_4dv true\
.outnl:"Address Space: "\
.in:bits_string\
?t bits int32(bits_string) >
!c proceed false\
? proceed true
? bits < 1
/? bits - .Int|bits ! 0
/? bits(/4) - .Int|bits(/4) ! 0
.inform_4dv true\
/? \.lp
\?
out:"Invalid input"\
? inform_4dv true
.out:"Address space must be divisable by 4"\
\?
/re
\sp

EDIT: Actually, here's zbinc (at least, the hex2dec and hex2bin one that I've posted recently) written completely in zzit:
Code: Select all
g standard\
g str BinaryString,choice,sign,HexString,hexr,bits_string
g dbl digit,bits
g bool proceed,inform_4dv
p init()>
.sp display_options()\
lp
.digit 0\
.BinaryString ""\
.outnl:"?: "\
.in:choice\
.lowc(choice)\
cs choice
? "quit">
.sp display_options()\
? "display">
.sp validate_bits()\
.sp validate_sign()\
.sp validate_HexString()\
.sp hex2dec()\
.out:digit\
? "hex2bin">
.sp validate_bits()\
.sp validate_HexString()\
.sp hex2bin()
.out:BinaryString\
? ""
/?
.out:"Invalid option"\
\cs
/re
\p
sp validate_bits()>
lp
.proceed true\
.inform_4dv true\
.outnl:"Address Space: "\
.in:bits_string\
?t bits int32(bits_string) >
!c proceed false\
? proceed true
? bits < 1
/? bits - .Int|bits ! 0
/? bits(/4) - .Int|bits(/4) ! 0
.inform_4dv true\
/? \.lp
\?
out:"Invalid input"\
? inform_4dv true
.out:"Address space must be divisable by 4"\
\?
/re
\sp
sp validate_sign()>
lp
.proceed true\
.outnl:"Sign: "\
.in:sign\
.lowc(sign)\
? sign "signed" | "unsigned">
\.lp
\?
.out:"Invalid input"\
/re
\sp
sp validate_HexString()>
lp
.proceed true\
.outnl:"Hex: "\
.in:HexString\
? HexString ""
.proceed false\
/?
.highc|HexString\
mv pos 1; 1 up .Length|HexString
.hexr .p; pos, 1: HexString\
? hexr s "A" up "F" | "#"
/? .proceed false\
\.mv
\?
/n
\?
? proceed true
? .length|HexString(/4) < bits(+1)
\.lp
\?
\?
.out:"Invalid input"\
/re
\sp
sp hex2dec()>
.sp hex2bin()\
mv 1; .Length|BinaryString down 1
? "1" .p; pos, 1: BinaryString
.digit := 2(^.Length|BinaryString(-pos)) +digit\
\?
.hexr .p; 1,1: BinaryString
? sign "signed" and .Length|BinaryString := bits and hexr "1"
.digit := digit - 2(^bits)\
\?
/n
\sp
sp hex2bin()
mv pos 1; 1 up .Length|HexString
cs .p; pos,1: HexString
? "0"
.BinaryString = BinaryString + "0000"\
? "1"
.BinaryString = BinaryString + "0001"\
? "2"
.BinaryString = BinaryString + "0010"\
? "3"
.BinaryString = BinaryString + "0011"\
? "4"
.BinaryString = BinaryString + "0100"\
? "5"
.BinaryString = BinaryString + "0101"\
? "6"
.BinaryString = BinaryString + "0110"\
? "7"
.BinaryString = BinaryString + "0111"\
? "8"
.BinaryString = BinaryString + "1000"\
? "9"
.BinaryString = BinaryString + "1001"\
? "A"
.BinaryString = BinaryString + "1010"\
? "B"
.BinaryString = BinaryString + "1011"\
? "C"
.BinaryString = BinaryString + "1100"\
? "D"
.BinaryString = BinaryString + "1101"\
? "E"
.BinaryString = BinaryString + "1110"\
? "F"
.BinaryString = BinaryString + "1111"\
\cs
/n
\sp
sp display_options()>
.out:"Commands available:"\
.out:"hex2dec - Hexadecimal to decimal conversion"\
.out:"hex2bin - Hexadecimal to binary conversion"\
.out:"display - display options"\
.out:"quit - exit this program"\
\sp
Last edited by ZH/Franky on Tue Nov 25, 2008 12:26 am, edited 1 time in total.
-
- Trooper
- Posts: 387
- Joined: Fri Jul 30, 2004 6:25 am
- Location: Mexico
- Contact:
Well, I actually enjoy its Smallfuck variant, if only for this little app.DOLLS (J) [!] wrote:Wow, that, my friend, is worse than this.
_-|-_
-
- ZSNES Shake Shake Prinny
- Posts: 5632
- Joined: Wed Jul 28, 2004 4:15 pm
- Location: PAL50, dood !
brainfuck isn't half as tough as malbolge to program with
皆黙って俺について来い!!
Pantheon: Gideon Zhi | CaitSith2 | Nach | kode54
Code: Select all
<jmr> bsnes has the most accurate wiki page but it takes forever to load (or something)
-
- ZNES Developer
- Posts: 215
- Joined: Mon Aug 02, 2004 11:22 pm
Ooooh.MisterJones wrote:Well, I actually enjoy its Smallfuck variant, if only for this little app.
Try doing that and you'll see what happens. Though, I think we all know what happens.gllt wrote:Can you make a program that properly divides by zero?
My calculator says "math error". Tell me people, how (and/or where) the fuck would you actually start in order to divide a number by zero.
Quite interesting really. Does 0/0 equal 1 or 0? I say 0.
-
- ZSNES Shake Shake Prinny
- Posts: 5632
- Joined: Wed Jul 28, 2004 4:15 pm
- Location: PAL50, dood !
1/0 and anything non 0 divided by 0 equals infinity, it's as simple as that.
positive/0 is +inf and negative/0 is -inf.
0/0 depends heavily on what produced each 0.
for example the (in?)famous lim[x->0] (sin x)/x == 1
obviously x/x (and many other funcs) equals 1 when x->0 too
obviously n*x/x (and many other funcs) equals n when x->0 too
so 0/0 can be anything really
positive/0 is +inf and negative/0 is -inf.
0/0 depends heavily on what produced each 0.
for example the (in?)famous lim[x->0] (sin x)/x == 1
obviously x/x (and many other funcs) equals 1 when x->0 too
obviously n*x/x (and many other funcs) equals n when x->0 too
so 0/0 can be anything really
皆黙って俺について来い!!
Pantheon: Gideon Zhi | CaitSith2 | Nach | kode54
Code: Select all
<jmr> bsnes has the most accurate wiki page but it takes forever to load (or something)
GET OUT OF MY HEAD, ABOMINATIONgrinvader wrote:1/0 and anything non 0 divided by 0 equals infinity, it's as simple as that.
positive/0 is +inf and negative/0 is -inf.
0/0 depends heavily on what produced each 0.
for example the (in?)famous lim[x->0] (sin x)/x == 1
obviously x/x (and many other funcs) equals 1 when x->0 too
obviously n*x/x (and many other funcs) equals n when x->0 too
so 0/0 can be anything really
-
- Inmate
- Posts: 1751
- Joined: Mon Dec 06, 2004 7:47 am
- Location: WA
this is interesting.funkyass wrote:you are getting ahead of yourself here.
after reading the first two pages again, that's pretty much been the theme of this thread.
exception handling was thrown out pretty quick, while he was still grasping some basics. unless recursion is the devil, nobody bothered to mention that factorials are like 3 lines of C++ using recursion instead of the paragraphs he was posting. but exception handling, which is kind of advanced, was thrown out immediately.
the only reason i even mention it just because i'm starting to teach myself a little c++ using www.learncpp.com and one of my cousin's books.
the website doesn't cover error handling until chapter 15 or so, and the book certainly doesn't cover it in the first few chapters.
and if anyone's curious, i'm only at the level of having two integers input by the user, then multiplying them or something. really basic stuff. i tried some reading on exception handling, and i'm just not ready for that yet. i do like #define, though
[img]http://i26.photobucket.com/albums/c128/sweener2001/StewieSIGPIC.png[/img]
-
- Seen it all
- Posts: 2302
- Joined: Mon Jan 03, 2005 5:04 pm
- Location: Germany
- Contact:
I don't know, can you use try..finally blocks in C++? Because that's about the only thing I've been using so far when dealing with exceptions - try..except seems a bit useless in practise.
vSNES | Delphi 10 BPLs
bsnes launcher with recent files list
bsnes launcher with recent files list
-
- ZSNES Shake Shake Prinny
- Posts: 5632
- Joined: Wed Jul 28, 2004 4:15 pm
- Location: PAL50, dood !
Learning how to make short code can wait.sweener2001 wrote:exception handling was thrown out pretty quick, while he was still grasping some basics. unless recursion is the devil, nobody bothered to mention that factorials are like 3 lines of C++ using recursion instead of the paragraphs he was posting. but exception handling, which is kind of advanced, was thrown out immediately.
Learning how to make good code is prioritary.
Once you have coded stuff without any user-input validation for 5 years, you're reluctant to start adding that tedious (yet essential) part of code, and you end up writing stuff like all those proggies with buffer overflow exploits and whatnots.
Better learn early to do the tiring stuff so you're used to it and code/check for it automatically.
Writing clean and short can wait, since you'll eventually be interested in that and will (should) naturally improve over time.
皆黙って俺について来い!!
Pantheon: Gideon Zhi | CaitSith2 | Nach | kode54
Code: Select all
<jmr> bsnes has the most accurate wiki page but it takes forever to load (or something)