macxq / foxess-ha

Home Assistant & FoxESS integration. Monitor you photovoltaic installation directly from HA ☀️ ⚡️
115 stars 37 forks source link

No Values! #206

Closed muhkuh666 closed 6 months ago

muhkuh666 commented 9 months ago

Hello,

is someone else expecting no values with the up to date HA Foxess?

Maesch1992 commented 9 months ago

I think about that -> https://www.youtube.com/watch?v=jRTE9UZkpHU But I understand that maybe it was off from my inverter. Yes?

This is the ModBus integration. The only way to get your inverter data into HA now.

But i dont work with the new Firmware right? Because Ethernet is deactivated. I got the foxess smart lan dongle. But it doesnt shows IP Adress or Mac adress in Inverter or Router.

ModBUS still works fine. The LAN port on the inverter doesn't work with newer firmware. I don't know what the smart LAN dongle is.

This one here :https://www.shop.menloelectric.com/de/foxess/1038-foxess-smart-lan-30.html

niallcook commented 9 months ago

I think about that -> https://www.youtube.com/watch?v=jRTE9UZkpHU But I understand that maybe it was off from my inverter. Yes?

This is the ModBus integration. The only way to get your inverter data into HA now.

But i dont work with the new Firmware right? Because Ethernet is deactivated. I got the foxess smart lan dongle. But it doesnt shows IP Adress or Mac adress in Inverter or Router.

ModBUS still works fine. The LAN port on the inverter doesn't work with newer firmware. I don't know what the smart LAN dongle is.

This one here :https://www.shop.menloelectric.com/de/foxess/1038-foxess-smart-lan-30.html

Not familiar with it, but looks like that just sends inverter data to the Fox Cloud platform. Doubt you'd be able to get any data directly from that into HA. ModBus is still the only viable solution for HA integration, unless Fox reverse the changes they made last night.

mhzawadi commented 9 months ago

@macxq needs to make contact with Craig Wollaston at FoxESS UK so that he can be added to the list of developers who need access to the cloud API. I have contact details if he needs them, but Craig has posted on the FoxESS Solar/Battery Owners Group on Facebook. Nothing end users can do at this point.

@macxq How do I find them on FB? I dont use FB much and cant seem to find the group, could they post something on Lemmy?

-> https://lemmy.horwood.cloud/c/foxessinverter

manuelsirianni commented 9 months ago

Please, take all of us updated with outcomes. I have no modbus but only a usb to Wi-Fi That can’t be handled directly.

thanks!

Golempl commented 9 months ago

Anyone know if there is any chance to obtain data from WIFI logger ? There is open web service on it.

pkudlins commented 9 months ago

in aplication and especially in web view there is option to see detail status of inverter / volts , power generated etc ... / could someone find what is url to call this / I tried but cant find exact url ...

arn1s-m commented 9 months ago

in aplication and especially in web view there is option to see detail status of inverter / volts , power generated etc ... / could someone find what is url to call this / I tried but cant find exact url ...

It's https://www.foxesscloud.com/c/v0/device/history/raw - but you need to be authenticated to see data. Authentication is the root problem of all this. This integration was getting the data from there too

kamyk commented 9 months ago

QQ: is it possible by that ModBus integration to see a value by WIFI in HA for example? I see IP address and a Foxess local webpage, but no idea if I can see a value there. I will check but maybe somebody already know? Best

Bishbosh02 commented 9 months ago

QQ: is it possible by that ModBus integration to see a value by WIFI in HA for example? I see IP address and a Foxess local webpage, but no idea if I can see a value there. I will check but maybe somebody already know? Best

How did you get the local IP address, my router is not showing the unit or its got a odd name in the DHCP table.......

kamyk commented 9 months ago

QQ: is it possible by that ModBus integration to see a value by WIFI in HA for example? I see IP address and a Foxess local webpage, but no idea if I can see a value there. I will check but maybe somebody already know? Best

How did you get the local IP address, my router is not showing the unit or its got a odd name in the DHCP table.......

I have seen an Adapter wifi SSID. I have connect there and have check. You can always try to search for MAC address. But I don't see any data yet or never. I will check next hours.

Screenshot 2023-12-21 at 10 32 00
Maesch1992 commented 9 months ago

QQ: is it possible by that ModBus integration to see a value by WIFI in HA for example? I see IP address and a Foxess local webpage, but no idea if I can see a value there. I will check but maybe somebody already know? Best

How did you get the local IP address, my router is not showing the unit or its got a odd name in the DHCP table.......

Same issue. See no Mac address, IP address or something else. So I don't know how to connect to modbus. I hope the cloud integration will be fixed soon

arn1s-m commented 9 months ago

QQ: is it possible by that ModBus integration to see a value by WIFI in HA for example? I see IP address and a Foxess local webpage, but no idea if I can see a value there. I will check but maybe somebody already know? Best

local page allows only to insert Wifi details for it to connect and upgrade firmware. Data isn't exposed there

kamyk commented 9 months ago

Why?! :) It will be so great to see that data by local page. That will fix all issues and not need any Modbus converter. Maybe some day.

snaiperr commented 9 months ago

Why?! :) It will be so great to see that data by local page. That will fix all issues and not need any Modbus converter. Maybe some day.

They are selling these data, access from local network possibly could block data to cloud.

I have requested numerous time from the foxess support to provide data and address list for the sensors for rs485 protocol - they have never replied to me.

Now I see two options:

  1. parse web data from cloud such as "web user" without api
  2. replace foxess cloud with the local service "cloud" - I see in the router that inverter sends data each 15 second to foxesscloud port 10001, thus we just need to replace their host with our own(dnsmasq easily helps us with this)

Boycott to foxess as this very unacceptable step from them

kamyk commented 9 months ago

Why?! :) It will be so great to see that data by local page. That will fix all issues and not need any Modbus converter. Maybe some day.

They are selling these data, access from local network possibly could block data to cloud.

I have requested numerous time from the foxess support to provide data and address list for the sensors for rs485 protocol - they have never replied to me.

Now I see two options:

  1. parse web data from cloud such as "web user" without api
  2. replace foxess cloud with the local service "cloud" - I see in the router that inverter sends data each 15 second to foxesscloud port 10001, thus we just need to replace their host with our own(dnsmasq easily helps us with this)

Boycott to foxess as this very unacceptable step from them

Have you tried that already? I see you already checked a port.

Best,

johannessteu commented 9 months ago

Should we really discuss configurations etc. here now? Let's please keep the topic of this thread to the actual authentication issue. Otherwise it's hard to follow the actual issue/solution here

MartinBlackburn commented 9 months ago

From a little more poking around. Calls to get the raw data (https://www.foxesscloud.com/c/v0/device/history/raw) need to be auth by three headers:

The signature is needed to obtain the token via the login call - which is the source of all the problems. The signature seems to be generated by this file: https://www.foxesscloud.com/js/signature.js, which does use a wasm file from here: https://www.foxesscloud.com/js/signature.wasm

Without much more reading on wasm and how it works, I'm hitting a bit of a wall. I also don't know python well enough to know if the wasm can be used with it.

Hopefully, this will help someone get a little further.

johannessteu commented 9 months ago

How the signature itself is generated is described in their API. I also posted it already here: https://github.com/macxq/foxess-ha/issues/206#issuecomment-1864124756

The main issue here is that you do need a secret/key to generate the very first call to authenticate. Not sure if we're able to 1) find a token everyone could use 2) this is a legal think at all to bypass their protections

MartinBlackburn commented 9 months ago

With that official API being limited to 20 calls a day, I was wondering how their website works

Their signature header differs and doesn't need an API key... It looks to be built up of two parts (begin_signature and end_signature)

I'm looking at the JS files and network traffic, so see what I can work out

johannessteu commented 9 months ago

Couldn't they have API-Keys that can bypass this limit?

Golempl commented 9 months ago

Website added signature and timestamp. Simple method of authentication stoped working because they check is signature match timestamp. To find out method to generate signature need spend some time to decompile and analyze JS and WASM components of webpage. Can reverse enginner it, however it may not be permanent because they may change it anytime they want. Webpage is using unlimited version of API for providing data. Let's hope manufacturer understand customers need and won't cripple functionality after product is sold. This change need be reverted or API needs remove limitations.

canton7 commented 9 months ago

I have requested numerous time from the foxess support to provide data and address list for the sensors for rs485 protocol - they have never replied to me.

@snaiperr We have all of this figured out at https://github.com/nathanmarlor/foxess_modbus. See the wiki for the protocol docs.

Golempl commented 9 months ago

I have workaround. But this is ridiculous way, running separate VM which keeps chrome running and refresh webpage with result saved to location available for Linux VM. That's huge waste of resources.

canton7 commented 9 months ago

It looks like the signature's been figured out: https://github.com/TonyM1958/FoxESS-Cloud/issues/3 . It also looks like FoxESS are reverting the change shortly, followed by a migration period to the new API.

macxq commented 9 months ago

@MartinBlackburn @Golempl indeed, heres decoded to c version of signature.wasm
I have used wasm-decompile. Looks quite complicated and not so easy to translate to python 🤦‍♂️


global g_a:int = 5245776;

export table indirect_function_table:funcref(min: 2, max: 2);

data d_02x0X0xllusrnsrnsrnsnullxjVp(offset: 1024) =
  "%02x\00-+   0X0x\00%llu\00%s\r\n%s\r\n%s\r\n%s\00(null)\00x\a4j\d7V\b7"
  "\c7\e8\dbp $\ee\ce\bd\c1\af\0f|\f5*\c6\87G\13F0\a8\01\95F\fd\d8\98\80i"
  "\af\f7D\8b\b1[\ff\ff\be\d7\\89"\11\90k\93q\98\fd\8eCy\a6!\08\b4Ib%\1e\f6"
  "@\b3@\c0QZ^&\aa\c7\b6\e9]\10/\d6S\14D\02\81\e6\a1\d8\c8\fb\d3\e7\e6\cd"
  "\e1!\d6\077\c3\87\0d\d5\f4\ed\14ZE\05\e9\e3\a9\f8\a3\ef\fc\d9\02og\8aL"
  "*\8dB9\fa\ff\81\f6q\87"a\9dm\0c8\e5\fdD\ea\be\a4\a9\cf\deK`K\bb\f6p\bc"
  "\bf\be\c6~\9b(\fa'\a1\ea\850\ef\d4\05\1d\88\049\d0\d4\d9\e5\99\db\e6\f8"
  "|\a2\1feV\ac\c4D")\f4\97\ff*C\a7#\94\ab9\a0\93\fc\c3Y[e\92\cc\0c\8f}\f4"
  "\ef\ff\d1]\84\85O~\a8o\e0\e6,\fe\14C\01\a3\a1\11\08N\82~S\f75\f2:\bd\bb"
  "\d2\d7*\91\d3\86\eb\07\00\00\00\0c\00\00\00\11\00\00\00\16\00\00\00\07"
  "\00\00\00\0c\00\00\00\11\00\00\00\16\00\00\00\07\00\00\00\0c\00\00\00\11"
  "\00\00\00\16\00\00\00\07\00\00\00\0c\00\00\00\11\00\00\00\16\00\00\00\05"
  "\00\00\00\09\00\00\00\0e\00\00\00\14\00\00\00\05\00\00\00\09\00\00\00\0e"
  "\00\00\00\14\00\00\00\05\00\00\00\09\00\00\00\0e\00\00\00\14\00\00\00\05"
  "\00\00\00\09\00\00\00\0e\00\00\00\14\00\00\00\04\00\00\00\0b\00\00\00\10"
  "\00\00\00\17\00\00\00\04\00\00\00\0b\00\00\00\10\00\00\00\17\00\00\00\04"
  "\00\00\00\0b\00\00\00\10\00\00\00\17\00\00\00\04\00\00\00\0b\00\00\00\10"
  "\00\00\00\17\00\00\00\06\00\00\00\0a\00\00\00\0f\00\00\00\15\00\00\00\06"
  "\00\00\00\0a\00\00\00\0f\00\00\00\15\00\00\00\06\00\00\00\0a\00\00\00\0f"
  "\00\00\00\15\00\00\00\06\00\00\00\0a\00\00\00\0f\00\00\00\15\00\00\00\19"
  "\00\0a\00\19\19\19\00\00\00\00\05\00\00\00\00\00\00\09\00\00\00\00\0b\00"
  "\00\00\00\00\00\00\00\19\00\11\0a\19\19\19\03\0a\07\00\01\00\09\0b\18\00"
  "\00\09\06\0b\00\00\0b\00\06\19\00\00\00\19\19\19";
data d_b(offset: 1665) =
  "\0e\00\00\00\00\00\00\00\00\19\00\0a\0d\19\19\19\00\0d\00\00\02\00\09\0e"
  "\00\00\00\09\00\0e\00\00\0e";
data d_c(offset: 1723) = "\0c";
data d_d(offset: 1735) =
"\13\00\00\00\00\13\00\00\00\00\09\0c\00\00\00\00\00\0c\00\00\0c";
data d_e(offset: 1781) = "\10";
data d_f(offset: 1793) =
"\0f\00\00\00\04\0f\00\00\00\00\09\10\00\00\00\00\00\10\00\00\10";
data d_g(offset: 1839) = "\12";
data d_h(offset: 1851) =
  "\11\00\00\00\00\11\00\00\00\00\09\12\00\00\00\00\00\12\00\00\12\00\00\1a"
  "\00\00\00\1a\1a\1a";
data d_i(offset: 1906) =
"\1a\00\00\00\1a\1a\1a\00\00\00\00\00\00\09";
data d_j(offset: 1955) = "\14";
data d_k(offset: 1967) =
"\17\00\00\00\00\17\00\00\00\00\09\14\00\00\00\00\00\14\00\00\14";
data d_l(offset: 2013) = "\16";
data d_0123456789ABCDEF(offset: 2025) =
  "\15\00\00\00\00\15\00\00\00\00\09\16\00\00\00\00\00\16\00\00\16\00\000"
  "123456789ABCDEF";
data d_n(offset: 2100) = "\01";
data d_o(offset: 2140) = "\ff\ff\ff\ff\ff\ff\ff\ff";
data d_p(offset: 2208) = "\14\04\00\00P\0bP";

import function env_emscripten_memcpy_big(a:int, b:int, c:int):int;

import function env_emscripten_resize_heap(a:int):int;

import function env_setTempRet0(a:int);

export function wasm_call_ctors() {
  2364[0]:int = 2252;
  2292[0]:int = 42;
}

export function begin_signature(a:int, b:int, c:int, d:int):int {
  var m:int;
  var q:int;
  var p:int;
  var e:int = g_a - 1104;
  g_a = e;
  var n:{ a:long, b:long, c:long, d:long } = f_u(1076);
  n.d = 0L;
  n.c = 0L;
  n.b = 0L;
  n.a = 0L;
  f_g(e + 80, 0, 1024);
  e[8]:int = a;
  e[9]:int = b;
  e[10]:int = c;
  e[11]:int = d;
  f_h(e + 80, d_p[0]:int, e + 32);
  var h:int = e + 80;
  a = f_j(e + 80);
  var g:{ a:byte, b:byte, c:byte, d:byte, e:byte, f:byte, g:byte, h:byte, i:byte, j:byte, k:byte, l:byte, m:byte, n:byte, o:byte, p:byte } = 
    e + 48;
  var r:int = g_a + -64;
  g_a = r;
  b = a + 1;
  var f:int = b;
  loop L_a {
    m = f;
    f = m + 1;
    if ((m & 63) != 56) continue L_a;
  }
  var o:int = f_f(f_u(m + 8), h, a);
  (o + a)[0]:byte = 128;
  if (b < m) { f_g(b + o, 0, m + (a ^ -1)) }
  f = m + o;
  f[4]:byte = a >> 29;
  f[3]:byte = a >> 21;
  f[2]:byte = a >> 13;
  f[1]:byte = a >> 5;
  f[0]:byte = a << 3;
  f[7]:byte = 0;
  f[5]:short@1 = 0;
  var i:int = -271733879;
  var j:int = -1732584194;
  var k:int = 271733878;
  var l:int = 1732584193;
  loop L_c {
    b = o + q;
    f = 0;
    loop L_d {
      (r + (a = f << 2))[0]:int = (a + b)[0]:int;
      f = f + 1;
      if (f != 16) continue L_d;
    }
    f = 0;
    c = k;
    a = j;
    d = i;
    b = l;
    loop L_e {
      var s:int = b;
      h = a;
      b = c;
      a = d;
      d = a +
          ((r +
            ({
               if (f <= 15) {
                 d = (b & (a ^ -1)) | (a & h);
                 f;
                 goto B_f;
               }
               if (f <= 31) {
                 d = (a & b) | (h & (b ^ -1));
                 f * 5 + 1 & 15;
                 goto B_f;
               }
               if (f <= 47) {
                 d = (a ^ h) ^ b;
                 f * 3 + 5 & 15;
                 goto B_f;
               }
               d = (a | (b ^ -1)) ^ h;
               f * 7 & 15;
               label B_f:
             } <<
             2))[0]:int +
           d + s + ((d = f << 2) + 1072)[0]:int <<
           (d + 1328)[0]:int);
      c = h;
      f = f + 1;
      if (f != 64) continue L_e;
    }
    k = h + k;
    j = a + j;
    i = d + i;
    l = b + l;
    q = q - -64;
    if (q < m) continue L_c;
  }
  f_v(o);
  g.p = k >> 24;
  g.o = k >> 16;
  g.n = k >> 8;
  g.m = k;
  g.l = j >> 24;
  g.k = j >> 16;
  g.j = j >> 8;
  g.i = j;
  g.h = i >> 24;
  g.g = i >> 16;
  g.f = i >> 8;
  g.e = i;
  g.d = l >> 24;
  g.c = l >> 16;
  g.b = l >> 8;
  g.a = l;
  g_a = r - -64;
  loop L_j {
    e[9]:long = 0L;
    e[4]:int = (e + 48 + p)[0]:ubyte;
    f_h(e + 72, 1024, e + 16);
    d = f_i(n, e + 72);
    p = p + 1;
    if (p != 16) continue L_j;
  }
  (f_j(d) + d)[0]:short@1 = 46;
  e[0]:long = i64_extend_i32_u(d);
  e[9]:long = 0L;
  f_h(e + 72, 1039, e);
  p = f_i(d, e + 72);
  f_f(p + 52, e + 80, f_j(e + 80));
  g_a = e + 1104;
  return p;
}

function f_f(a:int, b:int, c:int):int {
  var f:int;
  var e:int;
  if (c >= 512) {
    env_emscripten_memcpy_big(a, b, c);
    return a;
  }
  var d:int = a + c;
  if (eqz((a ^ b) & 3)) {
    if (eqz(a & 3)) {
      c = a;
      goto B_d;
    }
    if (eqz(c)) {
      c = a;
      goto B_d;
    }
    c = a;
    loop L_g {
      c[0]:byte = b[0]:ubyte;
      b = b + 1;
      c = c + 1;
      if (eqz(c & 3)) goto B_d;
      if (c < d) continue L_g;
    }
    label B_d:
    e = d & -4;
    if (e < 64) goto B_h;
    if (c > (f = e + -64)) goto B_h;
    loop L_i {
      c[0]:int = b[0]:int;
      c[1]:int = b[1]:int;
      c[2]:int = b[2]:int;
      c[3]:int = b[3]:int;
      c[4]:int = b[4]:int;
      c[5]:int = b[5]:int;
      c[6]:int = b[6]:int;
      c[7]:int = b[7]:int;
      c[8]:int = b[8]:int;
      c[9]:int = b[9]:int;
      c[10]:int = b[10]:int;
      c[11]:int = b[11]:int;
      c[12]:int = b[12]:int;
      c[13]:int = b[13]:int;
      c[14]:int = b[14]:int;
      c[15]:int = b[15]:int;
      b = b - -64;
      c = c - -64;
      if (c <= f) continue L_i;
    }
    label B_h:
    if (c >= e) goto B_b;
    loop L_j {
      c[0]:int = b[0]:int;
      b = b + 4;
      c = c + 4;
      if (c < e) continue L_j;
    }
    goto B_b;
  }
  if (d < 4) {
    c = a;
    goto B_b;
  }
  if (a > (e = d - 4)) {
    c = a;
    goto B_b;
  }
  c = a;
  loop L_m {
    c[0]:byte = b[0]:ubyte;
    c[1]:byte = b[1]:ubyte;
    c[2]:byte = b[2]:ubyte;
    c[3]:byte = b[3]:ubyte;
    b = b + 4;
    c = c + 4;
    if (c <= e) continue L_m;
  }
  label B_b:
  if (c < d) {
    loop L_o {
      c[0]:byte = b[0]:ubyte;
      b = b + 1;
      c = c + 1;
      if (c != d) continue L_o;
    }
  }
  return a;
}

function f_g(a:{ a:byte, b:byte, c:byte, d:byte }, b:{ a:long, b:long, c:long, d:long }, c:int) {
  var e:int;
  if (eqz(c)) goto B_a;
  a.a = b;
  var d:{ a:int, b:int, c:int, d:int, e:int, f:int, g:int } = a + c;
  (d - 1)[0]:byte = b;
  if (c < 3) goto B_a;
  a.c = b;
  a.b = b;
  (d - 3)[0]:byte = b;
  (d - 2)[0]:byte = b;
  if (c < 7) goto B_a;
  a.d = b;
  (d - 4)[0]:byte = b;
  if (c < 9) goto B_a;
  d = a + (e = 0 - a & 3);
  d.a = (b = (b & 255) * 16843009);
  c = d + (e = c - e & -4);
  (c - 4)[0]:int = b;
  if (e < 9) goto B_a;
  d.c = b;
  d.b = b;
  (c - 8)[0]:int = b;
  (c - 12)[0]:int = b;
  if (e < 25) goto B_a;
  d.g = b;
  d.f = b;
  d.e = b;
  d.d = b;
  (c - 16)[0]:int = b;
  (c - 20)[0]:int = b;
  (c - 24)[0]:int = b;
  (c - 28)[0]:int = b;
  c = e - (e = (d & 4) | 24);
  if (c < 32) goto B_a;
  var f:long = i64_extend_i32_u(b) * 4294967297L;
  b = d + e;
  loop L_b {
    b.d = f;
    b.c = f;
    b.b = f;
    b.a = f;
    b = b + 32;
    c = c - 32;
    if (c > 31) continue L_b;
  }
  label B_a:
}

function f_h(a:int, b:int, c:int) {
  var f:int;
  var g:int;
  var h:int_ptr = g_a - 16;
  g_a = h;
  h[3] = c;
  var e:int_ptr = g_a - 160;
  g_a = e;
  f_f(e + 8, 2064, 144);
  e[13] = a;
  e[7] = a;
  e[14] = (f = select_if(f = -2 - a, 2147483647, f < 2147483647));
  e[9] = (a = a + f);
  e[6] = a;
  a = e + 8;
  var d:int_ptr = g_a - 208;
  g_a = d;
  d[51] = c;
  f_g(d + 160, 0, 40);
  d[50] = d[51];
  if (f_n(0, b, d + 200, d + 80, d + 160) < 0) goto B_a;
  var j:int = a[19]:int >= 0;
  var i:int = a[0]:int;
  if (a[18]:int <= 0) { a[0]:int = i & -33 }
  c = {
        if (eqz(a[12]:int)) {
          a[12]:int = 80;
          a[7]:int = 0;
          a[2]:long = 0L;
          g = a[11]:int;
          a[11]:int = d;
          goto B_e;
        }
        if (a[4]:int) goto B_d;
        label B_e:
        -1;
        if (f_l(a)) goto B_c;
        label B_d:
        f_n(a, b, d + 200, d + 80, d + 160);
        label B_c:
      }
  b = i & 32;
  if (g) {
    call_indirect(a, 0, 0, a[9]:int);
    a[12]:int = 0;
    a[11]:int = g;
    a[7]:int = 0;
    a[5]:int;
    a[2]:long = 0L;
    0;
  } else {
    c
  }
  a[0]:int = a[0]:int | b;
  if (eqz(j)) goto B_a;
  label B_a:
  g_a = d + 208;
  if (f) {
    f = e[7];
    (f - (f == e[6]))[0]:byte = 0;
  }
  g_a = e + 160;
  g_a = h + 16;
}

function f_i(a:int, b:int):int {
  var d:int;
  var c:int;
  if ((b ^ (d = f_j(a) + a)) & 3) goto B_b;
  if (b & 3) {
    loop L_d {
      d[0]:byte = (c = b[0]:ubyte);
      if (eqz(c)) goto B_a;
      d = d + 1;
      b = b + 1;
      if (b & 3) continue L_d;
    }
  }
  c = b[0]:int;
  if (((c ^ -1) & c - 16843009) & -2139062144) goto B_b;
  loop L_e {
    d[0]:int = c;
    c = b[1]:int;
    d = d + 4;
    b = b + 4;
    if (eqz((c - 16843009 & (c ^ -1)) & -2139062144)) continue L_e;
  }
  label B_b:
  d[0]:byte = (c = b[0]:ubyte);
  if (eqz(c)) goto B_a;
  loop L_f {
    d[1]:byte = (c = b[1]:ubyte);
    d = d + 1;
    b = b + 1;
    if (c) continue L_f;
  }
  label B_a:
  return a;
}

function f_j(a:int):int {
  var d:int;
  var c:int;
  var b:ubyte_ptr = a;
  if (a & 3) {
    loop L_c {
      if (eqz(b[0])) goto B_a;
      b = b + 1;
      if (b & 3) continue L_c;
    }
  }
  loop L_d {
    c = b;
    b = c + 4;
    d = c[0]:int;
    if (eqz(((d ^ -1) & d - 16843009) & -2139062144)) continue L_d;
  }
  if (eqz(d & 255)) { return c - a }
  loop L_f {
    d = c[1]:ubyte;
    b = c + 1;
    c = b;
    if (d) continue L_f;
  }
  label B_a:
  return b - a;
}

export function errno_location():int {
  return 2216
}

function f_l(a:int):int {
  var b:int;
  a[18]:int = (b = a[18]:int) - 1 | b;
  b = a[0]:int;
  if (b & 8) {
    a[0]:int = b | 32;
    return -1;
  }
  a[1]:long@4 = 0L;
  a[7]:int = (b = a[11]:int);
  a[5]:int = b;
  a[4]:int = b + a[12]:int;
  return 0;
}

function f_m(a:int):int {
  return a - 48 < 10
}

function f_n(a:int, b:int, c:int_ptr, d:int, e:int):int {
  var l:int;
  var g:int;
  var h:int;
  var q:int;
  var n:int;
  var t:int;
  var w:long;
  var x:long;
  var p:ubyte_ptr;
  var i:int;
  var m:int;
  var k:int_ptr;
  var r:int;
  var f:int = g_a - 80;
  g_a = f;
  f[19]:int = b;
  var v:int = f + 55;
  var s:int = f + 56;
  b = 0;
  loop L_e {
    if (b > 2147483647 - l) goto B_d;
    l = b + l;
    var j:ubyte_ptr = f[19]:int;
    b = j;
    k = j[0];
    if (k) {
      loop L_j {
        k = k & 255;
        if (eqz(k)) {
          k = b;
          goto B_l;
        }
        if (k != 37) goto B_k;
        k = b;
        loop L_n {
          if (b[1]:ubyte != 37) goto B_l;
          f[19]:int = (g = b + 2);
          k = k + 1;
          h = b[2]:ubyte;
          b = g;
          if (h == 37) continue L_n;
        }
        label B_l:
        b = k - j;
        if (b > (k = 2147483647 - l)) goto B_d;
        if (a) { f_o(a, j, b) }
        if (b) continue L_e;
        r = -1;
        g = 1;
        h = f_m((f[19]:int)[1]:byte);
        b = f[19]:int;
        if (eqz(h)) goto B_p;
        if (b[2]:ubyte != 36) goto B_p;
        r = b[1]:byte - 48;
        t = 1;
        g = 3;
        label B_p:
        f[19]:int = (b = b + g);
        m = 0;
        q = b[0]:byte;
        h = q - 32;
        if (h > 31) {
          g = b;
          goto B_q;
        }
        g = b;
        h = 1 << h;
        if (eqz(h & 75913)) goto B_q;
        loop L_s {
          f[19]:int = (g = b + 1);
          m = h | m;
          q = b[1]:byte;
          h = q - 32;
          if (h >= 32) goto B_q;
          b = g;
          h = 1 << h;
          if (h & 75913) continue L_s;
        }
        label B_q:
        if (q == 42) {
          f[19]:int =
            (b = {
                   if (eqz(f_m(g[1]:byte))) goto B_w;
                   if ((g = f[19]:int)[2]:ubyte != 36) goto B_w;
                   ((g[1]:byte << 2) + e - 192)[0]:int = 10;
                   n = ((g[1]:byte << 3) + d - 384)[0]:int;
                   t = 1;
                   g + 3;
                   goto B_v;
                   label B_w:
                   if (t) goto B_h;
                   t = 0;
                   n = 0;
                   if (a) {
                     c[0] = (b = c[0]) + 4;
                     n = b[0]:int;
                   }
                   f[19]:int + 1;
                   label B_v:
                 });
          if (n >= 0) goto B_t;
          n = 0 - n;
          m = m | 8192;
          goto B_t;
        }
        n = f_p(f + 76);
        if (n < 0) goto B_d;
        b = f[19]:int;
        label B_t:
        g = 0;
        i = -1;
        var u:int = 
          {
            0;
            if (b[0]:ubyte != 46) goto B_y;
            if (b[1]:ubyte == 42) {
              f[19]:int =
                (b = {
                       if (eqz(f_m(b[2]:byte))) goto B_ba;
                       if ((h = f[19]:int)[3]:ubyte != 36) goto B_ba;
                       ((h[2]:byte << 2) + e - 192)[0]:int = 10;
                       i = ((h[2]:byte << 3) + d - 384)[0]:int;
                       h + 4;
                       goto B_aa;
                       label B_ba:
                       if (t) goto B_h;
                       i = if (a) {
                             c[0] = (b = c[0]) + 4;
                             b[0]:int;
                           } else {
                             0
                           }
                       f[19]:int + 2;
                       label B_aa:
                     });
              (i ^ -1) >> 31;
              goto B_y;
            }
            f[19]:int = b + 1;
            i = f_p(f + 76);
            b = f[19]:int;
            1;
            label B_y:
          }
        loop L_da {
          h = g;
          p = 28;
          if (b[0]:byte - 123 < -58) goto B_c;
          f[19]:int = (q = b + 1);
          g = b[0]:byte;
          b = q;
          g = (g + h * 58 + 1519)[0]:ubyte;
          if (g - 1 < 8) continue L_da;
        }
        if (g != 27) {
          if (eqz(g)) goto B_c;
          if (r >= 0) {
            e[r]:int = g;
            f[8]:long = d[r]:long;
            goto B_fa;
          }
          if (eqz(a)) goto B_f;
          f_q(f - -64, g, c);
          q = f[19]:int;
          goto B_ea;
        }
        if (r >= 0) goto B_c;
        label B_fa:
        b = 0;
        if (eqz(a)) continue L_e;
        label B_ea:
        var o:byte_ptr = m & -65537;
        g = select_if(o, m, m & 8192);
        m = 0;
        r = 1029;
        p = s;
        k = 
          {
            r = 
              {
                b = (q - 1)[0]:byte;
                b = select_if(select_if(b & -33, b, (b & 15) == 3), b, h);
                br_table[B_ta, B_g, B_g, B_g, B_g, B_g, B_g, B_g, B_g, B_ja, B_g, B_ia, B_ra, B_ja, B_ja, B_ja, B_g, B_ra, B_g, B_g, B_g, B_g, B_va, B_sa, B_ua, B_g, B_g, B_oa, B_g, B_wa, B_g, B_g, B_ta, ..B_xa](
                  b - 88);
                label B_xa:
                br_table[B_ja, B_g, B_ma, B_g, B_ja, B_ja, B_ja, ..B_ya](b - 65)
                label B_ya:
                if (b == 83) goto B_na;
                goto B_g;
                label B_wa:
                w = f[8]:long;
                1029;
                goto B_qa;
                label B_va:
                b = 0;
                br_table[B_fb, B_eb, B_db, B_cb, B_bb, L_e, B_ab, B_za, ..L_e](
                  h & 255)
                label B_fb:
                (f[16]:int)[0]:int = l;
                continue L_e;
                label B_eb:
                (f[16]:int)[0]:int = l;
                continue L_e;
                label B_db:
                (f[16]:int)[0]:long = i64_extend_i32_s(l);
                continue L_e;
                label B_cb:
                (f[16]:int)[0]:short = l;
                continue L_e;
                label B_bb:
                (f[16]:int)[0]:byte = l;
                continue L_e;
                label B_ab:
                (f[16]:int)[0]:int = l;
                continue L_e;
                label B_za:
                (f[16]:int)[0]:long = i64_extend_i32_s(l);
                continue L_e;
                label B_ua:
                i = select_if(i, 8, i > 8);
                g = g | 8;
                b = 120;
                label B_ta:
                o = s;
                h = b & 32;
                w = f[8]:long;
                if (eqz(eqz(w))) {
                  loop L_hb {
                    o = o - 1;
                    o[0] = ((i32_wrap_i64(w) & 15) + 2048)[0]:ubyte | h;
                    j = w > 15L;
                    w = w >> 4L;
                    if (j) continue L_hb;
                  }
                }
                j = o;
                if (eqz(f[8]:long)) goto B_pa;
                if (eqz(g & 8)) goto B_pa;
                r = (b >> 4) + 1029;
                m = 2;
                goto B_pa;
                label B_sa:
                b = s;
                w = f[8]:long;
                if (eqz(eqz(w))) {
                  loop L_jb {
                    b = b - 1;
                    b[0]:byte = (i32_wrap_i64(w) & 7) | 48;
                    o = w > 7L;
                    w = w >> 3L;
                    if (o) continue L_jb;
                  }
                }
                j = b;
                if (eqz(g & 8)) goto B_pa;
                i = select_if(i, (b = s - j) + 1, b < i);
                goto B_pa;
                label B_ra:
                w = f[8]:long;
                if (w < 0L) {
                  f[8]:long = (w = 0L - w);
                  m = 1;
                  1029;
                  goto B_qa;
                }
                if (g & 2048) {
                  m = 1;
                  1030;
                  goto B_qa;
                }
                select_if(1031, 1029, m = g & 1);
                label B_qa:
              }
            o = s;
            if (w < 4294967296L) {
              x = w;
              goto B_mb;
            }
            loop L_ob {
              o = o - 1;
              o[0] = i32_wrap_i64(w - (x = w / 10L) * 10L) | 48;
              b = w > 42949672959L;
              w = x;
              if (b) continue L_ob;
            }
            label B_mb:
            b = i32_wrap_i64(x);
            if (b) {
              loop L_qb {
                o = o - 1;
                o[0] = b - (j = b / 10) * 10 | 48;
                h = b > 9;
                b = j;
                if (h) continue L_qb;
              }
            }
            j = o;
            label B_pa:
            if (select_if(u, 0, i < 0)) goto B_d;
            g = select_if(g & -65537, g, u);
            w = f[8]:long;
            if (w != 0L) goto B_rb;
            if (i) goto B_rb;
            j = s;
            p = j;
            i = 0;
            goto B_g;
            label B_rb:
            i = select_if(i, b = eqz(w) + s - j, b < i);
            goto B_g;
            label B_oa:
            b = {
                  p = select_if(2147483647, i, i < 0);
                  g = p;
                  h = g != 0;
                  b = f[16]:int;
                  j = select_if(b, 1065, b);
                  b = j;
                  if (eqz(b & 3)) goto B_vb;
                  if (eqz(g)) goto B_vb;
                  loop L_wb {
                    if (eqz(b[0]:ubyte)) goto B_ub;
                    g = g - 1;
                    h = g != 0;
                    b = b + 1;
                    if (eqz(b & 3)) goto B_vb;
                    if (g) continue L_wb;
                  }
                  label B_vb:
                  if (eqz(h)) goto B_tb;
                  label B_ub:
                  if (eqz(b[0]:ubyte)) goto B_xb;
                  if (g < 4) goto B_xb;
                  loop L_yb {
                    h = b[0]:int;
                    if (((h ^ -1) & h - 16843009) & -2139062144) goto B_xb;
                    b = b + 4;
                    g = g - 4;
                    if (g > 3) continue L_yb;
                  }
                  label B_xb:
                  if (eqz(g)) goto B_tb;
                  loop L_zb {
                    b;
                    if (eqz(b[0]:ubyte)) goto B_sb;
                    b = b + 1;
                    g = g - 1;
                    if (g) continue L_zb;
                  }
                  label B_tb:
                  0;
                  label B_sb:
                }
            b = select_if(b - j, p, b);
            p = b + j;
            if (i >= 0) {
              g = o;
              i = b;
              goto B_g;
            }
            g = o;
            i = b;
            if (p[0]) goto B_d;
            goto B_g;
            label B_na:
            if (i) {
              f[16]:int;
              goto B_la;
            }
            b = 0;
            f_r(a, 32, n, 0, g);
            goto B_ka;
            label B_ma:
            f[3]:int = 0;
            f[2]:int = f[8]:long;
            f[16]:int = f + 8;
            i = -1;
            f + 8;
            label B_la:
          }
        b = 0;
        loop L_dc {
          h = k[0];
          if (eqz(h)) goto B_cc;
          h = f(f + 4, h);
          j = h < 0;
          if (j) goto B_ec;
          if (h > i - b) goto B_ec;
          k = k + 4;
          if (i > (b = b + h)) continue L_dc;
          goto B_cc;
          label B_ec:
        }
        if (j) goto B_b;
        label B_cc:
        p = 61;
        if (b < 0) goto B_c;
        f_r(a, 32, n, b, g);
        if (eqz(b)) {
          b = 0;
          goto B_ka;
        }
        h = 0;
        k = f[16]:int;
        loop L_gc {
          j = k[0];
          if (eqz(j)) goto B_ka;
          j = f(f + 4, j);
          h = j + h;
          if (h > b) goto B_ka;
          f_o(a, f + 4, j);
          k = k + 4;
          if (b > h) continue L_gc;
        }
        label B_ka:
        f_r(a, 32, n, b, g ^ 8192);
        b = select_if(n, b, b < n);
        continue L_e;
        label B_ja:
        if (select_if(u, 0, i < 0)) goto B_d;
        p = 61;
        b = call_indirect(a, f[8]:double, n, i, g, b, 0);
        if (b >= 0) continue L_e;
        goto B_c;
        label B_ia:
        f[55]:byte = f[8]:long;
        i = 1;
        j = v;
        g = o;
        goto B_g;
        label B_k:
        f[19]:int = (g = b + 1);
        k = b[1]:ubyte;
        b = g;
        continue L_j;
      }
      unreachable;
    }
    if (a) goto B_a;
    if (eqz(t)) goto B_f;
    b = 1;
    loop L_hc {
      k = e[b]:int;
      if (k) {
        f_q(d + (b << 3), k, c);
        l = 1;
        b = b + 1;
        if (b != 10) continue L_hc;
        goto B_a;
      }
    }
    l = 1;
    if (b >= 10) goto B_a;
    loop L_jc {
      if (e[b]:int) goto B_h;
      b = b + 1;
      if (b != 10) continue L_jc;
    }
    goto B_a;
    label B_h:
    p = 28;
    goto B_c;
    label B_g:
    q = p - j;
    i = select_if(q, i, i < q);
    if (i > 2147483647 - m) goto B_d;
    p = 61;
    h = i + m;
    b = select_if(h, n, h > n);
    if (b > k) goto B_c;
    f_r(a, 32, b, h, g);
    f_o(a, r, m);
    f_r(a, 48, b, h, g ^ 65536);
    f_r(a, 48, i, q, 0);
    f_o(a, j, q);
    f_r(a, 32, b, h, g ^ 8192);
    continue L_e;
    label B_f:
  }
  l = 0;
  goto B_a;
  label B_d:
  p = 61;
  label B_c:
  2216[0]:int = p;
  label B_b:
  l = -1;
  label B_a:
  g_a = f + 80;
  return l;
}

function f_o(a:ubyte_ptr, b:int, c:int) {
  var d:int_ptr;
  var e:int;
  var f:int;
  if (eqz(a[0] & 32)) {
    if (c >
        if (e = (d = a)[4]) {
          e
        } else {
          if (f_l(d)) goto B_b;
          d[4];
        } -
        (f = d[5])) {
      call_indirect(d, b, c, d[9]);
      goto B_b;
    }
    if (d[20] < 0) goto B_e;
    a = c;
    loop L_f {
      e = a;
      if (eqz(e)) goto B_e;
      if ((b + (a = e - 1))[0]:ubyte != 10) continue L_f;
    }
    if (call_indirect(d, b, e, d[9]) < e) goto B_b;
    b = b + e;
    c = c - e;
    f = d[5];
    label B_e:
    f_f(f, b, c);
    d[5] = d[5] + c;
    label B_b:
  }
}

function f_p(a:int_ptr):int {
  var c:int;
  var b:int;
  if (eqz(f_m((a[0])[0]:byte))) { return 0 }
  loop L_b {
    var d:{ a:byte, b:byte } = a[0];
    b = -1;
    if (c <= 214748364) {
      b = select_if(-1, (b = d.a - 48) + (c = c * 10), b > 2147483647 - c)
    }
    a[0] = d + 1;
    c = b;
    if (f_m(d.b)) continue L_b;
  }
  return b;
}

function f_q(a:int, b:int, c:int_ptr) {
  br_table[B_s, B_r, B_q, B_n, B_p, B_o, B_m, B_l, B_k, B_j, B_i, B_h, B_g, B_f, B_e, B_d, B_c, B_b, ..B_a](
    b - 9)
  label B_s:
  c[0] = (b = c[0]) + 4;
  a[0]:int = b[0]:int;
  return ;
  label B_r:
  c[0] = (b = c[0]) + 4;
  a[0]:long = b[0]:int;
  return ;
  label B_q:
  c[0] = (b = c[0]) + 4;
  a[0]:long = b[0]:uint;
  return ;
  label B_p:
  c[0] = (b = c[0]) + 4;
  a[0]:long = b[0]:int;
  return ;
  label B_o:
  c[0] = (b = c[0]) + 4;
  a[0]:long = b[0]:uint;
  return ;
  label B_n:
  c[0] = (b = c[0] + 7 & -8) + 8;
  a[0]:long = b[0]:long;
  return ;
  label B_m:
  c[0] = (b = c[0]) + 4;
  a[0]:long = b[0]:short;
  return ;
  label B_l:
  c[0] = (b = c[0]) + 4;
  a[0]:long = b[0]:ushort;
  return ;
  label B_k:
  c[0] = (b = c[0]) + 4;
  a[0]:long = b[0]:byte;
  return ;
  label B_j:
  c[0] = (b = c[0]) + 4;
  a[0]:long = b[0]:ubyte;
  return ;
  label B_i:
  c[0] = (b = c[0] + 7 & -8) + 8;
  a[0]:long = b[0]:long;
  return ;
  label B_h:
  c[0] = (b = c[0]) + 4;
  a[0]:long = b[0]:uint;
  return ;
  label B_g:
  c[0] = (b = c[0] + 7 & -8) + 8;
  a[0]:long = b[0]:long;
  return ;
  label B_f:
  c[0] = (b = c[0] + 7 & -8) + 8;
  a[0]:long = b[0]:long;
  return ;
  label B_e:
  c[0] = (b = c[0]) + 4;
  a[0]:long = b[0]:int;
  return ;
  label B_d:
  c[0] = (b = c[0]) + 4;
  a[0]:long = b[0]:uint;
  return ;
  label B_c:
  c[0] = (b = c[0] + 7 & -8) + 8;
  a[0]:double = b[0]:double;
  return ;
  label B_b:
  call_indirect(a, c, 0);
  label B_a:
}

function f_r(a:int, b:int, c:int, d:int, e:int) {
  var f:int = g_a - 256;
  g_a = f;
  if (c <= d) goto B_a;
  if (e & 73728) goto B_a;
  f_g(f, b & 255, select_if(c = c - d, 256, d = c < 256));
  if (eqz(d)) {
    loop L_c {
      f_o(a, f, 256);
      c = c - 256;
      if (c > 255) continue L_c;
    }
  }
  f_o(a, f, c);
  label B_a:
  g_a = f + 256;
}

function f_s(a:int_ptr, b:int, c:int):int {
  var g:int;
  var e:byte_ptr;
  var d:{ a:int, b:int } = a[21];
  var f:int = d.b;
  e = select_if(f, e = a[5] - (g = a[7]), e > f);
  if (e) {
    f_f(d.a, g, e);
    d.a = d.a + e;
    d.b = (f = d.b - e);
  }
  e = d.a;
  f = select_if(f, c, c > f);
  if (f) {
    f_f(e, b, f);
    d.a = (e = d.a + f);
    d.b = d.b - f;
  }
  e[0] = 0;
  a[7] = (d = a[11]);
  a[5] = d;
  return c;
}

function f(a:{ a:byte, b:byte, c:byte, d:byte }, b:int):int {
  if (eqz(a)) { return 0 }
  return {
           if (a) {
             if (b <= 127) goto B_c;
             if (eqz((2364[0]:int)[0]:int)) {
               if ((b & -128) == 57216) goto B_c;
               2216[0]:int = 25;
               goto B_e;
             }
             if (b <= 2047) {
               a.b = (b & 63) | 128;
               a.a = b >> 6 | 192;
               2;
               goto B_b;
             }
             if (eqz((b & -8192) != 57344 & b >= 55296)) {
               a.c = (b & 63) | 128;
               a.a = b >> 12 | 224;
               a.b = (b >> 6 & 63) | 128;
               3;
               goto B_b;
             }
             if (b - 65536 <= 1048575) {
               a.d = (b & 63) | 128;
               a.a = b >> 18 | 240;
               a.c = (b >> 6 & 63) | 128;
               a.b = (b >> 12 & 63) | 128;
               4;
               goto B_b;
             }
             2216[0]:int = 25;
             label B_e:
             -1;
           } else {
             1
           }
           goto B_b;
           label B_c:
           a.a = b;
           1;
           label B_b:
         }
}

function f_u(a:int):int {
  var f:int;
  var b:int;
  var h:int_ptr;
  var d:{ a:int, b:int, c:int, d:int, e:int, f:int }
  var c:{ a:int, b:int, c:int, d:int, e:int, f:int, g:int, h:int }
  var e:int;
  var i:{ a:int, b:int }
  var g:{ a:int, b:int, c:int, d:int, e:int, f:int, g:int, h:int }
  var j:int_ptr;
  var k:int_ptr;
  var l:int = g_a - 16;
  g_a = l;
  b = 
    {
      if (a <= 244) {
        g = 2388[0]:int;
        a = g >> (b = (f = select_if(16, a + 11 & -8, a < 11)) >> 3);
        if (a & 3) {
          d = ((a ^ -1) & 1) + b;
          c = d << 3;
          b = (c + 2436)[0]:int;
          a = b + 8;
          f = b[2]:int;
          if (f == (c = c + 2428)) {
            2388[0]:int = g & -2 << d;
            goto B_r;
          }
          f[3]:int = c;
          c.c = f;
          label B_r:
          b[1]:int = (d = d << 3) | 3;
          b = b + d;
          b[1]:int = b[1]:int | 1;
          goto B_a;
        }
        if (f <= (h = 2396[0]:int)) goto B_j;
        if (a) {
          a = a << b & ((a = 2 << b) | 0 - a);
          a = (a & 0 - a) - 1;
          b = a >> (a = a >> 12 & 16);
          d = b >> 5 & 8;
          d = 
            ((((d | a) | (b = (a = b >> d) >> 2 & 4)) | (b = (a = a >> b) >> 1 & 2)) |
             (b = (a = a >> b) >> 1 & 1)) +
            (a >> b);
          c = d << 3;
          b = (c + 2436)[0]:int;
          a = b[2]:int;
          if (a == (c = c + 2428)) {
            2388[0]:int = (g = g & -2 << d);
            goto B_u;
          }
          a[3]:int = c;
          c.c = a;
          label B_u:
          a = b + 8;
          b[1]:int = f | 3;
          c = b + f;
          c.b = (d = (e = d << 3) - f) | 1;
          (b + e)[0]:int = d;
          if (h) {
            e = h >> 3;
            f = (e << 3) + 2428;
            b = 2408[0]:int;
            e = {
                  if (eqz(g & (e = 1 << e))) {
                    2388[0]:int = e | g;
                    f;
                    goto B_x;
                  }
                  f[2]:int;
                  label B_x:
                }
            f[2]:int = b;
            e[3]:int = b;
            b[3]:int = f;
            b[2]:int = e;
          }
          2408[0]:int = c;
          2396[0]:int = d;
          goto B_a;
        }
        j = 2392[0]:int;
        if (eqz(j)) goto B_j;
        a = (j & 0 - j) - 1;
        b = a >> (a = a >> 12 & 16);
        d = b >> 5 & 8;
        c = 
          ((((((d | a) | (b = (a = b >> d) >> 2 & 4)) | (b = (a = a >> b) >> 1 & 2)) |
             (b = (a = a >> b) >> 1 & 1)) +
            (a >> b) <<
            2) +
           2692)[0]:int;
        b = (c.b & -8) - f;
        d = c;
        loop L_z {
          a = d.e;
          if (eqz(a)) {
            a = d.f;
            if (eqz(a)) goto B_aa;
          }
          d = (a[1]:int & -8) - f;
          b = select_if(d, b, d = b > d);
          c = select_if(a, c, d);
          d = a;
          continue L_z;
          label B_aa:
        }
        k = c.g;
        if (c != (e = c.d)) {
          a = c.c;
          a < 2404[0]:int;
          a[3]:int = e;
          e[2]:int = a;
          goto B_b;
        }
        d = c + 20;
        a = d.a;
        if (eqz(a)) {
          a = c.e;
          if (eqz(a)) goto B_o;
          d = c + 16;
        }
        loop L_ea {
          i = d;
          e = a;
          d = e + 20;
          a = d.a;
          if (a) continue L_ea;
          d = e + 16;
          a = e[4]:int;
          if (a) continue L_ea;
        }
        i.a = 0;
        goto B_b;
      }
      f = -1;
      if (a > -65) goto B_j;
      a = a + 11;
      f = a & -8;
      i = 2392[0]:int;
      if (eqz(i)) goto B_j;
      d = 0 - f;
      c = 
        f <<
        {
          if (f >= 256) {
            if (f <= 16777215) {
              if (
                b = 
                  (((c = ((a = (((c = (b = (a = a >> 8) << (a = a + 1048320 >> 16 & 8)) <<
                                      (b = b + 520192 >> 16 & 4)) <<
                                 (c = c + 245760 >> 16 & 2)) >>
                                15) -
                               ((a | b) | c)) <<
                          1 |
                          (f >> a + 21 & 1)) +
                         28) <<
                    2) +
                   2692)[0]:int) goto B_ha;
              goto B_n;
            }
            h = 31;
            a = 0;
            if (b = 2816[0]:int) goto B_fa;
            c = 31;
            0;
            goto B_m;
          }
          if (eqz(b = 2692[0]:int)) goto B_n;
          goto B_ga;
          label B_ha:
          h = 31;
          0;
          if (c == 31) goto B_fa;
          label B_ga:
          h = c;
          25 - (c >> 1);
          label B_fa:
        }
      a = 0;
      loop L_ka {
        e = (b[1]:int & -8) - f;
        if (e >= d) goto B_la;
        g = b;
        d = e;
        if (d) goto B_la;
        d = 0;
        a = b;
        goto B_l;
        label B_la:
        a = 
          select_if(
            select_if(a, e = b[5]:int, e == (b = (b + (c >> 29 & 4))[4]:int)),
            a,
            e);
        c = c << 1;
        if (b) continue L_ka;
      }
      c = h;
      g;
      goto B_m;
      label B_o:
      e = 0;
      goto B_b;
      label B_n:
      a = 0;
      0;
      label B_m:
    }
  if (eqz(a | b)) {
    b = 0;
    a = 2 << c;
    a = (a | 0 - a) & i;
    if (eqz(a)) goto B_j;
    a = (a & 0 - a) - 1;
    c = a >> (a = a >> 12 & 16);
    e = c >> 5 & 8;
    a = 
      ((((((e | a) | (c = (a = c >> e) >> 2 & 4)) | (c = (a = a >> c) >> 1 & 2)) |
         (c = (a = a >> c) >> 1 & 1)) +
        (a >> c) <<
        2) +
       2692)[0]:int;
  }
  if (eqz(a)) goto B_k;
  label B_l:
  loop L_na {
    g = (a[1]:int & -8) - f;
    e = g < d;
    d = select_if(g, d, e);
    b = select_if(a, b, e);
    c = a[4]:int;
    a = if (c) { c } else { a[5]:int }
    if (a) continue L_na;
  }
  label B_k:
  if (eqz(b)) goto B_j;
  if (d >= 2396[0]:int - f) goto B_j;
  h = b[6]:int;
  if (b != (e = b[3]:int)) {
    a = b[2]:int;
    a < 2404[0]:int;
    a[3]:int = e;
    e[2]:int = a;
    goto B_c;
  }
  c = b + 20;
  a = c.a;
  if (eqz(a)) {
    a = b[4]:int;
    if (eqz(a)) goto B_i;
    c = b + 16;
  }
  loop L_ra {
    g = c;
    e = a;
    c = e + 20;
    a = c.a;
    if (a) continue L_ra;
    c = e + 16;
    a = e[4]:int;
    if (a) continue L_ra;
  }
  g.a = 0;
  goto B_c;
  label B_j:
  if (f <= (a = 2396[0]:int)) {
    b = 2408[0]:int;
    d = a - f;
    if (d >= 16) {
      2396[0]:int = d;
      2408[0]:int = (c = b + f);
      c.b = d | 1;
      (a + b)[0]:int = d;
      b[1]:int = f | 3;
      goto B_ta;
    }
    2408[0]:int = 0;
    2396[0]:int = 0;
    b[1]:int = a | 3;
    a = a + b;
    a[1]:int = a[1]:int | 1;
    label B_ta:
    a = b + 8;
    goto B_a;
  }
  if (f < (c = 2400[0]:int)) {
    2400[0]:int = (b = c - f);
    2412[0]:int = (d = (a = 2412[0]:int) + f);
    d.b = b | 1;
    a[1]:int = f | 3;
    a = a + 8;
    goto B_a;
  }
  a = 0;
  h = f + 47;
  g = h +
      (b = {
             if (2860[0]:int) {
               2868[0]:int;
               goto B_wa;
             }
             2872[0]:long@4 = -1L;
             2864[0]:long@4 = 17592186048512L;
             2860[0]:int = (l + 12 & -16) ^ 1431655768;
             2880[0]:int = 0;
             2832[0]:int = 0;
             4096;
             label B_wa:
           });
  e = g & (i = 0 - b);
  if (e <= f) goto B_a;
  b = 2828[0]:int;
  if (b) {
    d = 2820[0]:int;
    j = d + e;
    if (j <= d) goto B_a;
    if (b < j) goto B_a;
  }
  if (2832[0]:ubyte & 4) goto B_f;
  b = 2412[0]:int;
  if (b) {
    a = 2836;
    loop L_cb {
      if (b >= (d = a[0]:int)) { if (d + a[1]:int > b) goto B_ab }
      a = a[2]:int;
      if (a) continue L_cb;
    }
  }
  c = f_w(0);
  if (c == -1) goto B_g;
  g = e;
  a = 2864[0]:int;
  b = a - 1;
  if (b & c) { g = e - c + (b + c & 0 - a) }
  if (f >= g) goto B_g;
  if (g > 2147483646) goto B_g;
  a = 2828[0]:int;
  if (a) {
    b = 2820[0]:int;
    d = b + g;
    if (d <= b) goto B_g;
    if (a < d) goto B_g;
  }
  a = f_w(g);
  if (a != c) goto B_za;
  goto B_e;
  label B_ab:
  g = g - c & i;
  if (g > 2147483646) goto B_g;
  c = f_w(g);
  if (c == a[0]:int + a[1]:int) goto B_h;
  a = c;
  label B_za:
  if (a == -1) goto B_gb;
  if (f + 48 <= g) goto B_gb;
  b = 2868[0]:int;
  b = b + h - g & 0 - b;
  if (b > 2147483646) {
    c = a;
    goto B_e;
  }
  if (f_w(b) != -1) {
    g = b + g;
    c = a;
    goto B_e;
  }
  f_w(0 - g);
  goto B_g;
  label B_gb:
  c = a;
  if (a != -1) goto B_e;
  goto B_g;
  label B_i:
  e = 0;
  goto B_c;
  label B_h:
  if (c != -1) goto B_e;
  label B_g:
  2832[0]:int = 2832[0]:int | 4;
  label B_f:
  if (e > 2147483646) goto B_d;
  c = f_w(e);
  a = f_w(0);
  if (c == -1) goto B_d;
  if (a == -1) goto B_d;
  if (a <= c) goto B_d;
  g = a - c;
  if (g <= f + 40) goto B_d;
  label B_e:
  2820[0]:int = (a = 2820[0]:int + g);
  if (2824[0]:int < a) { 2824[0]:int = a }
  b = 2412[0]:int;
  if (b) {
    a = 2836;
    loop L_ob {
      if (c == (d = a[0]:int) + (e = a[1]:int)) goto B_mb;
      a = a[2]:int;
      if (a) continue L_ob;
    }
    goto B_lb;
  }
  a = 2404[0]:int;
  if (eqz(select_if(a, 0, a <= c))) { 2404[0]:int = c }
  a = 0;
  2840[0]:int = g;
  2836[0]:int = c;
  2420[0]:int = -1;
  2424[0]:int = 2860[0]:int;
  2848[0]:int = 0;
  loop L_qb {
    b = a << 3;
    (b + 2436)[0]:int = (d = b + 2428);
    (b + 2440)[0]:int = d;
    a = a + 1;
    if (a != 32) continue L_qb;
  }
  2400[0]:int =
    (d = (a = g - 40) - (b = select_if(-8 - c & 7, 0, c + 8 & 7)));
  2412[0]:int = (b = b + c);
  b[1]:int = d | 1;
  (a + c)[1]:int = 40;
  2416[0]:int = 2876[0]:int;
  goto B_kb;
  label B_mb:
  if (a[12]:ubyte & 8) goto B_lb;
  if (b < d) goto B_lb;
  if (b >= c) goto B_lb;
  a[1]:int = e + g;
  2412[0]:int = (d = b + (a = select_if(-8 - b & 7, 0, b + 8 & 7)));
  2400[0]:int = (a = (c = 2400[0]:int + g) - a);
  d.b = a | 1;
  (b + c)[1]:int = 40;
  2416[0]:int = 2876[0]:int;
  goto B_kb;
  label B_lb:
  if (2404[0]:int > c) { 2404[0]:int = c }
  d = c + g;
  a = 2836;
  loop L_yb {
    if (d != a[0]:int) {
      a = a[2]:int;
      if (a) continue L_yb;
      goto B_xb;
    }
  }
  if (eqz(a[12]:ubyte & 8)) goto B_wb;
  label B_xb:
  a = 2836;
  loop L_ac {
    if (b >= (d = a[0]:int)) {
      d = d + a[1]:int;
      if (d > b) goto B_vb;
    }
    a = a[2]:int;
    continue L_ac;
  }
  unreachable;
  label B_wb:
  a[0]:int = c;
  a[1]:int = a[1]:int + g;
  i = c + select_if(-8 - c & 7, 0, c + 8 & 7);
  i.b = f | 3;
  g = d + select_if(-8 - d & 7, 0, d + 8 & 7);
  d = g - (f = f + i);
  if (b == g) {
    2412[0]:int = f;
    2400[0]:int = (a = 2400[0]:int + d);
    f[1]:int = a | 1;
    goto B_tb;
  }
  if (g == 2408[0]:int) {
    2408[0]:int = f;
    2396[0]:int = (a = 2396[0]:int + d);
    f[1]:int = a | 1;
    (a + f)[0]:int = a;
    goto B_tb;
  }
  a = g.b;
  if ((a & 3) == 1) {
    h = a & -8;
    if (a <= 255) {
      b = g.c;
      b == ((e = a >> 3) << 3) + 2428;
      if (b == (a = g.d)) {
        2388[0]:int = 2388[0]:int & -2 << e;
        goto B_fc;
      }
      b[3]:int = a;
      a[2]:int = b;
      goto B_fc;
    }
    j = g.g;
    if (g != (c = g.d)) {
      a = g.c;
      a[3]:int = c;
      c.c = a;
      goto B_ic;
    }
    a = g + 20;
    b = a[0]:int;
    if (b) goto B_kc;
    a = g + 16;
    b = a[0]:int;
    if (b) goto B_kc;
    c = 0;
    goto B_ic;
    label B_kc:
    loop L_lc {
      e = a;
      c = b;
      a = c + 20;
      b = a[0]:int;
      if (b) continue L_lc;
      a = c + 16;
      b = c.e;
      if (b) continue L_lc;
    }
    e[0]:int = 0;
    label B_ic:
    if (eqz(j)) goto B_fc;
    if (g == (a = ((b = g.h) << 2) + 2692)[0]:int) {
      a[0]:int = c;
      if (c) goto B_mc;
      2392[0]:int = 2392[0]:int & -2 << b;
      goto B_fc;
    }
    (j + select_if(16, 20, j[4] == g))[0]:int = c;
    if (eqz(c)) goto B_fc;
    label B_mc:
    c.g = j;
    a = g.e;
    if (a) {
      c.e = a;
      a[6]:int = c;
    }
    a = g.f;
    if (eqz(a)) goto B_fc;
    c.f = a;
    a[6]:int = c;
    label B_fc:
    g = g + h;
    d = d + h;
  }
  g.b = g.b & -2;
  f[1]:int = d | 1;
  (d + f)[0]:int = d;
  if (d <= 255) {
    b = d >> 3;
    a = (b << 3) + 2428;
    b = {
          d = 2388[0]:int;
          if (eqz(d & (b = 1 << b))) {
            2388[0]:int = b | d;
            a;
            goto B_qc;
          }
          a[2]:int;
          label B_qc:
        }
    a[2]:int = f;
    b[3]:int = f;
    f[3]:int = a;
    f[2]:int = b;
    goto B_tb;
  }
  a = 31;
  if (d <= 16777215) {
    a = d >> 8;
    b = a << (a = a + 1048320 >> 16 & 8);
    c = b << (b = b + 520192 >> 16 & 4);
    a = ((c << (c = c + 245760 >> 16 & 2)) >> 15) - ((a | b) | c);
    a = (a << 1 | (d >> a + 21 & 1)) + 28;
  }
  f[7]:int = a;
  f[4]:long@4 = 0L;
  b = (a << 2) + 2692;
  c = 2392[0]:int;
  if (eqz(c & (g = 1 << a))) {
    2392[0]:int = c | g;
    b[0]:int = f;
    f[6]:int = b;
    goto B_tc;
  }
  c = b[0]:int;
  a = d << select_if(25 - (a >> 1), 0, a != 31);
  loop L_vc {
    b = c;
    if ((b[1]:int & -8) == d) goto B_ub;
    c = a >> 29;
    a = a << 1;
    e = b + (c & 4) + 16;
    c = e[0]:int;
    if (c) continue L_vc;
  }
  e[0]:int = f;
  f[6]:int = b;
  label B_tc:
  f[3]:int = f;
  f[2]:int = f;
  goto B_tb;
  label B_vb:
  2400[0]:int =
    (i = (a = g - 40) - (e = select_if(-8 - c & 7, 0, c + 8 & 7)));
  2412[0]:int = (e = c + e);
  e[1]:int = i | 1;
  (a + c)[1]:int = 40;
  2416[0]:int = 2876[0]:int;
  e = select_if(b,
                a = d + select_if(39 - d & 7, 0, d - 39 & 7) - 47,
                a < b + 16);
  e[1]:int = 27;
  e[4]:long@4 = 2844[0]:long@4;
  e[2]:long@4 = 2836[0]:long@4;
  2844[0]:int = e + 8;
  2840[0]:int = g;
  2836[0]:int = c;
  2848[0]:int = 0;
  a = e + 24;
  loop L_wc {
    a[1]:int = 7;
    c = a + 8;
    a = a + 4;
    if (c < d) continue L_wc;
  }
  if (b == e) goto B_kb;
  e[1]:int = e[1]:int & -2;
  b[1]:int = (g = e - b) | 1;
  e[0]:int = g;
  if (g <= 255) {
    d = g >> 3;
    a = (d << 3) + 2428;
    d = {
          c = 2388[0]:int;
          if (eqz(c & (d = 1 << d))) {
            2388[0]:int = c | d;
            a;
            goto B_yc;
          }
          a[2]:int;
          label B_yc:
        }
    a[2]:int = b;
    d.d = b;
    b[3]:int = a;
    b[2]:int = d;
    goto B_kb;
  }
  a = 31;
  b[4]:long@4 = 0L;
  if (g <= 16777215) {
    a = g >> 8;
    d = a << (a = a + 1048320 >> 16 & 8);
    c = d << (d = d + 520192 >> 16 & 4);
    a = ((c << (c = c + 245760 >> 16 & 2)) >> 15) - ((a | d) | c);
    a = (a << 1 | (g >> a + 21 & 1)) + 28;
  }
  b[7]:int = a;
  d = (a << 2) + 2692;
  c = 2392[0]:int;
  if (eqz(c & (i = 1 << a))) {
    2392[0]:int = c | i;
    d.a = b;
    b[6]:int = d;
    goto B_bd;
  }
  c = d.a;
  a = g << select_if(25 - (a >> 1), 0, a != 31);
  loop L_dd {
    d = c;
    if ((d.b & -8) == g) goto B_sb;
    c = a >> 29;
    a = a << 1;
    e = d + (c & 4) + 16;
    c = e[0]:int;
    if (c) continue L_dd;
  }
  e[0]:int = b;
  b[6]:int = d;
  label B_bd:
  b[3]:int = b;
  b[2]:int = b;
  goto B_kb;
  label B_ub:
  a = b[2]:int;
  a[3]:int = f;
  b[2]:int = f;
  f[6]:int = 0;
  f[3]:int = b;
  f[2]:int = a;
  label B_tb:
  a = i + 8;
  goto B_a;
  label B_sb:
  a = d.c;
  a[3]:int = b;
  d.c = b;
  b[6]:int = 0;
  b[3]:int = d;
  b[2]:int = a;
  label B_kb:
  a = 2400[0]:int;
  if (a <= f) goto B_d;
  2400[0]:int = (b = a - f);
  2412[0]:int = (d = (a = 2412[0]:int) + f);
  d.b = b | 1;
  a[1]:int = f | 3;
  a = a + 8;
  goto B_a;
  label B_d:
  2216[0]:int = 48;
  a = 0;
  goto B_a;
  label B_c:
  if (eqz(h)) goto B_ed;
  c = b[7]:int;
  a = (c << 2) + 2692;
  if (a[0]:int == b) {
    a[0]:int = e;
    if (e) goto B_fd;
    2392[0]:int = (i = i & -2 << c);
    goto B_ed;
  }
  (h + select_if(16, 20, h[4] == b))[0]:int = e;
  if (eqz(e)) goto B_ed;
  label B_fd:
  e[6]:int = h;
  a = b[4]:int;
  if (a) {
    e[4]:int = a;
    a[6]:int = e;
  }
  a = b[5]:int;
  if (eqz(a)) goto B_ed;
  e[5]:int = a;
  a[6]:int = e;
  label B_ed:
  if (d <= 15) {
    b[1]:int = (a = d + f) | 3;
    a = a + b;
    a[1]:int = a[1]:int | 1;
    goto B_id;
  }
  b[1]:int = f | 3;
  e = b + f;
  e[1]:int = d | 1;
  (d + e)[0]:int = d;
  if (d <= 255) {
    d = d >> 3;
    a = (d << 3) + 2428;
    d = {
          f = 2388[0]:int;
          if (eqz(f & (d = 1 << d))) {
            2388[0]:int = d | f;
            a;
            goto B_ld;
          }
          a[2]:int;
          label B_ld:
        }
    a[2]:int = e;
    d.d = e;
    e[3]:int = a;
    e[2]:int = d;
    goto B_id;
  }
  a = 31;
  if (d <= 16777215) {
    a = d >> 8;
    f = a << (a = a + 1048320 >> 16 & 8);
    c = f << (f = f + 520192 >> 16 & 4);
    a = ((c << (c = c + 245760 >> 16 & 2)) >> 15) - ((a | f) | c);
    a = (a << 1 | (d >> a + 21 & 1)) + 28;
  }
  e[7]:int = a;
  e[4]:long@4 = 0L;
  f = (a << 2) + 2692;
  if (eqz(i & (c = 1 << a))) {
    2392[0]:int = c | i;
    f[0]:int = e;
    e[6]:int = f;
    goto B_pd;
  }
  c = f[0]:int;
  a = d << select_if(25 - (a >> 1), 0, a != 31);
  loop L_rd {
    f = c;
    if ((f[1]:int & -8) == d) goto B_od;
    c = a >> 29;
    a = a << 1;
    g = f + (c & 4) + 16;
    c = g.a;
    if (c) continue L_rd;
  }
  g.a = e;
  e[6]:int = f;
  label B_pd:
  e[3]:int = e;
  e[2]:int = e;
  goto B_id;
  label B_od:
  a = f[2]:int;
  a[3]:int = e;
  f[2]:int = e;
  e[6]:int = 0;
  e[3]:int = f;
  e[2]:int = a;
  label B_id:
  a = b + 8;
  goto B_a;
  label B_b:
  if (eqz(k)) goto B_sd;
  d = c.h;
  a = (d << 2) + 2692;
  if (a[0]:int == c) {
    a[0]:int = e;
    if (e) goto B_td;
    2392[0]:int = j & -2 << d;
    goto B_sd;
  }
  (k + select_if(16, 20, k[4] == c))[0]:int = e;
  if (eqz(e)) goto B_sd;
  label B_td:
  e[6]:int = k;
  a = c.e;
  if (a) {
    e[4]:int = a;
    a[6]:int = e;
  }
  a = c.f;
  if (eqz(a)) goto B_sd;
  e[5]:int = a;
  a[6]:int = e;
  label B_sd:
  if (b <= 15) {
    c.b = (a = b + f) | 3;
    a = a + c;
    a[1]:int = a[1]:int | 1;
    goto B_wd;
  }
  c.b = f | 3;
  d = c + f;
  d.b = b | 1;
  (b + d)[0]:int = b;
  if (h) {
    e = h >> 3;
    f = (e << 3) + 2428;
    a = 2408[0]:int;
    e = {
          e = 1 << e;
          if (eqz(e & g)) {
            2388[0]:int = e | g;
            f;
            goto B_zd;
          }
          f[2]:int;
          label B_zd:
        }
    f[2]:int = a;
    e[3]:int = a;
    a[3]:int = f;
    a[2]:int = e;
  }
  2408[0]:int = d;
  2396[0]:int = b;
  label B_wd:
  a = c + 8;
  label B_a:
  g_a = l + 16;
  return a;
}

function f_v(a:int_ptr) {
  var b:int_ptr;
  var g:int_ptr;
  var d:int_ptr;
  var e:{ a:int, b:int, c:int, d:int }
  var h:int_ptr;
  if (eqz(a)) goto B_a;
  var c:int = a - 8;
  var f:{ a:int, b:int, c:int, d:int, e:int, f:int, g:int, h:int } = 
    c + (a = (b = (a - 4)[0]:int) & -8);
  if (b & 1) goto B_b;
  if (eqz(b & 3)) goto B_a;
  c = c - (b = c[0]:int);
  if (c < 2404[0]:int) goto B_a;
  a = a + b;
  if (c != 2408[0]:int) {
    if (b <= 255) {
      e = c[2]:int;
      e == ((g = b >> 3) << 3) + 2428;
      if (e == (b = c[3]:int)) {
        2388[0]:int = 2388[0]:int & -2 << g;
        goto B_b;
      }
      e.d = b;
      b[2] = e;
      goto B_b;
    }
    h = c[6]:int;
    if (c != (d = c[3]:int)) {
      b = c[2]:int;
      b[3] = d;
      d[2] = b;
      goto B_f;
    }
    b = c + 20;
    e = b[0];
    if (e) goto B_h;
    b = c + 16;
    e = b[0];
    if (e) goto B_h;
    d = 0;
    goto B_f;
    label B_h:
    loop L_i {
      g = b;
      d = e;
      b = d + 20;
      e = b[0];
      if (e) continue L_i;
      b = d + 16;
      e = d[4];
      if (e) continue L_i;
    }
    g[0] = 0;
    label B_f:
    if (eqz(h)) goto B_b;
    if (c == (b = ((e = c[7]:int) << 2) + 2692)[0]) {
      b[0] = d;
      if (d) goto B_j;
      2392[0]:int = 2392[0]:int & -2 << e;
      goto B_b;
    }
    (h + select_if(16, 20, h[4] == c))[0]:int = d;
    if (eqz(d)) goto B_b;
    label B_j:
    d[6] = h;
    b = c[4]:int;
    if (b) {
      d[4] = b;
      b[6] = d;
    }
    b = c[5]:int;
    if (eqz(b)) goto B_b;
    d[5] = b;
    b[6] = d;
    goto B_b;
  }
  b = f.b;
  if ((b & 3) != 3) goto B_b;
  2396[0]:int = a;
  f.b = b & -2;
  c[1]:int = a | 1;
  (a + c)[0]:int = a;
  return ;
  label B_b:
  if (c >= f) goto B_a;
  b = f.b;
  if (eqz(b & 1)) goto B_a;
  if (eqz(b & 2)) {
    if (f == 2412[0]:int) {
      2412[0]:int = c;
      2400[0]:int = (a = 2400[0]:int + a);
      c[1]:int = a | 1;
      if (c != 2408[0]:int) goto B_a;
      2396[0]:int = 0;
      2408[0]:int = 0;
      return ;
    }
    if (f == 2408[0]:int) {
      2408[0]:int = c;
      2396[0]:int = (a = 2396[0]:int + a);
      c[1]:int = a | 1;
      (a + c)[0]:int = a;
      return ;
    }
    a = (b & -8) + a;
    if (b <= 255) {
      e = f.c;
      e == ((g = b >> 3) << 3) + 2428;
      if (e == (b = f.d)) {
        2388[0]:int = 2388[0]:int & -2 << g;
        goto B_q;
      }
      e.d = b;
      b[2] = e;
      goto B_q;
    }
    h = f.g;
    if (f != (d = f.d)) {
      b = f.c;
      b < 2404[0]:int;
      b[3] = d;
      d[2] = b;
      goto B_t;
    }
    b = f + 20;
    e = b[0];
    if (e) goto B_v;
    b = f + 16;
    e = b[0];
    if (e) goto B_v;
    d = 0;
    goto B_t;
    label B_v:
    loop L_w {
      g = b;
      d = e;
      b = d + 20;
      e = b[0];
      if (e) continue L_w;
      b = d + 16;
      e = d[4];
      if (e) continue L_w;
    }
    g[0] = 0;
    label B_t:
    if (eqz(h)) goto B_q;
    if (f == (b = ((e = f.h) << 2) + 2692)[0]) {
      b[0] = d;
      if (d) goto B_x;
      2392[0]:int = 2392[0]:int & -2 << e;
      goto B_q;
    }
    (h + select_if(16, 20, h[4] == f))[0]:int = d;
    if (eqz(d)) goto B_q;
    label B_x:
    d[6] = h;
    b = f.e;
    if (b) {
      d[4] = b;
      b[6] = d;
    }
    b = f.f;
    if (eqz(b)) goto B_q;
    d[5] = b;
    b[6] = d;
    label B_q:
    c[1]:int = a | 1;
    (a + c)[0]:int = a;
    if (c != 2408[0]:int) goto B_m;
    2396[0]:int = a;
    return ;
  }
  f.b = b & -2;
  c[1]:int = a | 1;
  (a + c)[0]:int = a;
  label B_m:
  if (a <= 255) {
    b = a >> 3;
    a = (b << 3) + 2428;
    b = {
          e = 2388[0]:int;
          if (eqz(e & (b = 1 << b))) {
            2388[0]:int = b | e;
            a;
            goto B_ba;
          }
          a[2];
          label B_ba:
        }
    a[2] = c;
    b[3] = c;
    c[3]:int = a;
    c[2]:int = b;
    return ;
  }
  b = 31;
  c[4]:long@4 = 0L;
  if (a <= 16777215) {
    b = a >> 8;
    e = b << (b = b + 1048320 >> 16 & 8);
    d = e << (e = e + 520192 >> 16 & 4);
    b = ((d << (d = d + 245760 >> 16 & 2)) >> 15) - ((b | e) | d);
    b = (b << 1 | (a >> b + 21 & 1)) + 28;
  }
  c[7]:int = b;
  e = (b << 2) + 2692;
  f = 0;
  d = 2392[0]:int;
  if (eqz(d & (g = 1 << b))) {
    2392[0]:int = d | g;
    e.a = c;
    c[6]:int = e;
    goto B_ga;
  }
  d = e.a;
  b = a << select_if(25 - (b >> 1), f, b != 31);
  loop L_ia {
    e = d;
    if ((e.b & -8) == a) goto B_fa;
    d = b >> 29;
    b = b << 1;
    f = e + (d & 4) + 16;
    d = f.a;
    if (d) continue L_ia;
  }
  f.a = c;
  c[6]:int = e;
  label B_ga:
  c[3]:int = c;
  c[2]:int = c;
  goto B_ea;
  label B_fa:
  a = e.c;
  a[3] = c;
  e.c = c;
  c[6]:int = 0;
  c[3]:int = e;
  c[2]:int = a;
  label B_ea:
  2420[0]:int = select_if(c = 2420[0]:int - 1, -1, c);
  label B_a:
}

function f_w(a:int):int {
  var c:int;
  var b:int = d_p[1]:int;
  a = b + (c = a + 3 & -4);
  if (select_if(c, 0, a <= b)) goto B_a;
  if (a > memory_size() << 16) {
    if (eqz(env_emscripten_resize_heap(a))) goto B_a
  }
  d_p[1]:int = a;
  return b;
  label B_a:
  2216[0]:int = 48;
  return -1;
}

export function stackSave():int {
  return g_a
}

export function stackRestore(a:int) {
  g_a = a
}

export function stackAlloc(a:int):int {
  a = g_a - a & -16;
  g_a = a;
  return a;
}

export function end_signature(a:int):int {
  var c:ubyte_ptr;
  var b:ubyte_ptr;
  var d:int;
  var k:long;
  var o:long;
  var l:long;
  var m:long;
  var e:int;
  var h:int;
  var g:int;
  var i:int = g_a - 16;
  g_a = i;
  o = {
        e = f_j(a);
        if (e > 0) {
          loop L_d {
            b = a + c;
            if (b[0] == 46) goto B_b;
            c = c + 1;
            if (c != e) continue L_d;
          }
        }
        0L;
        goto B_a;
        label B_b:
        var j:int_ptr = i + 12;
        e = 0;
        var n:long = 4294967295L;
        var f:{ a:long, b:long } = g_a - 16;
        g_a = f;
        c = b + 1;
        b = c[0];
        if (eqz(b)) {
          a = c;
          goto B_e;
        }
        a = c;
        loop L_h {
          b = (b << 24) >> 24;
          if (eqz(b == 32 | b - 9 < 5)) goto B_g;
          b = a[1]:ubyte;
          d = a + 1;
          a = d;
          if (b) continue L_h;
        }
        a = d;
        goto B_e;
        label B_g:
        b = a[0]:ubyte;
        br_table[B_i, B_e, B_i, ..B_e](b - 43);
        label B_i:
        g = select_if(-1, 0, b == 45);
        a = a + 1;
        label B_e:
        loop L_j {
          b = -48;
          d = a[0]:byte;
          if ((d - 48 & 255) < 10) goto B_l;
          b = -87;
          if ((d - 97 & 255) < 26) goto B_l;
          b = -55;
          if ((d - 65 & 255) > 25) goto B_k;
          label B_l:
          d = b + d;
          if (d >= 10) goto B_k;
          f.b =
            (o = k >> 32L) * 0L +
            ((m = (l = (k & 4294967295L) * 10L) >> 32L) >> 32L) +
            ((m = o * 10L + (m & 4294967295L)) >> 32L);
          f.a = (l & 4294967295L) | m << 32L;
          b = 1;
          if (f.b != 0L) goto B_m;
          l = k * 10L;
          if (l > ((m = i64_extend_i32_s(d)) ^ -1L)) goto B_m;
          k = l + m;
          h = 1;
          b = e;
          label B_m:
          a = a + 1;
          e = b;
          continue L_j;
          label B_k:
        }
        if (j) { j[0] = select_if(a, c, h) }
        if (e) {
          2216[0]:int = 68;
          g = 0;
          k = 4294967295L;
          goto B_q;
        }
        if (k < 4294967295L) goto B_p;
        label B_q:
        if (k <= 4294967295L) goto B_p;
        2216[0]:int = 68;
        goto B_o;
        label B_p:
        n = (k ^ (n = i64_extend_i32_s(g))) - n;
        label B_o:
        g_a = f + 16;
        c = i32_wrap_i64(n);
        f_v(c);
        i64_extend_i32_u(c);
        label B_a:
      }
  g_a = i + 16;
  l = o;
  env_setTempRet0(i32_wrap_i64(l >> 32L));
  return i32_wrap_i64(l);
}
canton7 commented 9 months ago

@macxq Note that end_signature doesn't seem to be used (it's called from the js, but the result is discarded). Most of begin_signature is just an implementation of MD5 (see my link above for the very simple Python equivalent). The only bit we're unsure of is the "5245784" which is appended to the MD5 -- it appears to be a constant (see the other thread I linked), and using a constant appears to work...

johannessteu commented 9 months ago

So yeah, i was actually able to update my scripts! I can fetch data again. This is what works our for me, written in go lang

Basically you need to set all of those headers and compute the sign string as shown here. Easiest way to reproduce this is to go to the foxess site, search for the login request and then try to replicate the signature sent there. On login token is always an empty string. The token you get back on login is then used for all other requests.

func SignRequest(r *http.Request, token string) *http.Request {
    lang := "en"
    path := r.URL.Path
    timestamp := time.Now().UnixMilli()
    str := fmt.Sprintf("%s\\r\\n%s\\r\\n%s\\r\\n%d", path, token, lang, timestamp)

    hash := md5.Sum([]byte(str))
    signature := fmt.Sprintf("%x.5245784", hash)

    r.Header.Set("User-Agent'", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")
    r.Header.Set("Token", token)
    r.Header.Set("Timezone", "Europe/Berlin")
    r.Header.Set("Lang", lang)
    r.Header.Set("Timestamp", fmt.Sprintf("%d", timestamp))
    r.Header.Set("Content-Type", "application/json")
    r.Header.Set("Signature", signature)

    return r
}
muhkuh666 commented 9 months ago

So yeah, i was actually able to update my scripts! I can fetch data again. This is what works our for me, written in go lang

Basically you need to set all of those headers and compute the sign string as shown here. Easiest way to reproduce this is to go to the foxess site, search for the login request and then try to replicate the signature sent there. On login token is always an empty string. The token you get back on login is then used for all other requests.

func SignRequest(r *http.Request, token string) *http.Request {
  lang := "en"
  path := r.URL.Path
  timestamp := time.Now().UnixMilli()
  str := fmt.Sprintf("%s\\r\\n%s\\r\\n%s\\r\\n%d", path, token, lang, timestamp)

  hash := md5.Sum([]byte(str))
  signature := fmt.Sprintf("%x.5245784", hash)

  r.Header.Set("User-Agent'", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")
  r.Header.Set("Token", token)
  r.Header.Set("Timezone", "Europe/Berlin")
  r.Header.Set("Lang", lang)
  r.Header.Set("Timestamp", fmt.Sprintf("%d", timestamp))
  r.Header.Set("Content-Type", "application/json")
  r.Header.Set("Signature", signature)

  return r
}

So can you use Foxess in Homeassistant again? Or what does this mean?

johannessteu commented 9 months ago

I don't use the Homeassistant at all. I hacked a small box for my parents for christmas. It shows them the current status of their usage. Therefore i do have some custom scripts to get the actual data. Mittel (IMG_3494)

But for this code base it should be rather easy to upgrade i'd say. Those places https://github.com/macxq/foxess-ha/blob/main/custom_components/foxess/sensor.py#L128

needs to be updated. @macxq it might be a good idea to have a convenient signHeader method here as well that could be re-used in all places.

Golempl commented 9 months ago

Example of fetch data using bash script, can't be easier:

!/bin/bash

signatureGen() { local token="$1" local path="/c/v0/plant/earnings/all" timestamp=$(date +%s%3N) local str="${path}\r\n${token}\r\nen\r\n${timestamp}" local hash=$(echo -n "$str" | md5sum | cut -d ' ' -f1) signature="${hash}.5245784" }

token=cat /tmp/token.txt signatureGen "$token"

curl 'https://www.foxesscloud.com/c/v0/plant/earnings/all' -H 'contenttype: application/json' -H 'lang: en' -H "signature: $signature" -H "timestamp: $timestamp" -H "token: $token"

You need provide token, but nothing changed here

MartinBlackburn commented 9 months ago

The problem will be if that unknown number at the end of the signature changes: "5245784" While it looks like we are all getting the same now, it might change at some point without warning and break all over again

manuelsirianni commented 9 months ago

Tomorrow they will restore the functionality and give the time to create a new method.

Wait for some news..

craigmcfly commented 9 months ago

mine started working at around 01:17 GMT :)

goodsat commented 9 months ago

hello I just modified the code for new method , so that it is functional
sensor.zip

Maesch1992 commented 9 months ago

mine started working at around 01:17 GMT :)

Its working now!!

goodsat commented 9 months ago

hello add to patch files patch.zip

johannessteu commented 9 months ago

@goodsat would you mind creating a PR?

goodsat commented 9 months ago

@goodsat would you mind creating a PR?

hello add to commit

link

ruisantox commented 8 months ago

It started working here too. Tks for all the help and if it is the case Merry Christmas

FozzieUK commented 7 months ago

Just a quick update for this thread, I realise the old cloud API is currently working again, but FoxESS have said this is time limited and will be discontinued; going forward they will only be supporting the new Foxess OpenAPI.

With support from @TonyM1958 I have modified / re-written this integration to use the new Foxess OpenAPI to allow existing cloud installations to keep working - Tony is continuing to work with the FoxESS R&D team to process outstanding issues.

The FoxESS OpenAPI is up and running but still under development and changes may occur, but the better news is that I already have a modified version of this integration working reliably and running against it.

There are many changes in the code to support this but from a users perspective it requires only minimal work to make the re-worked code run, it needs the Inverter Serial number and apiKey (see note below in API access) added to the platform config in configuration.yaml and after that it will respect the existing entity naming convention - all existing sensors will continue to populate as before but from the OpenAPI.

The new OpenAPI provides more information and so I have added the following sensors -

Sadly some extended attributes of the sensor.foxess_inverter have needed to be removed (Country, Country Code and Address) but I suspect many users do not use / or are even aware of these.

Open API Access and Limits The OpenAPI access is limited and must have a personal_api_key to operate, each user can generate their own personal_api_key in their own user profile at the FoxESS cloud - the number of API calls are limited to 1,440 calls per day, and when used up the OpenAPI will stop responding to requests.

This sounds like a reasonable number of calls, however multiple API calls have to be made on each scan to gain the complete dataset.

To manage this I have added code to pace the number of API calls that are made, currently it is getting all real time sensor information every 5 minutes (as now , and in-line with the datalogger update frequency), the report information that provides the current 'daily' figures for Feedin, Generation, GridConsumption, Battery Charge, Battery Discharge and Load, and the Energy Generated (todays yield) and the battery settings are read every 15 minutes.

As it stands the integration is using approximately 40 API calls an hour (960 a day and well within the 1,440), however there are some outstanding requests on FoxESS R&D that could reduce this further and hopefully in future allow faster updates.

It also fixes a few bugs and the deprecation warning errors that HA 2024.x is generating https://github.com/macxq/foxess-ha/issues/211

@macxq - not sure how to proceed with this?, I could send PR's but the code changes are extensive and the OpenAPI still subject to change, plus in the early days there will be a need for beta testing and user support - adding me as a collaborator to your repo would allow me to respond to that?. My code is in this fork https://github.com/FozzieUK/foxess-ha - if you would like to review it. Just for information for now I have a boolean in the code (TRY_OLD_CLOUD_API) that will fall back on the old cloud interface should the OpenAPI fail. It is set to False as default as the OpenAPI has been quite stable.

Please don't openly use the forked repository code yet as it is still under test and change, hence I can't respond to any PR's or provide support at this stage.

FozzieUK commented 7 months ago

@macxq Thanks for the add, I will add all changes into a testing branch for now 👍

craigmcfly commented 7 months ago

This seems to have reared its ugly head again. Stopped as of about 04:00 GMT.

FozzieUK commented 7 months ago

Yep this took everyone by surprise 😒 i'm on it now, the OpenAPI version is written and awaiting release.

@macxq - I've raised the PR to release the OpenAPI version, be grateful if you could review please 👍

snaiperr commented 7 months ago

@FozzieUK is it possible to use standard web version instead this unstable api ? i mean is not it easier to adopt it to standard web version ? now it's not possible to generate api key since error 500... looks so bad..

FozzieUK commented 7 months ago

@snaiperr the openAPI is actually working fine, but only if you already have a personal_api_key - FoxESS have been made aware of the problems and in the short term have to either get the old cloud access working, or get the request personal_api_key working - in the medium term the only access we will have is via the openapi.

craigmcfly commented 7 months ago

It's alive again! Much obliged.

manuelsirianni commented 7 months ago

Here still no values… How to fix?

craigmcfly commented 7 months ago

Here still no values… How to fix?

What errors do you have on the logs screen?

manuelsirianni commented 7 months ago

Missed the update, now works great :)

Qbackii commented 6 months ago

Hi All. I have a problem with new integration. My instance of Home Assistance is running on dedicated platform with tailored made linux distribution and I have a problem with too many established connection opened by foxess integration. The system do not automatically close it so after couple of hours system freeze. With last integration (before API included) I have to change "Connection" type to Closed in two places in phyton code. Can you help me what can I change in updated version to close connection after single session of reading parameters?