Project

General

Profile

Download (21.1 KB) Statistics
| Branch: | Tag: | Revision:

magiccube / src / main / java / org / distorted / objects / RubikObjectList.java @ 00fcfefa

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2021 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8
///////////////////////////////////////////////////////////////////////////////////////////////////
9

    
10
package org.distorted.objects;
11

    
12
import java.util.ArrayList;
13
import java.util.Locale;
14

    
15
import android.content.Context;
16
import android.content.SharedPreferences;
17

    
18
import org.distorted.external.RubikFiles;
19
import org.distorted.external.RubikScores;
20
import org.distorted.main.RubikActivity;
21
import org.distorted.objectlib.main.ObjectSignatures;
22
import org.distorted.objectlib.main.ObjectType;
23

    
24
import static org.distorted.objectlib.main.TwistyObject.MESH_NICE;
25
import static org.distorted.objectlib.main.ObjectType.NUM_OBJECTS;
26
import static org.distorted.main.RubikActivity.SHOW_DOWNLOADED_DEBUG;
27
import static org.distorted.screens.RubikScreenPlay.LEVELS_SHOWN;
28

    
29
///////////////////////////////////////////////////////////////////////////////////////////////////
30

    
31
public class RubikObjectList
32
{
33
  public static final int DEF_OBJECT= ObjectSignatures.CUBE_3;
34
  private static RubikObjectList mThis;
35
  private static int mNumObjects;
36
  private static int mNumExtras;
37
  private static ArrayList<RubikObject> mObjects;
38
  private static int mObject = DEF_OBJECT;
39

    
40
  public static class DownloadedObject
41
    {
42
    String shortName;
43
    boolean icon,object,extras,free;
44
    int numScrambles, objectMinor, extrasMinor;
45

    
46
    DownloadedObject(String sName, int scrambles, boolean isFree, int oMinor, int eMinor, boolean i, boolean o, boolean e)
47
      {
48
      shortName = sName;
49

    
50
      numScrambles= scrambles;
51
      free        = isFree;
52
      objectMinor = oMinor;
53
      extrasMinor = eMinor;
54

    
55
      icon   = i;
56
      object = o;
57
      extras = e;
58
      }
59
    }
60

    
61
  private static ArrayList<DownloadedObject> mDownloadedObjects;
62
  /*
63
  private static String mFreeSolvedObjects;
64
  private static String mFreeBoughtObjects;
65
  private static int mNumFreeSolved;
66
  */
67
///////////////////////////////////////////////////////////////////////////////////////////////////
68

    
69
  private RubikObjectList()
70
    {
71
    mNumObjects    = 0;
72
    mNumExtras     = 0;
73
    //mNumFreeSolved = 0;
74

    
75
    mObjects           = new ArrayList<>();
76
    mDownloadedObjects = new ArrayList<>();
77

    
78
    createBuiltinObjects();
79
    }
80

    
81
///////////////////////////////////////////////////////////////////////////////////////////////////
82

    
83
  private void createBuiltinObjects()
84
    {
85
    for(int i=0; i<NUM_OBJECTS; i++)
86
      {
87
      ObjectType type = ObjectType.getObject(i);
88
      RubikObject obj = new RubikObject(type);
89
      mObjects.add(obj);
90
      mNumObjects++;
91

    
92
      if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "creating local object "+type.name() );
93

    
94
      if( obj.hasExtras() )
95
        {
96
        if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "has extras "+mNumExtras );
97

    
98
        obj.setExtrasOrdinal(mNumExtras);
99
        mNumExtras++;
100
        }
101
      else
102
        {
103
        if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "no extras");
104
        }
105
      }
106
    }
107

    
108
///////////////////////////////////////////////////////////////////////////////////////////////////
109

    
110
  private static boolean internalAddDownloadedObject(DownloadedObject object)
111
    {
112
    String name = object.shortName;
113

    
114
    for(RubikObject ro : mObjects )
115
      if( ro.getLowerName().equals(name) )
116
        {
117
        return ro.updateObject(object);
118
        }
119

    
120
    RubikObject obj = new RubikObject(object);
121
    mObjects.add(obj);
122
    mNumObjects++;
123
    /*
124
    int numUnclaimed = getNumUnclaimedSolves();
125

    
126
    if( numUnclaimed>0 && !obj.isFree() )
127
      {
128
      String objname = obj.getUpperName();
129
      if( SHOW_SOLVED_DEBUG ) android.util.Log.e("D", "downloadedObject: "+objname+" making it solved. Unclaimed: "+numUnclaimed);
130
      solveObject(obj,objname);
131
      }
132
    */
133
    if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "creating downloaded object "+obj.getUpperName() );
134

    
135
    if( obj.hasExtras() )
136
      {
137
      if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "has extras "+mNumExtras );
138

    
139
      obj.setExtrasOrdinal(mNumExtras);
140
      mNumExtras++;
141
      }
142
    else
143
      {
144
      if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "no extras");
145
      }
146

    
147
    return true;
148
    }
149

    
150
///////////////////////////////////////////////////////////////////////////////////////////////////
151

    
152
  private static void restoreFreedObjects(SharedPreferences preferences)
153
    {
154
    /*
155
    mFreeSolvedObjects = preferences.getString("rol_freeSolved", "");
156
    mFreeBoughtObjects = preferences.getString("rol_freeBought", "");
157

    
158
    if( SHOW_SOLVED_DEBUG )
159
      {
160
      android.util.Log.e("D", "freeSolved: "+mFreeSolvedObjects);
161
      android.util.Log.e("D", "freeBought: "+mFreeBoughtObjects);
162
      }
163

    
164
    if( mFreeBoughtObjects.length()>0 )
165
      {
166
      if( mFreeBoughtObjects.charAt(0)=='*' )
167
        {
168
        for(int i=0; i<mNumObjects; i++)
169
          {
170
          RubikObject o = mObjects.get(i);
171
          o.markFree();
172
          }
173
        }
174
      else
175
        {
176
        String[] objs = mFreeBoughtObjects.split(",");
177

    
178
        for( String obj : objs )
179
          {
180
          RubikObject o = getObject(obj);
181
          if( o!=null ) o.markFree();
182
          }
183
        }
184
      }
185

    
186
    if( mFreeSolvedObjects.length()>0 )
187
      {
188
      String[] objs = mFreeSolvedObjects.split(",");
189
      mNumFreeSolved = objs.length;
190

    
191
      for( String obj : objs )
192
        {
193
        RubikObject o = getObject(obj);
194
        if( o!=null ) o.markFree();
195
        }
196
      }
197
     */
198
    }
199

    
200
///////////////////////////////////////////////////////////////////////////////////////////////////
201

    
202
  private static int getNumUnclaimedSolves()
203
    {
204
    /*
205
    RubikScores scores = RubikScores.getInstance();
206
    int numMAXes = scores.numberOfSolvedMAXes();
207
    return numMAXes-mNumFreeSolved;
208
     */
209

    
210
    return 0;
211
    }
212

    
213
///////////////////////////////////////////////////////////////////////////////////////////////////
214

    
215
  private static int markAllSolvedAsFree()
216
    {
217
    RubikScores scores = RubikScores.getInstance();
218
    int numObjects = RubikObjectList.getNumObjects();
219
    int ret = 0;
220

    
221
    for(int obj=0; obj<numObjects; obj++)
222
      {
223
      RubikObject object = getObject(obj);
224

    
225
      if( object!=null && !object.isFree() && scores.isSolved(obj,LEVELS_SHOWN) )
226
        {
227
        solveObject(object.getUpperName());
228
        ret++;
229
        }
230
      }
231

    
232
    return ret;
233
    }
234

    
235
///////////////////////////////////////////////////////////////////////////////////////////////////
236

    
237
  private static void markAsFree(int numToBeMarked)
238
    {
239
    int numObjects = RubikObjectList.getNumObjects();
240

    
241
    for(int obj=0; obj<numObjects && numToBeMarked>0; obj++)
242
      {
243
      RubikObject object = getObject(obj);
244

    
245
      if( object!=null && !object.isFree() )
246
        {
247
        solveObject(object.getUpperName());
248
        numToBeMarked--;
249
        }
250
      }
251
    }
252

    
253
///////////////////////////////////////////////////////////////////////////////////////////////////
254

    
255
  public static boolean solveObject(RubikObject object, String shortName)
256
    {
257
    /*
258
    if( object!=null && !object.isFree() )
259
      {
260
      if( SHOW_SOLVED_DEBUG ) android.util.Log.e("D", "object "+shortName+" marked as solved");
261
      object.markFree();
262
      String add = mFreeSolvedObjects.length()==0 ? shortName : (","+shortName);
263
      mFreeSolvedObjects += add;
264
      mNumFreeSolved++;
265
      return true;
266
      }
267
    */
268
    return false;
269
    }
270

    
271
///////////////////////////////////////////////////////////////////////////////////////////////////
272
// PUBLIC API
273

    
274
  public static boolean addDownloadedObject(Context context, String shortName, int numScrambles, boolean isFree, int objectMinor,
275
                                         int extrasMinor, boolean icon, boolean object, boolean extras)
276
    {
277
    if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "New downloaded object "+shortName+" icon="+icon+" object="+object+" extras="+extras);
278

    
279
    for( DownloadedObject obj : mDownloadedObjects )
280
      {
281
      if( obj.shortName.equals(shortName) )
282
        {
283
        obj.icon  |= icon;
284
        obj.object|= object;
285
        obj.extras|= extras;
286

    
287
        if( !obj.object ) objectMinor=-1;
288
        if( !obj.extras ) extrasMinor=-1;
289

    
290
        obj.objectMinor = objectMinor;
291
        obj.extrasMinor = extrasMinor;
292

    
293
        if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "Updating downloaded object "+shortName+" icon="+obj.icon+" object="+obj.object+" extras="+obj.extras);
294

    
295
        try
296
          {
297
          RubikActivity ract = (RubikActivity)context;
298
          ract.reloadObject(shortName);
299
          }
300
        catch(Exception ex)
301
          {
302
          android.util.Log.e("D", "exception trying to reload object: "+ex.getMessage() );
303
          }
304

    
305
        return false;
306
        }
307
      }
308

    
309
    if( !object ) objectMinor=-1;
310
    if( !extras ) extrasMinor=-1;
311

    
312
    DownloadedObject obj = new DownloadedObject(shortName,numScrambles,isFree,objectMinor,extrasMinor,icon,object,extras);
313
    if ( internalAddDownloadedObject(obj) )
314
      {
315
      if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "Adding new downloaded object "+shortName+" icon="+obj.icon+" object="+obj.object+" extras="+obj.extras);
316
      mDownloadedObjects.add(obj);
317
      return true;
318
      }
319
    else
320
      {
321
      if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "New downloaded object "+shortName+" is already built-in, deleting");
322
      RubikFiles files = RubikFiles.getInstance();
323
      files.deleteIcon(context,shortName);
324
      files.deleteJsonObject(context,shortName);
325
      files.deleteJsonExtras(context,shortName);
326
      return false;
327
      }
328
    }
329

    
330
///////////////////////////////////////////////////////////////////////////////////////////////////
331

    
332
  public static void setMeshState(int ordinal, int state)
333
    {
334
    if( ordinal>=0 && ordinal<mNumObjects ) mObjects.get(ordinal).setMeshState(state);
335
    }
336

    
337
///////////////////////////////////////////////////////////////////////////////////////////////////
338

    
339
  public static int getMeshState(int ordinal)
340
    {
341
    return (ordinal>=0 && ordinal<mNumObjects) ? mObjects.get(ordinal).getMeshState() : MESH_NICE;
342
    }
343

    
344
///////////////////////////////////////////////////////////////////////////////////////////////////
345

    
346
  public static void saveMeshState(SharedPreferences.Editor editor)
347
    {
348
    for(int i=0; i<mNumObjects; i++)
349
      {
350
      RubikObject obj = getObject(i);
351

    
352
      if( obj!=null )
353
        {
354
        String name = obj.getUpperName();
355
        editor.putInt("rol_"+name, obj.getMeshState() );
356
        }
357
      }
358
    }
359

    
360
///////////////////////////////////////////////////////////////////////////////////////////////////
361

    
362
  public static boolean allAlreadyBought()
363
    {
364
    //return mFreeBoughtObjects.equals("*");
365
    return false;
366
    }
367

    
368
///////////////////////////////////////////////////////////////////////////////////////////////////
369

    
370
  public static boolean thereAreLockedObjects()
371
    {
372
    for(int i=0; i<mNumObjects; i++)
373
      {
374
      RubikObject o = mObjects.get(i);
375
      if( !o.isFree() ) return true;
376
      }
377

    
378
    return false;
379
    }
380

    
381
///////////////////////////////////////////////////////////////////////////////////////////////////
382

    
383
  public static boolean objectAlreadyBought(String shortName)
384
    {
385
    RubikObject o = getObject(shortName);
386
    return ( o!=null && o.isFree() );
387
    }
388

    
389
///////////////////////////////////////////////////////////////////////////////////////////////////
390

    
391
  public static void buyAll()
392
    {
393
    /*
394
    mFreeBoughtObjects = "*";
395
    if( SHOW_SOLVED_DEBUG ) android.util.Log.e("D", "all objects marked as bought");
396

    
397
    for(int i=0; i<mNumObjects; i++)
398
      {
399
      RubikObject o = mObjects.get(i);
400
      o.markFree();
401
      }
402
    */
403
    }
404

    
405
///////////////////////////////////////////////////////////////////////////////////////////////////
406

    
407
  public static boolean buyObject(String shortName)
408
    {
409
    /*
410
    RubikObject o = getObject(shortName);
411

    
412
    if( o!=null && !o.isFree() )
413
      {
414
      if( SHOW_SOLVED_DEBUG ) android.util.Log.e("D", "object "+shortName+" marked as bought");
415
      o.markFree();
416
      String add = mFreeBoughtObjects.length()==0 ? shortName : (","+shortName);
417
      mFreeBoughtObjects += add;
418
      return true;
419
      }
420
    */
421
    return false;
422
    }
423

    
424
///////////////////////////////////////////////////////////////////////////////////////////////////
425

    
426
  public static boolean solveObject(String shortName)
427
    {
428
    RubikObject object = getObject(shortName);
429
    return solveObject(object,shortName);
430
    }
431

    
432
///////////////////////////////////////////////////////////////////////////////////////////////////
433

    
434
  public static void savePreferences(SharedPreferences.Editor editor)
435
    {
436
    RubikObject obj = getObject(mObject);
437
    if( obj!=null ) editor.putString("rol_objName", obj.getUpperName() );
438

    
439
    int numDownloaded = mDownloadedObjects.size();
440

    
441
    if( numDownloaded>0 )
442
      {
443
      StringBuilder downloadedObjects = new StringBuilder();
444

    
445
      for(int i=0; i<numDownloaded; i++)
446
        {
447
        if( i>0 ) downloadedObjects.append(',');
448

    
449
        DownloadedObject object = mDownloadedObjects.get(i);
450
        downloadedObjects.append(object.shortName);
451
        downloadedObjects.append(' ');
452
        downloadedObjects.append(object.numScrambles);
453
        downloadedObjects.append(' ');
454
        downloadedObjects.append(object.objectMinor);
455
        downloadedObjects.append(' ');
456
        downloadedObjects.append(object.extrasMinor);
457
        downloadedObjects.append(' ');
458
        downloadedObjects.append(object.icon   ? "1":"0");
459
        downloadedObjects.append(' ');
460
        downloadedObjects.append(object.object ? "1":"0");
461
        downloadedObjects.append(' ');
462
        downloadedObjects.append(object.extras ? "1":"0");
463
        downloadedObjects.append(' ');
464
        downloadedObjects.append(object.free ? "true":"false");
465
        }
466

    
467
      String objects = downloadedObjects.toString();
468
      if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "saving: "+objects);
469
      editor.putString("rol_downloaded", objects );
470
      }
471
    else
472
      {
473
      editor.putString("rol_downloaded", "" );
474
      }
475
/*
476
    editor.putString("rol_freeSolved", mFreeSolvedObjects);
477
    editor.putString("rol_freeBought", mFreeBoughtObjects);
478

    
479
    if( SHOW_SOLVED_DEBUG )
480
      {
481
      android.util.Log.e("D", "saving solved objects: "+mFreeSolvedObjects);
482
      android.util.Log.e("D", "saving bought objects: "+mFreeBoughtObjects);
483
      }
484
 */
485
    }
486

    
487
///////////////////////////////////////////////////////////////////////////////////////////////////
488

    
489
  public static void restorePreferences(Context context, SharedPreferences preferences, boolean justStarted)
490
    {
491
    if( mThis==null ) mThis = new RubikObjectList();
492

    
493
    String downloaded = preferences.getString("rol_downloaded","");
494

    
495
    if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", downloaded);
496

    
497
    if( !downloaded.equals(""))
498
      {
499
      String[] dObjects = downloaded.split(",");
500

    
501
      for(String dObj : dObjects)
502
        {
503
        String[] parts = dObj.split(" ");
504
        int length = parts.length;
505

    
506
        if( length==7 || length==8 )
507
          {
508
          String name = parts[0];
509
          String scra = parts[1];
510
          String objM = parts[2];
511
          String extM = parts[3];
512
          String icon = parts[4];
513
          String obje = parts[5];
514
          String extr = parts[6];
515
          boolean isFree = (length==7 || Boolean.parseBoolean(parts[7]));
516

    
517
          int scrambles = Integer.parseInt(scra);
518
          int oMinor    = Integer.parseInt(objM);
519
          int eMinor    = Integer.parseInt(extM);
520

    
521
          boolean bIcon = icon.equals("1");
522
          boolean bObje = obje.equals("1");
523
          boolean bExtr = extr.equals("1");
524

    
525
          addDownloadedObject(context,name,scrambles,isFree,oMinor,eMinor,bIcon,bObje,bExtr);
526
          }
527
        }
528
      }
529

    
530
    RubikObject object = getObject(DEF_OBJECT);
531
    String defName = object==null ? "CUBE_3" : object.getUpperName();
532
    String objName= preferences.getString("rol_objName",defName);
533
    mObject = getOrdinal(objName);
534
    if( mObject<0 || mObject>=mNumObjects ) mObject = DEF_OBJECT;
535

    
536
    if( justStarted) restoreFreedObjects(preferences);
537
    }
538

    
539
///////////////////////////////////////////////////////////////////////////////////////////////////
540

    
541
  public static void restoreMeshState(SharedPreferences preferences)
542
    {
543
    for(int i=0; i<mNumObjects; i++)
544
      {
545
      RubikObject obj = getObject(i);
546

    
547
      if( obj!=null )
548
        {
549
        String name  = obj.getUpperName();
550
        int meshState= preferences.getInt("rol_"+name,MESH_NICE);
551
        obj.setMeshState(meshState);
552
        }
553
      }
554
    }
555

    
556
///////////////////////////////////////////////////////////////////////////////////////////////////
557

    
558
  public static void setObjectFreeState()
559
    {
560
    int numUnclaimed = getNumUnclaimedSolves();
561

    
562
    if( numUnclaimed>0 )
563
      {
564
      int marked = markAllSolvedAsFree();
565
      int stillUnclaimed = numUnclaimed-marked;
566
      if( stillUnclaimed>0) markAsFree(stillUnclaimed);
567
      }
568
    }
569

    
570
///////////////////////////////////////////////////////////////////////////////////////////////////
571

    
572
  public static boolean setCurrObject(int ordinal)
573
    {
574
    if( mObject!=ordinal )
575
      {
576
      mObject = ordinal;
577
      return true;
578
      }
579

    
580
    return false;
581
    }
582

    
583
///////////////////////////////////////////////////////////////////////////////////////////////////
584

    
585
  public static int getCurrObject()
586
    {
587
    return mObject;
588
    }
589

    
590
///////////////////////////////////////////////////////////////////////////////////////////////////
591

    
592
  public static String getCurrentName()
593
    {
594
    RubikObject object = mObjects.get(mObject);
595
    return object==null ? "" : object.getUpperName();
596
    }
597

    
598
///////////////////////////////////////////////////////////////////////////////////////////////////
599

    
600
  public static RubikObject getObject(int ordinal)
601
    {
602
    if( mThis==null ) mThis = new RubikObjectList();
603
    return ordinal>=0 && ordinal<mNumObjects ? mObjects.get(ordinal) : null;
604
    }
605

    
606
///////////////////////////////////////////////////////////////////////////////////////////////////
607

    
608
  public static RubikObject getObject(String shortUpperName)
609
    {
610
    if( mThis==null ) mThis = new RubikObjectList();
611

    
612
    for(int i=0; i<mNumObjects; i++)
613
      {
614
      RubikObject object = mObjects.get(i);
615
      if( object.getUpperName().equals(shortUpperName) )
616
        {
617
        return object;
618
        }
619
      }
620

    
621
    return null;
622
    }
623

    
624
///////////////////////////////////////////////////////////////////////////////////////////////////
625

    
626
  public static int getNumObjects()
627
    {
628
    if( mThis==null ) mThis = new RubikObjectList();
629
    return mNumObjects;
630
    }
631

    
632
///////////////////////////////////////////////////////////////////////////////////////////////////
633

    
634
  public static int getOrdinal(String name)
635
    {
636
    if( mThis==null ) mThis = new RubikObjectList();
637

    
638
    String lowerName = name.toLowerCase(Locale.ENGLISH);
639

    
640
    for(int i=0; i<mNumObjects; i++)
641
      {
642
      RubikObject obj = mObjects.get(i);
643
      if( obj.getLowerName().equals(lowerName) ) return i;
644
      }
645

    
646
    return -1;
647
    }
648

    
649
///////////////////////////////////////////////////////////////////////////////////////////////////
650

    
651
  public static int getNumExtrasObjects()
652
    {
653
    return mNumExtras;
654
    }
655

    
656
///////////////////////////////////////////////////////////////////////////////////////////////////
657

    
658
  public static int getNumTutorialObjects()
659
    {
660
    return mNumExtras;
661
    }
662

    
663
///////////////////////////////////////////////////////////////////////////////////////////////////
664

    
665
  public static int getObjectOrdinal(int extrasOrdinal)
666
    {
667
    for(int i=extrasOrdinal; i<mNumObjects; i++)
668
      {
669
      RubikObject object = getObject(i);
670
      int extOrd = object!=null ? object.getExtrasOrdinal() : -1;
671
      if( extOrd==extrasOrdinal ) return i;
672
      }
673

    
674
    return -1;
675
    }
676

    
677
///////////////////////////////////////////////////////////////////////////////////////////////////
678

    
679
  public static int getExtrasOrdinal(int objectOrdinal)
680
    {
681
    RubikObject object = getObject(objectOrdinal);
682
    return object!=null ? object.getExtrasOrdinal() : -1;
683
    }
684

    
685
///////////////////////////////////////////////////////////////////////////////////////////////////
686

    
687
  public static int getTutorialOrdinal(int objectOrdinal)
688
    {
689
    RubikObject object = getObject(objectOrdinal);
690
    return object!=null ? object.getExtrasOrdinal() : -1;
691
    }
692

    
693
///////////////////////////////////////////////////////////////////////////////////////////////////
694

    
695
  public static int getLocalObjectMinor(int objectOrdinal)
696
    {
697
    RubikObject object = getObject(objectOrdinal);
698
    return object!=null ? object.getObjectMinor() : -1;
699
    }
700

    
701
///////////////////////////////////////////////////////////////////////////////////////////////////
702

    
703
  public static int getLocalExtrasMinor(int objectOrdinal)
704
    {
705
    RubikObject object = getObject(objectOrdinal);
706
    return object!=null ? object.getExtrasMinor() : -1;
707
    }
708
}
(2-2/2)