Wednesday, May 4, 2011

ObjectScript Cheat Sheet for Ensemble [Cache]


Action

Code
Alternative way
Call a class method
##class(package.class).method(arguments)
set variable = ##class(package.class).method(arguments)
Call an instance method
do oref.method(arguments) 
set variable = oref.method(arguments)
Create a new object
set oref = ##class(package.class).%New()

Open an existing object
set oref = ##class(package.class).%OpenId(id)

Save an object
set status = oref.%Save()

Validate an object without saving
set status = oref.%ValidateObject()

Validate a property without saving
set status = ##class(package.class).PropertyIsValid(oref.Property)

Delete an existing object
set status = ##class(package.class).%DeleteId(id)

Link two objects
set oref1.property = oref2


Clone an object
set clonedOref = oref.%ConstructClone()


Start the SQL shell
do $system.SQL.Shell()

>>go
>> SELECTMODE = DISPLAY

Test a class query
do ##class(%ResultSet).RunQuery(class, query)

Create a new standalone array
set arrayOref=##class(%ArrayOfDataTypes).%New()

Insert an element into an array
do oref.arrayProperty.SetAt(value,key)
do arrayOref.SetAt(value,key)
Display an element of an array
do oref.arrayProperty.GetAt(key)
do oref.arrayProperty.GetAt(key)
Display the size of an array
do oref.arrayProperty.Count()
write arrayOref.Count()
Date conversion (external à internal)
set variable = $zdh(“mm/dd/yyyy”)

Date conversion (internal à external)
set variable = $zd(internalDate, format)

Time conversion (external à internal)
set variable = $zth(“hh:mm:ss”)

Time conversion (internal à external)      
set variable = $zt(internalTime, format)

Display internal date/time string
write $system.SYS.Horolog()
write $horolog
Display UTC date/time string
write $system.SYS.TimeStamp()

Check if variable exists
write $data(variable)

Return value of variable, or "" if undefined
write $get(variable)

For Loop Syntax
For ControlVariable = StartValue:IncrementAmount:EndValue


Cheat Sheet for Crystal Report Formulas

Conversion Functions:
Conversion Function
Description
CBool(number), CBool(currency)
Convert to Boolean.
CCur(number), CCur(string)
Convert to Currency.
CDbl(currency), CDbl(string),
CDbl(boolean)
Convert to Number. Equivalent to ToNumber().
CStr()
Convert to String. Equivalent to ToText().
CDate(string), CDate(year, month, day), CDate(DateTime)
Convert to Date.
CTime(string), CTime(hour, min, sec), CDate(DateTime)
Convert to Time.
CDateTime(string),
CDateTime(date),
CDateTime(date, time),
CDateTime(year, month, day)
Convert to DateTime.
CDateTime(year, month, day, hour, min, sec)
Convert to DateTime.
ToNumber(string), ToNumber(boolean)
Convert to a Number.
ToText()
Convert to String. Same as CStr().
IsDate(string), IsTIme(), IsDateTime()
Test a string for being a valid date/time.
IsNumber(string)
Test a string for being a valid number.
ToWords(number),
ToWords(number, decimals)
Convert a number to its word equivalent.


·         Formula = ToWords(123.45) Result is one hundred twenty-three 45 / 100
 Math Functions:
Function Name
Description
Abs(number)
Return the absolute value.
Fix(number, decimals)
Return a number with a specified number of significant digits.
Int(number), numerator \ denominator
Return the integer portion of a fractional number.
Remainder(numerator, denominator),
Return the remainder of dividing the numerator by the denominator.
numerator Mod denominator
Return the remainder of dividing the numerator by the denominator.
Round(number, decimals)
Round up a number with a specified number of significant digits.
Sgn(number)
Return a number's sign.
Sqr(number), Exp(number), Log(number)
The standard arithmetic functions.
Cos(number), Sin(number), Tan(number), Atn(number)
The standard scientific functions.


Convert display string to cost: 
CStr (CCur(ToNumber({Data.SupplyCost})/100))

New Line in formula : ChrW(13)
New Line in XML     :  

Alternate Row Color:
if RecordNumber mod 2 = 0 then crSilver else crNoColor



3-Formula Trick:     Init/Calc/Display:










Tuesday, May 3, 2011

Trick to create separate .cs file for global.asax file and using JavaScript to redirect to custom error page for unauthorized users (code 401)

There is no way to create a global.asax.cs page in vs 2008 or older versions of Visual studio. So we have a work around.

1. Add Global.asax file to your project, notice it won’t let you put the code in separate .cs file.

2. Add a new code file to your project "Global.cs". It will ask you to put the file in App_Code folder (Important step).You click "Yes" which will put the file in App_code folder.


3. Now open the global.cs file you just created and add
using System.Web.Configration;
4. Inherit the Global class from System.Web.HttpApplication like
public class Global : System.Web.HttpApplication

5. Now go back to your old Global.asax file and copy everything inside <Script> tag to this Global.cs file.
6. In Global.asax add Inherit property in Application tag to point to this new code file, remove everything from Global.asax file but only one line is left
<%@ Application Language="C#"  Inherits="Global" %> 

7. Inherits tag in the above line points to the .cs file we are using "Global"
8. You should be good to go and use the Global.cs file without any problem.


Now to create a custom error page for Unauthorized users (code 401/ code 401.2) simply add Application_EndRequest() function in Global.cs page and use JavaScript code to redirect self to custom error page by trapping the 401 Unauthorized code.
1. Create a custom error Page ( E.g. CustomError.cs)
2. Create authorization tag in web.config file to deny or allow users.
3. If the user’s access is denied the Application_EndRequest() function will try to capture the Context Response. We can all kinds of response like error code 401, 402, 404 for my example I am using 401.
4. If the code is indeed 401 (we only look for first 3 letters of the Response status ignoring all the other detail) we redirect the user to the custom error page with this line of code.
context.Response.Write("<script language=javascript>self.location='CustomError.aspx';</script>");
5. So the whole function will look like this:
protected void Application_EndRequest(Object sender, EventArgs e)
{
   HttpContext context = HttpContext.Current;
   if (context.Response.Status.Substring(0, 3).Equals("401"))
   {
      context.Response.ClearContent();
      context.Response.Write("<script  
      language=javascript>self.location='CustomError.aspx'; </script>");
    }
 }


6. You have successfully created a custom code file for Global.asax as well as created a custom error page for unauthorized users.

Wednesday, May 26, 2010

The List of Real Life Cheat Codes!!!!

1. Stop: Stop: Play. Skip advertisements in movies and go straight to the movie.

2. Dial 0 during most automatic menu phone systems to be taken to operator to route your call. Whenever you have a voice automated phone system, typically saying "representative" gets you someone right away.

3. When getting lectured into voice mail, hit 1, pause momentarily. If you aren't put through immediately, hit *, pause. Finally, hit # if neither 1 or * worked. It is called the 1-star-pound technique, and it works for all cell carriers.

4. At the end of your shower turn the water really (or all the way) cold. This will wake you up and get the blood flowing.

5. Macy's credit cards usually have a 20% discount on purchases. I pay with the Macy's card, and then while still at the register, I immediately pay off the charge with my debit card. I just got 20% off my purchase and I never get a credit card bill. - This also works with JCP and kohl's cards.

6. How to eliminate late movie rental fees: Acquire late fees, call and tell them you lost the movies, they wipe the fees and put the cost of the movies on your account. Bring the movies back saying you found them, they wipe the cost of the movies, and now your account is back to zero. This can work in other situations such as libraries as well.

7. Buy things out of season, this can save you money. Unless its food, then buy it in season.

8. When you have forgotten someone’s name, simply say : "I'm sorry, but what was your name one more time." They may act offended, but when they give you there first name you simply reply "No, I meant your last name." (More socially acceptable to forget). Bingo. First and last names.

9. Gently work an orange in your hands to loosen the peel from the fruit. This makes it easy enough to get the whole peel in one shot.

10. Holding your car remote up under your chin and opening your mouth increases the range you can unlock the car from.(This is a good one)

11. If you get a ticket on the windshield of your car, you can potentially get away with parking illegally in the same lot for a few more days (or at least for the remainder of that day) by keeping the ticket on your windshield.

12. Most tinfoil and saran wrap boxes have little push-in tabs on the sides. If you push them in, the roll won't fall out when you try to rip out a sheet of it.

13. If you are driving an unfamiliar car and you don't know which side the gas tank is on, just look at the little pump icon next to the gas gauge on the dashboard. The pump handle on the icon will be on the side of the tank.

14. When you park, always reverse into the parking space. It is much easier to reverse into a confined space than into a place where other people drive. You are also more alert. The chance of an accident is reduced dramatically.

15. To get through tech support quickly with an ISP, choose the option for becoming a new customer. Then when you get there ask to transfer to tech support. Usually they won't put you on hold because they see the number coming from the new customer line.

16. When you're giving a presentation, bring a bottle of water up to the podium. If you find yourself in a spot where you blank, taking a drink will allow you to gather your thoughts. Nobody will be the wiser.

17. If your paper is just a bit short of the length guidelines, do a find/replace for all your punctuation in 2 font sizes larger. The extra spacing may give you the few lines you need without changing the letter font size.

18. Sprinkle some salt on your napkin coaster at the bar. Your beer won't stick to it every time.

19. Lift yourself a little off the toilet if noise is a concern and you're having a particularly gaseous bowel movement. The volume will decrease at least 50-60%.

20. Drop a square of Toilet Paper in the toilet, it will break the surface tension and prevent splash back.

21. On most elevators, press "close door" and your floor number at the same time for express service. You will skip all floors between even if people are calling the elevator.

22. If you feel uncomfortable looking into someone's eyes when they're talking to you, look at their nose instead. They cannot tell the difference.

23. Always get in the leftmost line. Unless you're in Britain, then get in the rightmost queue. People naturally line up on the same side that they're used to driving on the road.

24. Tie a knot to one of your earphone wires right at the top, to easily distinguish from left to right.

25. When receiving a call from a solicitor, simply press 9; the call will be dropped and your phone number is then put on the companies do not call list. 95% of companies support this feature.

Source: Reddit.com

Thursday, April 8, 2010

ObjectScript Iterators in Cache Database

I found a very good blog from Phil Jones who talks in depth about the ObjectScript Iterators in his series. Here is the link to the series.
In this post he gives some background and explanations of how Caché ObjectScript programs see the database.

The Caché database is structured as sparse, multi-dimensional arrays (known as "globals") containing chunks of data in strings. Because the arrays can use strings as indexes (ie. the keys can be strings) meaningful information in a record is usually spread across both the keys and the actual value. But only keys are easy to search on. This is different from a relational database where all fields are more or less equal.

Let's create an example. A rather simplistic patient record might be stored something like this :

^Patient("general hospital",324542)=john~smith~malaria

where the hospital name is the first key, patient id is the second, and the actual data (first name, last name and disease) is encoded as sub-strings (known as "pieces" in Caché terminology)
separated by the ~ character.

Such a database structure makes it easy and very fast, to pull out data if you have all the necessary keys. To get this record from the database into a variable p :
set p = ^Patient("general hospital",324542)

It's also pretty simple to manipulate a subtree. For example there are operations which can copy an entire subtree to another variable.

merge gh = ^Patient("general hospital")

will grab all general hospital patients and put them into a subtree in the variable gh.

You can delete subtrees with

kill ^Patient("old hospital")

On the other hand, if you want to find all patients who have malaria, you have a slog. You either have to manually run through all the records checking which contain "malaria" in the disease field of the string. Or, if looking-up patients by disease is a common requirement that needs to be fast, you make a second array as a fast, searchable index, that is structured like this.

^PatientDiseaseIndex("malaria","general hospital",324542)

Iterating through these multi-dimensional arrays is "baroque" to say the least. Caché ObjectScript provides two commands : $order and $query for looping through tables.

$order takes as argument an array descriptor (name and keys), and returns the next key at the same level of hierarchy as the right-most key listed in the array expression.

To make that last sentence clearer, here's an example.

Let's suppose we have three patient records :

^Patient("general hospital",324542)=john~smith~malaria
^Patient("general hospital",324549)=martha~jones~measles
^Patient("local clinic",2323)=donna~noble~flu



Calling the $order function like this:
$order(^Patient("general hospital",324542))

will return the value 324549. Why? Because 324549 is the next key at the "patient id" level of the key indexes.

Similarly

$order(^Patient("general hospital"))

will return the string "local clinic", because here we're only giving the top-level key of ^Patient. And the next key after "general hospital" is "local clinic".

Using $order, then, it's possible to loop through each key at a particular level of the hierarchy. It also knows how to find the first key at any level; you simply pass it an empty string. So

$order(^Patient(""))

returns "general hospital", the first top level key. And

$order(^Patient("general hospital",""))

returns 324542, the first second level key below "general hospital".

When the $order runs out of keys at any particular level of a subtree, it returns an empty string.

For example,

$order(^Patient("general hospital",324549))

returns "", which signals to us that there are no patient ids after 324549 in the "general hospital" subtree.

To loop through all records in the table we have to use nested loops. Typically something like this


set hospital=""
for {
set hospital=$order(^Patient(hospital))
quit:hospital=""
set id=""
for {
set id=$order(^Patient(hospital,id))
quit:id=""
set p = $get(^Patient(hospital,id))

... do something with patient p
}
}

it's a huge performance! Especially when you come from the sort of language where you're used to being able to write something like this :


for p in Patient {
... do something with patient p
}

But the problem is far more pernicious than simple verbosity. This code hardwires a great deal of commitment to the particular database structure. Let's suppose we realize at a later date that we really need to add a third key to Patients. For example, our hospital network expands into a neighbouring state and we now need to support a new structure :

^NewPatient(region,hospital,id)

Migrating the existing data is a bit of work. But now every single place in the code that loops through patients looking for records that match some criteria will have to be rewritten as well!

The alternative iterating function $query offers some help. But has its own bizarre qualities.

Like $order, the $query function takes an array name and keys. But it returns a string which contains the full array access expression of the next item regardless of the level of hierarchy. So

$query(^Patient("general hospital",324542))

will return a string containing "^Patient("general hospital",324549)"

This can then be evaled in the next statement. ObjectScript has an @ operator for eval, so we loop through the array like this.

set q=$query(^Patient)
for {
if q '= ""
{
set p = @q
... do something with patient p
}
set q=$query(@q)
quit:q=""
}


As before, there's a way to get at the first record - the $query(^Patient), and when $query returns "" we've reached the end.

This is somewhat of an improvement in that we're back to one loop. And it would still work if we moved to a new structure for ^Patient. It's a minor inconvenience that we've got ourselves into a "for" which only tests for the exit condition at the end of the loop body so we need an extra test that q isn't "" for the actual "do something" part.

The bigger concern is that we've now lost our keys. The value of q is going to be something like "^Patient("general hospital",324549)" while the value of p is "martha~jones~measles". If, in the "do something", I want to know what hospital we're talking about I'm going to have to cut up the string q to extract it. That's a bit painful.

RootComponent types in solution.xml file in Dynamics CRM 365/2016

In Microsoft Dynamic CRM 2016/365 are you as confused as me when looking at the solution.xml from the solution export? looking at the xml a...