887 | | @@ -365,43 +347,33 @@ |
888 | | CASE ( np_COR ) !* Coriolis (planetary vorticity) |
889 | | zwz(:,:) = ff_f(:,:) |
890 | | CASE ( np_RVO ) !* relative vorticity |
891 | | - DO jj = 1, jpjm1 |
892 | | - DO ji = 1, fs_jpim1 ! vector opt. |
893 | | - zwz(ji,jj) = ( e2v(ji+1,jj ) * pvn(ji+1,jj ,jk) - e2v(ji,jj) * pvn(ji,jj,jk) & |
894 | | - & - e1u(ji ,jj+1) * pun(ji ,jj+1,jk) + e1u(ji,jj) * pun(ji,jj,jk) ) * r1_e1e2f(ji,jj) |
895 | | - END DO |
| 888 | |
| 889 | }}} |
| 890 | |
| 891 | ''' Extending for the 3D loops ''' |
| 892 | |
| 893 | Dealing with the 2D loops can be considered as the first stage of converting suitable 3D loops. In the simplest cases a small variation of the do2dfinder.pl perl script which subsequently looks for consecutive `DO jk =` `DO_2D` statements instead of `DO jj`-`DO ji` pairs should work. However, finding such consecutive statements, in the 3D case, is a much less certain indication of a valid loop to process. Take, for example, this snippet of `dynadv_cen2.F90` which has been processed for 2D loops: |
| 894 | |
| 895 | {{{ |
| 896 | DO jk = 2, jpkm1 ! interior advective fluxes |
| 897 | DO_2D( 2, jpi , 2, jpj ) |
| 898 | zfw(ji,jj,jk) = 0.25_wp * e1e2t(ji,jj) * wn(ji,jj,jk) |
| 899 | END_2D |
| 900 | DO_2D( fs_2, fs_jpim1 , 2, jpjm1 ) |
| 901 | zfu_uw(ji,jj,jk) = ( zfw(ji,jj,jk) + zfw(ji+1,jj ,jk) ) * ( un(ji,jj,jk) + un(ji,jj,jk-1) ) |
| 902 | zfv_vw(ji,jj,jk) = ( zfw(ji,jj,jk) + zfw(ji ,jj+1,jk) ) * ( vn(ji,jj,jk) + vn(ji,jj,jk-1) ) |
| 903 | END_2D |
| 904 | END DO |
| 905 | DO jk = 1, jpkm1 ! divergence of vertical momentum flux divergence |
| 906 | DO_2D( fs_2, fs_jpim1 , 2, jpjm1 ) |
| 907 | ua(ji,jj,jk) = ua(ji,jj,jk) - ( zfu_uw(ji,jj,jk) - zfu_uw(ji,jj,jk+1) ) * r1_e1e2u(ji,jj) / e3u_n(ji,jj,jk) |
| 908 | va(ji,jj,jk) = va(ji,jj,jk) - ( zfv_vw(ji,jj,jk) - zfv_vw(ji,jj,jk+1) ) * r1_e1e2v(ji,jj) / e3v_n(ji,jj,jk) |
| 909 | END_2D |
| 910 | END DO |
| 911 | }}} |
| 912 | |
| 913 | Only the second 3D loop can be collapsed to a single construct. Unfortunately, this decision can't be made until the end of the loop is reached so a modification is required that allows two versions of a loop to be mantained in memory and the appropriate set written out on decision. The IO:stringy perl package provides the ideal tools by allowing string variables to be treated like files. Here is the modified script that will apply the 2nd stage conversion of 3D loops were possible: |
| 914 | |
| 915 | {{{ |
| 916 | cat do3dfinder.pl |
| 917 | # |
| 918 | use IO::Scalar; |
| 919 | open(F,$ARGV[0]) || die "Cannot open $ARGV[0]: $!"; |
| 920 | while(<F>) { |
| 921 | if ( $_ =~ /^\s*DO\s* jk/i) { |
| 922 | # Start processing loop if line contains DO jk (case and whitespace independent) |
| 923 | # |
| 924 | # 1. Store the current line |
| 925 | # |
| 926 | $jline = $_; |
| 927 | # |
| 928 | # 2. Read the next line and check if it contains DO_2D |
| 929 | # |
| 930 | my $iline = <F> || die "DO jk line at end of file?"; |
| 931 | if ( $iline =~ /^\s*DO_2D\s*\(/i) { |
| 932 | my $isinavlid = 0; |
| 933 | # |
| 934 | # 3. Initialise a count to track any nested do loops |
| 935 | # |
| 936 | my $docount = 0; |
| 937 | # |
| 938 | # 4. Store the loop limits from the two lines stored and remove spaces and new-lines |
| 939 | # |
| 940 | ($jargs = $jline) =~ s/(^.*)=([^\!\n]*)(\!*.*)/\2/; |
| 941 | ($iargs = $iline) =~ s/(^.*)\(([^\!\n]*)\)(\!*.*)/\2/; |
| 942 | chomp($iargs); |
| 943 | chomp($jargs); |
| 944 | $iargs =~ s/^\s+//; $iargs =~ s/\s+$//; |
| 945 | $jargs =~ s/^\s+//; $jargs =~ s/\s+$//; |
| 946 | # |
| 947 | # 5. Store the leading indentation for the outer loop |
| 948 | # |
| 949 | ($jspac = $jline) =~ s/(^[\s]*)([^\s]*).*/\1/; |
| 950 | chomp($jspac); |
| 951 | # |
| 952 | # 6. Construct a DO_3D line to replace the original statements |
| 953 | # |
| 954 | # Keep two versions of output until we know if it is transformable |
| 955 | # |
| 956 | my $ostr = ""; |
| 957 | my $astr = ""; |
| 958 | my $orig = new IO::Scalar \$ostr; |
| 959 | print $orig $jline; |
| 960 | print $orig $iline; |
| 961 | my $altr = new IO::Scalar \$astr; |
| 962 | print $altr $jspac,"DO_3D( ",$iargs," , ",$jargs," )\n"; |
| 963 | # |
| 964 | # 7. Now process the loop contents until the matching END_2D statement |
| 965 | # |
| 966 | while ( $docount >= 0 || ! ( $iline =~ /^\s*END_2D/i ) ) { |
| 967 | $iline = <F> || eval{ $isinvalid = 1 }; |
| 968 | #print $orig $iline; |
| 969 | # |
| 970 | # 8. Increment a counter if another DO_2D statement is found |
| 971 | # |
| 972 | if ( $iline =~ /^\s*do_2d/i ) { $docount++ }; |
| 973 | # |
| 974 | # 9. Decrement a counter if a END DO statement is found |
| 975 | # |
| 976 | if ( $iline =~ /^\s*end_2d/i ) { $docount-- }; |
| 977 | # |
| 978 | # 10. A negative counter means the matching END_2D for the ji loop has been reached |
| 979 | # |
| 980 | if ( $docount < 0 ) { |
| 981 | # |
| 982 | # 11. Check the next line is the expected END DO for the jk loop. |
| 983 | # Output END_3D statement if it is |
| 984 | # |
| 985 | $jline = <F> || eval {$isinvalid = 1} ; |
| 986 | if ( ! ($jline =~ /^\s*end\s*do/i) ) { |
| 987 | $isinvalid = 1 ; |
| 988 | print $orig $iline; |
| 989 | print $orig $jline; |
| 990 | } else { |
| 991 | print $altr $jspac,"END_3D\n"; |
| 992 | } |
| 993 | if ( $isinvalid == 0 ) { |
| 994 | print $altr; |
| 995 | } else { |
| 996 | print $orig; |
| 997 | $isinvalid = 0; |
| 998 | } |
| 999 | |
| 1000 | } else { |
| 1001 | # |
| 1002 | # 12. This is a line inside the loop. Remove three leading spaces (if any) and output. |
| 1003 | # |
| 1004 | print $orig $iline; |
| 1005 | $iline =~ s/^\s\s\s//; |
| 1006 | print $altr $iline; |
| 1007 | } |
| 1008 | } |
| 1009 | } else { |
| 1010 | # |
| 1011 | # 13. Consecutive DO statements were not found. Do not process these loops. |
| 1012 | # |
| 1013 | print $jline; |
| 1014 | print $iline; |
| 1015 | } |
| 1016 | } else { |
| 1017 | # |
| 1018 | # 14. Code outside of a DO construct. Leave unchanged. |
| 1019 | # |
| 1020 | print $_; |
| 1021 | } |
| 1022 | } |
| 1023 | }}} |
| 1024 | These scripts can be run sequentially; for example: |
| 1025 | {{{ |
| 1026 | cp TEST_FILES_ORG/dynadv_cen2.F90 TESTDO_FILES/ |
| 1027 | perl do2dfinder.pl TESTDO_FILES/dynadv_cen2.F90 > TESTDO_FILES_2D/dynadv_cen2.F90 |
| 1028 | perl do3dfinder.pl TESTDO_FILES_2D/dynadv_cen2.F90 > TESTDO_FILES_3D/dynadv_cen2.F90 |
| 1029 | }}} |
| 1030 | And the difference between the original and final version is: |
| 1031 | {{{#!diff |
| 1032 | --- TESTDO_FILES/dynadv_cen2.F90 2019-03-01 13:35:29.000000000 +0000 |
| 1033 | +++ TESTDO_FILES_3D/dynadv_cen2.F90 2019-03-01 13:40:02.000000000 +0000 |
| 1034 | @@ -68,22 +68,18 @@ |
| 1035 | DO jk = 1, jpkm1 ! horizontal transport |
| 1036 | zfu(:,:,jk) = 0.25_wp * e2u(:,:) * e3u_n(:,:,jk) * un(:,:,jk) |
| 1037 | zfv(:,:,jk) = 0.25_wp * e1v(:,:) * e3v_n(:,:,jk) * vn(:,:,jk) |
| 1038 | - DO jj = 1, jpjm1 ! horizontal momentum fluxes (at T- and F-point) |
| 1039 | - DO ji = 1, fs_jpim1 ! vector opt. |
| 1040 | - zfu_t(ji+1,jj ,jk) = ( zfu(ji,jj,jk) + zfu(ji+1,jj,jk) ) * ( un(ji,jj,jk) + un(ji+1,jj ,jk) ) |
| 1041 | - zfv_f(ji ,jj ,jk) = ( zfv(ji,jj,jk) + zfv(ji+1,jj,jk) ) * ( un(ji,jj,jk) + un(ji ,jj+1,jk) ) |
| 1042 | - zfu_f(ji ,jj ,jk) = ( zfu(ji,jj,jk) + zfu(ji,jj+1,jk) ) * ( vn(ji,jj,jk) + vn(ji+1,jj ,jk) ) |
| 1043 | - zfv_t(ji ,jj+1,jk) = ( zfv(ji,jj,jk) + zfv(ji,jj+1,jk) ) * ( vn(ji,jj,jk) + vn(ji ,jj+1,jk) ) |
897 | | + DO_2D( 1, fs_jpim1 , 1, jpjm1 ) |
898 | | + zwz(ji,jj) = ( e2v(ji+1,jj ) * pvn(ji+1,jj ,jk) - e2v(ji,jj) * pvn(ji,jj,jk) & |
899 | | + & - e1u(ji ,jj+1) * pun(ji ,jj+1,jk) + e1u(ji,jj) * pun(ji,jj,jk) ) * r1_e1e2f(ji,jj) |
900 | | + END_2D |
901 | | CASE ( np_MET ) !* metric term |
902 | | - DO jj = 1, jpjm1 |
903 | | - DO ji = 1, fs_jpim1 ! vector opt. |
904 | | - zwz(ji,jj) = ( pvn(ji+1,jj ,jk) + pvn(ji,jj,jk) ) * di_e2v_2e1e2f(ji,jj) & |
905 | | - & - ( pun(ji ,jj+1,jk) + pun(ji,jj,jk) ) * dj_e1u_2e1e2f(ji,jj) |
906 | | - END DO |
| 1045 | - END DO |
| 1046 | - DO jj = 2, jpjm1 ! divergence of horizontal momentum fluxes |
| 1047 | - DO ji = fs_2, fs_jpim1 ! vector opt. |
| 1048 | - ua(ji,jj,jk) = ua(ji,jj,jk) - ( zfu_t(ji+1,jj,jk) - zfu_t(ji,jj ,jk) & |
| 1049 | - & + zfv_f(ji ,jj,jk) - zfv_f(ji,jj-1,jk) ) * r1_e1e2u(ji,jj) / e3u_n(ji,jj,jk) |
| 1050 | - va(ji,jj,jk) = va(ji,jj,jk) - ( zfu_f(ji,jj ,jk) - zfu_f(ji-1,jj,jk) & |
| 1051 | - & + zfv_t(ji,jj+1,jk) - zfv_t(ji ,jj,jk) ) * r1_e1e2v(ji,jj) / e3v_n(ji,jj,jk) |
908 | | + DO_2D( 1, fs_jpim1 , 1, jpjm1 ) |
909 | | + zwz(ji,jj) = ( pvn(ji+1,jj ,jk) + pvn(ji,jj,jk) ) * di_e2v_2e1e2f(ji,jj) & |
910 | | + & - ( pun(ji ,jj+1,jk) + pun(ji,jj,jk) ) * dj_e1u_2e1e2f(ji,jj) |
911 | | + END_2D |
912 | | CASE ( np_CRV ) !* Coriolis + relative vorticity |
913 | | - DO jj = 1, jpjm1 |
914 | | - DO ji = 1, fs_jpim1 ! vector opt. |
915 | | - zwz(ji,jj) = ff_f(ji,jj) + ( e2v(ji+1,jj) * pvn(ji+1,jj,jk) - e2v(ji,jj) * pvn(ji,jj,jk) & |
916 | | - & - e1u(ji,jj+1) * pun(ji,jj+1,jk) + e1u(ji,jj) * pun(ji,jj,jk) ) * r1_e1e2f(ji,jj) |
917 | | - END DO |
918 | | - END DO |
919 | | + DO_2D( 1, fs_jpim1 , 1, jpjm1 ) |
920 | | + zwz(ji,jj) = ff_f(ji,jj) + ( e2v(ji+1,jj) * pvn(ji+1,jj,jk) - e2v(ji,jj) * pvn(ji,jj,jk) & |
921 | | + & - e1u(ji,jj+1) * pun(ji,jj+1,jk) + e1u(ji,jj) * pun(ji,jj,jk) ) * r1_e1e2f(ji,jj) |
922 | | + END_2D |
923 | | CASE ( np_CME ) !* Coriolis + metric |
924 | | - DO jj = 1, jpjm1 |
925 | | - DO ji = 1, fs_jpim1 ! vector opt. |
926 | | - zwz(ji,jj) = ff_f(ji,jj) + ( pvn(ji+1,jj ,jk) + pvn(ji,jj,jk) ) * di_e2v_2e1e2f(ji,jj) & |
927 | | - & - ( pun(ji ,jj+1,jk) + pun(ji,jj,jk) ) * dj_e1u_2e1e2f(ji,jj) |
928 | | - END DO |
929 | | - END DO |
930 | | + DO_2D( 1, fs_jpim1 , 1, jpjm1 ) |
931 | | + zwz(ji,jj) = ff_f(ji,jj) + ( pvn(ji+1,jj ,jk) + pvn(ji,jj,jk) ) * di_e2v_2e1e2f(ji,jj) & |
932 | | + & - ( pun(ji ,jj+1,jk) + pun(ji,jj,jk) ) * dj_e1u_2e1e2f(ji,jj) |
933 | | + END_2D |
934 | | CASE DEFAULT ! error |
935 | | CALL ctl_stop('STOP','dyn_vor: wrong value for kvor' ) |
936 | | END SELECT |
937 | | ! |
938 | | IF( ln_dynvor_msk ) THEN !== mask/unmask vorticity ==! |
939 | | - DO jj = 1, jpjm1 |
940 | | - DO ji = 1, fs_jpim1 ! vector opt. |
941 | | - zwz(ji,jj) = zwz(ji,jj) * fmask(ji,jj,jk) |
942 | | - END DO |
943 | | - END DO |
944 | | + DO_2D( 1, fs_jpim1 , 1, jpjm1 ) |
945 | | + zwz(ji,jj) = zwz(ji,jj) * fmask(ji,jj,jk) |
946 | | + END_2D |
947 | | ENDIF |
948 | | |
949 | | IF( ln_sco ) THEN |
950 | | @@ -413,16 +385,14 @@ |
951 | | zwy(:,:) = e1v(:,:) * pvn(:,:,jk) |
952 | | ENDIF |
953 | | ! !== compute and add the vorticity term trend =! |
| 1053 | - END DO |
| 1054 | + DO_2D( 1, fs_jpim1 , 1, jpjm1 ) |
| 1055 | + zfu_t(ji+1,jj ,jk) = ( zfu(ji,jj,jk) + zfu(ji+1,jj,jk) ) * ( un(ji,jj,jk) + un(ji+1,jj ,jk) ) |
| 1056 | + zfv_f(ji ,jj ,jk) = ( zfv(ji,jj,jk) + zfv(ji+1,jj,jk) ) * ( un(ji,jj,jk) + un(ji ,jj+1,jk) ) |
| 1057 | + zfu_f(ji ,jj ,jk) = ( zfu(ji,jj,jk) + zfu(ji,jj+1,jk) ) * ( vn(ji,jj,jk) + vn(ji+1,jj ,jk) ) |
| 1058 | + zfv_t(ji ,jj+1,jk) = ( zfv(ji,jj,jk) + zfv(ji,jj+1,jk) ) * ( vn(ji,jj,jk) + vn(ji ,jj+1,jk) ) |
| 1059 | + END_2D |
| 1060 | + DO_2D( fs_2, fs_jpim1 , 2, jpjm1 ) |
| 1061 | + ua(ji,jj,jk) = ua(ji,jj,jk) - ( zfu_t(ji+1,jj,jk) - zfu_t(ji,jj ,jk) & |
| 1062 | + & + zfv_f(ji ,jj,jk) - zfv_f(ji,jj-1,jk) ) * r1_e1e2u(ji,jj) / e3u_n(ji,jj,jk) |
| 1063 | + va(ji,jj,jk) = va(ji,jj,jk) - ( zfu_f(ji,jj ,jk) - zfu_f(ji-1,jj,jk) & |
| 1064 | + & + zfv_t(ji,jj+1,jk) - zfv_t(ji ,jj,jk) ) * r1_e1e2v(ji,jj) / e3v_n(ji,jj,jk) |
| 1065 | + END_2D |
| 1066 | END DO |
| 1067 | ! |
| 1068 | IF( l_trddyn ) THEN ! trends: send trend to trddyn for diagnostic |
| 1069 | @@ -96,41 +92,29 @@ |
| 1070 | ! |
| 1071 | ! !== Vertical advection ==! |
| 1072 | ! |
| 1073 | - DO jj = 2, jpjm1 ! surface/bottom advective fluxes set to zero |
| 1074 | - DO ji = fs_2, fs_jpim1 |
| 1075 | - zfu_uw(ji,jj,jpk) = 0._wp ; zfv_vw(ji,jj,jpk) = 0._wp |
| 1076 | - zfu_uw(ji,jj, 1 ) = 0._wp ; zfv_vw(ji,jj, 1 ) = 0._wp |
| 1077 | - END DO |
| 1078 | - END DO |
| 1079 | + DO_2D( fs_2, fs_jpim1 , 2, jpjm1 ) |
| 1080 | + zfu_uw(ji,jj,jpk) = 0._wp ; zfv_vw(ji,jj,jpk) = 0._wp |
| 1081 | + zfu_uw(ji,jj, 1 ) = 0._wp ; zfv_vw(ji,jj, 1 ) = 0._wp |
| 1082 | + END_2D |
| 1083 | IF( ln_linssh ) THEN ! linear free surface: advection through the surface |
955 | | - DO ji = fs_2, fs_jpim1 ! vector opt. |
956 | | - zy1 = zwy(ji,jj-1) + zwy(ji+1,jj-1) |
957 | | - zy2 = zwy(ji,jj ) + zwy(ji+1,jj ) |
958 | | - zx1 = zwx(ji-1,jj) + zwx(ji-1,jj+1) |
959 | | - zx2 = zwx(ji ,jj) + zwx(ji ,jj+1) |
960 | | - pua(ji,jj,jk) = pua(ji,jj,jk) + r1_4 * r1_e1u(ji,jj) * ( zwz(ji ,jj-1) * zy1 + zwz(ji,jj) * zy2 ) |
961 | | - pva(ji,jj,jk) = pva(ji,jj,jk) - r1_4 * r1_e2v(ji,jj) * ( zwz(ji-1,jj ) * zx1 + zwz(ji,jj) * zx2 ) |
| 1085 | - DO ji = fs_2, fs_jpim1 |
| 1086 | - zfu_uw(ji,jj,1) = 0.5_wp * ( e1e2t(ji,jj) * wn(ji,jj,1) + e1e2t(ji+1,jj) * wn(ji+1,jj,1) ) * un(ji,jj,1) |
| 1087 | - zfv_vw(ji,jj,1) = 0.5_wp * ( e1e2t(ji,jj) * wn(ji,jj,1) + e1e2t(ji,jj+1) * wn(ji,jj+1,1) ) * vn(ji,jj,1) |
972 | | ! ! =============== |
973 | | END DO ! End of slab |
974 | | ! ! =============== |
975 | | }}} |
976 | | |
| 1094 | ENDIF |
| 1095 | DO jk = 2, jpkm1 ! interior advective fluxes |
| 1096 | - DO jj = 2, jpj ! 1/4 * Vertical transport |
| 1097 | - DO ji = 2, jpi |
| 1098 | - zfw(ji,jj,jk) = 0.25_wp * e1e2t(ji,jj) * wn(ji,jj,jk) |
| 1099 | - END DO |
| 1100 | - END DO |
| 1101 | - DO jj = 2, jpjm1 |
| 1102 | - DO ji = fs_2, fs_jpim1 ! vector opt. |
| 1103 | - zfu_uw(ji,jj,jk) = ( zfw(ji,jj,jk) + zfw(ji+1,jj ,jk) ) * ( un(ji,jj,jk) + un(ji,jj,jk-1) ) |
| 1104 | - zfv_vw(ji,jj,jk) = ( zfw(ji,jj,jk) + zfw(ji ,jj+1,jk) ) * ( vn(ji,jj,jk) + vn(ji,jj,jk-1) ) |
| 1105 | - END DO |
| 1106 | - END DO |
| 1107 | - END DO |
| 1108 | - DO jk = 1, jpkm1 ! divergence of vertical momentum flux divergence |
| 1109 | - DO jj = 2, jpjm1 |
| 1110 | - DO ji = fs_2, fs_jpim1 ! vector opt. |
| 1111 | - ua(ji,jj,jk) = ua(ji,jj,jk) - ( zfu_uw(ji,jj,jk) - zfu_uw(ji,jj,jk+1) ) * r1_e1e2u(ji,jj) / e3u_n(ji,jj,jk) |
| 1112 | - va(ji,jj,jk) = va(ji,jj,jk) - ( zfv_vw(ji,jj,jk) - zfv_vw(ji,jj,jk+1) ) * r1_e1e2v(ji,jj) / e3v_n(ji,jj,jk) |
| 1113 | - END DO |
| 1114 | - END DO |
| 1115 | + DO_2D( 2, jpi , 2, jpj ) |
| 1116 | + zfw(ji,jj,jk) = 0.25_wp * e1e2t(ji,jj) * wn(ji,jj,jk) |
| 1117 | + END_2D |
| 1118 | + DO_2D( fs_2, fs_jpim1 , 2, jpjm1 ) |
| 1119 | + zfu_uw(ji,jj,jk) = ( zfw(ji,jj,jk) + zfw(ji+1,jj ,jk) ) * ( un(ji,jj,jk) + un(ji,jj,jk-1) ) |
| 1120 | + zfv_vw(ji,jj,jk) = ( zfw(ji,jj,jk) + zfw(ji ,jj+1,jk) ) * ( vn(ji,jj,jk) + vn(ji,jj,jk-1) ) |
| 1121 | + END_2D |
| 1122 | END DO |
| 1123 | + DO_3D( fs_2, fs_jpim1 , 2, jpjm1 , 1, jpkm1 ) |
| 1124 | + ua(ji,jj,jk) = ua(ji,jj,jk) - ( zfu_uw(ji,jj,jk) - zfu_uw(ji,jj,jk+1) ) * r1_e1e2u(ji,jj) / e3u_n(ji,jj,jk) |
| 1125 | + va(ji,jj,jk) = va(ji,jj,jk) - ( zfv_vw(ji,jj,jk) - zfv_vw(ji,jj,jk+1) ) * r1_e1e2v(ji,jj) / e3v_n(ji,jj,jk) |
| 1126 | + END_3D |
| 1127 | ! |
| 1128 | IF( l_trddyn ) THEN ! trends: send trend to trddyn for diagnostic |
| 1129 | zfu_t(:,:,:) = ua(:,:,:) - zfu_t(:,:,:) |
| 1130 | }}} |