root/trunk/install/perl/recwrap.pl

リビジョン 91, 16.1 kB (コミッタ: sorshi, コミット時期: 15 年 前)

PT1対応。

  • svn:executable 属性の設定値:
Line 
1 #!/usr/bin/perl
2 #usage recwrap.pl ch length(sec) [bitrate(5)] [TID] [NO] [PID] [stationid] [digitalflag] [digitalband] [digitalch]
3 #
4 # Anime recording system foltia
5 # http://www.dcc-jpl.com/soft/foltia/
6 #
7 #
8 #レコーディングラッパ
9 #atから呼び出され、tvrecordingを呼び出し録画
10 #そのあとMPEG4トラコンを呼び出す
11 #
12 # DCC-JPL Japan/foltia project
13 #
14
15 use DBI;
16 use DBD::Pg;
17 use Schedule::At;
18 use Time::Local;
19 use Jcode;
20
21 $path = $0;
22 $path =~ s/recwrap.pl$//i;
23 if ($pwd  ne "./"){
24 push( @INC, "$path");
25 }
26
27 require "foltialib.pl";
28 #引き数がアルか?
29 $recch = $ARGV[0] ;
30 if ($recch eq "" ){
31         #引き数なしで実行されたら、終了
32         print "usage recwrap.pl  ch length(sec) [bitrate(5)] [TID] [NO] [PID]\n";
33         exit;
34 }
35
36 $recch = $ARGV[0] ;
37 $reclength = $ARGV[1] ;
38 $bitrate  = $ARGV[2] ;
39 $tid  = $ARGV[3] ;
40 $countno  = $ARGV[4] ;
41 $pid = $ARGV[5] ;
42 $stationid = $ARGV[6] ;
43 $usedigital = $ARGV[7] ;
44 $digitalstationband = $ARGV[8] ;
45 $digitalch= $ARGV[9] ;
46
47 #DB初期化
48         my $data_source = sprintf("dbi:%s:dbname=%s;host=%s;port=%d",
49                 $DBDriv,$DBName,$DBHost,$DBPort);
50          $dbh = DBI->connect($data_source,$DBUser,$DBPass) ||die $DBI::error;;
51
52
53 if ($usedigital == 1){
54         $extension = ".m2t";#TSの拡張子
55 }else{
56         $extension = ".m2p";#MPEG2の拡張子
57 }
58
59 $outputfile = `date  +%Y%m%d-%H%M --date "1 min "`;
60 chomp($outputfile);
61
62 if ($tid == 0){
63                 $outputfilename = "0--".$outputfile."-".$recch.$extension;
64                 $mp4newstylefilename = "-0--".$outputfile."-".$recch;
65 }else{
66         if ($countno == 0){
67                 $outputfilename = $tid ."--".$outputfile.$extension;
68                 $mp4newstylefilename = "-" . $tid ."--".$outputfile;
69         }else{
70                 $outputfilename = $tid ."-".$countno."-".$outputfile.$extension;
71                 $mp4newstylefilename = "-" . $tid ."-".$countno."-".$outputfile;
72         }
73 }
74
75 if ($usedigital == 1){
76 #デジタルなら
77 &writelog("recwrap RECSTART DIGITAL $digitalstationband $digitalch $reclength $stationid 0 $outputfilename $tid $countno friio");
78 #録画
79 $starttime = (`date +%s`);
80 $oserr = system("$toolpath/perl/digitaltvrecording.pl $digitalstationband $digitalch $reclength $stationid 0 $outputfilename $tid $countno friio");
81 $oserr = $oserr / 256;
82
83 if ($oserr == 1){
84         &writelog("recwrap ABORT recfile exist. [$outputfilename] $digitalstationband $digitalch $reclength $stationid 0  $outputfilename $tid $countno");
85         exit;
86 }elsif ($oserr == 2){
87         &writelog("recwrap ERR 2:friio busy;retry.");
88         &continuousrecordingcheck;#もうすぐ終わる番組をkill
89         sleep(2);
90         $oserr = system("$toolpath/perl/digitaltvrecording.pl $digitalstationband $digitalch $reclength $stationid N $outputfilename $tid $countno friio");
91         $oserr = $oserr / 256;
92         if ($oserr == 2){
93         &writelog("recwrap ERR 2:friio busy;Giving up digital recording.");
94         }
95 }elsif ($oserr == 3){
96 &writelog("recwrap ABORT:ERR 3");
97 exit ;
98 }
99 }else{
100 #リモコン操作
101 # $haveirdaunit = 1;リモコンつないでるかどうか確認
102 if ($haveirdaunit == 1){
103 # 録画チャンネルが0なら
104         if ($recch == 0){
105 # &つけて非同期でchangestbch.pl呼び出し
106         &writelog("recwrap Call Change STB CH :$pid");
107         system ("$toolpath/perl/changestbch.pl $pid &");
108         }#end if
109 }#end if
110
111 if($recch == -10){
112 #非受信局なら
113         &writelog("recwrap Not recordable channel;exit:PID $pid");
114         exit;
115         }#end if
116 # アナログ録画
117 &writelog("recwrap RECSTART $recch $reclength 0 $outputfilename $bitrate $tid $countno $pid $usedigital $digitalstationband $digitalch");
118
119 #録画
120 #system("$toolpath/perl/tvrecording.pl $recch $reclength 0 $outputfile $bitrate $tid $countno");
121 $starttime = (`date +%s`);
122
123 $oserr = system("$toolpath/perl/tvrecording.pl $recch $reclength 0 $outputfilename $bitrate $tid $countno");
124 $oserr = $oserr / 256;
125 if ($oserr == 1){
126         &writelog("recwrap ABORT recfile exist. [$outputfilename] $recch $reclength 0 0 $bitrate $tid $countno $pid");
127         exit;
128 }
129
130 }#endif #デジタル優先フラグ
131
132 #デバイスビジーで即死してないか検出
133 $now = (`date +%s`);
134         if ($now < $starttime + 100){ #録画プロセス起動してから100秒以内に戻ってきてたら
135         $retrycounter == 0;
136                 while($now < $starttime + 100){
137                         if($retrycounter >= 5){
138                                 &writelog("recwrap WARNING  Giving up recording.");
139                                 last;
140                         }
141                 &writelog("recwrap retry recording $now $starttime");
142                 #アナログ録画
143 $starttime = (`date +%s`);
144 if($outputfilename =~ /.m2t$/){
145         $outputfilename =~ s/.m2t$/.m2p/;
146 }
147 $oserr = system("$toolpath/perl/tvrecording.pl $recch $reclength N $outputfilename $bitrate $tid $countno");
148 $now = (`date +%s`);
149 $oserr = $oserr / 256;
150                         if ($oserr == 1){
151                                 &writelog("recwrap ABORT recfile exist. in resume process.[$outputfilename] $recch $reclength 0 0 $bitrate $tid $countno $pid");
152                                 exit;
153                         }# if
154                 $retrycounter++;
155                 }# while
156         } # if
157
158         &writelog("recwrap RECEND [$outputfilename] $recch $reclength 0 0 $bitrate $tid $countno $pid");
159
160
161 # m2pファイル名をPIDレコードに書き込み
162         $DBQuery =  "UPDATE foltia_subtitle SET m2pfilename = '$outputfilename' WHERE pid = '$pid' ";
163          $sth = $dbh->prepare($DBQuery);
164         $sth->execute();
165 &writelog("recwrap DEBUG UPDATEDB $DBQuery");
166 &changefilestatus($pid,$FILESTATUSRECEND);
167
168 # m2pファイル名をPIDレコードに書き込み
169         $DBQuery =  "insert into foltia_m2pfiles values ('$outputfilename')";
170          $sth = $dbh->prepare($DBQuery);
171         $sth->execute();
172 &writelog("recwrap DEBUG UPDATEDB $DBQuery");
173
174 # Starlight breaker向けキャプチャ画像作成
175 if (-e "$toolpath/perl/captureimagemaker.pl"){
176         &writelog("recwrap Call captureimagemaker $outputfilename");
177 &changefilestatus($pid,$FILESTATUSCAPTURE);
178         system ("$toolpath/perl/captureimagemaker.pl $outputfilename");
179 &changefilestatus($pid,$FILESTATUSCAPEND);
180 }
181
182
183
184 # MPEG4 ------------------------------------------------------
185 #MPEG4トラコン必要かどうか
186 $DBQuery =  "SELECT psp,aspect,title FROM foltia_program WHERE tid = '$tid' ";
187          $sth = $dbh->prepare($DBQuery);
188         $sth->execute();
189  @psptrcn= $sth->fetchrow_array;
190 if ($psptrcn[0]  == 1 ){#トラコン番組
191 &writelog("recwrap Launch ipodtranscode.pl");
192 exec ("$toolpath/perl/ipodtranscode.pl");
193 exit;
194 #
195 # ここから下は旧エンコード#2008/12/23
196 # 新エンコードはDBを見て未完了MPEG2を順次トラコン処理、
197 # 分散エンコードもきっとラクチンに対応可能
198 # 新エンコードではXviD/M4VスタイルとPSPファイル名対応を廃止
199
200 &changefilestatus($pid,80);
201 #MPEG4ムービーディレクトリがあるかどうか
202  
203 #TIDが100以上の3桁の場合はそのまま
204 my $pspfilnamehd = "";
205
206 $pspfilnamehd = $tid;
207 &makemp4dir($tid);
208 $pspdirname = "$tid.localized/";
209 $pspdirname = $recfolderpath."/".$pspdirname;
210
211 #なければ作る
212 #unless (-e $pspdirname ){
213 #       system("$toolpath/perl/mklocalizeddir.pl $tid");
214 #       #&writelog("recwrap mkdir $pspdirname");
215 #}
216 $pspdirname = "$tid.localized/mp4/";
217 $pspdirname = $recfolderpath."/".$pspdirname;
218 #なければ作る
219 #unless (-e $pspdirname ){
220 #       mkdir $pspdirname ,0777;
221 #       #&writelog("recwrap mkdir $pspdirname");
222 #}
223
224 #ファイル名決定
225 if ($mp4filenamestyle == 1){# 1;よりわかりやすいファイル名
226  $pspfilname = $mp4newstylefilename ;
227  
228 }else{##0:PSP ファームウェアver.2.80より前と互換性を持つファイル名
229 #・フォルダ名[100MNV01]の100の部分は変更可(100〜999)。
230 # MP_ROOT ━ 100MNV01 ┳ M4V00001.MP4(動画)
231 #┃                  ┗ M4V00001.THM(サムネイル)※必須ではない
232
233 #ファイル名決定
234 #ファイル名決定 #新アルゴリズム
235 #TID 0000-3599まで[3桁]
236 #話数 00-999まで[2桁]
237
238 my $pspfilnameft = "";
239 my $pspfilnameyearhd = "";
240 my $pspfilnameyearft = "";
241
242 $btid = $tid % 3600;
243 # print "$btid\n";
244
245 if($btid >= 0 && $btid < 1000){
246
247         $pspfilnamehd = sprintf("%03d",$btid);
248
249 }elsif ($btid >= 1000 && $btid < 3600){
250         $pspfilnameyearhd = substr($btid, 0, 2);
251         $pspfilnameyearhd =~ s/10/A/;
252         $pspfilnameyearhd =~ s/11/B/;
253         $pspfilnameyearhd =~ s/12/C/;
254         $pspfilnameyearhd =~ s/13/D/;
255         $pspfilnameyearhd =~ s/14/E/;
256         $pspfilnameyearhd =~ s/15/F/;
257         $pspfilnameyearhd =~ s/16/G/;
258         $pspfilnameyearhd =~ s/17/H/;
259         $pspfilnameyearhd =~ s/18/I/;
260         $pspfilnameyearhd =~ s/19/J/;
261         $pspfilnameyearhd =~ s/20/K/;
262         $pspfilnameyearhd =~ s/21/L/;
263         $pspfilnameyearhd =~ s/22/M/;
264         $pspfilnameyearhd =~ s/23/N/;
265         $pspfilnameyearhd =~ s/24/O/;
266         $pspfilnameyearhd =~ s/25/P/;
267         $pspfilnameyearhd =~ s/26/Q/;
268         $pspfilnameyearhd =~ s/27/R/;
269         $pspfilnameyearhd =~ s/28/S/;
270         $pspfilnameyearhd =~ s/29/T/;
271         $pspfilnameyearhd =~ s/30/U/;
272         $pspfilnameyearhd =~ s/31/V/;
273         $pspfilnameyearhd =~ s/32/W/;
274         $pspfilnameyearhd =~ s/33/X/;
275         $pspfilnameyearhd =~ s/34/Y/;
276         $pspfilnameyearhd =~ s/35/Z/;
277        
278 $pspfilnameyearft = substr($btid, 2, 2);
279 $pspfilnameyearft = sprintf("%02d",$pspfilnameyearft);
280 $pspfilnamehd = $pspfilnameyearhd . $pspfilnameyearft;
281
282 }
283
284 # 話数
285 if (0 < $countno && $countno < 100 ){
286 # 2桁
287         $pspfilnameft = sprintf("%02d",$countno);
288 }elsif(100 <= $countno && $countno < 1000 ){
289 # 3桁
290         $pspfilnameft = sprintf("%03d",$countno); # 話数3桁
291         $pspfilnamehd = substr($pspfilnamehd, 0, 2); # TID 二桁 後ろ1バイト落とし
292 }elsif(1000 <= $countno && $countno < 10000 ){
293 # 4桁
294         $pspfilnameft = sprintf("%04d",$countno); # 話数4桁
295         $pspfilnamehd = substr($pspfilnamehd, 0, 1); # TID 1桁 後ろ2バイト落とし
296
297
298 }elsif($countno == 0){
299 #タイムスタンプが最新のMP4ファイル名取得
300 my $newestmp4filename = `cd $pspdirname ; ls -t *.MP4 | head -1`;
301  if ($newestmp4filename =~ /M4V$tid/){
302         $nowcountno = $' ;
303                 $nowcountno++;
304                 $pspfilnameft = sprintf("%02d",$nowcountno);
305         while (-e "$pspdirname/M4V".$pspfilnamehd.$pspfilnameft.".MP4"){
306                 $nowcountno++;
307                 $pspfilnameft = sprintf("%02d",$nowcountno);   
308         print "File exist:$nowcountno\n";
309         }
310 #print "NeXT\n";
311 }else{
312 # 0の場合 週番号を100から引いたもの
313 # week number of year with Monday as first day of week (01..53)
314 #だったけど常に0に
315 #       my $weeno = `date "+%V"`;
316 #       $weeno = 100 - $weeno ;
317 #       $pspfilnameft = sprintf("%02d",$weeno);
318         $pspfilnameft = sprintf("%02d",0);
319 #print "WEEKNO\n";
320 }
321
322 }
323
324 my $pspfilname = $pspfilnamehd.$pspfilnameft  ;
325 # print "$pspfilname($pspfilnamehd/$pspfilnameft)\n";
326 }# endif MP4ファイル名が新styleなら
327 #2006/12/03_10:30:24 recwrap TRCNSTART vfr4psp.sh /home/foltia/php/tv/591-87-20061203-1000.m2p -591-87-20061203-1000 /home/foltia/php/tv/591.localized/mp4/ 3
328
329
330 # トラコンキューイング #2007/7/10
331 my $trcnprocesses = "";
332 my $cpucores = `ls /proc/acpi/processor | wc -l`;
333 $cpucores =~ s/[^0-9]//gi;
334 unless ($cpucores >= 1 ){
335         $cpucores = 1;
336 }
337 do {
338         $trcnprocesses = `ps ax | grep ffmpeg | grep -v grep |  wc -l `;
339         $trcnprocesses =~ s/[^0-9]//gi;
340         # 既にトラコンプロセスが走っているなら適当に待機
341         if ($trcnprocesses  >= $cpucores){
342                         if (-e "/proc/uptime" ){
343                         $loadaverage = `uptime`;
344                         chomp($loadaverage);
345                         }else{
346                         $loadaverage = "";
347                         }
348                         &writelog("recwrap TRCN WAITING :$trcnprocesses / $cpucores :$outputfilename $loadaverage");
349                 sleep 113;
350                 sleep ($recch)*5;
351         }
352 } until ($trcnprocesses  < $cpucores);
353
354
355 if (($trconqty eq "")||($trconqty == 0 )){
356         &writelog("recwrap TRCNSTART vfr4psp.sh $recfolderpath/$outputfilename $pspfilname $pspdirname $psptrcn[1]");
357         system("$toolpath/perl/transcode/vfr4psp.sh $recfolderpath/$outputfilename $pspfilname $pspdirname $psptrcn[1]");
358         &writelog("recwrap TRCNEND  vfr4psp.sh $recfolderpath/$outputfilename $pspfilname $pspdirname $psptrcn[1]");
359         #最適化
360         $DBQuery =  "SELECT subtitle  FROM  foltia_subtitle WHERE tid = '$tid' AND countno = '$countno' ";
361                  $sth = $dbh->prepare($DBQuery);
362                 $sth->execute();
363          @programtitle = $sth->fetchrow_array;
364         if ( $countno == "0" ){
365                 $pspcountno = "";
366         }else{
367                 $pspcountno = $countno ;
368         }
369         &writelog("recwrap OPTIMIZE  mp4psp -p $pspdirname/M4V$pspfilname.MP4   -t  '$psptrcn[2] $pspcountno $programtitle[0]' ");
370         Jcode::convert(\$programtitle[0],'euc');
371         system ("/usr/local/bin/mp4psp -p $pspdirname/M4V$pspfilname.MP4   -t  '$psptrcn[2] $pspcountno $programtitle[0]'") ;
372 $mp4filename = "M4V${pspfilname}.MP4";
373 $thmfilename = "M4V${pspfilname}.THM";
374 }else{# #2006/12/6 新エンコーダ
375
376         &writelog("recwrap TRCNSTART ipodtranscode.pl $recfolderpath/$outputfilename $pspfilname $pspdirname $pid $psptrcn[1]");
377         system("$toolpath/perl/ipodtranscode.pl $recfolderpath/$outputfilename $pspfilname $pspdirname $pid $psptrcn[1]");
378         &writelog("recwrap TRCNEND  ipodtranscode.pl $recfolderpath/$outputfilename $pspfilname $pspdirname $psptrcn[1]");
379
380         if($trconqty >= 2){#H.264/AVCなら
381         $mp4filename = "MAQ${pspfilname}.MP4";
382         $thmfilename = "MAQ${pspfilname}.THM";
383         }else{
384         $mp4filename = "M4V${pspfilname}.MP4";
385         $thmfilename = "M4V${pspfilname}.THM";
386         }
387 }
388
389 #サムネール
390
391 # mplayer -ss 00:01:20 -vo jpeg:outdir=/home/foltia/php/tv/443MNV01 -ao null -sstep 1 -frames 3  -v 3 /home/foltia/php/tv/443-07-20050218-0030.m2p
392 #2005/02/22_18:30:05 recwrap TRCNSTART vfr4psp.sh /home/foltia/php/tv/447-21-20050222-1800.m2p 44721 /home/foltia/php/tv/447MNV01 3
393 &writelog("recwrap THAMJ  mplayer -ss 00:01:20 -vo jpeg:outdir=$pspdirname -ao null -sstep 1 -frames 3  -v 3 $recfolderpath/$outputfilename ");
394 system ("mplayer -ss 00:01:20 -vo jpeg:outdir=$pspdirname -ao null -sstep 1 -frames 3  -v 3 $recfolderpath/$outputfilename");
395 &writelog("recwrap THAMI  convert -crop 160x120+1+3 -resize 165x126\! $pspdirname/00000002.jpg $pspdirname/M4V$pspdirname.THM ");
396
397 if (-e "$pspdirname/$thmfilename"){
398 $timestamp =`date "+%Y%m%d-%H%M%S"`;
399 chomp $timestamp;
400         system("convert -crop 160x120+1+3 -resize 165x126\! $pspdirname/00000002.jpg $pspdirname/$thmfilename".$timestamp.".THM");
401
402 }else{
403         system("convert -crop 160x120+1+3 -resize 165x126\! $pspdirname/00000002.jpg $pspdirname/$thmfilename");
404 }
405 # rm -rf 00000001.jpg     
406 # convert -resize 160x120\! 00000002.jpg M4V44307.THM
407 # rm -rf 00000002.jpg 
408 system("rm -rf $pspdirname/0000000*.jpg ");
409
410
411
412
413 # MP4ファイル名をPIDレコードに書き込み
414         $DBQuery =  "UPDATE foltia_subtitle SET PSPfilename = '$mp4filename' WHERE pid = '$pid' ";
415          $sth = $dbh->prepare($DBQuery);
416         $sth->execute();
417 &writelog("recwrap UPDATEsubtitleDB  $DBQuery");
418
419 # MP4ファイル名をfoltia_mp4files挿入
420         $DBQuery = "insert into foltia_mp4files values ('$tid','$mp4filename') ";
421          $sth = $dbh->prepare($DBQuery);
422         $sth->execute();
423 &writelog("recwrap UPDATEmp4DB  $DBQuery");
424
425 &changefilestatus($pid,200);
426 }#PSPトラコンあり
427
428 sub continuousrecordingcheck(){
429 my $now = `date  +%s --date "2 min "`;
430 &writelog("recwrap DEBUG continuousrecordingcheck() now $now");
431 my @processes =`ps ax | grep recfriio`;
432
433 my $psline = "";
434 my @processline = "";
435 my $pid = "";
436 my @pid;
437 my $sth;
438 foreach (@processes){
439         if (/friiodetect/) {
440                 if (/^.[0-9]*\s/){
441                         push(@pid, $&);
442                 }#if
443         }#if
444 }#foreach
445
446 if (@pid > 0){
447 my @filenameparts;
448 my $tid = "";
449 my $startdate = "";
450 my $starttime = "";
451 my $startdatetime = "";
452 my @recfile;
453 my $endtime = "";
454 my $endtimeepoch = "";
455 foreach $pid (@pid){
456 #print "DEBUG  PID $pid\n";
457 &writelog("recwrap DEBUG continuousrecordingcheck() PID $pid");
458
459         my @lsofoutput = `/usr/sbin/lsof -p $pid`;
460         my $filename = "";
461         #print "recfolferpath $recfolderpath\n";
462         foreach (@lsofoutput){
463                 if (/m2t/){
464                 @processline = split(/\s+/,$_);
465                 $filename = $processline[8];
466                 $filename =~ s/$recfolderpath\///;
467                 &writelog("recwrap DEBUG continuousrecordingcheck()  FILENAME $filename");
468                 # 1520-9-20081201-0230.m2t
469                 @filenameparts = split(/-/,$filename);
470                 $tid = $filenameparts[0];
471                 $startdate = $filenameparts[2];
472                 $starttime = $filenameparts[3];
473                 @filenameparts = split(/\./,$starttime);
474                 $startdatetime = $startdate.$filenameparts[0];
475                 #DBから録画中番組のデータ探す
476         $DBQuery =  "
477 SELECT foltia_subtitle.tid,foltia_subtitle.countno,foltia_subtitle.subtitle,foltia_subtitle.startdatetime ,foltia_subtitle.enddatetime ,foltia_subtitle.lengthmin ,foltia_tvrecord.bitrate , foltia_subtitle.startoffset , foltia_subtitle.pid ,foltia_tvrecord.digital
478 FROM foltia_subtitle ,foltia_tvrecord
479 WHERE
480 foltia_tvrecord.tid = foltia_subtitle.tid AND
481 foltia_tvrecord.tid = $tid AND
482 foltia_subtitle.startdatetime = $startdatetime AND
483 foltia_tvrecord.digital = 1";
484         &writelog("recwrap DEBUG continuousrecordingcheck() $DBQuery");
485         $sth = $dbh->prepare($DBQuery);
486         &writelog("recwrap DEBUG continuousrecordingcheck() prepare");
487         $sth->execute();
488         &writelog("recwrap DEBUG continuousrecordingcheck() execute");
489         @recfile = $sth->fetchrow_array;
490         &writelog("recwrap DEBUG continuousrecordingcheck() @recfile  $recfile[0] $recfile[1] $recfile[2] $recfile[3] $recfile[4] $recfile[5] $recfile[6] $recfile[7] $recfile[8] $recfile[9] ");
491         #終了時刻
492         $endtime = $recfile[4];
493         $endtimeepoch = &foldate2epoch($endtime);
494         &writelog("recwrap DEBUG continuousrecordingcheck() $recfile[0] $recfile[1] $recfile[2] $recfile[3] $recfile[4] $recfile[5] endtimeepoch $endtimeepoch");
495         if ($endtimeepoch < $now){#まもなく終わる番組なら
496                 #kill
497                 system("kill $pid");
498                 &writelog("recwrap recording process killed $pid/$endtimeepoch/$now");
499         }
500                 }#endif m2t
501         }#foreach lsofoutput
502 }#foreach
503 }else{
504 #print "DEBUG fecfriio NO PID\n";
505 &writelog("recwrap No recording process killed.");
506 }
507 }#endsub
508
509
510
511
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。
track feed