Author Topic: ASM Delvar - Clean and free up from BASIC variables  (Read 12966 times)

0 Members and 2 Guests are viewing this topic.

Offline Galandros

  • LV9 Veteran (Next: 1337)
  • *********
  • Posts: 1140
  • Rating: +42/-10
    • View Profile
ASM Delvar - Clean and free up from BASIC variables
« on: April 17, 2010, 07:34:12 am »
Coded this morning. Not that useful but just some practise and wanted to do.
This is an assembly version of DelVar ADelVar B(...)DelVar /theta/.

Features for now:
- custom builds
- small, fast and stable
- TI-83+ and some TI-83 compatibility

Suggested uses:
 - include in your custom asm library to TI-BASIC, this is a faster and smaller way to clean up variables after use
 - can be also used in APPS that allocate memory, through bcall(_InsertMem), and in the case it has not enough memory (prompting the user or not is up to you),
try to free enough memory to execute.

Source Code:

Make sure you have a complete ti83plus.inc and ti83.inc. especially the ti83.inc. Check the src folder in the zip file attached.

- Deletes variables real and complex variables from A to Z and Theta
Code: [Select]
#ifdef TI83
#undefine DELARCVARS ; bcall(_DelVarArc) not documented in TI83
#undefine ZEROANS
#endif

;Delete Real and Complex Vars from A to Z and Theta
deleteAtoZaTheta:
#ifdef ZEROANS
bcall(_OP1Set0) ; This will set OP1 to FP 0 ( .db 0,$80,0,0,0,0,0,0,0)
bcall(_StoAns) ; Ans will be equal 0 (Ans can be a huge list or string and take huge space)
#else
bcall(_ZeroOP1) ; OP1 needs to be zeroed or it will not work for some reason
#endif
call deleteAZ ; (OP1) = RealObj = $00 because OP1 is zeroed
deleteAZcplx:
ld a,CplxObj
ld (OP1+0),a
deleteAZ:
ld a,tA
deleteAZloop:
push af
ld (OP1+1),a
bcall(_FindSym) ; look up
jr c,sdelarcAZ
#ifndef DELARCVARS
#ifndef TI83 ; TI-83 does not have flash
inc b ;\
dec b ; | if b!=0 (it is in flash), then skip
jr nz,sdelarcAZ ;/
#endif
bcall(_DelVar) ; delete variable only if in RAM
#else
bcall(_DelVarArc)
#endif
sdelarcAZ:
pop af
inc a
cp tTheta+1
jr nz,deleteAZloop
ret

;OPTIMIZE TRY: use ld hl,OP1, push and pop hl in deleAZloop
;and other changes but is exactly the same size

deleteAtoZaThetaEnd:

 .echo "code size: ",deleteAtoZaThetaEnd-deleteAtoZaTheta

- Deletes many variables: A-Z and Theta, L1-L6, [A]-[Z], Y1-Y6, X1T-X6T, Y1T-Y6T, r1-r6 and u-w.
- DOES NOT WORK WITH TI-83 besides has some #if's for TI-83 in my attempt to work
Code: [Select]
;Clean Up Basic Variables
;all numbers A-Z and /theta/, lists L1 to L6, matrices [A]-[J], Ans, graphics functions
;detects real and complex numbers or lists
CleanUpBASICvars:
#ifndef TI83
bcall(_CleanAll) ; delete all temp variables
#endif
#ifdef ZEROANS
bcall(_OP1Set0) ; This will set OP1 to FP 0 ( .db 0,$80,0,0,0,0,0,0,0)
bcall(_StoAns) ; Ans will be equal 0 (Ans can be a huge list or string and take huge space)
#else
bcall(_ZeroOP1) ; OP1 needs to be zeroed or it will not work for some reason
#endif
ld ix,OP1 ; the pointer
ld d,0 ; a flag for activate equ create with 0 bytes (needed to not crash TI-OS)
; it is preserved in deletevars2
ld c,d ; c = RealObj = $00
ld a,tA ; (OP1+0) = $00 = RealObj, already
ld b,tTheta+1
call deletevars2
ld c,CplxObj
ld a,tA
; ld b,tTheta+1 ; it was preserved!
call deletevars2

;these vars have 3 bytes, so a smart solution is coded
inc ix
ld e,d ; e = RealObj = $00
ld c,tVarLst
ld a,tL1
ld b,tL6+1
call deletevars3
ld e,CListObj
; ld c,tVarLst ; it was preserved!
ld a,tL1
; ld b,tL6+1 ; it was preserved!
call deletevars3
ld e,MatObj
ld c,tVarMat
ld a,tMatA
ld b,tMatJ+1
call deletevars3

inc d ; activate bcall(_Create0Equ)
ld e,EquObj
ld c,tVarEqu
ld a,tY1
ld b,tY0+1
call deletevars3
; ld e,EquObj
; ld c,tVarEqu ; it was preserved!
ld a,tX1T ;\tX1T to tX6T
ld b,tY6T+1 ;/tY1T to tY6T
call deletevars2
; ld e,EquObj
; ld c,tVarEqu ; it was preserved!
ld a,tR1
ld b,tR6+1
call deletevars2
; ld e,EquObj
; ld c,tVarEqu ; it was preserved!
ld a,tun
ld b,twn+1
;fall back

deletevars3:
ld (ix-1),e
deletevars2:
ld (ix+0),c
deletevarloop:
push af
push bc
push de ; all preserved
ld (ix+1),a
bcall(_FindSym) ; look up
jr c,sdelarc ; if doesn't exist, then skip
#ifndef DELARCVARS
#ifndef TI83 ; TI-83 does not have flash
inc b ;\
dec b ; | if b!=0 (it is in flash), then skip
jr nz,sdelarc ;/
#endif
bcall(_DelVar) ; delete variable only if in RAM
#else
bcall(_DelVarArc) ; delete variable archived or not
#endif
sdelarc:
pop de
inc d ;\
dec d ; | if d=0, then we don't need to recreate the equation var
jr z,notequvar ;/
bcall(_Create0Equ) ; OP1 destroyed, OP4 has variable name
bcall(_OP4toOP1) ; restore OP1 ^^
notequvar:
pop bc
pop af
inc a
cp b ; b holds the end value
jr nz,deletevarloop ; if we arrived b, then return
ret

; ld hl,OPFomarts
; rst 20h ; rMov9ToOP1 ; OP1 is variable
;OPFomarts:
; .db RealObj,tA,0,0,0,0,0,0,0
; .db CplxObj,tTheta,0,0
; .db RealObj,tVarLst,tL1,0
; .db CListObj,tVarLst,tL6,0
; .db MatObj, tVarMat, tMatA, 0
; .db MatObj, tVarMat, tMatJ, 0
; .db EquObj, tVarEqu, tY1, 0
; tY1 to tY9 and tY0, tX1T to tX6T, tY1T to tY6T, tR1 to tR6, tun, tvn, twn
; if graph equations do not exist, TI-OS will crash
;delete with bcall(_DelVar) and bcall(_Create0Equ)
; NewEquObj, what it does???

;ToDo:
;ClearEntries
;clear GDBs, Pics, Strs
;LRESID
;http://wikiti.brandonw.net/?title=83Plus:BCALLs:5041

cleanupBASICvarsend:

 .echo "code size: ",cleanupBASICvarsend-cleanupBASICvars

EDIT: rewritten post with recent code
« Last Edit: May 06, 2010, 07:57:01 am by Galandros »
Hobbing in calculator projects.

Offline DJ Omnimaga

  • Clacualters are teh gr33t
  • CoT Emeritus
  • LV15 Omnimagician (Next: --)
  • *
  • Posts: 55943
  • Rating: +3154/-232
  • CodeWalrus founder & retired Omnimaga founder
    • View Profile
    • Dream of Omnimaga Music
Re: ASM Delvar - Clean and free up from BASIC variables
« Reply #1 on: April 17, 2010, 12:05:37 pm »
interesting, I wonder how fast will it be compared to using several dozens of delvar commands, since it is actually larger than those delvar commands? (81 bytes total for all 27 vars). Does it also delete archived vars?

Offline jsj795

  • LV9 Veteran (Next: 1337)
  • *********
  • Posts: 1105
  • Rating: +84/-3
    • View Profile
Re: ASM Delvar - Clean and free up from BASIC variables
« Reply #2 on: April 17, 2010, 01:34:45 pm »
I think since this is assembly, it will be faster? And I'm also curious about if it deletes archived vars.


Spoiler For funny life mathematics:
1. ROMANCE MATHEMATICS
Smart man + smart woman = romance
Smart man + dumb woman = affair
Dumb man + smart woman = marriage
Dumb man + dumb woman = pregnancy
2. OFFICE ARITHMETIC
Smart boss + smart employee = profit
Smart boss + dumb employee = production
Dumb boss + smart employee = promotion
Dumb boss + dumb employee = overtime
3. SHOPPING MATH
A man will pay $2 for a $1 item he needs.
A woman will pay $1 for a $2 item that she doesn't need.
4. GENERAL EQUATIONS & STATISTICS
A woman worries about the future until she gets a husband.
A man never worries about the future until he gets a wife.
A successful man is one who makes more money than his wife can spend.
A successful woman is one who can find such a man.
5. HAPPINESS
To be happy with a man, you must understand him a lot and love him a little.
To be happy with a woman, you must love her a lot and not try to understand her at all.
6. LONGEVITY
Married men live longer than single men do, but married men are a lot more willing to die.
7. PROPENSITY TO CHANGE
A woman marries a man expecting he will change, but he doesn't.
A man marries a woman expecting that she won't change, and she does.
8. DISCUSSION TECHNIQUE
A woman has the last word in any argument.
Anything a man says after that is the beginning of a new argument.

Girls = Time * Money (Girls are a combination of time and money)
Time = Money (Time is money)
Girls = Money squared (So, girls are money squared)
Money = sqrt(Evil) (Money is also the root of all evil)
Girls = sqrt(Evil) squared (So, girls are the root of all evil squared)
Girls = Evil (Thus, girls are evil)
*Girls=Evil credit goes to Compynerd255*

Offline DJ Omnimaga

  • Clacualters are teh gr33t
  • CoT Emeritus
  • LV15 Omnimagician (Next: --)
  • *
  • Posts: 55943
  • Rating: +3154/-232
  • CodeWalrus founder & retired Omnimaga founder
    • View Profile
    • Dream of Omnimaga Music
Re: ASM Delvar - Clean and free up from BASIC variables
« Reply #3 on: April 17, 2010, 02:02:11 pm »
Well it would be faster code-wise, but just the action of doing Asm(prgmNAME is slow. It needs to copy the program in a RAM area to run it and other stuff and when you're running low in RAM or have several sub-programs, the Asm( command takes almost a second to execute at all (altough the program ASM code will be executed at lightning speed. See The Reign Of Legends 3 map loading speed for an example of how slow it can be

Offline jsj795

  • LV9 Veteran (Next: 1337)
  • *********
  • Posts: 1105
  • Rating: +84/-3
    • View Profile
Re: ASM Delvar - Clean and free up from BASIC variables
« Reply #4 on: April 17, 2010, 02:06:57 pm »
ahh okay. Yeah, it's something about searching through the whole program list to find the asm program, right? So if you have a lot of programs, than it takes long time to load the program... Got it^^


Spoiler For funny life mathematics:
1. ROMANCE MATHEMATICS
Smart man + smart woman = romance
Smart man + dumb woman = affair
Dumb man + smart woman = marriage
Dumb man + dumb woman = pregnancy
2. OFFICE ARITHMETIC
Smart boss + smart employee = profit
Smart boss + dumb employee = production
Dumb boss + smart employee = promotion
Dumb boss + dumb employee = overtime
3. SHOPPING MATH
A man will pay $2 for a $1 item he needs.
A woman will pay $1 for a $2 item that she doesn't need.
4. GENERAL EQUATIONS & STATISTICS
A woman worries about the future until she gets a husband.
A man never worries about the future until he gets a wife.
A successful man is one who makes more money than his wife can spend.
A successful woman is one who can find such a man.
5. HAPPINESS
To be happy with a man, you must understand him a lot and love him a little.
To be happy with a woman, you must love her a lot and not try to understand her at all.
6. LONGEVITY
Married men live longer than single men do, but married men are a lot more willing to die.
7. PROPENSITY TO CHANGE
A woman marries a man expecting he will change, but he doesn't.
A man marries a woman expecting that she won't change, and she does.
8. DISCUSSION TECHNIQUE
A woman has the last word in any argument.
Anything a man says after that is the beginning of a new argument.

Girls = Time * Money (Girls are a combination of time and money)
Time = Money (Time is money)
Girls = Money squared (So, girls are money squared)
Money = sqrt(Evil) (Money is also the root of all evil)
Girls = sqrt(Evil) squared (So, girls are the root of all evil squared)
Girls = Evil (Thus, girls are evil)
*Girls=Evil credit goes to Compynerd255*

Offline DJ Omnimaga

  • Clacualters are teh gr33t
  • CoT Emeritus
  • LV15 Omnimagician (Next: --)
  • *
  • Posts: 55943
  • Rating: +3154/-232
  • CodeWalrus founder & retired Omnimaga founder
    • View Profile
    • Dream of Omnimaga Music
Re: ASM Delvar - Clean and free up from BASIC variables
« Reply #5 on: April 17, 2010, 02:47:57 pm »
I don,t remember, it was something a bit different I think. I would need to quote what Quigibo said in a chat convo if I can find the log of it

Also this keyboard friggin' sucks x.x

Offline Galandros

  • LV9 Veteran (Next: 1337)
  • *********
  • Posts: 1140
  • Rating: +42/-10
    • View Profile
Re: ASM Delvar - Clean and free up from BASIC variables
« Reply #6 on: April 17, 2010, 03:02:23 pm »
interesting, I wonder how fast will it be compared to using several dozens of delvar commands, since it is actually larger than those delvar commands? (81 bytes total for all 27 vars). Does it also delete archived vars?
It is always faster than TI-BASIC because of the interpreting overhead but it shouldn't be a hell lot faster. The routines (bcalls) used are the same...

No, it don't delete archived but if you want I can very easily change that. Just use bcall(_DelVarArc) instead of bcall(_DelVar) and comment 3 lines of the check if it is in RAM. (minus 4 bytes, bonus!) I might do that for A-Z variables. Later when I add deletion to lists, matrices, etc I will preserve archived ones because it probably means the user wants to preserve them and not take RAM.

ahh okay. Yeah, it's something about searching through the whole program list to find the asm program, right? So if you have a lot of programs, than it takes long time to load the program... Got it^^
Yes, the bcall to search the list of programs and other variables deserved more speed (MirageOS uses its own routine to that) and moving the programs around in RAM takes some time when you have few RAM left.
When finally the fixed location of the assembly program is free it needs to get copied there.


Clearing Ans is easy. Two bcalls and is done. I know the format of the other variables names. >_> I just need courage to mesh all everything into one loop. (I am trying to reuse DelVar)
« Last Edit: April 17, 2010, 03:03:10 pm by Galandros »
Hobbing in calculator projects.

Offline DJ Omnimaga

  • Clacualters are teh gr33t
  • CoT Emeritus
  • LV15 Omnimagician (Next: --)
  • *
  • Posts: 55943
  • Rating: +3154/-232
  • CodeWalrus founder & retired Omnimaga founder
    • View Profile
    • Dream of Omnimaga Music
Re: ASM Delvar - Clean and free up from BASIC variables
« Reply #7 on: April 17, 2010, 05:02:42 pm »
Maybe this could be integrated in future Celtic III versions too? In hook form, it would eliminate the slowness of the Asm() command and be blazing fast. Celtic III games could run this when exiting so all unused vars are cleared

Offline Galandros

  • LV9 Veteran (Next: 1337)
  • *********
  • Posts: 1140
  • Rating: +42/-10
    • View Profile
Re: ASM Delvar - Clean and free up from BASIC variables
« Reply #8 on: April 17, 2010, 05:15:01 pm »
Maybe this could be integrated in future Celtic III versions too? In hook form, it would eliminate the slowness of the Asm() command and be blazing fast. Celtic III games could run this when exiting so all unused vars are cleared
Sure. :D Cool idea. The code is to be used. But the 2 uses I though were:
-use for quick deletion of the variables (and small oncalc)
-games like Escheron if at first attempt don't have enough free memory, can free sometimes enough with this routine (optionally prompting the user)

And UPDATE!

I did it! Only 135 bytes of assembly! Deletes everything I planned: Real and complex numbers, real and complex lists, matrices and all graphical equations. Preserves ALL of them if archived.
I will try to come with ClearEntries in assembly but I don't know the bcall. Maybe I can access it through TI-BASIC interpreter.
Who wants the program to delete GDBs, Strings and Pics? (strings and pictures sometimes hold important data)
And maybe even delete LRESID (a list made by TIOS) and other custom lists (LL1,LL2,LA,etc..)?
Yes, I am happy with the code. The way the subroutine is reused is a bit smart.

I will polish the source code, divide into 2 programs (one just for A-Z and theta vars) and another for all. Then I release in ticalc.

This code and program is beta. Due to the weirdest and most artistic bug I provoked and I can't replicate and don't have an heck of a idea why occurred. TI-OS was ok until I entered equation editor.
Code: [Select]
;Clean Up Basic Variables
;all numbers A-Z /theta/, lists L1 to L6, matrices [A]-[Z], Ans, graphics functions
cleanupBASICvars:
bcall(_CleanAll) ; delete all temp variables
bcall(_OP1Set0) ; This will set OP1 to 0,$80,0,0,0,0,0,0,0
bcall(_StoAns) ; Ans will be equal 0 (Ans can be a huge list or string and take huge space)

; b_call(_ZeroOP1) ; OP1 needs to be zeroed or it will not work for some reason
ld ix,OP1 ; the pointer
ld d,0 ; a flag for activate equ create with 0 bytes (needed to not crash TI-OS)
; it is preserved in deletevars2
ld c,RealObj
ld a,tA ; (OP1+0) = $00 = RealObj, already
ld b,tTheta+1
call deletevars2
ld c,CplxObj
ld a,tA
; ld b,tTheta+1 ; it was preserved!
call deletevars2

;these vars have 3 bytes, so a smart solution is coded
inc ix
ld e,RealObj
ld c,tVarLst
ld a,tL1
ld b,tL6+1
call deletevars3
ld e,CListObj
; ld c,tVarLst ; it was preserved!
ld a,tL1
; ld b,tL6+1 ; it was preserved!
call deletevars3
ld e,MatObj
ld c,tVarMat
ld a,tMatA
ld b,tMatJ+1
call deletevars3

ld d,1 ; activate bcall(_Create0Equ)
ld e,EquObj
ld c,tVarEqu
ld a,tY1
ld b,tY0+1
call deletevars3
; ld e,EquObj
; ld c,tVarEqu ; it was preserved!
ld a,tX1T ;\tX1T to tX6T
ld b,tY6T+1 ;/tY1T to tY6T
call deletevars2
; ld e,EquObj
; ld c,tVarEqu ; it was preserved!
ld a,tR1
ld b,tR6+1
call deletevars2
; ld e,EquObj
; ld c,tVarEqu ; it was preserved!
ld a,tun
ld b,twn+1
;fall back

deletevars3:
ld (ix-1),e
deletevars2:
ld (ix+0),c
deletevarloop:
push af
push bc
push de
ld (ix+1),a
bcall(_FindSym) ; look up
jr c,cdelarc ; if doesn't exist, then skip
inc b ;\
dec b ; | if b!=0 (it is in flash), then skip
jr nz,cdelarc ;/
bcall(_DelVar) ; delete variable
cdelarc:
pop de
inc d
dec d
jr z,notequvar
bcall(_Create0Equ) ;OP1 destroyed, OP4 has variable name
bcall(_OP4toOP1) ;restore OP1 ^^
notequvar:
pop bc
pop af
inc a
cp b
jr nz,deletevarloop
ret

cleanupBASICvarsend:

 .echo "code and data size: ",cleanupBASICvarsend-cleanupBASICvars
;

Enjoy!
EDIT: finally uploaded files! I will update first topic when I finish some things...
EDIT2: I assembled for TI-83 (Regular) too! It seems the bcalls exist for it.
Now how the heck I test it in emulator? I have to install a shell... Anyone willing to give the steps or tutorial? Or there is some wacky exploit to run easily?
EDIT3: Used Venus shell and I did it. My program does nothing on TI-83. Either delete variables or crash TI-OS. Nothing I can see. Unless someone request I will not debug soon.
« Last Edit: April 17, 2010, 06:12:29 pm by Galandros »
Hobbing in calculator projects.

Offline DJ Omnimaga

  • Clacualters are teh gr33t
  • CoT Emeritus
  • LV15 Omnimagician (Next: --)
  • *
  • Posts: 55943
  • Rating: +3154/-232
  • CodeWalrus founder & retired Omnimaga founder
    • View Profile
    • Dream of Omnimaga Music
Re: ASM Delvar - Clean and free up from BASIC variables
« Reply #9 on: April 17, 2010, 06:27:37 pm »
Mhmm strange x.x I wonder if someone could help

Offline Galandros

  • LV9 Veteran (Next: 1337)
  • *********
  • Posts: 1140
  • Rating: +42/-10
    • View Profile
Re: ASM Delvar - Clean and free up from BASIC variables
« Reply #10 on: April 18, 2010, 03:19:01 am »
Mhmm strange x.x I wonder if someone could help
Hopefully it can't repeat the error.
I will try to mess a bit with code to see if it triggers. It is probably because between assembles and debugs there was one that deleted equation vars without recreating them with 0 bytes. The TI-OS always assumes graphics equations are created and if aren't the SDK warns it will crash.
EDIT: nevermind, it crashes but doesn't give that odd screen.
« Last Edit: April 18, 2010, 03:59:21 am by Galandros »
Hobbing in calculator projects.

Offline DJ Omnimaga

  • Clacualters are teh gr33t
  • CoT Emeritus
  • LV15 Omnimagician (Next: --)
  • *
  • Posts: 55943
  • Rating: +3154/-232
  • CodeWalrus founder & retired Omnimaga founder
    • View Profile
    • Dream of Omnimaga Music
Re: ASM Delvar - Clean and free up from BASIC variables
« Reply #11 on: April 18, 2010, 04:24:00 am »
good luck with it x.x

I wish I could help but I don't know ASM and am not good at reading other people code

Offline Galandros

  • LV9 Veteran (Next: 1337)
  • *********
  • Posts: 1140
  • Rating: +42/-10
    • View Profile
Re: ASM Delvar - Clean and free up from BASIC variables
« Reply #12 on: April 18, 2010, 05:53:50 am »
I commented even more the source code and optimized further in size. (I think there is still some ways)
I cleaned the source, added the defines and final tested.

Now write the readme, do the batch files to compile , decide the program names and upload. :P

The interesting now would be someone help me debug the TI-83 build. For the TI-83 there is few documentation on bcalls, but I will try to compare to TI-83+ to see what differences come out. Debugging on calculator and watch the entire bcall disassembly is a thing I won't do. >:( Maybe it is not worth to put on TI-83 nowadays.
« Last Edit: April 18, 2010, 05:54:34 am by Galandros »
Hobbing in calculator projects.

Offline ztrumpet

  • The Rarely Active One
  • CoT Emeritus
  • LV13 Extreme Addict (Next: 9001)
  • *
  • Posts: 5712
  • Rating: +364/-4
  • If you see this, send me a PM. Just for fun.
    • View Profile
Re: ASM Delvar - Clean and free up from BASIC variables
« Reply #13 on: April 18, 2010, 11:09:13 am »
Hmm, interesting.  I think this would be useful. :)
In my opinion, I'd delete just (for the lists) L1 to L6 and LRESID.  I think custom lists are there for a reason in most cases, and normally they hold some sort of data the user wants. :)
« Last Edit: April 18, 2010, 11:09:21 am by ztrumpet »

Offline DJ Omnimaga

  • Clacualters are teh gr33t
  • CoT Emeritus
  • LV15 Omnimagician (Next: --)
  • *
  • Posts: 55943
  • Rating: +3154/-232
  • CodeWalrus founder & retired Omnimaga founder
    • View Profile
    • Dream of Omnimaga Music
Re: ASM Delvar - Clean and free up from BASIC variables
« Reply #14 on: April 18, 2010, 11:22:43 am »
I commented even more the source code and optimized further in size. (I think there is still some ways)
I cleaned the source, added the defines and final tested.

Now write the readme, do the batch files to compile , decide the program names and upload. :P

The interesting now would be someone help me debug the TI-83 build. For the TI-83 there is few documentation on bcalls, but I will try to compare to TI-83+ to see what differences come out. Debugging on calculator and watch the entire bcall disassembly is a thing I won't do. >:( Maybe it is not worth to put on TI-83 nowadays.
It may be a good idea to add it, since it's still sold in France and Belgium (renamed to TI-82 STATS, but exact same calc, same ROM image) and the TI-76.Fr supposedly run 83 programs too and is still sold. But again it's still not as popular as the 83+ worldwide.