Vitaliy Serdtsev · Apr 10, 2024 go to post

Check your TRUNCATE parameter.

Common Parameters:TRUNCATE TRUNCATE — Specifies whether to truncate the string to MAXLEN characters, where 1 is TRUE and 0 is FALSE. This parameter is used by the Normalize() and IsValid() methods but is not used by database drivers.
Class dc.test Extends %Persistent
{

Property s1 As %String(TRUNCATE 1);

Property s2 As %String;

ClassMethod Test()
{
  ..%KillExtent(,$$$YES)

   t=..%New()
   t.s1=$tr($j("",51)," ","a")
   sc=t.%Save()
   "s1: ",$s($$$ISERR(sc):$system.Status.GetErrorText(sc),1:"OK"),!

   t=..%New()
   t.s2=$tr($j("",51)," ","a")
   sc=t.%Save()
   "s2: ",$s($$$ISERR(sc):$system.Status.GetErrorText(sc),1:"OK"),!
}

}

USER>##class(dc.test).Test()
s1: OK
s2: ERROR #7201: Datatype value 'aaaa..aa' length longer than MAXLEN allowed of 50
	> ERROR #5802: Datatype validation failed on property 'dc.test:s2', with value equal to "aaaa..aa"

The same error occurs in the Management Portal.

Vitaliy Serdtsev · Apr 10, 2024 go to post

MAXLEN is not applicable for %GlobalCharacterStream (Blob). You will get compilation error #5480

Vitaliy Serdtsev · Apr 4, 2024 go to post
select lpad(s\3600,2,0)||':'||lpad(s\60#60,2,0)||':'||lpad((s)#3600#60,2,0) diff
from (select DATEDIFF('s','2024-04-01 09:13:46','2024-04-01 11:11:44's)
Vitaliy Serdtsev · Apr 2, 2024 go to post

I noticed that you are using the {Stream} syntax, which is typical for trigger code or calculated field. Could you check the following code at your place:

Class dc.test Extends %Persistent
{

Property stream As %GlobalCharacterStream;

Trigger NewTrigger1 [ Event = INSERT ]
{
 i $IsObject({stream}{
   t={stream}
   ^||tmp=t.Size
 }
}

ClassMethod Test()
{
  ..%KillExtent(,$$$YES)
  
  f=##class(%Stream.FileBinary).%New()
  f.LinkToFile("C:\test.jpg")
  
  &sql(insert into dc.test(streamvalues(:f))
  'SQLCODE {
    &sql(select CHAR_LENGTH(streaminto :len from dc.test where %id=1)
    len," ",^||tmp,!
  }
}

}

I have saved a 16 MB file without any problems:

USER><FONT COLOR="#0000ff">d </FONT><FONT COLOR="#000080">##class</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#008080">dc.test</FONT><FONT COLOR="#000000">).</FONT><FONT COLOR="#0000ff">Test</FONT><FONT COLOR="#000000">()</FONT>
16446809 16446809
Vitaliy Serdtsev · Apr 1, 2024 go to post

The resulting archive is easily recognized/unpacked in WinRAR, 7z:

<FONT COLOR="#0000ff">s </FONT><FONT COLOR="#800000">f</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#000080">##class</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#008080">%Stream.FileCharacterGzip</FONT><FONT COLOR="#000000">).</FONT><FONT COLOR="#0000ff">%New</FONT><FONT COLOR="#000000">()
</FONT><FONT COLOR="#0000ff">s </FONT><FONT COLOR="#800000">f</FONT><FONT COLOR="#000000">.</FONT><FONT COLOR="#0000ff">TranslateTable</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#008000">"UTF8"
</FONT><FONT COLOR="#0000ff">s </FONT><FONT COLOR="#800000">f</FONT><FONT COLOR="#000000">.</FONT><FONT COLOR="#0000ff">Filename</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#008000">"C:\test.gz"
</FONT><FONT COLOR="#0000ff">d </FONT><FONT COLOR="#800000">f</FONT><FONT COLOR="#000000">.</FONT><FONT COLOR="#0000ff">WriteLine</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#008000">"test"</FONT><FONT COLOR="#000000">)
</FONT><FONT COLOR="#0000ff">d </FONT><FONT COLOR="#800000">f</FONT><FONT COLOR="#000000">.</FONT><FONT COLOR="#0000ff">Write</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#008000">"Привет Caché"</FONT><FONT COLOR="#000000">)
</FONT><FONT COLOR="#0000ff">d </FONT><FONT COLOR="#800000">f</FONT><FONT COLOR="#000000">.</FONT><FONT COLOR="#0000ff">%Save</FONT><FONT COLOR="#000000">()</FONT>
Vitaliy Serdtsev · Mar 29, 2024 go to post

See Defining Custom Class Queries

 

Example of a stored procedure

Class dc.test [ Abstract ]{

Query Intervals(start As %TimeStamp,end As %TimeStamp,minute As %TinyInt) As %Query(ROWSPEC = "intStart:%PosixTime,intEnd:%PosixTime") [ SqlName = Intervals, SqlProc ]{}

ClassMethod IntervalsExecute(ByRef qHandle As %Binary,start As %TimeStamp,end As %TimeStamp,minute As %TinyInt) As %Status{  qHandle(0)=##class(%PosixTime).OdbcToLogical(start),
    qHandle(1)=##class(%PosixTime).OdbcToLogical(end),
    qHandle=minute
  
  $$$OK}

ClassMethod IntervalsFetch(ByRef qHandle As %Binary,ByRef Row As %List,ByRef AtEnd As %Integer = 0) As %Status [ PlaceAfter = IntervalsExecute ]{  qHandle(0)<=qHandle(1) {
    j=$system.SQL.Functions.DATEADD("minute",qHandle,qHandle(0)),
      Row=$lb(qHandle(0),$s(j>=qHandle(1):qHandle(1),1:j-1)),
      qHandle(0)=j=qHandle(1)+j
  }else{
    Row="", AtEnd=$$$YES
  }
  $$$OK}ClassMethod IntervalsClose(ByRef qHandle As %Binary) As %Status [ PlaceAfter = IntervalsExecute ]{
  $$$OK}
}

The result of calling a stored procedure in the Management Portal:

SELECT * FROM dc.Intervals({ts '2024-01-01 10:00:00'},{ts '2024-01-01 11:00:00'},15)
Display/ODBC Mode
intStart intEnd
2024-01-01 10:00:00 2024-01-01 10:14:59.999999
2024-01-01 10:15:00 2024-01-01 10:29:59.999999
2024-01-01 10:30:00 2024-01-01 10:44:59.999999
2024-01-01 10:45:00 2024-01-01 11:00:00.000000

Logical Mode

intStart intEnd
1154625607806846976 1154625608706846975
1154625608706846976 1154625609606846975
1154625609606846976 1154625610506846975
1154625610506846976 1154625611406846976


Accordingly, your query needs to be rewritten, for example:

SELECT
intStart,
intEnd,
COALESCE((SELECT SUM(CASE WHEN value_after_changing 'GENERATE' THEN ELSE ENDFROM service_log WHERE id = 11 AND created_at BETWEEN intStart AND intEnd), 0) generatedCount,
COALESCE((SELECT SUM(CASE WHEN value_after_changing 'FINISH' THEN ELSE ENDFROM service_log WHERE id = 11 AND created_at BETWEEN intStart AND intEnd), 0) finishedCount,
COALESCE((SELECT SUM(CASE WHEN value_after_changing 'DROPOUT' THEN ELSE ENDFROM service_log WHERE id = 11 AND created_at BETWEEN intStart AND intEnd), 0) dropoutCount,
COALESCE((SELECT SUM(CASE WHEN value_after_changing 'CANCEL' THEN ELSE ENDFROM service_log WHERE id = 11 AND created_at BETWEEN intStart AND intEnd), 0) cancelledCount
FROM dc.Intervals({ts '2024-01-01 10:00:00'},{ts '2024-01-01 11:00:00'},15)
Vitaliy Serdtsev · Mar 25, 2024 go to post

I would like to supplement the above with such parameters as STORAGEDEFAULT, SQLTABLENAME, and SQLPROJECTION: Storage and SQL Projection of Collection Properties

However a collection property is actually stored, the property can be projected as a column in the parent table, as a child table, or in both ways (as of release 2022.1, this is true for both list and array properties). To control this, you specify the SQLPROJECTION parameter of the property.
Vitaliy Serdtsev · Mar 15, 2024 go to post

Thanks for the hint, I fixed it. By the way, your code can be reduced to 173:  <FONT COLOR="#0000ff">f </FONT><FONT COLOR="#800000">i</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#0000ff">$i</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#800000">r</FONT><FONT COLOR="#000000">):1:</FONT><FONT COLOR="#800000">a</FONT>

Vitaliy Serdtsev · Mar 15, 2024 go to post

There is no limit to perfection.

By the way, your code shows 175 characters, where did the number 174 come from?

Vitaliy Serdtsev · Mar 13, 2024 go to post
 

size = 207 195 179

ClassMethod Type(a...) As %String
{
 j=$i(r):1:a{w=$tr(a(j)," "),p=$f(w,",")-2 i=2:1:$l(w,","c=$l($p(w,",",i)),r=$s(p=c:r,r+p-c<2:2,c<p*2#r:3,1:4),p=cq $p("Constant7Increasing7Decreasing7Unsorted",7,r)
}
Vitaliy Serdtsev · Mar 1, 2024 go to post

Try this:

<FONT COLOR="#000080">ClassMethod </FONT><FONT COLOR="#000000">test2()
{
  </FONT><FONT COLOR="#0000ff">set </FONT><FONT COLOR="#800000">tKP </FONT><FONT COLOR="#000000">= ..</FONT><FONT COLOR="#0000ff">%New</FONT><FONT COLOR="#000000">()
  </FONT><FONT COLOR="#0000ff">set </FONT><FONT COLOR="#800000">tIdentifierSerial </FONT><FONT COLOR="#000000">= </FONT><FONT COLOR="#000080">##class</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#008080">HS.Message.AddUpdateHubRequest</FONT><FONT COLOR="#000000">).</FONT><FONT COLOR="#0000ff">%OpenId</FONT><FONT COLOR="#000000">(21986071).</FONT><FONT COLOR="#0000ff">Identifiers
  zw </FONT><FONT COLOR="#800000">tIdentifierSerial
  </FONT><FONT COLOR="#0000ff">set </FONT><FONT COLOR="#800000">tKP</FONT><FONT COLOR="#000000">.</FONT><FONT COLOR="#0000ff">IsSerial </FONT><FONT COLOR="#000000">= 1
  </FONT><FONT COLOR="#0000ff">set </FONT><FONT COLOR="#800000">tKP</FONT><FONT COLOR="#000000">.</FONT><FONT COLOR="#0000ff">IsList </FONT><FONT COLOR="#000000">= 1
  </FONT><FONT COLOR="#0000ff">set </FONT><FONT COLOR="#800000">tSerial </FONT><FONT COLOR="#000000">= </FONT><FONT COLOR="#800000">tIdentifierSerial</FONT><FONT COLOR="#000000">.</FONT><FONT COLOR="#0000ff">GetObjectNext</FONT><FONT COLOR="#000000">(.</FONT><FONT COLOR="#800000">tKey</FONT><FONT COLOR="#000000">)
  </FONT><FONT COLOR="#0000ff">for </FONT><FONT COLOR="#800080">{
    </FONT><FONT COLOR="#0000ff">if </FONT><FONT COLOR="#800000">tKey</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#008000">"" </FONT><FONT COLOR="#800080">{</FONT><FONT COLOR="#0000ff">quit</FONT><FONT COLOR="#800080">}
    </FONT><FONT COLOR="#0000ff">do </FONT><FONT COLOR="#800000">tKP</FONT><FONT COLOR="#000000">.</FONT><FONT COLOR="#0000ff">SerialList</FONT><FONT COLOR="#000000">.</FONT><FONT COLOR="#0000ff">InsertObject</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#800000">tSerial</FONT><FONT COLOR="#000000">)
    </FONT><FONT COLOR="#0000ff">set </FONT><FONT COLOR="#800000">tSerial </FONT><FONT COLOR="#000000">= </FONT><FONT COLOR="#800000">tIdentifierSerial</FONT><FONT COLOR="#000000">.</FONT><FONT COLOR="#0000ff">GetObjectNext</FONT><FONT COLOR="#000000">(.</FONT><FONT COLOR="#800000">tKey</FONT><FONT COLOR="#000000">)
  </FONT><FONT COLOR="#800080">}
  </FONT><FONT COLOR="#0000ff">w </FONT><FONT COLOR="#800000">tKP</FONT><FONT COLOR="#000000">.</FONT><FONT COLOR="#0000ff">%Save</FONT><FONT COLOR="#000000">()
}</FONT>
Vitaliy Serdtsev · Feb 20, 2024 go to post

As far as I understand, the author wants to calculate the value of a field based on some list of fields whose names he takes from some table. Right?

Vitaliy Serdtsev · Feb 20, 2024 go to post

Try inserting an apostrophe through concatenation, something like

INSERT INTO MyText
    (text)
VALUES
    ('I visited O' || CHAR(39) || 'Brien before heading out of town.')
Vitaliy Serdtsev · Feb 8, 2024 go to post

I'm getting an error:

ERROR #9406: Unexpected format for value of field, searchCriteria, using class base mapping
After fixing the JSON, the error disappeared:
<FONT COLOR="#ff00ff">{</FONT><FONT COLOR="#008000">"searchCriteria"</FONT><FONT COLOR="#808080">: </FONT><FONT COLOR="#ff00ff">{..}}</FONT> ==> <FONT COLOR="#ff00ff">{</FONT><FONT COLOR="#008000">"searchCriteria"</FONT><FONT COLOR="#808080">: </FONT><FONT COLOR="#ff00ff">[{..}]}</FONT>
Also note the mapping between the fields professionalId/professionalNif and preparation/actPreparation
Vitaliy Serdtsev · Feb 8, 2024 go to post

Your code does not take into account the numbers, so an incorrect result is given for "L33T C0d3r".

Vitaliy Serdtsev · Feb 7, 2024 go to post
SELECT JSON_ARRAYAGG(json_obj)
  FROM (SELECT TOP 5
            JSON_OBJECT(
              'Name':name
              ,'Age':age
              ,'DOB':to_char(dob,'Day DD Month YYYY')
            ) json_obj
           FROM sample.person
       )
SELECT JSON_ARRAYAGG(json_obj)
  FROM (SELECT JSON_OBJECT(
                'Name':name
                ,'Age':age
                ,'DOB':to_char(dob,'Day DD Month YYYY')
                ) json_obj
       FROM sample.person
       )
  WHERE %VID BETWEEN 1 AND 5
Vitaliy Serdtsev · Jan 30, 2024 go to post
 

Reduced your code to 127:

ClassMethod ToKeyPad(pAs %String
{
l=$f(" 0   1    ABC2 DEF3 GHI4 JKL5 MNO6 PQRS7TUV8 WXYZ9",$$$UPPER($e(p,$i(i)))) q:l=1 s:$p(r,l-2\5,*+l-2#5+1)="" a
}
Vitaliy Serdtsev · Jan 29, 2024 go to post

Reduced your code to 137:

<FONT COLOR="#000080">ClassMethod </FONT><FONT COLOR="#000000">ToKeyPad(</FONT><FONT COLOR="#ff00ff">p</FONT><FONT COLOR="#000000">) </FONT><FONT COLOR="#000080">As %String
</FONT><FONT COLOR="#000000">{
 </FONT><FONT COLOR="#0000ff">f </FONT><FONT COLOR="#800000">i</FONT><FONT COLOR="#000000">=1:1:</FONT><FONT COLOR="#0000ff">$l</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#800000">p</FONT><FONT COLOR="#000000">)</FONT><FONT COLOR="#800080">{</FONT><FONT COLOR="#0000ff">f </FONT><FONT COLOR="#800000">j</FONT><FONT COLOR="#000000">=0:1:9</FONT><FONT COLOR="#800080">{</FONT><FONT COLOR="#0000ff">f </FONT><FONT COLOR="#800000">l</FONT><FONT COLOR="#000000">=1:1:</FONT><FONT COLOR="#0000ff">$f</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#0000ff">$p</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#008000">" 0^1^ABC2^DEF3^GHI4^JKL5^MNO6^PQRS7^TUV8^WXYZ9"</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#008000">"^"</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#800000">j</FONT><FONT COLOR="#000000">+1),</FONT><FONT COLOR="#0000ff">$e</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#0000ff">$$$UPPER</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#800000">p</FONT><FONT COLOR="#000000">),</FONT><FONT COLOR="#800000">i</FONT><FONT COLOR="#000000">))-1 </FONT><FONT COLOR="#0000ff">s </FONT><FONT COLOR="#800000">r</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#0000ff">$g</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#800000">r</FONT><FONT COLOR="#000000">)_</FONT><FONT COLOR="#800000">j</FONT><FONT COLOR="#800080">}} </FONT><FONT COLOR="#0000ff">q </FONT><FONT COLOR="#800000">r
</FONT><FONT COLOR="#000000">}</FONT>
Vitaliy Serdtsev · Dec 20, 2023 go to post

Yes, most likely this is legacy code. For some reason I thought that since the %JSON package classes appeared only in IRIS, the code would also have to be new.

PS: by the way, can you compile an XData block without a name? Studio doesn't highlight the error?

Vitaliy Serdtsev · Dec 19, 2023 go to post

It is strange that the bug has not been fixed yet, because it is easy to fix it by adding one line to <FONT COLOR="#000080">##class</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#008080">%JSON.Generator</FONT><FONT COLOR="#000000">).</FONT><FONT COLOR="#0000ff">GenerateMappingFromXdata</FONT><FONT COLOR="#000000">()</FONT>:

<..>
For i=1:1:count {
  Set xdata=compiledclass.XDatas.GetAt(i)
  Set configName=xdata.Name
  If configName="" Continue ; since the Name field is required, how can it be empty?
  If xdata.MimeType'="text/xml" Continue
<..>

PS: by the way, I didn't quite understand why need to check "configName", given that "Name" is a required field. Any ideas?

Vitaliy Serdtsev · Nov 15, 2023 go to post

For versions of Caché 5.0.x, try the following code:

<FONT COLOR="#0000ff">#include </FONT><FONT COLOR="#000000">%systemInclude

</FONT><FONT COLOR="#0000ff">n

s </FONT><FONT COLOR="#800000">list</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#0000ff">$lb</FONT><FONT COLOR="#000000">(   </FONT><FONT COLOR="#008000">"test"</FONT><FONT COLOR="#000000">,   </FONT><FONT COLOR="#008000">"for"</FONT><FONT COLOR="#000000">,   </FONT><FONT COLOR="#008000">"searching unknown strings here is a very long piece with enough characters to get a lowercase alpha as a $list marker"</FONT><FONT COLOR="#000000">,   </FONT><FONT COLOR="#008000">"items"</FONT><FONT COLOR="#000000">,   </FONT><FONT COLOR="#008000">"in"</FONT><FONT COLOR="#000000">,   </FONT><FONT COLOR="#008000">"aaatArGetwaaaa"</FONT><FONT COLOR="#000000">,   </FONT><FONT COLOR="#008000">"lists"</FONT><FONT COLOR="#000000">,     </FONT><FONT COLOR="#0000ff">$lb</FONT><FONT COLOR="#000000">(     </FONT><FONT COLOR="#008000">"/subs"</FONT><FONT COLOR="#000000">,     </FONT><FONT COLOR="#008000">"/values"</FONT><FONT COLOR="#000000">,     </FONT><FONT COLOR="#008000">"nested list"</FONT><FONT COLOR="#000000">,     </FONT><FONT COLOR="#008000">"did you see that ""w"" before the third piece?"</FONT><FONT COLOR="#000000">,     </FONT><FONT COLOR="#008000">"Stuart Strickland"</FONT><FONT COLOR="#000000">,     </FONT><FONT COLOR="#008000">"Yaron Munz"</FONT><FONT COLOR="#000000">) )

</FONT><FONT COLOR="#0000ff">s </FONT><FONT COLOR="#800000">str</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#0000ff">$$$UPPER</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#0000ff">$$</FONT><FONT COLOR="#ff0000">cccvt</FONT><FONT COLOR="#000000">^%Wpglo(</FONT><FONT COLOR="#800000">list</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#0000ff">$$$MaxStringLength</FONT><FONT COLOR="#000000">,.</FONT><FONT COLOR="#800000">warn</FONT><FONT COLOR="#000000">)) </FONT><FONT COLOR="#008000">; or ; s str=$$$UPPER($$listDump^%Wprim(list,9))

</FONT><FONT COLOR="#0000ff">i </FONT><FONT COLOR="#000000">'</FONT><FONT COLOR="#800000">warn </FONT><FONT COLOR="#800080">{  </FONT><FONT COLOR="#0000ff">s </FONT><FONT COLOR="#800000">str</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#0000ff">$e</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#800000">str</FONT><FONT COLOR="#000000">,3,</FONT><FONT COLOR="#0000ff">$l</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#800000">str</FONT><FONT COLOR="#000000">)-2) </FONT><FONT COLOR="#008000">; remove << & >>  ;s @("LIST="_str) zw LIST    </FONT><FONT COLOR="#0000ff">w </FONT><FONT COLOR="#000000">!,</FONT><FONT COLOR="#0000ff">$f</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#800000">str</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#0000ff">$$$UPPER</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#008000">"Targetw"</FONT><FONT COLOR="#000000">)) </FONT><FONT COLOR="#800080">}</FONT>

Result: 162

If you end up searching for globals that use $lb(), then you might find it useful:

Vitaliy Serdtsev · Nov 10, 2023 go to post

You can convert a list to a string (and vice versa), regardless of the number of nestings. Unfortunately, I can't test this code for Caché 5.x, but I think it should work. Here is a small example of searching for a string in a list:

#include %systemInclude

 n
 
 s list=$lb(
   "test",
   "for",
   "searching unknown strings here is a very long piece with enough characters to get a lowercase alpha as a $list marker",
   "items",
   "in",
   "aaatArGetwaaaa",
   "lists",
     $lb(
     "/subs",
     "/values",
     "nested list",
     "did you see that ""w"" before the third piece?",
     "Stuart Strickland",
     "Yaron Munz")
 )
 
 str=$$$UPPER(##class(%Utility).FormatString(list,,.overflow))
 'overflow {
   ;s @("LIST="_str) zw LIST
   
   !,$f(str,$$$UPPER("Targetw"))
 }
Result: 162
Vitaliy Serdtsev · Aug 25, 2023 go to post

There are much more interesting examples in the documentation, for example:

<FONT COLOR="#0000ff">w </FONT><FONT COLOR="#000000">-</FONT><FONT COLOR="#008000">"2Cats"</FONT><FONT COLOR="#000000">_</FONT><FONT COLOR="#008000">"Rats"
</FONT><FONT COLOR="#0000ff">w </FONT><FONT COLOR="#008000">"8 apples" </FONT><FONT COLOR="#000000">- </FONT><FONT COLOR="#008000">"4 oranges"
</FONT><FONT COLOR="#0000ff">w </FONT><FONT COLOR="#008000">"8 apples" </FONT><FONT COLOR="#000000">- </FONT><FONT COLOR="#008000">"four oranges"</FONT>