Browse Source

cmScoreProc.h : Completed the cmSpAssocProc_t based processing.

Added kNoteNoSpid and kFailSpId messages to the score tracking processor callback.
master
Kevin Larke 9 years ago
parent
commit
e5dbc44c61
1 changed files with 226 additions and 53 deletions
  1. 226
    53
      app/cmScoreProc.c

+ 226
- 53
app/cmScoreProc.c View File

20
 #include "cmProcObj.h"
20
 #include "cmProcObj.h"
21
 #include "cmProc4.h"
21
 #include "cmProc4.h"
22
 
22
 
23
-enum
24
-{
25
-  kOkSpRC,
26
-  kJsonFailSpRC,
27
-  kScoreFailSpRC,
28
-  kTimeLineFailSpRC,
29
-  kScoreMatchFailSpRC,
30
-  kFileFailSpRC,
31
-  kProcFailSpRC
32
-};
33
-
34
 typedef enum
23
 typedef enum
35
 {
24
 {
36
-  kBeginSectionSpId,
37
-  kEndSectionSpId
25
+  kBeginSectionSpId,  // tlObjPtr points to a cmTlMarker_t object.
26
+  kEndSectionSpId,    // tlObjPtr is NULL.
27
+  kNoteOnSpId,        // tlObjPtr points to a cmTlMidiEvt_t note-on object.
28
+  kFailSpId           // tlObjPtr points to a cmTlMarker_t object (This section score tracking failed.)
38
 } cmScoreProcSelId_t;
29
 } cmScoreProcSelId_t;
39
 
30
 
40
 struct cmSp_str;
31
 struct cmSp_str;
41
 
32
 
42
-typedef cmSpRC_t (*cmScoreProcCb_t)( void* arg, struct cmSp_str* p, cmScoreProcSelId_t id, cmTlMarker_t* curMarkPtr );
33
+typedef cmSpRC_t (*cmScoreProcCb_t)( void* arg, struct cmSp_str* p, cmScoreProcSelId_t id, cmTlObj_t* tlObjPtr );
43
 
34
 
44
 typedef struct cmSp_str
35
 typedef struct cmSp_str
45
 {
36
 {
46
   cmErr_t         err;          // score proc object error state
37
   cmErr_t         err;          // score proc object error state
47
   cmCtx*          ctx;          // application context
38
   cmCtx*          ctx;          // application context
48
   cmScH_t         scH;          // score object
39
   cmScH_t         scH;          // score object
49
-  const cmChar_t* tlFn;         // time-line filename
50
   cmTlH_t         tlH;          // time-line object
40
   cmTlH_t         tlH;          // time-line object
51
   cmJsonH_t       jsH;          // 
41
   cmJsonH_t       jsH;          // 
52
   unsigned*       dynArray;     // dynArray[dynCnt] dynamics reference array
42
   unsigned*       dynArray;     // dynArray[dynCnt] dynamics reference array
54
   double          srate;        // 
44
   double          srate;        // 
55
   cmScMatcher*    match;        // score follower
45
   cmScMatcher*    match;        // score follower
56
 
46
 
57
-  cmScMatcherCb_t  matchCb;     // score follower callback
58
-  cmScoreProcCb_t  procCb;      // score processor callback
47
+  cmScoreProcCb_t  procCb;      // score processor callback - called whenever a new 'marker' section or note-on is about to be processed
48
+  cmScMatcherCb_t  matchCb;     // score follower callback  - called whenever the score follower detects a matched event
59
   void*            cbArg;       // callback arg. for both matchCb and procCb.
49
   void*            cbArg;       // callback arg. for both matchCb and procCb.
60
 
50
 
61
 } cmSp_t;
51
 } cmSp_t;
81
   return kOkSpRC;  
71
   return kOkSpRC;  
82
 }
72
 }
83
 
73
 
84
-cmSpRC_t _cmScoreProcInit( cmCtx_t* ctx, cmSp_t* p, const cmChar_t* rsrcFn, cmScoreProcCb_t procCb, cmScMatcherCb_t matchCb, void* cbArg  )
74
+cmSpRC_t _cmScoreProcInit( 
75
+  cmCtx_t*        ctx, 
76
+  cmSp_t*         p, 
77
+  const cmChar_t* rsrcFn, 
78
+  cmScoreProcCb_t procCb, 
79
+  cmScMatcherCb_t matchCb, 
80
+  void*           cbArg  )
85
 {
81
 {
86
   cmSpRC_t        rc     = kOkSpRC;
82
   cmSpRC_t        rc     = kOkSpRC;
87
   const cmChar_t* scFn   = NULL;
83
   const cmChar_t* scFn   = NULL;
143
     goto errLabel;
139
     goto errLabel;
144
   }
140
   }
145
 
141
 
146
-  p->ctx  = cmCtxAlloc(NULL, &ctx->rpt, cmLHeapNullHandle, cmSymTblNullHandle );
142
+  p->ctx     = cmCtxAlloc(NULL, &ctx->rpt, cmLHeapNullHandle, cmSymTblNullHandle );
147
   p->matchCb = matchCb;
143
   p->matchCb = matchCb;
148
   p->procCb  = procCb;
144
   p->procCb  = procCb;
149
   p->cbArg   = cbArg;
145
   p->cbArg   = cbArg;
153
 }
149
 }
154
 
150
 
155
 
151
 
152
+// This function iterates through each sequence and advances
153
+// to each 'begin-marker' position.  
156
 cmSpRC_t _cmScoreProcProcess(cmCtx_t* ctx, cmSp_t* sp)
154
 cmSpRC_t _cmScoreProcProcess(cmCtx_t* ctx, cmSp_t* sp)
157
 {
155
 {
158
   cmSpRC_t rc     = kOkSpRC;
156
   cmSpRC_t rc     = kOkSpRC;
199
 
197
 
200
       cmRptPrintf(&ctx->rpt,"Processing loc:%i seq:%i %s %s\n",locPtr->index,seqId,cmStringNullGuard(markPtr->obj.name),cmStringNullGuard(markPtr->text));
198
       cmRptPrintf(&ctx->rpt,"Processing loc:%i seq:%i %s %s\n",locPtr->index,seqId,cmStringNullGuard(markPtr->obj.name),cmStringNullGuard(markPtr->text));
201
 
199
 
202
-      // inform the score processor that we are about to start a new section
203
-      if( sp->procCb( sp->cbArg, sp, kBeginSectionSpId, markPtr ) != kOkSpRC )
200
+      // reset the score matcher to begin searching at the bar location
201
+      if( cmScMatcherReset(sp->match, locPtr->index ) != cmOkRC )
204
       {
202
       {
205
-        cmErrMsg(&sp->err,kProcFailSpRC,"The score process object failed on reset.");
203
+        cmErrMsg(&sp->err,kScoreMatchFailSpRC,"The score matcher reset failed on location: %i.",locPtr->index);
206
         continue;
204
         continue;
207
       }
205
       }
208
 
206
 
209
-      // reset the score matcher to begin searching at the bar location
210
-      if( cmScMatcherReset(sp->match, locPtr->index ) != cmOkRC )
207
+      // inform the score processor that we are about to start a new section
208
+      if( sp->procCb( sp->cbArg, sp, kBeginSectionSpId, o0p ) != kOkSpRC )
211
       {
209
       {
212
-        cmErrMsg(&sp->err,kScoreMatchFailSpRC,"The score matcher reset failed on location: %i.",locPtr->index);
210
+        cmErrMsg(&sp->err,kProcFailSpRC,"The score process object failed on reset.");
213
         continue;
211
         continue;
214
       }
212
       }
215
 
213
 
216
-      cmTlObj_t* o1p = o0p;
214
+      cmTlObj_t* o1p   = o0p;
215
+      bool       errFl = false;
217
 
216
 
218
       // as long as more MIDI events are available get the next MIDI msg 
217
       // as long as more MIDI events are available get the next MIDI msg 
219
       while( (rc == kOkSpRC) && (o1p = cmTimeLineNextTypeObj(sp->tlH, o1p, seqId, kMidiEvtTlId )) != NULL )
218
       while( (rc == kOkSpRC) && (o1p = cmTimeLineNextTypeObj(sp->tlH, o1p, seqId, kMidiEvtTlId )) != NULL )
225
         if( mep->obj.seqSmpIdx != cmInvalidIdx && mep->obj.seqSmpIdx > markEndSmpIdx )
224
         if( mep->obj.seqSmpIdx != cmInvalidIdx && mep->obj.seqSmpIdx > markEndSmpIdx )
226
           break;
225
           break;
227
         
226
         
228
-        // if the time line MIDI msg a note-on
227
+        // if the time line MIDI msg is a note-on
229
         if( mep->msg->status == kNoteOnMdId )
228
         if( mep->msg->status == kNoteOnMdId )
230
         {
229
         {
230
+          sp->procCb( sp->cbArg, sp, kNoteOnSpId,  o1p );
231
+
231
           cmRC_t cmRC = cmScMatcherExec(sp->match, mep->obj.seqSmpIdx, mep->msg->status, mep->msg->u.chMsgPtr->d0, mep->msg->u.chMsgPtr->d1, NULL );
232
           cmRC_t cmRC = cmScMatcherExec(sp->match, mep->obj.seqSmpIdx, mep->msg->status, mep->msg->u.chMsgPtr->d0, mep->msg->u.chMsgPtr->d1, NULL );
232
 
233
 
233
           switch( cmRC )
234
           switch( cmRC )
240
 
241
 
241
             case cmInvalidArgRC: // p->eli was not set correctly
242
             case cmInvalidArgRC: // p->eli was not set correctly
242
               rc = cmErrMsg(&sp->err,kScoreMatchFailSpRC,"The score matcher failed due to an invalid argument.");
243
               rc = cmErrMsg(&sp->err,kScoreMatchFailSpRC,"The score matcher failed due to an invalid argument.");
243
-              goto errLabel;
244
+              errFl = true;
244
               break;
245
               break;
245
 
246
 
246
             case cmSubSysFailRC: // scan resync failed
247
             case cmSubSysFailRC: // scan resync failed
247
               rc = cmErrMsg(&sp->err,kScoreMatchFailSpRC,"The score matcher failed on resync.");
248
               rc = cmErrMsg(&sp->err,kScoreMatchFailSpRC,"The score matcher failed on resync.");
248
-              cmScMatcherPrint(sp->match);
249
+
250
+              sp->procCb( sp->cbArg, sp, kFailSpId, o0p );
251
+
252
+              //cmScMatcherPrint(sp->match);
249
               //goto errLabel;
253
               //goto errLabel;
250
               break;
254
               break;
251
 
255
 
259
       if( sp->procCb( sp->cbArg, sp, kEndSectionSpId, NULL ) != kOkSpRC )
263
       if( sp->procCb( sp->cbArg, sp, kEndSectionSpId, NULL ) != kOkSpRC )
260
         cmErrMsg(&sp->err,kProcFailSpRC,"The score process object failed on reset.");
264
         cmErrMsg(&sp->err,kProcFailSpRC,"The score process object failed on reset.");
261
 
265
 
266
+      // error flag is used to break out of the loop after the 'end-section' is called
267
+      // so that the user defined processes has a chance to clean-up 
268
+      if( errFl )
269
+        goto errLabel;
270
+
262
       rc = kOkSpRC;
271
       rc = kOkSpRC;
263
     }
272
     }
264
   }
273
   }
477
 }
486
 }
478
 
487
 
479
 // measurement proc callback
488
 // measurement proc callback
480
-cmSpRC_t  _cmSpProcMeasCb( void* arg, cmSp_t* sp, cmScoreProcSelId_t id, cmTlMarker_t* curMarkPtr )
489
+cmSpRC_t  _cmSpProcMeasCb( void* arg, cmSp_t* sp, cmScoreProcSelId_t id, cmTlObj_t* tlObjPtr )
481
 {
490
 {
482
   cmSpRC_t         rc = kOkSpRC;
491
   cmSpRC_t         rc = kOkSpRC;
483
   _cmSpMeasProc_t* m = (_cmSpMeasProc_t*)arg;
492
   _cmSpMeasProc_t* m = (_cmSpMeasProc_t*)arg;
490
       if( cmScMeasReset(m->meas) != cmOkRC )
499
       if( cmScMeasReset(m->meas) != cmOkRC )
491
         rc = cmErrMsg(&sp->err,kScoreMatchFailSpRC,"The score performance evaluation object failed on reset.");
500
         rc = cmErrMsg(&sp->err,kScoreMatchFailSpRC,"The score performance evaluation object failed on reset.");
492
 
501
 
493
-      m->curMarkPtr = curMarkPtr;
502
+      m->curMarkPtr = cmTimeLineMarkerObjPtr(sp->tlH,tlObjPtr);
503
+      break;
504
+
505
+    case kNoteOnSpId:
494
       break;
506
       break;
495
 
507
 
496
     case kEndSectionSpId:
508
     case kEndSectionSpId:
497
       break;
509
       break;
510
+
511
+    case kFailSpId:
512
+      break;
498
   }
513
   }
499
 
514
 
500
   return rc;
515
   return rc;
559
 }
574
 }
560
 
575
 
561
 //==================================================================================================
576
 //==================================================================================================
577
+typedef struct cmSpAssoc_str
578
+{
579
+  unsigned              scEvtIdx; // score event index
580
+  unsigned              tlUid;    // time-line MIDI note-on object id
581
+  struct cmSpAssoc_str* link;
582
+} cmSpAssoc_t;
583
+
584
+typedef struct cmSpNoteMap_str
585
+{
586
+  unsigned                tlUid; // time-line MIDI note-on object id
587
+  unsigned                mni;  // assocated 'mni' returned in a cmScMatcherResult_t record
588
+  struct cmSpNoteMap_str* link;
589
+} cmSpNoteMap_t;
590
+
562
 typedef struct
591
 typedef struct
563
 {
592
 {
564
-  cmSp_t* sp; 
565
-} cmSpPerfProc_t;
593
+  cmCtx_t*       ctx;
594
+  cmSp_t*        sp; 
595
+  unsigned       mni;
596
+  bool           failFl;
597
+  cmJsonH_t      jsH;
598
+  cmJsonNode_t*  sectObj;
599
+  cmJsonNode_t*  array;
600
+
601
+  cmSpAssoc_t*   bap;  
602
+  cmSpAssoc_t*   eap;
603
+  cmSpNoteMap_t* bmp;
604
+  cmSpNoteMap_t* emp;
605
+
606
+  
607
+} cmSpAssocProc_t;
566
 
608
 
567
-void _cmSpMatchPerfCb( cmScMatcher* p, void* arg, cmScMatcherResult_t* rp )
609
+void _cmSpMatchAssocCb( cmScMatcher* p, void* arg, cmScMatcherResult_t* rp )
568
 {
610
 {
569
-  cmSpPerfProc_t* m = (cmSpPerfProc_t*)arg;
611
+  cmSpAssocProc_t* m   = (cmSpAssocProc_t*)arg;
612
+
613
+  
614
+  if( cmJsonCreateFilledObject(m->jsH, m->array,
615
+      "mni",      kIntTId, rp->mni,
616
+      "scEvtIdx", kIntTId, rp->scEvtIdx,
617
+      "flags",    kIntTId, rp->flags, 
618
+      NULL ) == NULL )
619
+  {
620
+    cmErrMsg(&m->ctx->err,kJsonFailSpRC,"JSON association record create failed.");
621
+  }
622
+  
623
+  //cmScoreEvt_t*    sep = rp->scEvtIdx == -1 ? NULL : cmScoreEvt( m->sp->scH, rp->scEvtIdx );
624
+  //printf("%3i loc:%4i pitch=%3i %3i  flags=0x%x\n",rp->mni,rp->locIdx,rp->pitch,sep==NULL ? -1 : sep->pitch,rp->flags );
570
   
625
   
571
 }
626
 }
572
 
627
 
573
-cmSpRC_t  _cmSpProcPerfCb( void* arg, cmSp_t* sp, cmScoreProcSelId_t id, cmTlMarker_t* curMarkPtr )
628
+cmSpRC_t  _cmSpProcAssocCb( void* arg, cmSp_t* sp, cmScoreProcSelId_t id, cmTlObj_t* tlObjPtr )
574
 {
629
 {
575
-  cmSpPerfProc_t* m = (cmSpPerfProc_t*)arg;
630
+  cmSpRC_t         rc = kOkSpRC;
631
+  cmSpAssocProc_t* m  = (cmSpAssocProc_t*)arg;
632
+
633
+  switch( id )
634
+  {
635
+    case kBeginSectionSpId:
636
+      {
637
+        cmTlMarker_t* markPtr = cmTimeLineMarkerObjPtr( sp->tlH, tlObjPtr );
638
+        assert( markPtr != NULL );
639
+        m->mni    = 0;
640
+        m->failFl = false;
641
+
642
+        // insert a section object
643
+        if((m->sectObj = cmJsonInsertPairObject(m->jsH, cmJsonRoot(m->jsH), "section" )) == NULL )
644
+        {
645
+          rc = cmErrMsg(&m->ctx->err,kJsonFailSpRC,"Section insert failed on seq:%i '%s' : '%s'.", tlObjPtr->seqId, cmStringNullGuard(tlObjPtr->text),cmStringNullGuard(markPtr->text));
646
+          goto errLabel; 
647
+        }
648
+
649
+        // set the section time-line UID
650
+        if( cmJsonInsertPairInt(m->jsH, m->sectObj,"markerUid", tlObjPtr->uid ) != kOkJsRC )
651
+        {
652
+          rc = cmErrMsg(&m->ctx->err,kJsonFailSpRC,"Marker uid field insert failed on seq:%i '%s' : '%s'.", tlObjPtr->seqId, cmStringNullGuard(tlObjPtr->text),cmStringNullGuard(markPtr->text));
653
+          goto errLabel;           
654
+        }
655
+
656
+        // create an array to hold the assoc results
657
+        if(( m->array = cmJsonInsertPairArray(m->jsH, m->sectObj, "array")) == NULL )
658
+        {
659
+          rc = cmErrMsg(&m->ctx->err,kJsonFailSpRC,"Marker array field insert failed on seq:%i '%s' : '%s'.", tlObjPtr->seqId, cmStringNullGuard(tlObjPtr->text),cmStringNullGuard(markPtr->text));
660
+          goto errLabel;           
661
+        }          
662
+      }
663
+      break;
664
+
665
+    case kEndSectionSpId:
666
+      {
667
+        while( m->bmp != NULL )
668
+        {
669
+          cmSpNoteMap_t* nmp = m->bmp->link;
670
+          cmMemFree(m->bmp);
671
+          m->bmp = nmp;
672
+        }
673
+      
674
+        m->bmp = NULL;
675
+        m->emp = NULL;
576
 
676
 
677
+        if( cmJsonInsertPairInt( m->jsH, m->sectObj, "failFl", m->failFl ) != kOkJsRC )
678
+        {
679
+          rc = cmErrMsg(&m->ctx->err,kJsonFailSpRC,"JSON fail flag insert failed.");
680
+          goto errLabel;
681
+        }
682
+        
683
+      }
684
+      break;
685
+
686
+    case kNoteOnSpId:
687
+      {
688
+        // create a cmSpNoteMap_t record ...
689
+        cmSpNoteMap_t* map = cmMemAllocZ(cmSpNoteMap_t,1);
690
+        map->tlUid = tlObjPtr->uid;
691
+        map->mni   = m->mni;
692
+
693
+        // .. and insert it in the note-map list
694
+        if( m->emp == NULL )
695
+        {
696
+          m->bmp = map;
697
+          m->emp = map;
698
+        }
699
+        else
700
+        {
701
+          m->emp->link = map;
702
+          m->emp       = map;
703
+        }
704
+
705
+        m->mni += 1;
706
+      }
707
+      break;
708
+
709
+    case kFailSpId:
710
+      m->failFl = true;
711
+      break;
712
+
713
+  }
714
+
715
+ errLabel:
716
+  return rc;
577
 }
717
 }
578
 
718
 
579
-cmSpRC_t _cmScoreProcGenPerfMain(cmCtx_t* ctx)
719
+cmSpRC_t _cmScoreProcGenAssocMain(cmCtx_t* ctx)
580
 {
720
 {
581
-  const cmChar_t* rsrcFn = "/home/kevin/.kc/time_line.js";
582
-  const cmChar_t* outFn  = "/home/kevin/src/cmkc/src/kc/data/meas0.js";
583
-
584
-  cmSpRC_t        rc     = kOkSpRC;
585
-  cmSpPerfProc_t* m      = cmMemAllocZ(cmSpPerfProc_t,1);
586
-  cmSp_t          s;
587
-  cmSp_t*         sp     = &s;
721
+  const cmChar_t*  rsrcFn = "/home/kevin/.kc/time_line.js";
722
+  const cmChar_t*  outFn  = "/home/kevin/src/cmkc/src/kc/data/assoc0.js";
723
+  cmSpRC_t         rc     = kOkSpRC;
724
+  cmSpAssocProc_t* m      = cmMemAllocZ(cmSpAssocProc_t,1);
725
+  cmSp_t           s;
726
+  cmSp_t*          sp     = &s;
588
 
727
 
589
   memset(sp,0,sizeof(s));
728
   memset(sp,0,sizeof(s));
590
 
729
 
591
-  cmRptPrintf(&ctx->rpt,"Score Performance Start\n");
730
+  m->ctx = ctx;
731
+
732
+  cmRptPrintf(&ctx->rpt,"Score Association Start\n");
733
+
734
+  // create a JSON object to hold the results
735
+  if( cmJsonInitialize(&m->jsH, ctx ) != kOkJsRC )
736
+  {
737
+    cmErrMsg(&m->ctx->err,kJsonFailSpRC,"Score association JSON output object create failed.");
738
+    goto errLabel;
739
+  }
740
+
741
+  // create the JSON root object
742
+  if( cmJsonCreateObject(m->jsH, NULL ) == NULL )
743
+  {
744
+    cmErrMsg(&m->ctx->err,kJsonFailSpRC,"Create JSON root object.");
745
+    goto errLabel;
746
+  }
592
 
747
 
593
   // initialize the score processor
748
   // initialize the score processor
594
-  if((rc = _cmScoreProcInit(ctx,sp,rsrcFn,_cmSpProcPerfCb,_cmSpMatchPerfCb,m)) != kOkSpRC )
749
+  if((rc = _cmScoreProcInit(ctx,sp,rsrcFn,_cmSpProcAssocCb,_cmSpMatchAssocCb, m)) != kOkSpRC )
595
     goto errLabel;
750
     goto errLabel;
596
 
751
 
597
   m->sp = sp;
752
   m->sp = sp;
598
 
753
 
754
+  // store the time-line and score file name
755
+  if( cmJsonInsertPairs(m->jsH, cmJsonRoot(m->jsH), 
756
+      "tlFn",    kStringTId, cmTimeLineFileName( sp->tlH),
757
+      "scoreFn", kStringTId, cmScoreFileName( sp->scH ),
758
+      NULL ) != kOkJsRC )
759
+  {
760
+    cmErrMsg(&m->ctx->err,kJsonFailSpRC,"File name JSON field insertion failed.");
761
+    goto errLabel;
762
+  }
763
+
599
   // run the score processor
764
   // run the score processor
600
   _cmScoreProcProcess(ctx,sp);
765
   _cmScoreProcProcess(ctx,sp);
601
 
766
 
602
-  // write the results of the performance evaluation
603
-  if((rc = _cmScWriteMeasFile(ctx, sp, m, outFn )) != kOkSpRC )
604
-    cmErrMsg(&sp->err,kFileFailSpRC,"The measurement output did not complete without errors."); 
767
+  cmRptPrintf(&ctx->rpt,"Writing results to '%s'.",outFn);
605
 
768
 
606
-  //cmScorePrint(sp.scH,&ctx->rpt);
607
-  //cmScorePrintLoc(sp.scH);
769
+  // write the results to a JSON file
770
+  if(cmJsonWrite(m->jsH, NULL, outFn ) != kOkJsRC )
771
+  {
772
+    cmErrMsg(&m->ctx->err,kJsonFailSpRC,"Score association output file write failed.");
773
+    goto errLabel;
774
+  }
608
  
775
  
609
  errLabel:
776
  errLabel:
777
+  if( cmJsonFinalize(&m->jsH) != kOkJsRC )
778
+  {
779
+    cmErrMsg(&m->ctx->err,kJsonFailSpRC,"JSON finalize failed.");
780
+  }
781
+
610
   _cmScoreProcFinal(sp);
782
   _cmScoreProcFinal(sp);
611
 
783
 
612
   cmMemFree(m);
784
   cmMemFree(m);
625
 {
797
 {
626
   cmSpRC_t rc = kOkSpRC;
798
   cmSpRC_t rc = kOkSpRC;
627
 
799
 
628
-  _cmScoreProcGenAllMeasurementsMain(ctx);
800
+  //_cmScoreProcGenAllMeasurementsMain(ctx);
801
+  _cmScoreProcGenAssocMain(ctx);
629
 
802
 
630
   return rc;
803
   return rc;
631
   
804
   

Loading…
Cancel
Save