Shoutbox

[?] Pow... err, triggering some function on certain convo events? - Printable Version

-Shoutbox (https://shoutbox.menthix.net)
+-- Forum: MsgHelp Archive (/forumdisplay.php?fid=58)
+--- Forum: Messenger Plus! for Live Messenger (/forumdisplay.php?fid=4)
+---- Forum: Scripting (/forumdisplay.php?fid=39)
+----- Thread: [?] Pow... err, triggering some function on certain convo events? (/showthread.php?tid=66314)

[?] Pow... err, triggering some function on certain convo events? by Matti on 09-16-2006 at 11:41 AM

Good, I'm trying to make a calculator script in the conversation window. It has a tab which opens a small typing panel with toolbar underneath the editting panel, so it will look very cool. :P

Now, I'm trying to work out the math functions. I want to let this:

code:
8^2
change into this:
code:
64
by using Math.pow(8, 2). The problem is: how can I replace that? :S
It also has to parse this:

code:
(-9*7)^(7-5)
to:
code:
3969
for example, so brackets should also be parsed first. (I think eval() can help here?)

Okay, Cookie just told me that would be very very hard. (read: too hard for me) So I would like to fix 2 other problems problems:
  • Does anyone know how I can trigger a function when the user shows/hides the display pictures in the conversation window? I'm trying to make the tab be positioned almost perfectly, so this one is quite important for me.
  • Also, is there a way to know if the "is typing message" is shown? I need to call this since if the other contact has emoticons in his/her name, the tab bar gets higher. Therefore, my tab should resize too.
Anyone has an idea to do these? ^o)
RE: [?] Powers by markee on 09-16-2006 at 11:51 AM

Shouldn't if you take the brackets as well it should work out properly?

* markee goes to check this out

EDIT: confirmed, if you use a regExp taking the brackets then it will work.


RE: [?] Powers by Matti on 09-16-2006 at 12:06 PM

Then, what expression should I use? Since I'm a bit of n00bish with expressions. :P


RE: [?] Powers by markee on 09-16-2006 at 12:23 PM

quote:
Originally posted by Mattike
Then, what expression should I use? Since I'm a bit of n00bish with expressions. [Image: msn_tongue.gif]
I wish I could help, I'm very noobish in that area too.  Maybe PM the likes of Shondoit as he prides himself on his regExp knowledge.  Or you could also maybe hope that the likes of CookieRevised helps you out.
RE: [?] Powers by CookieRevised on 09-16-2006 at 01:27 PM

It wouldn't be easy.... In fact, it would be hard, especially if you'r not used to regular expressions, parsing (sub)strings and manipulating (sub)strings, and other stuff...

To make what you want you need to make your own eval() function so to speak, from scratch. This means you need to take in account all the possible math operators which are to be used, the operator precedence and what not...

You need to parse each and every operator seperatly (since they can occur in any place in the expression), taking in account parenthesis and brackets and keeping everything in the correct order of precedence, etc etc.

----

To make it a bit easier, you can try to first make a parser which converts the normal math expression (called an infix expression) into a postfix expression (this would be the hardest part).

In that way, you can easly parse/evaluate everything from left to right instead of taking in account parenthesis, order of precedence, etc.

An example of a postfix expression is: "1 2 * 3 +", which will result in 5. Since it is converted from the normal math expression "1*2+3".

There are even already many JavaScript sources for evaluating a postfix expression (as it is actually dead easy). An example, including a very detailed explanation on how it works can be found here:
http://www.qiksearch.com/articles/cs/postfix-evaluation/index.htm

----

Infix notation

What most people understand under a mathematical expression. The operators are written in infix-style.

The major problem with this notation is that it is not that simple to parse. The parentheses surrounding the groups of operands and operators are necessary to indicate the order in which the operations are to be parsed. In the absence of parentheses, certain rules determine the order of operations.

eg1: (5+3)*9
eg2: 9*(5+3)


Postfix notation

Also called Reverse Polish notation (RPN)

This notation is also used in some scientific calculators, mostly in HP calculators. The most noticeable difference is that the operands come before the operator, thus leaving out the need for parentheses.

Unlike infix notation, parsing postfix notations is stack-based: operands are popped from a stack, and results are pushed back into it.

Although this might seem strange at first, postfix has the very big advantage of being extremely easy and fast.

Thus, calculations proceed from left to right.
There are no brackets or parentheses, as they are unnecessary.
Operands precede operator, they are removed as the operation is evaluated.
When an operation is done, the result becomes an operand itself (for later use for other operators).
There are no hidden states, and thus also no need to worry about checking if you have hit an operator or not.

eg1: 5 3 + 9 *
eg2: 9 5 3 + *


Convertion from infix to postfix

This is relativly hard (depends on how much experience you have on the matter). In fact, you better copy existing routines which are trialed and tested before if you don't fully understand the logic behind it.

Here is again a very easy explanation:
http://www.qiksearch.com/articles/cs/infix-postfix/
the source posted there is buggy, see the updated source here:
http://www.qiksearch.com/javascripts/infix-postfix.htm
http://www.codingforums.com/showthread.php?t=5692


Others:
http://www.cs.man.ac.uk/~pjj/cs2121/fix.html
http://www.unf.edu/~rzucker/cot3100dir/parser.html
http://trubetskoy1.narod.ru/english/alg/ppne.html


RE: [?] Powers by Matti on 09-16-2006 at 02:02 PM

Oh damn... :|
But what about decimal numbers like 1.5? Those can't be processed through a postfix expressions, or am I wrong?


RE: [?] Powers by CookieRevised on 09-16-2006 at 02:11 PM

quote:
Originally posted by Mattike
Oh damn... :|
But what about decimal numbers like 1.5? Those can't be processed through a postfix expressions, or am I wrong?
1.5 is just a number like everything else... so yes, it can be parsed.

In fact, you can parse whatever you want including functions you invent yourself.

eg:
Infix: (1.5 + 98) * 2 ^ blah(4)
Postfix: 1.5 98 + 2 4 blah ^ *

PS: I updated my previous post with some links which explain everything in detailed way. It is a very good base to start of with.







PSS: why don't you work further on your CountDown Live script? some stuff todo there ;)
RE: [?] Pow... err, triggering some function on certain convo events? by Matti on 09-16-2006 at 02:25 PM

Right... ^o) I think I'll wait a bit with such functions and keep it simple so far. :P Whenever I got really nothing, but nothing to do, I can think about it. :)
I'm having lots more problems with the tab itself to change position when the user shows/hides the display pictures, or when the "is typing" message contains emoticons. Read the first post for more, detailed information. ;)


RE: [?] Pow... err, triggering some function on certain convo events? by deAd on 09-16-2006 at 08:00 PM

If I were you, instead of a tab, you could make it a command that popped the answer in a toast.

Instead of checking when the dps are closed, you can just reposition it on a timer. (100 ms will work well :P)


RE: [?] Pow... err, triggering some function on certain convo events? by Matti on 09-17-2006 at 09:19 AM

quote:
Originally posted by deAd
If I were you, instead of a tab, you could make it a command that popped the answer in a toast.
That kills the idea. The thing was to share your calculations with your contacts, not calculating some things for yourself. And I wanted to try something different of simple commands, but I'll make it possible. (that won't be too hard after all)

quote:
Instead of checking when the dps are closed, you can just reposition it on a timer. (100 ms will work well :P)
I already have a timer which repositions the tab/box, since it has to follow when the user resizes the window. The problem is that the script has to know if the DPs are shown or not, so it can change the distance of the right side of the window. ;)
RE: [?] Pow... err, triggering some function on certain convo events? by phalanxii on 09-17-2006 at 10:18 AM

quote:
Originally posted by Mattike
  • Also, is there a way to know if the "is typing message" is shown? I need to call this since if the other contact has emoticons in his/her name, the tab bar gets higher. Therefore, my tab should resize too.
Anyone has an idea to do these? ^o)

I'm not 100% sure on this, but you *may* be able to use Pai's Xniff (ActiveX Packet Sniffer) for this. Personally, I would only use this as a last resort, because it's an extra 500kb for something so minor.

Also, for your functions, you may want to check out Huhu_Manix's Huhu Calculator 1.0. It parses all the examples in your first post perfectly, and includes square roots, trigonometric functions, logarithms and more.
RE: [?] Pow... err, triggering some function on certain convo events? by Plik on 09-17-2006 at 12:30 PM

quote:
Originally posted by phalanxii
Also, for your functions, you may want to check out Huhu_Manix's Huhu Calculator 1.0. It parses all the examples in your first post perfectly, and includes square roots, trigonometric functions, logarithms and more.
But the method it uses (using a http request to use google to parse the equation) is a really horrible way todo it :dodgy:
RE: [?] Pow... err, triggering some function on certain convo events? by Matti on 09-17-2006 at 12:38 PM

quote:
Originally posted by phalanxii
I'm not 100% sure on this, but you *may* be able to use Pai's Xniff (ActiveX Packet Sniffer) for this. Personally, I would only use this as a last resort, because it's an extra 500kb for something so minor.
The problem is that I can't test it myself, since I am on a wireless connection! :(
quote:
Originally posted by Plik
But the method it uses (using a http request to use google to parse the equation) is a really horrible way todo it :dodgy:
No, really? :P
RE: [?] Pow... err, triggering some function on certain convo events? by markee on 09-17-2006 at 12:46 PM

I think I might have a solution for you.  You can use calc.exe and parse keystrokes to it, then one the equation is finished you just get your script to copy (ctrl+v) and you can the read the last entry in the clipboard.  Read the help file to get the keyboard shortcuts like 'y' for to the power.  It might not be a very nice way of going about this but if anyone else has a better suggestion about doing this have a go at it.


RE: [?] Pow... err, triggering some function on certain convo events? by Matti on 09-17-2006 at 01:04 PM

But that would force the script to open the calculator, so the user can close it while it enters the keys. :-/

I guess the best thing I can use is a calculator ActiveX object which accepts a string as input and returns the result. I know it's very lazy, but I really don't know any better. :(


RE: [?] Pow... err, triggering some function on certain convo events? by Shondoit on 09-17-2006 at 03:30 PM

Or perhaps you could use the Postfix method Cookie brought up
I already worked out the parsing of infix to postfix...
Now I'm working on calculating the postfix expression

So hang-on

-edit- Almost finished, done within an hour, I hope (I have to eat :P)

-edit2- It took a little longer than I expected, becuase the function weren't called correctly... But here it is anyway
It's very easy to use... Just call StringName.Calculate()
i.e.:
var Expression = Message.substr(0,4)
Result = Expression.Calculate()

It supports presedence, exponents, parenthese multiplication ( 3(4+1) = 15) and Math object functions and constants, for example, you can calculate a function like this:
Result = "3(1 + sin(PI))^2".Calculate()
or
var x = -4
Result = "-sqrt(abs(x))".Calculate()

code:
String.prototype.ToPostfix = function () {
   var Stack = ""
   var Token = ""
   var Result = ""
   for (var i = 0; i < this.length; i++) {
      Token = this.charAt(i)
      switch (Token) {
         case "(":
            Stack += "("
            break
         case ")":
            while (Stack.length > 0 && Stack.charAt(Stack.length - 1) != "(") {
               Result += Stack.charAt(Stack.length - 1)
               Stack = Stack.substring(0, Stack.length - 1)
            }
            Stack = Stack.substring(0, Stack.length - 1)
            break
         case "^": case "*": case "/": case "+": case "-":
            PopStack()
            break
         default:
            while (/[^()\^*/+-]/.test(this.charAt(i + 1)) && i < this.length) {
               Token += this.charAt(i++ + 1)
            }
            if (/\+|-/.test(this.charAt(i + 1))) {
               if (/e/i.test(this.charAt(i)) && i > 0 && /\d/.test(this.charAt(i - 1))) {
                  Token += this.charAt(i++ + 1)
                  while (/[^()\^*/+-]/.test(this.charAt(i + 1)) && i < this.length) {
                     Token += this.charAt(i++ + 1)
                  }
               }
            }
            if (this.charAt(i + 1) == "(") {
               try {
                  if (typeof(Math[Token])=="function" || eval("typeof("+Token+")=='function'")) {
                     if (eval("typeof("+Token+")!='function'")) {
                        Token = "Math." + Token
                     }
                     Token += this.charAt(i++ + 1)
                     var ParamToken = ""
                     var Parentheses = 0
                     while ((/[^)]/.test(this.charAt(i + 1)) || Parentheses > 0) && i < this.length) {
                        if (this.charAt(i + 1) == "(") Parentheses++; else if (this.charAt(i + 1) == ")") Parentheses--
                        ParamToken += this.charAt(i++ + 1)
                     }
                     var Params = ParamToken.split(/\s*,\s*/)
                     for (Index in Params) {
                        Params[Index] = Params[Index].Calculate()
                     }
                     Token += Params.join(",")
                     Token += this.charAt(i++ + 1)
                  } else {
                     PopStack("*")
                  }
               } catch (e) {
                  return undefined
               }
            }
            Result += "\x01" + Token + "\x01"
            break
      }
   }
   while (Stack.length > 0) {
      Result += Stack.charAt(Stack.length - 1)
      Stack = Stack.substring(0, Stack.length-1)
   }
   return Result.replace(/\s/g, "")
   
   function PopStack (Operator) {
      if (Operator == undefined) Operator = Token
      while (Stack.length > 0 && ((/[\^*/+-]/.test(Operator) && /[\^]/.test(Stack.charAt(Stack.length - 1))) || (/[*/+-]/.test(Operator) && /[*/]/.test(Stack.charAt(Stack.length - 1))) || (/[+-]/.test(Operator) && /[+-]/.test(Stack.charAt(Stack.length - 1))))) {
         Result += Stack.charAt(Stack.length - 1)
         Stack = Stack.substring(0, Stack.length - 1)
      }
      Stack += Operator
   }
}
String.prototype.CalculatePostfix = function () {
   var Stack = new Array()
   var Token = ""
   for (var i = 0; i < this.length; i++) {
      Token = this.charAt(i)
      if (/[^\^*/+-]/.test(Token)) {
         while (/[^\x01]/.test(this.charAt(i + 1)) && i < this.length) {
            Token += this.charAt(i++ + 1)
         }
         Token += this.charAt(i++ + 1)
         if (/\+|-/.test(this.charAt(i + 1))) {
            if (/e/i.test(this.charAt(i)) && i > 0 && /\d/.test(this.charAt(i - 1))) {
               Token += this.charAt(i++ + 1)
               while (/[^()\^*/+-]/.test(this.charAt(i + 1)) && i < this.length) {
                  Token += this.charAt(i++ + 1)
               }
            }
         }
         if (/\x01(.+)\x01/.test(Token)) {
            var Operands = RegExp.$1.split(/\x01\x01/)
            for (Index in Operands) {
               if(eval("typeof("+Operands[Index]+")=='undefined'")) {
                  if (typeof(Math[Operands[Index]]) != "undefined" && typeof(Math[Operands[Index]]) != "function") {
                     Operands[Index] = Math[Operands[Index]]
                  }
               }
            }
            Stack = Stack.concat(Operands)
         } else {
            return undefined
         }
      } else {
         if (Stack.length >= 2) {
            if (Token == "^") {
               Stack[Stack.length - 2] = Math.pow(eval(Stack[Stack.length - 2]), eval(Stack[Stack.length - 1]))
            } else {
               Stack[Stack.length - 2] = eval(eval(Stack[Stack.length - 2]) + Token + eval(Stack[Stack.length - 1]))
            }
            Stack.pop()
         }
      }
   }
   try {
      return eval(Stack[0])
   } catch (e) {
      return undefined
   }
}
String.prototype.Calculate = function () {
   var Postfix = this.ToPostfix()
   if (Postfix != undefined) return Postfix.CalculatePostfix()
}

Cookie, I'm not sure if I missed something... Could you have a look?
I think I took care off all the basic operations..., thx (y) (Why is [noparse] not working for smilies?)
RE: RE: [?] Pow... err, triggering some function on certain convo events? by CookieRevised on 09-17-2006 at 11:03 PM

quote:
Originally posted by Mattike
I'm having lots more problems with the tab itself to change position when the user shows/hides the display pictures, or when the "is typing" message contains emoticons. Read the first post for more, detailed information. ;)
adding something to the formatting bar like that is not going to work. There are way too many complications. Just to name one:
[Image: attachment.php?pid=730968]
where are you going to show the icon/window?

Personally, I would even not attempt to do it because it is a waste of time (unless you do it in the proper way, like Plus! does it... which is extremely hard...)




quote:
Originally posted by Mattike
The thing was to share your calculations with your contacts, not calculating some things for yourself.
Which can perfectly be done with a command... It's just a matter of what you output. see
"CookieRevised's reply to An idea for a script" for an extremely easy Calculator script using the JScript's eval() function.
(a thread which you also participated in ;))


And to make something different, but still based upon the same thing, you can take the idea which is described in this thread, namely: showing all the steps of the calculation.
(though this requires you to forget about infox to postfix calculation (almost) as the calculation need to be calculated in your script using infix style)




quote:
Originally posted by markee
I think I might have a solution for you.  You can use calc.exe and parse keystrokes to it, then one the equation is finished you just get your script to copy (ctrl+v) and you can the read the last entry in the clipboard.
I dunno which is worse, using a HTTP stream and using some form on the web, or sending keystrokes to the (very limited) calc application... :p
quote:
Originally posted by markee
It might not be a very nice way of going about this but if anyone else has a better suggestion about doing this have a go at it.
well... see all my posts in this thread ;):D




quote:
Originally posted by Shondoit
Cookie, I'm not sure if I missed something... Could you have a look?
I'm not going to strip down your routine line per line though (way too much work :p:d).

If your script is based upon the modified version 23/10/02 of Premshree Pillai's code, it should work.

PS: I added yet another link to my infix/postfix post which explains a similar, but other method of converting (recursive method instead of using a stack).

However, I can see you use strings to store the stack? If so, this is not so good. It would be better if you use arrays for this like you do in your CalculatePostfix function.



----------------


Related, and of use for all who are interested in making something which has todo with calulating math expressions:
CookieRevised's reply to Advanced VB coders
RE: RE: RE: [?] Pow... err, triggering some function on certain convo events? by deAd on 09-17-2006 at 11:18 PM

quote:
Originally posted by CookieRevised
quote:
Originally posted by Mattike
I'm having lots more problems with the tab itself to change position when the user shows/hides the display pictures, or when the "is typing" message contains emoticons. Read the first post for more, detailed information. ;)
adding something to the formatting bar like that is not going to work. There are way too many complications. Just to name one:
[Image: attachment.php?pid=730968]
where are you going to show the icon/window?

Personally, I would even not attempt to do it because it is a waste of time (unless you do it in the proper way, like Plus! does it... which is extremely hard...)
He wants it with the tabs, not the toolbar.
RE: [?] Pow... err, triggering some function on certain convo events? by CookieRevised on 09-17-2006 at 11:42 PM

quote:
Originally posted by deAd
He wants it with the tabs, not the toolbar.
oh yeah, right... I stand corrected.

Still, what if the writing tab isn't there, what if another tab is added there (some (official) addons add a tab there)...

unless you do it like it should be done, I wouldn't attempt to do it either for same reasons.
RE: [?] Pow... err, triggering some function on certain convo events? by phalanxii on 09-18-2006 at 03:54 AM

Changing the subject a little bit, Shondoit's code works really well for me. However, two things:

1. How can I change some of the functions to degrees, not radians?
2. How can I make the functions and properties case-insensitive?

I've sort of figured out 2, but I don't want to edit anything because the script is so complex. :S


RE: [?] Pow... err, triggering some function on certain convo events? by Shondoit on 09-18-2006 at 05:57 AM

The first one is pretty easy too... But I don't have the time atm (school :S )
If you could post how you solved the second issue (y) ...


RE: [?] Pow... err, triggering some function on certain convo events? by phalanxii on 09-18-2006 at 08:02 AM

Well, I haven't gone through all your code to know if I'm changing the right thing, but for functions, I think you can add .toLowerCase() to Token in some places so that the code reads:

code:
if (typeof(Math[Token.toLowerCase()])=="function" || eval("typeof("+Token+")=='function'")) {
   if (eval("typeof("+Token+")!='function'")) {
      Token = "Math." + Token.toLowerCase()
   }
   (...)
I'm not sure what to do for properties though, because I don't know where these are evaluated. :S

Also, it seems that sometimes the values are approximated before further functions are performed on them. For example, "sin(PI)" doesn't return "0", but "1.22460635382238E-16" (really close to 0). I guess this doesn't matter too much, but it would be good if it returned "0". :)

As for the degrees, I think this works for sin, cos and tan (not sure about asin, acos, atan and atan2 though):
code:
for (Index in Params) {
   Params[Index] = Params[Index].Calculate()
   if(Degrees & /\b(cos|sin|tan)\b/.test(Token)) Params[Index] *= Math.PI / 180
}
Degrees is a global boolean. (Y)

EDIT: Found where to change for properties. :)
code:
if (typeof(Math[Operands[Index].toUpperCase()]) != "undefined" && typeof(Math[Operands[Index]]) != "function") {
   Operands[Index] = Math[Operands[Index].toUpperCase()]
}
This time we use .toUpperCase because the properties are uppercase.

EDIT #2: I've also just noticed that the calculate function will parse "1 + 2 + 3" and "1+(2+3)" but not "1+ (2+3)". Any way to fix that? (It seems to not parse if there is a space before the open bracket.)
RE: [?] Pow... err, triggering some function on certain convo events? by Shondoit on 09-18-2006 at 11:09 AM

Thanks for the reply, I'll look into it as soon as I get home...

I checked, and the properties are indeed all uppercase, and the functions all lowercase...
It's normal for JScript to begin lowercase and use an capital by a wordbreak, so I thought it wasn't possible...

And about the sin(PI), this is a limitation of JScript, if you type this in a random HTML file, it still evaluates to 1.2246063538223772e-16

About the space before the parenthese, I though I fixed that... :S

-edit- I did fix it, but I haven't updated the code... will update when I get home (schoolbell is ringing, gtg)


RE: [?] Pow... err, triggering some function on certain convo events? by Matti on 09-18-2006 at 06:35 PM

quote:
Originally posted by Shondoit
It took a little longer than I expected, becuase the function weren't called correctly... But here it is anyway
It's very easy to use... Just call StringName.Calculate()
i.e.:
var Expression = Message.substr(0,4)
Result = Expression.Calculate()

It supports presedence, exponents, parenthese multiplication ( 3(4+1) = 15) and Math object functions and constants, for example, you can calculate a function like this:
Result = "3(1 + sin(PI))^2".Calculate()
or
var x = -4
Result = "-sqrt(abs(x))".Calculate()
Awesome. :|
I think if there's a need of a calculator script, you deserve to make it, not me. My tab placement just sucks, and it's not worth to release it. I am sure you can make a good script with just that one function. (y)

* Matti ends his crappy project. :P
RE: [?] Pow... err, triggering some function on certain convo events? by Shondoit on 09-18-2006 at 08:07 PM

This is the fixed code... It supports different angle types (Angle = "degree" or Angle = "radians" and even supports "grad")
It supports Mixed case functions (Only if it is a function of the Math object) and I fixed the space problem...

But Mattike, please go on, you can desgin the GUI, the scriptcommands, ...etc. I don't really have the time for it, if you need any help, add me to WLM (I speak Dutch (y))

code:
String.prototype.ToPostfix = function () {
   var Stack = ""
   var Token = ""
   var Result = ""
   for (var i = 0; i < this.length; i++) {
      Token = this.charAt(i)
      switch (Token) {
         case "(":
            Stack += "("
            break
         case ")":
            while (Stack.length > 0 && Stack.charAt(Stack.length - 1) != "(") {
               Result += Stack.charAt(Stack.length - 1)
               Stack = Stack.substring(0, Stack.length - 1)
            }
            Stack = Stack.substring(0, Stack.length - 1)
            break
         case "^": case "*": case "/": case "+": case "-":
            PopStack()
            break
         default:
            while (/[^()\^*/+-]/.test(this.charAt(i + 1)) && i < this.length) {
               Token += this.charAt(i++ + 1)
            }
            if (/\+|-/.test(this.charAt(i + 1))) {
               if (/e/i.test(this.charAt(i)) && i > 0 && /\d/.test(this.charAt(i - 1))) {
                  Token += this.charAt(i++ + 1)
                  while (/[^()\^*/+-]/.test(this.charAt(i + 1)) && i < this.length) {
                     Token += this.charAt(i++ + 1)
                  }
               }
            }
            if (this.charAt(i + 1) == "(") {
               try {
                  if (typeof(Math[Token.toLowerCase()])=="function" || eval("typeof("+Token+")=='function'")) {
                     if (eval("typeof("+Token+")!='function'")) {
                        Token = "Math." + Token.toLowerCase()
                     }
                     Token += this.charAt(i++ + 1)
                     var ParamToken = ""
                     var Parentheses = 0
                     while ((/[^)]/.test(this.charAt(i + 1)) || Parentheses > 0) && i < this.length) {
                        if (this.charAt(i + 1) == "(") Parentheses++; else if (this.charAt(i + 1) == ")") Parentheses--
                        ParamToken += this.charAt(i++ + 1)
                     }
                     var Params = ParamToken.split(/\s*,\s*/)
                     for (Index in Params) {
                        Params[Index] = Params[Index].Calculate()
                     }
                     Token += Params.join(",")
                     Token += this.charAt(i++ + 1)
                     if (/^Math\.(sin|cos|tan)\((.+)\)$/.test(Token)) {
                        var Func = "Math." + RegExp.$1 + "(" + RegExp.$2 + "*Math.PI"
                        if (/^degrees?$/i.test(Angle)){
                           Token = Func + "/180)"
                        } else if (/^grad$/i.test(Angle)) {
                           Token = Func + "/200)"
                        }
                     }
                     if (/^Math\.(a(?:sin|cos|tan2?))\((.+)\)$/.test(Token)) {
                        var Func = "Math." + RegExp.$1 + "(" + RegExp.$2 + ")/Math.PI"
                        if (/^degrees?$/i.test(Angle)){
                           Token = Func + "*180"
                        } else if (/^grad$/i.test(Angle)) {
                           Token = Func + "*200"
                        }
                        Token = Token.Calculate()
                     }
                  } else {
                     PopStack("*")
                  }
               } catch (e) {
                  return undefined
               }
            }
            Result += "\x01" + Token + "\x01"
            break
      }
   }
   while (Stack.length > 0) {
      Result += Stack.charAt(Stack.length - 1)
      Stack = Stack.substring(0, Stack.length-1)
   }
   return Result.replace(/\s/g, "")
   
   function PopStack (Operator) {
      if (Operator == undefined) Operator = Token
      while (Stack.length > 0 && ((/[\^*/+-]/.test(Operator) && /[\^]/.test(Stack.charAt(Stack.length - 1))) || (/[*/+-]/.test(Operator) && /[*/]/.test(Stack.charAt(Stack.length - 1))) || (/[+-]/.test(Operator) && /[+-]/.test(Stack.charAt(Stack.length - 1))))) {
         Result += Stack.charAt(Stack.length - 1)
         Stack = Stack.substring(0, Stack.length - 1)
      }
      Stack += Operator
   }
}
String.prototype.CalculatePostfix = function () {
   var Stack = new Array()
   var Token = ""
   for (var i = 0; i < this.length; i++) {
      Token = this.charAt(i)
      if (/[^\^*/+-]/.test(Token)) {
         while (/[^\x01]/.test(this.charAt(i + 1)) && i < this.length) {
            Token += this.charAt(i++ + 1)
         }
         Token += this.charAt(i++ + 1)
         if (/\+|-/.test(this.charAt(i + 1))) {
            if (/e/i.test(this.charAt(i)) && i > 0 && /\d/.test(this.charAt(i - 1))) {
               Token += this.charAt(i++ + 1)
               while (/[^()\^*/+-]/.test(this.charAt(i + 1)) && i < this.length) {
                  Token += this.charAt(i++ + 1)
               }
            }
         }
         if (/\x01(.+)\x01/.test(Token)) {
            var Operands = RegExp.$1.split(/\x01\x01/)
            for (Index in Operands) {
               if(eval("typeof("+Operands[Index]+")=='undefined'")) {
                  if (typeof(Math[Operands[Index].toUpperCase()]) != "undefined" && typeof(Math[Operands[Index]]) != "function") {
                     Operands[Index] = Math[Operands[Index].toUpperCase()]
                  }
               }
            }
            Stack = Stack.concat(Operands)
         } else {
            return undefined
         }
      } else {
         if (Stack.length >= 2) {
            if (Token == "^") {
               Stack[Stack.length - 2] = Math.pow(eval(Stack[Stack.length - 2]), eval(Stack[Stack.length - 1]))
            } else {
               Stack[Stack.length - 2] = eval(eval(Stack[Stack.length - 2]) + Token + eval(Stack[Stack.length - 1]))
            }
            Stack.pop()
         }
      }
   }
   try {
      return eval(Stack[0])
   } catch (e) {
      return undefined
   }
}
String.prototype.Calculate = function () {
    var Infix = this.replace(/\s/, "")
    var Postfix = Infix.ToPostfix()
    if (Postfix != undefined) return Postfix.CalculatePostfix()
}

RE: [?] Pow... err, triggering some function on certain convo events? by phalanxii on 09-18-2006 at 11:15 PM

Awesome! This is just what I need. :) For those of you who want it, here's a little code that I made for this:

code:
var Angle = "Radian";

function OnEvent_ChatWndEditKeyDown(ChatWnd, KeyCode, CtrlKeyDown, ShiftKeyDown){
   if(KeyCode == 116 && !CtrlKeyDown && !ShiftKeyDown) {
      var x = ChatWnd.EditText.substring(ChatWnd.EditText_GetCurSelStart(), ChatWnd.EditText_GetCurSelEnd()).Calculate()
      if(x != undefined) {
         ChatWnd.EditText_ReplaceSel(x)
      }
   }
}
This is to add to Shondoit's calculator so that you can use it in your chats. All you have to do, is type your expression, highlight it and press F5. Also, you can change Angle to "Radian", "Degree", or "Grad" (as seen in Shondoit's script). :D

Also, Shondoit you might want to check:
code:
if (/^Math\.(a(?:sin|cos|tan2?))\((.+)\)$/.test(Token)) {
   var Func = "Math." + RegExp.$1 + "(" + RegExp.$2 + ")/Math.PI"
   if (/^degrees?$/i.test(Angle)){
      Token = Func + "*180"
   } else if (/^grads?$/i.test(Angle)) {
      Token = Func + "*200"
   }
   [b]Token = Token.Calculate()[/b]
}
When I debug trace it, it seems that this loops because the angle setting is not changed. Perhaps change this to Token = eval(Token)?

-----

EDIT: Thought I might just add this in. If you want to make your own custom calculator functions, add the following code inside the script (you will need to match where it goes):
code:
      Token = eval(Token)
   }
else if (typeof(Custom[Token.toLowerCase()])=="function" || eval("typeof("+Token+")=='function'")) {
   if (eval("typeof("+Token+")!='function'")) {
      Token = "Custom." + Token.toLowerCase()
   }
   Token += this.charAt(i++ + 1)
   var ParamToken = ""
   var Parentheses = 0
   while ((/[^)]/.test(this.charAt(i + 1)) || Parentheses > 0) && i < this.length) {
      if (this.charAt(i + 1) == "(") Parentheses++; else if (this.charAt(i + 1) == ")") Parentheses--
      ParamToken += this.charAt(i++ + 1)
   }
   var Params = ParamToken.split(/\s*,\s*/)
   for (Index in Params) {
      Params[Index] = Params[Index].Calculate()
   }
   Token += Params.join(",")
   Token += this.charAt(i++ + 1)
}
else {
   PopStack("*")
}
If you know how to shorten this into the code, that would be great (Y).

Next, you define your own functions like this (these are a few of mine):
code:
var Custom = {
   "base" : function (Number, FromBase, ToBase) {
      if (Number != Math.floor(Number) || FromBase != Math.floor(FromBase) || ToBase != Math.floor(ToBase)) return undefined
      Number = String(Number)
      if (FromBase < 2) FromBase = 2
      if (FromBase > 10) FromBase = 10
      if (ToBase < 2) ToBase = 2
      if (ToBase > 36) ToBase = 36
      var Internal = 0
      var Character
      for (var i = Number.length - 1; i >= 0; i--) {
         Character = Number.charAt(i)
         if (Character >= FromBase) return undefined
         Internal += Character * Math.pow(FromBase, Number.length - 1 - i)
      }
      var Result = ""
      while (Internal > 0) {
         if (Internal % ToBase > 9) Result = String.fromCharCode(Internal % ToBase + 55) + Result
         else Result = Internal % ToBase + Result
         Internal = Math.floor(Internal / ToBase)
      }
      return Result
   },
   "choose" : function (Total, Choose) {
      if (Total == Choose || Total == 0 || Choose == 0) return 1
      if (Choose > Total) return 0
      Result = eval(Factorial(Total) + "/(" + Factorial(Total - Choose) + "*" + Factorial(Choose) + ")")
      return Result
      function Factorial (Number) {
         var Factorial = ""
         for (var i = 1; i < Number; i++) {
            Factorial += i + "*"
         }
         Factorial += Number
         return Factorial
      }
   },
   "root" : function (Base, Root) {
      if (Root == undefined) Root = 2
      return Math.pow(Base, 1 / Root)
   }
}
These functions work normally, like "choose(5,4)" will return 5. (Just if you wanted to know, "base" converts bases, "choose" finds the number of ways to choose k objects from n (max: 170, otherwise it returns infinity), and "root" finds the nth root of a number.)

-----

EDIT #2: I also noticed that you can't type negative numbers in your expression...?
RE: [?] Pow... err, triggering some function on certain convo events? by Shondoit on 09-19-2006 at 05:20 AM

At the first piece: Yes indeed, it loops infinetly :S
At the second piece: No need to change my code, it already supports custom functions... Just write a function in the script, like this:

code:
function Root (Base, Root) {
   if (Root == undefined) Root = 2
   return Math.pow(Base, 1 / Root)
}
Debug.Trace("4".Calculate())

At the third piece: True, in normal maths the minus is used as negation and subtraction, I have to take a look at how to know the difference between the two... (After I get back from school again)
RE: RE: [?] Pow... err, triggering some function on certain convo events? by CookieRevised on 09-19-2006 at 06:34 AM

quote:
Originally posted by phalanxii
Next, you define your own functions like this (these are a few of mine):
code:
var Custom = {
   "base" : function (Number, FromBase, ToBase) {
             ...much stuff...
      }


objectname.toString([radix])
(convert to a base)

and

parseInt(numString, [radix])
(convert from a base)

?

RE: RE: RE: [?] Pow... err, triggering some function on certain convo events? by phalanxii on 09-19-2006 at 06:48 AM

quote:
Originally posted by CookieRevised
quote:
Originally posted by phalanxii
Next, you define your own functions like this (these are a few of mine):
code:
var Custom = {
   "base" : function (Number, FromBase, ToBase) {
             ...much stuff...
      }


objectname.toString([radix])
(convert to a base)

and

parseInt(numString, [radix])
(convert from a base)

?


Oh, cool. Never knew about that :$. Thanks, Cookie!



PS. Using Shondoit's way to make functions is much better and easier now... :)

EDIT: Here are my new and improved functions. :D
code:
function base (x, fromBase, toBase) {
   return parseInt(x, fromBase).toString(toBase).toUpperCase()
}
function choose (n, k) {
   if (n != Math.floor(n) || k != Math.floor(k) || n < 0 || k < 0 || k > n) return 0
   if (n == k || n == 0 || k == 0) return 1
   if (n > 170) return Number.POSITIVE_INFINITY
   return eval(Factorial(n) + "/(" + Factorial(n - k) + "*" + Factorial(k) + ")")
   function Factorial (x) {
      var Factorial = ""
      for (var i = 1; i < x; i++) {
         Factorial += i + "*"
      }
      Factorial += x
      return Factorial
   }
}
function gcd (a, b) {
   if (a != Math.floor(a) || b != Math.floor(b)) return undefined
   if (b == 0) return Math.abs(a)
   else return Math.abs(gcd(b, a % b))
}
function isprime (n) {
   if (n != Math.floor(n) || n < 0) return undefined
   if (n == 0 || n == 1) return false
   if (n == 2 || n == 3) return true
   if (n % 2 == 0 || n % 3 == 0) return false
   for (var k = 1; 6 * k <= Math.sqrt(n); k++) {
      if (n % (6 * k - 1) == 0 || n % (6 * k + 1) == 0) return false
   }
   return true
}
function lcm (a, b) {
   if (a != Math.floor(a) || b != Math.floor(b)) return undefined
   return Math.abs(a * b / gcd(a, b))
}
function root (b, n) {
   if (n == undefined) n = 2
   return Math.pow(b, 1 / n)
}

RE: [?] Pow... err, triggering some function on certain convo events? by CookieRevised on 09-19-2006 at 10:50 AM

Note that with those functions, the operands can be negative too. Returning "undefined" when they are negative is not correct.

eg: even the result (eg: cgd) can be negative.......

PS: 2 and 3 are also prime numbers, your functions says it is not (n % 2 = 0).

In many books this isn't talked about (out of convenience, to avoid discussion, because they deal with lower grade maths, etc...), but the fact remains that it can and that they exist. Hence why you usually see "the greatest common divered of two positive integers" and not "greatest common divider of two integers" as the latter also requires the book or paper to explain those...

;)


RE: [?] Pow... err, triggering some function on certain convo events? by phalanxii on 09-19-2006 at 12:16 PM

I've updated the functions (I think they are correct now ;)) taking into account what Cookie said. Just to make sure, choose has to use positive integers right? And primes cannot be negative? (You'll have to bare with me, my maths is only middle school level :(.)

By the way, thanks for all your help. (Y)


RE: [?] Pow... err, triggering some function on certain convo events? by Matti on 09-19-2006 at 06:33 PM

Okay guys, Shondoit motivated me to go on with this. I'll make a nice design for this script, and you'll be on the first rules of the about window of course! :D

Wish me luck! ;)


RE: [?] Pow... err, triggering some function on certain convo events? by Shondoit on 09-19-2006 at 08:53 PM

Good luck (y)


RE: [?] Pow... err, triggering some function on certain convo events? by phalanxii on 09-20-2006 at 12:31 AM

Good luck, Mattike! Hope it all goes well. :)



@Shondoit - I think I've found a few bug fixes:

code:
String.prototype.Calculate = function () {
   var Infix = this.replace(/\s/g, "")
   var Postfix = Infix.ToPostfix()
   if (Postfix != undefined) return Postfix.CalculatePostfix()
}
code:
case "^": case "*": case "/": case "+":// case "-":
   PopStack()
   break
In the first one, you forgot to put the global flag ;) (you got this right somewhere else in the code though (Y)). In the second one, I think this allows negative values to work. Tell me if any of these stuff up the code. :)
RE: [?] Pow... err, triggering some function on certain convo events? by Shondoit on 09-20-2006 at 05:06 AM

The frist one is great, thanks. I forgot that one...

About the second one, it does allow negatives, but it also disables sutraction. if you type '3-2' the subtraction sign isn't evaluated, and is seen as part of the number. If you try this calculation it still works, because this 'number' is calculated with eval(). However, this is not the correct way to do it, because it doesn't take presedence into account...
It can be fixed by checking, when the Token is '-', if there is a operator in front of it. If true, it is a negation sign, else it is a subtraction operator...

When I have the time, I'll try to fix it (y)