carray 1.3.3 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +0 -7
- data/Rakefile +31 -0
- data/carray.gemspec +9 -14
- data/carray.h +4 -0
- data/carray_access.c +50 -8
- data/carray_conversion.c +3 -3
- data/carray_generate.c +67 -1
- data/carray_math.rb +22 -22
- data/carray_operator.c +23 -0
- data/devel/im2col.rb +17 -0
- data/ext/calculus/carray_calculus.c +235 -95
- data/ext/calculus/carray_interp.c +3 -1
- data/ext/calculus/lib/math/calculus.rb +4 -4
- data/lib/carray.rb +32 -1
- data/lib/carray/autoload/autoload_base.rb +0 -4
- data/lib/carray/autoload/autoload_gem_cairo.rb +9 -0
- data/lib/carray/autoload/autoload_gem_ffi.rb +9 -0
- data/lib/carray/autoload/autoload_gem_gnuplot.rb +2 -0
- data/lib/carray/autoload/autoload_gem_io_csv.rb +14 -0
- data/lib/carray/autoload/autoload_gem_io_pg.rb +6 -0
- data/lib/carray/autoload/autoload_gem_io_sqlite3.rb +12 -0
- data/lib/carray/autoload/autoload_gem_narray.rb +10 -0
- data/lib/carray/autoload/autoload_gem_numo_narray.rb +14 -0
- data/lib/carray/autoload/autoload_gem_opencv.rb +16 -0
- data/lib/carray/autoload/autoload_gem_rmagick.rb +23 -0
- data/lib/carray/autoload/{autoload_graphics_zimg.rb → autoload_gem_zimg.rb} +0 -0
- data/lib/carray/base/autoload.rb +47 -5
- data/lib/carray/base/basic.rb +70 -6
- data/lib/carray/base/math.rb +1 -1
- data/lib/carray/base/string.rb +242 -0
- data/lib/carray/base/struct.rb +4 -4
- data/lib/carray/io/table.rb +1 -0
- data/mkmath.rb +12 -2
- data/version.h +5 -5
- metadata +48 -141
- data/Gemfile +0 -8
- data/Gemfile.lock +0 -33
- data/ext/calculus/lib/autoload/autoload_math_calculus.rb +0 -2
- data/ext/fortio/extconf.rb +0 -3
- data/ext/fortio/lib/carray/autoload/autoload_fortran_format.rb +0 -5
- data/ext/fortio/lib/carray/io/fortran_format.rb +0 -43
- data/ext/fortio/lib/fortio.rb +0 -3
- data/ext/fortio/lib/fortio/fortran_format.rb +0 -605
- data/ext/fortio/lib/fortio/fortran_format.tab.rb +0 -536
- data/ext/fortio/lib/fortio/fortran_format.y +0 -215
- data/ext/fortio/lib/fortio/fortran_namelist.rb +0 -151
- data/ext/fortio/lib/fortio/fortran_namelist.tab.rb +0 -470
- data/ext/fortio/lib/fortio/fortran_namelist.y +0 -213
- data/ext/fortio/lib/fortio/fortran_sequential.rb +0 -345
- data/ext/fortio/ruby_fortio.c +0 -182
- data/ext/fortio/test/test_H.rb +0 -5
- data/ext/fortio/test/test_T.rb +0 -7
- data/ext/fortio/test/test_fortran_format.rb +0 -86
- data/ext/fortio/test/test_namelist.rb +0 -25
- data/ext/fortio/test/test_namelist_write.rb +0 -10
- data/ext/fortio/test/test_sequential.rb +0 -13
- data/ext/fortio/test/test_sequential2.rb +0 -13
- data/ext/fortio/work/test.rb +0 -10
- data/ext/fortio/work/test_e.rb +0 -19
- data/ext/fortio/work/test_ep.rb +0 -10
- data/ext/fortio/work/test_parse.rb +0 -12
- data/ext/imagemap/carray_imagemap.c +0 -495
- data/ext/imagemap/doc/call_graph.dot +0 -28
- data/ext/imagemap/draw.c +0 -567
- data/ext/imagemap/extconf.rb +0 -13
- data/ext/imagemap/lib/autoload/autoload_graphics_imagemap.rb +0 -1
- data/ext/imagemap/lib/graphics/imagemap.rb +0 -273
- data/ext/imagemap/lib/image_map.rb +0 -4
- data/ext/imagemap/test/swath_index.rb +0 -83
- data/ext/imagemap/test/swath_warp.rb +0 -99
- data/ext/imagemap/test/test.rb +0 -23
- data/ext/imagemap/test/test_image.rb +0 -42
- data/ext/imagemap/test/test_line.rb +0 -14
- data/ext/imagemap/test/test_rotate.rb +0 -17
- data/ext/imagemap/test/test_triangle.rb +0 -20
- data/ext/imagemap/test/test_warp.rb +0 -26
- data/ext/mathfunc/lib/autoload/autoload_math_mathfunc.rb +0 -1
- data/ext/mathfunc/lib/math/mathfunc.rb +0 -15
- data/ext/narray/README +0 -22
- data/ext/narray/ca_wrap_narray.c +0 -500
- data/ext/narray/carray_narray.c +0 -21
- data/ext/narray/extconf.rb +0 -57
- data/ext/narray/lib/autoload/autoload_math_narray.rb +0 -1
- data/ext/narray/lib/autoload/autoload_math_narray_miss.rb +0 -11
- data/ext/narray/lib/math/narray.rb +0 -17
- data/ext/narray/lib/math/narray_miss.rb +0 -45
- data/lib/carray/autoload/autoload_graphics_gnuplot.rb +0 -2
- data/lib/carray/autoload/autoload_io_csv.rb +0 -14
- data/lib/carray/autoload/autoload_io_pg.rb +0 -6
- data/lib/carray/autoload/autoload_io_sqlite3.rb +0 -12
- data/lib/carray/graphics/gnuplot.rb +0 -2131
- data/lib/carray/graphics/zimg.rb +0 -296
- data/lib/carray/io/csv.rb +0 -572
- data/lib/carray/io/pg.rb +0 -101
- data/lib/carray/io/sqlite3.rb +0 -215
- data/mkmf.log +0 -18
data/devel/im2col.rb
ADDED
@@ -498,63 +498,127 @@ deriv_penta (double *x, double *y, double xx)
|
|
498
498
|
static double
|
499
499
|
interpolate_linear (double *x, double *y, ca_size_t n, double xx)
|
500
500
|
{
|
501
|
+
double xt[2];
|
501
502
|
double ri;
|
502
503
|
ca_size_t i0;
|
503
504
|
if ( n == 1) {
|
504
505
|
return y[0];
|
505
506
|
}
|
506
|
-
if (
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
i0
|
507
|
+
if ( x != NULL ) {
|
508
|
+
if ( xx == x[0] ) {
|
509
|
+
return y[0];
|
510
|
+
}
|
511
|
+
if ( xx == x[1] ) {
|
512
|
+
return y[1];
|
513
|
+
}
|
514
|
+
if ( n == 2 ) {
|
515
|
+
return interp_lin(x, y, xx);
|
516
|
+
}
|
517
|
+
linear_index(n, x, xx, &ri);
|
518
|
+
i0 = floor(ri);
|
519
|
+
if ( i0 <= 0 ) {
|
520
|
+
i0 = 0;
|
521
|
+
}
|
522
|
+
else if ( i0 + 1 >= n - 1 ) {
|
523
|
+
i0 = n - 2;
|
524
|
+
}
|
525
|
+
return interp_lin(&x[i0], &y[i0], xx);
|
519
526
|
}
|
520
|
-
else
|
521
|
-
|
527
|
+
else {
|
528
|
+
if ( xx == 0 ) {
|
529
|
+
return y[0];
|
530
|
+
}
|
531
|
+
if ( xx == 1 ) {
|
532
|
+
return y[1];
|
533
|
+
}
|
534
|
+
if ( n == 2 ) {
|
535
|
+
xt[0] = 0.0;
|
536
|
+
xt[1] = 1.0;
|
537
|
+
return interp_lin(xt, y, xx);
|
538
|
+
}
|
539
|
+
i0 = floor(xx);
|
540
|
+
if ( i0 <= 0 ) {
|
541
|
+
i0 = 0;
|
542
|
+
}
|
543
|
+
else if ( i0 + 1 >= n - 1 ) {
|
544
|
+
i0 = n - 2;
|
545
|
+
}
|
546
|
+
xt[0] = i0;
|
547
|
+
xt[1] = i0+1;
|
548
|
+
return interp_lin(xt, &y[i0], xx);
|
522
549
|
}
|
523
|
-
return interp_lin(&x[i0], &y[i0], xx);
|
524
550
|
}
|
525
551
|
|
526
552
|
static double
|
527
553
|
interpolate_cubic (double *x, double *y, ca_size_t n, double xx)
|
528
554
|
{
|
555
|
+
static double xt[4];
|
529
556
|
double ri;
|
530
557
|
ca_size_t i0;
|
531
558
|
if ( n == 1) {
|
532
559
|
return y[0];
|
533
560
|
}
|
534
|
-
if (
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
i0
|
561
|
+
if ( x != NULL ) {
|
562
|
+
if ( xx == x[0] ) {
|
563
|
+
return y[0];
|
564
|
+
}
|
565
|
+
if ( xx == x[1] ) {
|
566
|
+
return y[1];
|
567
|
+
}
|
568
|
+
if ( xx == x[2] ) {
|
569
|
+
return y[2];
|
570
|
+
}
|
571
|
+
if ( n == 2 ) {
|
572
|
+
return interp_lin(x, y, xx);
|
573
|
+
}
|
574
|
+
if ( n == 3 ) {
|
575
|
+
return interp_qual(x, y, xx);
|
576
|
+
}
|
577
|
+
linear_index(n, x, xx, &ri);
|
578
|
+
i0 = floor(ri) - 1;
|
579
|
+
if ( i0 <= 0 ) {
|
580
|
+
i0 = 0;
|
581
|
+
}
|
582
|
+
else if ( i0 + 3 >= n - 1 ) {
|
583
|
+
i0 = n - 4;
|
584
|
+
}
|
585
|
+
return interp_cubic(&x[i0], &y[i0], xx);
|
553
586
|
}
|
554
|
-
else
|
555
|
-
|
587
|
+
else {
|
588
|
+
if ( xx == 0 ) {
|
589
|
+
return y[0];
|
590
|
+
}
|
591
|
+
if ( xx == 1 ) {
|
592
|
+
return y[1];
|
593
|
+
}
|
594
|
+
if ( xx == 2 ) {
|
595
|
+
return y[2];
|
596
|
+
}
|
597
|
+
if ( n == 2 ) {
|
598
|
+
xt[0] = 0.0;
|
599
|
+
xt[1] = 1.0;
|
600
|
+
return interp_lin(xt, y, xx);
|
601
|
+
}
|
602
|
+
if ( n == 3 ) {
|
603
|
+
xt[0] = 0.0;
|
604
|
+
xt[1] = 1.0;
|
605
|
+
xt[2] = 2.0;
|
606
|
+
return interp_qual(xt, y, xx);
|
607
|
+
}
|
608
|
+
ri = xx;
|
609
|
+
i0 = floor(ri) - 1;
|
610
|
+
if ( i0 <= 0 ) {
|
611
|
+
i0 = 0;
|
612
|
+
}
|
613
|
+
else if ( i0 + 3 >= n - 1 ) {
|
614
|
+
i0 = n - 4;
|
615
|
+
}
|
616
|
+
xt[0] = i0;
|
617
|
+
xt[1] = i0+1;
|
618
|
+
xt[2] = i0+2;
|
619
|
+
xt[3] = i0+3;
|
620
|
+
return interp_cubic(xt, &y[i0], xx);
|
556
621
|
}
|
557
|
-
return interp_cubic(&x[i0], &y[i0], xx);
|
558
622
|
}
|
559
623
|
|
560
624
|
static double
|
@@ -624,77 +688,153 @@ rb_ca_interpolate (int argc, VALUE *argv, VALUE self)
|
|
624
688
|
"invalid interpolation type <%s>", StringValuePtr(inspect));
|
625
689
|
}
|
626
690
|
|
627
|
-
|
628
|
-
sc = ca_wrap_readonly(vsc, CA_DOUBLE);
|
629
|
-
|
630
|
-
if ( ca_is_any_masked(cv) || ca_is_any_masked(sc) ) {
|
631
|
-
rb_raise(rb_eRuntimeError,
|
632
|
-
"can't calculate interpolation when masked elements exist");
|
633
|
-
}
|
634
|
-
|
635
|
-
if ( cv->elements != sc->elements ) {
|
636
|
-
rb_raise(rb_eRuntimeError, "data num mismatch with scale");
|
637
|
-
}
|
638
|
-
|
639
|
-
cx = ca_wrap_readonly(vx, CA_DOUBLE);
|
691
|
+
if ( ! NIL_P(vsc) ) {
|
640
692
|
|
641
|
-
|
642
|
-
|
643
|
-
co = ca_wrap_writable(out, CA_DOUBLE);
|
693
|
+
cv = ca_wrap_readonly(rval, CA_DOUBLE);
|
694
|
+
sc = ca_wrap_readonly(vsc, CA_DOUBLE);
|
644
695
|
|
645
|
-
|
696
|
+
if ( ca_is_any_masked(cv) || ca_is_any_masked(sc) ) {
|
697
|
+
rb_raise(rb_eRuntimeError,
|
698
|
+
"can't calculate interpolation when masked elements exist");
|
699
|
+
}
|
646
700
|
|
647
|
-
|
648
|
-
|
701
|
+
if ( cv->elements != sc->elements ) {
|
702
|
+
rb_raise(rb_eRuntimeError, "data num mismatch with scale");
|
703
|
+
}
|
649
704
|
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
705
|
+
cx = ca_wrap_readonly(vx, CA_DOUBLE);
|
706
|
+
|
707
|
+
co0 = carray_new(ca->data_type, cx->rank, cx->dim, 0, NULL);
|
708
|
+
out = out0 = ca_wrap_struct(co0);
|
709
|
+
co = ca_wrap_writable(out, CA_DOUBLE);
|
710
|
+
|
711
|
+
ca_attach_n(4, cv, sc, cx, co);
|
712
|
+
|
713
|
+
px = (double*) cx->ptr;
|
714
|
+
po = (double*) co->ptr;
|
715
|
+
|
716
|
+
ca_update_mask(cx);
|
717
|
+
if ( cx->mask ) {
|
718
|
+
boolean8_t *mx, *mo;
|
719
|
+
ca_create_mask(co);
|
720
|
+
mx = (boolean8_t *) cx->mask->ptr;
|
721
|
+
mo = (boolean8_t *) co->mask->ptr;
|
722
|
+
if ( type == 3 ) {
|
723
|
+
for (i=0; i<cx->elements; i++) {
|
724
|
+
if ( ! *mx ) {
|
725
|
+
*po = interpolate_cubic((double*)sc->ptr, (double*)cv->ptr,
|
726
|
+
cv->elements, *px);
|
727
|
+
}
|
728
|
+
else {
|
729
|
+
*mo = 1;
|
730
|
+
}
|
731
|
+
mx++; mo++; po++; px++;
|
661
732
|
}
|
662
|
-
|
663
|
-
|
733
|
+
}
|
734
|
+
else {
|
735
|
+
for (i=0; i<cx->elements; i++) {
|
736
|
+
if ( ! *mx ) {
|
737
|
+
*po = interpolate_linear((double*)sc->ptr, (double*)cv->ptr,
|
738
|
+
cv->elements, *px);
|
739
|
+
}
|
740
|
+
else {
|
741
|
+
*mo = 1;
|
742
|
+
}
|
743
|
+
mx++; mo++; po++; px++;
|
664
744
|
}
|
665
|
-
mx++; mo++; po++; px++;
|
666
745
|
}
|
667
746
|
}
|
668
747
|
else {
|
669
|
-
|
670
|
-
|
671
|
-
*po =
|
672
|
-
|
748
|
+
if ( type == 3 ) {
|
749
|
+
for (i=0; i<cx->elements; i++) {
|
750
|
+
*po++ = interpolate_cubic((double*)sc->ptr, (double*)cv->ptr,
|
751
|
+
cv->elements, *px++);
|
673
752
|
}
|
674
|
-
|
675
|
-
|
753
|
+
}
|
754
|
+
else {
|
755
|
+
for (i=0; i<cx->elements; i++) {
|
756
|
+
*po++ = interpolate_linear((double*)sc->ptr, (double*)cv->ptr,
|
757
|
+
cv->elements, *px++);
|
676
758
|
}
|
677
|
-
mx++; mo++; po++; px++;
|
678
759
|
}
|
679
760
|
}
|
761
|
+
|
762
|
+
ca_sync(co);
|
763
|
+
ca_detach_n(4, cv, sc, cx, co);
|
764
|
+
|
680
765
|
}
|
681
766
|
else {
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
767
|
+
|
768
|
+
|
769
|
+
cv = ca_wrap_readonly(rval, CA_DOUBLE);
|
770
|
+
|
771
|
+
|
772
|
+
if ( ca_is_any_masked(cv) ) {
|
773
|
+
rb_raise(rb_eRuntimeError,
|
774
|
+
"can't calculate interpolation when masked elements exist");
|
775
|
+
}
|
776
|
+
|
777
|
+
cx = ca_wrap_readonly(vx, CA_DOUBLE);
|
778
|
+
|
779
|
+
co0 = carray_new(ca->data_type, cx->rank, cx->dim, 0, NULL);
|
780
|
+
out = out0 = ca_wrap_struct(co0);
|
781
|
+
co = ca_wrap_writable(out, CA_DOUBLE);
|
782
|
+
|
783
|
+
ca_attach_n(3, cv, cx, co);
|
784
|
+
|
785
|
+
px = (double*) cx->ptr;
|
786
|
+
po = (double*) co->ptr;
|
787
|
+
|
788
|
+
ca_update_mask(cx);
|
789
|
+
if ( cx->mask ) {
|
790
|
+
boolean8_t *mx, *mo;
|
791
|
+
ca_create_mask(co);
|
792
|
+
mx = (boolean8_t *) cx->mask->ptr;
|
793
|
+
mo = (boolean8_t *) co->mask->ptr;
|
794
|
+
if ( type == 3 ) {
|
795
|
+
for (i=0; i<cx->elements; i++) {
|
796
|
+
if ( ! *mx ) {
|
797
|
+
*po = interpolate_cubic(NULL, (double*)cv->ptr,
|
798
|
+
cv->elements, *px);
|
799
|
+
}
|
800
|
+
else {
|
801
|
+
*mo = 1;
|
802
|
+
}
|
803
|
+
mx++; mo++; po++; px++;
|
804
|
+
}
|
805
|
+
}
|
806
|
+
else {
|
807
|
+
for (i=0; i<cx->elements; i++) {
|
808
|
+
if ( ! *mx ) {
|
809
|
+
*po = interpolate_linear(NULL, (double*)cv->ptr,
|
810
|
+
cv->elements, *px);
|
811
|
+
}
|
812
|
+
else {
|
813
|
+
*mo = 1;
|
814
|
+
}
|
815
|
+
mx++; mo++; po++; px++;
|
816
|
+
}
|
686
817
|
}
|
687
818
|
}
|
688
819
|
else {
|
689
|
-
|
690
|
-
|
691
|
-
|
820
|
+
if ( type == 3 ) {
|
821
|
+
for (i=0; i<cx->elements; i++) {
|
822
|
+
*po++ = interpolate_cubic(NULL, (double*)cv->ptr,
|
823
|
+
cv->elements, *px++);
|
824
|
+
}
|
825
|
+
}
|
826
|
+
else {
|
827
|
+
for (i=0; i<cx->elements; i++) {
|
828
|
+
*po++ = interpolate_linear(NULL, (double*)cv->ptr,
|
829
|
+
cv->elements, *px++);
|
830
|
+
}
|
692
831
|
}
|
693
832
|
}
|
694
|
-
}
|
695
833
|
|
696
|
-
|
697
|
-
|
834
|
+
ca_sync(co);
|
835
|
+
ca_detach_n(3, cv, cx, co);
|
836
|
+
|
837
|
+
}
|
698
838
|
|
699
839
|
if ( rb_ca_is_scalar(vx) ) {
|
700
840
|
return rb_funcall(out0, rb_intern("[]"), 1, INT2NUM(0));
|
@@ -716,18 +856,18 @@ rb_ca_differentiate (volatile VALUE self,
|
|
716
856
|
|
717
857
|
Data_Get_Struct(self, CArray, ca);
|
718
858
|
|
719
|
-
cv = ca_wrap_readonly(rval, CA_DOUBLE);
|
720
859
|
sc = ca_wrap_readonly(vsc, CA_DOUBLE);
|
721
860
|
|
722
|
-
if ( ca_is_any_masked(
|
861
|
+
if ( ca_is_any_masked(ca) || ca_is_any_masked(sc) ) {
|
723
862
|
rb_raise(rb_eRuntimeError,
|
724
863
|
"can't calculate differentiation when masked elements exist");
|
725
864
|
}
|
726
865
|
|
727
|
-
if (
|
866
|
+
if ( ca->elements != sc->elements ) {
|
728
867
|
rb_raise(rb_eRuntimeError, "data num mismatch with scale");
|
729
868
|
}
|
730
869
|
|
870
|
+
cv = ca_wrap_readonly(rval, CA_DOUBLE);
|
731
871
|
cx = ca_wrap_readonly(vx, CA_DOUBLE);
|
732
872
|
|
733
873
|
co0 = carray_new(ca->data_type, cx->rank, cx->dim, 0, NULL);
|
@@ -747,8 +887,8 @@ rb_ca_differentiate (volatile VALUE self,
|
|
747
887
|
mo = (boolean8_t *) co->mask->ptr;
|
748
888
|
for (i=0; i<cx->elements; i++) {
|
749
889
|
if ( ! *mx ) {
|
750
|
-
*po = differentiate((double*)sc->ptr, (double*)
|
751
|
-
|
890
|
+
*po = differentiate((double*)sc->ptr, (double*)cv->ptr,
|
891
|
+
cv->elements, *px);
|
752
892
|
}
|
753
893
|
else {
|
754
894
|
*mo = 1;
|
@@ -758,8 +898,8 @@ rb_ca_differentiate (volatile VALUE self,
|
|
758
898
|
}
|
759
899
|
else {
|
760
900
|
for (i=0; i<cx->elements; i++) {
|
761
|
-
*po = differentiate((double*)sc->ptr, (double*)
|
762
|
-
|
901
|
+
*po = differentiate((double*)sc->ptr, (double*)cv->ptr,
|
902
|
+
cv->elements, *px);
|
763
903
|
px++, po++;
|
764
904
|
}
|
765
905
|
}
|
@@ -119,7 +119,7 @@ find_index (ca_size_t n, double *y, double yy, ca_size_t *major, double *frac)
|
|
119
119
|
|
120
120
|
static int
|
121
121
|
linear_interp_loop (CArray *ca, ca_size_t *major, double *frac,
|
122
|
-
int level,
|
122
|
+
int level, ca_size_t *idx, double wt, double *valp)
|
123
123
|
{
|
124
124
|
double tmp;
|
125
125
|
|
@@ -177,6 +177,7 @@ ca_interpolate_loop (CArray *ca, double **scale,
|
|
177
177
|
double val, frc;
|
178
178
|
ca_size_t maj;
|
179
179
|
ca_size_t i;
|
180
|
+
|
180
181
|
if ( level == ca->rank-1 ) {
|
181
182
|
if ( ! value[level] ) {
|
182
183
|
for (i=0; i<ca->dim[level]; i++) {
|
@@ -303,6 +304,7 @@ rb_ca_interpolate_bilinear (int argc, VALUE *argv, volatile VALUE self)
|
|
303
304
|
}
|
304
305
|
}
|
305
306
|
|
307
|
+
|
306
308
|
ca_attach(ca);
|
307
309
|
ca_interpolate(ca, scales, values, (double*) co->ptr);
|
308
310
|
ca_detach(ca);
|