KazMuzik.net
Music / Technology / Healthcare / Immigration / アメリカ
Google
 
Google SiteSearch Box - KazMuzik Blog
2009-05-28 07:07

KazMuzik.net

Music / Technology / Immigration / アメリカ

Google
 

145303 <- 205797 205872 206190 206548 206825 207062 207320 207493 207679 207967 208347 208527 208712 209045 209208 209509 209845 210114 210264 210456 210825 211054 211268 211494 211799 212195 212373 212731 212843 213073 213444 213707 213801 214104 214389 214736 214893 215047 215315 215731 215896 216117 216402 216649 216851 217187 217415 217728 217981 218151 218420 218709 219104 219369 219446 219810 220035 220198 220575 220737 221027 221433 221541 221736 221961 222220 222634 222901 223216 223430 223586 223981 224060 224306 224532 224991 225133 225388 225644 225982 226153 226485 226617 226993 227201 227374 227695 227993 228312 228505 228744 229048 229180 229579 229743 230024 230164 230637 230728 230963 231309 231574 231695 232129 232338 232677 232828 232990 233467 233632 233937 234034 234368 234695 234878 235220 235443 235570 235811 236189 236454 236592 236948 237064 237459 237724 237905 238245 238339 238780 238890 239183 239368 239642 239888 240213 240581 240649 240923 241334 241577 241773 241997 242330 242620 242890 243158 243211 243506 243718 243969 244328 244599 244918 245219 245345 245506 245909 246163 246503 246649 246911 247204 247344 247683 247889 248127 248344 248751 248898 249161 249526 249674 249934 250271 250529 250906 251272 250653 251489 251840 251951 252405 252671 252771 253029 253243 253629 253820 254021 254251 254480 254946 255198 255304 255640 255949 256078 256502 256703 256845 257525 257544 257900 257251 258440 258634 258182 258941 259137 259519 259828 259950 260212 260494 260839 261095 261166 261588 261883 262066 262188 262614 262783 262921 263237 263622 263725 264181 264363 264658 264712 265221 265167 265536 265925 266110 266295 266549 266967 267127 267328 267647 267861 268736 268895 269191 268120 269357 268352 269692 269950 270110 270403 270783 271091 271270 271586 271847 272056 272253 272468 272697 272960 273285 273630 273870 273962 274185 274647 274892 275049 275352 275678 275836 276048 276338 276735 276894 277104 277413 277535 277946 278133 278287 278772 278925 279261 279364 279561 280046 280185 280341 280590 280979 281294 281502 281829 281953 282338 282622 282655 283151 283102 283565 283776 284137 284220 284727 285077 284626 285191 285656 285936 286066 286281 286566 286959 287091 287327 287491 287761 288043 288396 288734 288966 289104 289456 289641 290029 290293 290438 290775 291029 291096 291348 291706 291958 292148 292606 292672 293035 293173 293581 293678 293995 294277 294433 294904 294944 295198 295531 295688 295997 296414 296580 296931 297056 297332 297661 297899 297991 298462 298686 298777 299075 299453 299586 300028 300113 300486 300757 301029 301444 301676 301952 302286 302621 302501 301184 302896 303252 303589 303792 304046 304149 304544 304804 305572 305114 305269 305778 306118 306402 306496 306769 306984 307302 307688 307964 308195 308344 308546 308841 309232 309314 309711 309854 310041 310417 310567 310959 311092 311382 311576 311970 312300 312491 312752 313010 313181 313538 313735 313969 314318 314376 314692 315097 315235 315430 315743 315996 316411 316610 316803 316951 317267 317489 317737 318044 318447 318562 318767 319216 319292 319520 319908 320021 320329 320709 320902 321236 321392 321568 322004 322079 322341 322682 322961 323152 323471 323783 323956 324204 324582 324828 324945 325267 325563 325791 325930 326237 326655 326805 327140 327360 327669 327925 328132 328223 328489 328819 329120 329442 329486 329825 330126 330279 330727 330785 331197 331290 331693 331840 332127 332317 332666 332934 333296 333487 333757 333838 334215 334485 334745 334924 335131 335568 335627 336012 336252 336568 336769 337067 337278 337499 337676 338010 338383 338606 338771 338957 339301 339476 339949 340137 340465 340482 340856 341145 341249 341649 341891

2009-05-28 長い間、このエントリをアップデートしてきましたが、ブログの移行に際して、今後はアップデートはアップデートしないことにしました。

Tags: american_life, caltrain, computer_technology, español, français, game, health, immigration, internet, japanese, jobs_in_america, music, music_and_computer, music_gear, music_technology, programming, rebate, recycle_and_donation, second_life, tax, test, useful_link, walking

Fingerprint - Naturalization #11 - KazMuzik Blog
2009-03-12 20:02

3/10 に帰宅すると、USCIS から、Fingerprint Notification の I-797, Notice of Action が届いていました。Appointment は、3/19 1pm となっています。ただし、walk-in で、事前に行っても、だいたいは大丈夫なので、早めに済ませておこうと思い、今日の昼休みを利用して行ってきました。30分程度で終了して、1pm には Application Support Center の外に出ていました。

I-485 の時は、大幅な processing delay のために、何度も fingerprint をさせられましたが、今回の fingerprint が一生で最後の、少なくともアメリカ連邦政府に対しての、fingerprint になるはずです。

Tags: immigration

I-797C, Notice of Action delivered #10 - KazMuzik Blog
2009-02-26 20:10

今朝、昨日(2/25)付けでチェックが換金されているのを確認しましたが、帰宅すると、USCIS から I-797C, Notice of Action が届いていました。Priority Date は USCIS が N-400 を受領した 2/18/2008 です。

なお、NoA (Notice of Action) には、application number があり、NBC*0000xxxxx となっていました。NBC から始まるので、USCIS National Benefits Center の扱いになるようです。ちなみに、I-485 の時は、WAC02124xxxxx という番号で、WAC は California Service Center (Western Application Center), 02 は 2002年度、124 は 2002年度の 124 日目(営業日), 以下 5桁は、WAC での他の application も含めての 50000 からの連番でした。今回は '*' がはいっていたり、かなり numbering scheme が変更になっているようです。なお、これで、USCIS の Case Status Online で status を確認できるようになりました。また、registration すると、status が変更されたときに、自動的にメールを受け取ることができます。

今後は、fingerprint, interview (and tests), oath という順で、晴れて U.S.Citizen になることができます。

Tags: immigration

N-400 status update #9 - KazMuzik Blog
2009-02-23 19:55

N-400 の Express Mail は、2/18 には usps.com では "Notice Left"となっていましたが、今朝、確認したところ、同じ日(2/18)の午後に、"Delivered" になっていました。これで、配達されたのは確実になったので、今後は、チェックが換金されたのを確認して、receipt notice が郵送されてくるのを、待つことになります。

なお、USCIS の Processing Times を確認すると、2/20/2009 付けで update されており、12/31/2008 現在では、San Jose Field Office では、5/4/2008 の N-400 を処理していることになっています。つまり、約 8ヶ月のバックログということです。ちなみに、San Francisco は 6/25/2008 (6ヶ月), Los Angeles は 2/5/2008 (10ヶ月)となっています。

Tags: immigration

minor traffic ticket(s) - N-400 #8 - KazMuzik Blog
2009-02-19 08:08

N-400 は、すでに郵送しましたが、ImmigrationPortal ForumUS Citizenship に関する sub-forums を読んでいると、minor な traffic ticket の扱いに関しては、意見が分かれています。

N-400 Instructions の 5ページには、"Note that unless a traffic incident was alcohol or drug related, you do not need to submit documentation for traffic fines and incidents that did not involve an actual arrest if the only penalty was a fine of less than $500 or points on your driver's license." とあるので、このような軽い交通違反に関してはドキュメントを提出する必要はないのですが、N-400 の 9ページには、Part 10, D. Good Moral Character として、"16. Have you ever been arrested, cited, or detained by any law enforcement officer (including USCIS or former INS and military officers) for any reason ?" とあります。Instructions の記述を考慮して、私の場合は、No にチェックして出しましたが、質問だけを取り出して、厳密に答えると、minor な traffic ticket でも citation には違いないので、Yes となってしまいます。つまり、慎重な人は、16 の質問には Yes と答えるべきで、Instructions には、それに関する文書を提出する必要がない、という意味にとらえています。

また、interview や oath の時には、嘘をつくのはだめで、最悪、その事実に基づいて de-naturalization, deportation という risk があります。そこで、徹底的に USCIS を信用していない paranoia 的な人は、minor な traffic ticket でも、すべて報告するべきだと考えています。

一方、現実的に考えて、いくら悪名の高い USCIS (元 INS)とはいえ、minor な traffic ticket をひとつずつ調べて、それを根拠に de-naturalization, deportation という処置に出るとは、考えられません。また、Yes にチェックがある場合、USCIS の職員は、一応、それを考慮しなくてはならなくなるので、手間がかかりますし、実際、interview の時に、minor な traffic ticket に関しては、報告しないでほしい、と言われた例まであるようです。

また、極端な例としては、過去 5年間に、2回の軽微な speeding tickets があった、というだけで、deny された例もあるようです。これは、USCIS の担当者の方が異常で、運が悪かったとしか言えません。

私の場合は、すでに 16 に No にチェックして、提出してしまったので、interview のときに、"Have you ever arrested ?" と質問された場合は、"No" と答え、また "Have you ever arrested or CITED ?" と明確に質問された場合にだけ、"Yes" と答えて、ただし、minor な traffic ticket だったため、Instructions に従って、No にチェックした、と説明することになります。

Tags: immigration

N-400 mailed to USCIS (#7) - KazMuzik Blog
2009-02-17 21:21

昨日、N-400 の準備が出来たので、今朝一番で、近所の郵便局へ行きましたが、すでに 10人以上の待ち行列ができていたために、あきらめて、昼前に、San Francisco の郵便局から発送しました。今年の 1月あたりから郵送先が変更になったようで、Phoenix, AZ の Lockbox 宛に Express Mail ($17.50) で出しました。特に、application で面倒な箇所はなかったので、郵送したのは、N-400 (10ページ), green card の表裏のコピー、2枚の写真($0.21), $675 のチェックと最低限のもので済みました。現在のところ、費用の合計は、$692.71 です。

2009-02-18 update
Express Mail は、usps.com で tracking できますが、今日(2/18)の昼前に、無事に配達されたようで、"Notice Left" となっていました。次は、チェックが換金されるのを確認することです。これは、来週になりそうです。USCIS の処理は、どこで滞っているか、信用できないので、ひとつひとつ確実に tracking しておく必要があります。

Tags: immigration

Adobe Reader 9 and GIMP - N-400 #6 - KazMuzik Blog
2009-02-16 21:04

今日は、Presidents Day で、私が約 8年前に U.S. へ来てからは、ずっと Bush が大統領でしたが、去年、めでたく、Obama が勝利して、先月、正式に大統領になりました。本当は、去年の選挙で vote したかったのですが、INS / USCIS の悪質な processing delay のため green card の取得が大幅に遅れ、今月、やっと N-400 をファイルできるところまで、きました。N-400 をファイルして、U.S.Citizen になるのが、Bush の時ではなく、Obama の時で、良かった、と思うことにしておきます。



N-400 は、まだ eFile できないので、記入して郵送することになりますが、PDF ファイルは form になっていて、自分のコンピュウータでタイプして、プリントできるようになっています。先週、保険関係の申請の PDF では、Mac OS X 付属の Preview でもできたのですが、N-400 は最新のバージョンを使っているようで、Adobe Reader 9 を使う必要がありました。



また、30日以内に撮影した photo も必要ですが、妻に digital camera で撮影してもらいました。iMaC#m7 で編集するので、USB ケーブルで接続しました。今回、初めてでしたが、自動的に iPhoto が立ち上がってきて、簡単に取り込むことができました。その後、2"x2" の正方形のイメージを作成するところまでは iPhoto で簡単に出来たのですが、それを、2x3 に並べて、4"x6" のイメージを作成することが出来ず、結局、GIMP を使うことにしました。ただし、今までは、Linux (Fedora) で使っていたので、install されているか、yum で簡単に install できたのですが、今回は Mac OS X なので、Mac OS X 用の GIMP を install しなければいけません。まずは、MacPorts を試してみようと思いましたが、先週、DarwinPorts をインストールしたので、それを使って port install gimp とやりましたが、すぐに止まってしまいます。ただし、CPU は消費しているようですが、ディスクやネットワークにアクセスしている気配もありません。そこで、GIMP on OS X をダウンロードして、インストールしました。こちらの方は X11 の上で、正常に立ち上がってきました。ただし、以前 Linux で使った時とは、若干、操作が異なるところがあり、戸惑うことが何度かありました。また、マウスの移動にカーソルの追従がかなり遅れる場合もありました。しかし、なんとか目的のイメージを作成することができ、Walgreens.com でオーダーしました。今日は、19¢+tax=21¢でした。

Tags: computer_technology, immigration

New Naturalization Test - N-400 #5 - KazMuzik Blog
2009-02-13 04:34

Naturalization における English and civics test について、2/3 には、実際あまり影響のない、年齢に関する取り扱いについて書きましたが、最近、新しいテストが導入されたようで、10/1/2008 以降にファイルした人は、必ず、新しいテストで受けなければいけないようです。従来のテストは、10/1/2009 まで継続するようで、10/1/2008 以前にファイルした人は、それまでの間、どちらか選択できるようです。

Study Materials をさっと見る限りでは、極端に難しくなったという印象はありませんが、interview が近くなったら、まじめに勉強しておいた方が良さそうです。

Tags: immigration

field office processing time - N-400 #4 - KazMuzik Blog
2009-02-12 23:53

2007年夏の申請料の大幅な値上げの前に、駆け込みの申請が殺到して、膨大な backlog を抱えていた USCIS ですが、一応、ここ 1年でだいぶん改善してきているようです。2/4/2009 に update されている USCIS Processing Times Progressing Toward FY 2009 Goals によると、N-400 に関しては、値上げ前の goal は、7ヶ月だったところ、FY2009 の終わり(9/30/2009)には、5ヶ月を goal に設定しているようで、現状は 7.6ヶ月とあります。

実際に、Processing Times のページから、いくつかの field office を調べてみると、1/23/2009 に post されたデータで、11/30/2008 現在での processing date は、San Jose で 4/24/2009 (7ヶ月), San Francisco で 6/8/2008 (6ヶ月), Los Angeles で 9/3/2007 (14ヶ月) などとなっています。このあたり(Silicon Valley 近辺)では、順調に推移してきているようですが、Latino の多い大都会である Los Angeles では遅れているようです。

ちなみに、現在の申請料は、N-400 で $595 に、biometrics の費用 $80 を加えて、$675 となっています。

Tags: immigration

good moral chracter and traffic fines - N-400 #3 - KazMuzik Blog
2009-02-12 21:15

Naturalization のためには、good moral character であることが必要で、このために、N-400 には犯罪履歴に関する質問があります。ここで、交通違反がどのような扱いになるかが気になるところですが、alcohol または drug 関連ではなくて、罰金が $500 以下で、実際に逮捕されなければ、特に問題はないようです。


2009-02-19 update
-> minor traffic ticket(s) - N-400 #8

Tags: immigration

Name change (optional) - N-400 #2 - KazMuzik Blog
2009-02-10 21:07

N-400 の下書きを始めましたが、最初のページに、Name change の項目がありました。Naturalization の時には、legally に name change できることは知っていましたが、N-400 をファイルする時点で、記入する必要があるようです。特に名前を変えたいということもないのですが、妻は、せっかくだから、middle name ぐらいつけておいたら、などと言っています。

Tags: immigration

N-400 : English and civics testing requirements - KazMuzik Blog
2009-02-03 21:38

Naturalization に関する準備を始めました。このためには、USCISN-400 をファイルしますが、その Instructions の 1ページには、English and civics tesging requirements に関しての記述がありました。

ファイルするときの年齢が 50歳以上で lawful permanent resident として 20年以上、あるいは 55歳以上で 15年以上住んでいる場合は、English test が免除され、civic test は、自分の指定した言語で受けることができるようです。N-400 の関連するところをみると、interpreter が手配されるようです。また、65歳以上で、同様に 20年以上住んでいる場合は、civics test は simple version になるようです。

A Guide to Naturalization (M-476) という 58ページの guidebook があります。

Tags: immigration

uscis.gov crawled with Ntuch-0.9 - KazMuzik Blog
2008-07-05 22:49

uscis.gov のサイトを、Nutch で crawl してみました。Nutch は、4/12/2007 に 0.9 が release されてから、1年以上 update がありませんが、なれているので、使いました。基本的には、2/24/2007 に紹介した 0.81 のときの手順と同様です。

$ mkdir /KazMuzik/uscis.gov
$ cd /KazMuzik/uscis.gov
$ tar zxvpf .../nutch-0.9.tar.gz
$ cd nutch-0.9
$ vi conf/nutch-site.xml
$ mkdir seeds
$ vi seeds/seeds.txt
$ cat seeds/seeds.txt
http://www.uscis.gov/portal/site/uscis
$ vi conf/crawl-urlfilter.txt
$ cat conf/crawl-urlfilter.txt
-^(file|ftp|mailto):
-\.(gif|GIF|jpg|JPG|png|PNG|ico|ICO|css|sit|eps|wmf|zip|ppt|mpg|xls|gz|rpm|tgz|mov|MOV|exe|jpeg|JPEG|bmp|BMP)$
# -[?*!@=]
-.*(/.+?)/.*?\1/.*?\1/
+^http://([a-z0-9]*\.)*uscis.gov/
-.
$ export NUTCH_JAVA_HOME=/usr/java/jdk
$ nohup bin/nutch crawl seeds &
$ tail -f nohup.out
crawl started in: crawl-20080705105148
rootUrlDir = seeds
threads = 10
depth = 5
Injector: starting
...
merging indexes to: crawl-20080705105148/index
Adding crawl-20080705105148/indexes/part-00000
done merging
crawl finished: crawl-20080705105148
^C
$ bin/nutch readseg -list -dir crawl-20080705105148/segments | sort
20080705105152  1               2008-07-05T10:51:56     2008-07-05T10:51:56     1       1
20080705105202  33              2008-07-05T10:52:06     2008-07-05T10:52:42     39      24
20080705105254  248             2008-07-05T10:52:57     2008-07-05T10:58:28     287     184
20080705105910  1146            2008-07-05T10:59:22     2008-07-05T11:29:36     1191    903
20080705113222  2998            2008-07-05T11:32:29     2008-07-05T12:53:59     3046    2196
NAME            GENERATED       FETCHER START           FETCHER END             FETCHED PARSED
$ 

/usr/local に、Tomcat 6.0.16 がインストールされていたので、deploy してみます。

$ cp nutch-0.9.war /usr/loca/tomcat/webapps/uscis.war
$ /usr/local/tomcat/bin/shutdown.sh
$ vi /usr/local/tomcat/webapps/uscis/WEB-INF/classes/nutch-site.xml
$ cat /usr/local/tomcat/webapps/uscis/WEB-INF/classes/nutch-site.xml
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
  <property>
    <name>searcher.dir</name>
    <value>/KazMuzik/uscis.gov/nutch-0.9/crawl-20080705105148</value>
  </property>
</configuration>
$ /usr/local/tomcat/bin/startup.sh
$ 


Tags: computer_technology, immigration

Naturalization (N-400) backlog - KazMuzik Blog
2008-03-03 12:12

去年の 12月に、Naturalization (N-400) の backlog について、紹介しましたが、1/17/2008 に、USCIS の Director である Emilio T. Gonzalez が、House Judiciary Committee の前で証言しています。これによると、2007年の値上げの前に大量の申請が殺到して、特に、Naturalization については、6,7月の申請数は、前年比 350% 増で、FY2007 の1年では、前年の倍にあたる約 140万件に達したため、processing time が 7ヶ月から 18ヶ月になってしまった、とあります。これの対応策としては、基本的には、人海戦術で、1,500人の新しい employee(s) を雇ったり、temporary staff を permanent にしたり、retire した employee を再雇用したりと、1,800人増員して処理にあたると、あり、これにより、FY2010 の第3四半期(2010年の6~8月)までには、processing time を、6ヶ月までに減らす、そうです。

これについては、MPI (Migration Policy Institute) という independent, nonpartisan, nonprofit think tank からも、Behind the Naturalization backlog という詳しい Fast Sheet が出ています。

申請料値上げの前の 5/29/2007 付けの Q&A では、"By the end of FY2009, we intend to reduce by 20 percent the average case processing times across the spectrum of applications and petitions." (4ページ目の最初の段落) と調子のいいことを約束しておきながら、結果的に、膨大な backlog を抱えることになり、それの対処に FY2010 までかかる、という本末転倒なことをしでかす USCIS なので、あまり期待はできないようです。

Tags: immigration
Current Mood: disappointed

Blue Card to Europe - KazMuzik Blog
2008-01-02 07:42

2007年も、とうとう SKIL Act を含む、Comprehensive Immigration Reform Act が通りませんでしたが、今年は、大統領選挙の年なので、このような bill が可決されるチャンスは、ほとんどないと思われます。H-1B や green card の EB-3 (国によっては EB-2) の現状をなんとかしないと、優秀な人材が、どんどん外に流れていって、immigrant(s) で成り立っている U.S. の競争力が低下するのは、必至です。Bush 政権が Iraq 戦争で失敗して、アメリカの地位もどんどん低下する一方ですが、今年は、初の女性大統領か黒人大統領が誕生するかもしれません。



一方、European Union (EU)では、
Blue Card
を検討しているようです。(日本を除く)アジアが力を発揮してくるのはまだ先なので、やはり、これからしばらくは、ヨーロッパの時代でしょうか。今年は、españolfrançais の勉強を加速しようと思います。

Tags: español, français, immigration

Spring Framework JdbcTemplate - USCIS Processing Times #7 - KazMuzik Blog
2007-12-18 21:14

前回、予告したように、今回からデータベースを用いることにします。12/12 に紹介した Spring Framework から、今回は、JdbcTemplate を用います。

前回の ProcessingTime オブジェクトに対応するテーブルを作成します。
package net.java.sampo.immigration.processingTime.db;

import javax.sql.DataSource;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
import org.apache.commons.chain.impl.ContextBase;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class CreateTableCommand implements Command {
  private static Log log = LogFactory.getLog(CreateTableCommand.class);

  private static final String sql
    = "create table PROCESSINGTIME ("
    + "FACILITY varchar(32),"
    + "POSTEDDATE timestamp,"
    + "LINENO integer,"
    + "FORM varchar(8),"
    + "TITLE varchar(128),"
    + "CLASSIFICATION varchar(128),"
    + "TIMEFRAME varchar(32),"
    + "PROCESSINGDATE timestamp,"
    + "DAYS integer,"
    + "primary key(FACILITY, POSTEDDATE, LINENO))";

  private JdbcTemplate jdbcTemplate;

  public CreateTableCommand() {
  }

  public void setDataSource(DataSource dataSource) {
    jdbcTemplate = new JdbcTemplate(dataSource);
  }

  public void execute() {
    execute(new ContextBase());
  }

  public boolean execute(Context context) {
    try {
      jdbcTemplate.execute(sql);
    }
    catch (DataAccessException e) {
      log.error(e);
      return true;
    }
    return false;
  }

  public static void main(String[] args) throws Exception {
    Resource resource = new ClassPathResource("processingTime.xml");
    XmlBeanFactory factory = new XmlBeanFactory(resource);
    log.info("getting command bean ..");
    CreateTableCommand command
      = (CreateTableCommand)factory.getBean("createTableCommand");
    log.info("executing ...");
    command.execute();
  }
} 

今までと同様、Command クラスとして、実装しています。Spring Framework の IoC により、Bean の property として、DataSource を与えて、execute() メソッドで、SQL を実行しています。

次は、Spring のリソースファイルです。
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
      http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-2.5.xsd
    ">

  <bean id="createTableCommand"
     class="net.java.sampo.immigration.processingTime.db.CreateTableCommand">
    <property name="dataSource" ref="dataSource" />
  </bean>

  <bean id="dataSource" destroy-method="close"
     class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName"
             value="org.apache.derby.jdbc.EmbeddedDriver" />
    <property name="url"
             value="jdbc:derby:processingTime.db;create=true" />
  </bean>
</beans>

DataSource では、Apache Commons DBCP (DataBase Connection Pool) を利用しました。データベースは、いつもの Apache Derby です。なお、commons-dbcp は、Commons Pool を使っているので、実行時には、commons-pool の JAR ファイルも必要になります。

Tags: immigration, programming

USCIS Processing Times Tracking Project #6 - Processing Time & ParserUtils - KazMuzik Blog
2007-12-17 22:19

12/7 に、USCIS の Processing Times について書いてから、posted date は 11/14 のままで、更新はされていません。12/8 に、ProcessingTime クラスと、parser を紹介しましたが、今日は、今後の計画も含めて、アップデートしておきます。

まずは、ProcessingTime ですが、データベースのテーブルの 1行と対応させるため、Facility の名前、Posted Date, (そのページでの) 行番号を追加しておきます。また、元の timeframe は、せっかくデータベースに入れても扱いにくいので、Date 型の Processing Date と、int の timeframe (日数) を返す method も加えておきました。12/10 の snapshot の画像で、サンプルを見ることができます。
package net.java.sampo.immigration.processingTime;

import java.io.Serializable;
import java.util.Date;
import java.util.Formatter;
import org.apache.commons.lang.time.DateUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import static net.java.sampo.immigration.processingTime.ParserUtils.parseDate;

public class ProcessingTime implements Serializable {
  private static final Log log = LogFactory.getLog(ProcessingTime.class);

  private String facility;
  private Date date;
  private int lineNo;
  private String form;
  private String title; // name
  private String classification; // basis
  private String timeframe;

  public ProcessingTime(String facility, Date date, int lineNo,
           String form, String name, String timeframe) {
    this(facility, date, lineNo, form, name, null, timeframe);
  }

  public ProcessingTime(String facility, Date date, int lineNo,
           String form, String title, String classification, String timeframe) {
    this.facility = facility;
    this.date = date;
    this.lineNo = lineNo;
    this.form = form;
    this.title = title;
    this.classification = classification;
    this.timeframe = timeframe;
  }

  public String getFacility() {
    return facility;
  }

  public Date getDate() {
    return date;
  }

  public int getLineNO() {
    return lineNo;
  }

  public String getForm() {
    return form;
  }

  public String getTitle() {
    return title;
  }

  public String getName() {
    return title;
  }

  public String getClassification() {
    return classification;
  }

  public String getTimeframe() {
    return timeframe;
  }

  public String toString() {
    return toString(false);
  }

  public String toString(boolean additionalInfo) {
    Formatter f = new Formatter();
    f.format("[%s|%tF|%d|%s|%s|", facility, date, lineNo, form, title);
    if (classification != null) {
      f.format("%s|", classification);
    }
    f.format("%s", timeframe);
    if (additionalInfo) {
      f.format("|%tF|%d", getProcessingDate(), getTimeframeInDay());
    }
    f.format("]");
    return f.toString();
  }

  public Date getProcessingDate() {
    Date postedDate = date;
    if (timeframe == null || timeframe.length() == 0) {
      return null;
    }
    String s = timeframe.toLowerCase();
    char c = s.charAt(0);
    if (c >= 'a' && c <= 'z') {
      return parseDate(s);
    }
    int i = s.indexOf(' ');
    int n = 0 - Integer.parseInt(s.substring(0,i));
    s = s.substring(i+1);
    if (s.startsWith("day")) {
      return DateUtils.addDays(postedDate, n);
    }
    else if (s.startsWith("week")) {
      return DateUtils.addWeeks(postedDate, n);
    }
    else if (s.startsWith("month")) {
      return DateUtils.addMonths(postedDate, n);
    }
    else if (s.startsWith("year")) {
      return DateUtils.addYears(postedDate, n);
    }
    else if (s.startsWith("semana")) {
      return DateUtils.addWeeks(postedDate, n);
    }
    else if (s.startsWith("mese")) {
      return DateUtils.addMonths(postedDate, n);
    }
    else {
      log.warn("invalid time frame \"" + timeframe + "\"");
      return null;
    }
  }

  public int getTimeframeInDay() {
    Date postedDate = date;
    Date processingDate = getProcessingDate();
    if (processingDate == null) {
      return -1;
    }
    return (int)((postedDate.getTime() - processingDate.getTime()) / 86400000L);
    // 86400000 = 24 x 60 x 60 x 1000
  }
} 


次は、ParserUtils ですが、parser 関係の method(s) を static として、まとめました。また、USCIS の Processing Times の web での公開は、4年前の 2003年11月から始まっていますが、当時のデータも保存してあったので、それを利用するために、昔のデータも parse できるよう、変更を加えてました。
package net.java.sampo.immigration.processingTime;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Formatter;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class ParserUtils {
  private static Log log = LogFactory.getLog(ParserUtils.class);

  public static String toTrimedString(Reader in) throws IOException {
    StringBuilder sb = new StringBuilder();
    for (String line : (List<String>)IOUtils.readLines(in)) {
      sb.append(line.trim());
    }
    return sb.toString();
  }

  public static String cutContent(byte[] bytes) throws IOException {
    Reader in = new InputStreamReader(new ByteArrayInputStream(bytes), "US-ASCII");
    return cutContent( toTrimedString(in) );
  }

  public static String cutContent(File file) throws IOException {
    Reader in = new InputStreamReader(new FileInputStream(file), "US-ASCII");
    return cutContent(in);
  }

  public static String cutContent(Reader in) throws IOException {
    return cutContent( toTrimedString(in) );
  }

  public static String cutContent(String html) {
    String sl = html.toLowerCase();
    int n = sl.indexOf("posted ");
    n = sl.indexOf("posted ", n+7);

    int m1 = sl.lastIndexOf("<b><big>", n);
    if (m1 < 0) { // NBC 2003-11-14
      m1 = n;
    }
    m1 = sl.lastIndexOf(">", m1);
    int m2 = sl.indexOf("<", n);
    StringBuilder sb = new StringBuilder();
    sb.append("<p align=\"center\">");
    sb.append(html.substring(m1+1,m2));
    sb.append("</p>");

    m1 = sl.indexOf("<table", m2);
    m2 = sl.indexOf("</table>", m1);
    sb.append(html.substring(m1,m2+8));
    return sb.toString();
  }

  public static String parseFacilityName(String content) {
    String s = content.toLowerCase();
    int n = s.indexOf("<big>");
    if (n < 0) {
      if (log.isWarnEnabled()) {
        log.warn("\"<big> \" tag not found.");
      }
      return "National Benefits Center"; // NBC 2003-11-14
    }
    int m = s.indexOf("</", n+5); // 2003-11-14
    if (m < 0) {
      if (log.isWarnEnabled()) {
        log.warn("\"</big> \" tag not found.");
      }
      return null;
    }
    String name = content.substring(n+5, m).trim();
    // 2003-11-14
    if (s.substring(0,n).indexOf("service center") >= 0
     && name.toLowerCase().indexOf("service center") < 0) {
      name = name + " Service Center";
    }
    return name;
  }

  public static Date parsePostedDate(String content) {
    int n = content.toLowerCase().indexOf("posted ");
    if (n < 0) {
      if (log.isWarnEnabled()) {
        log.warn("\"Posted \" not found.");
      }
      return null;
    }
    return parseDate(content.substring(n+7));
  }

  public static ProcessingTime[] parseProcessingTimes(String content) {
    String facility = parseFacilityName(content);
    Date date = parsePostedDate(content);
    int lineNo = 0;
    //
    String s = content.toLowerCase();
    int n = s.indexOf("form");
    List<ProcessingTime> list = new ArrayList<ProcessingTime>();
    while (true) {
      n = s.indexOf("<tr", n);
      if (n < 0) {
        break;
      }
      int m = s.indexOf("<tr", n+4); // CSC 2003-11-14 </tr> missing !!
      String line = null;
      if (m < 0) {
        line = content.substring(n);
      }
      else {
        line = content.substring(n, m);
      }
      list.add( parseLine(facility, date, lineNo, line) );
      lineNo ++;
      if (m < 0) {
        break;
      }
      n = m;
    }
    ProcessingTime[] array = new ProcessingTime[ list.size() ];
    list.toArray(array);
    return array;
  }

  private static ProcessingTime parseLine(String facility, Date date, int lineNo, String s) {
    if (log.isDebugEnabled()) {
      log.debug(s);
    }
    String sl = s.toLowerCase();
    int m = sl.indexOf("<b>");
    int n = sl.indexOf("<", m+3); // 2003-11-14
    List<String> list = new ArrayList<String>(4);
    list.add(s.substring(m+3, n).trim()); // form
    if (log.isDebugEnabled()) {
      log.debug(list);
    }
    while (true) {
      n = sl.indexOf("</td", n+5); // 2005-10-19 District Office
      if (n < 0) {
        break;
      }
      m = sl.lastIndexOf(">", n);
      list.add( s.substring(m+1, n).trim() );
      if (log.isDebugEnabled()) {
        log.debug(list);
      }
    }
    ProcessingTime processingTime = null;
    if (list.size() == 3) {
      processingTime = new ProcessingTime(facility, date, lineNo,
                             list.get(0), list.get(1), list.get(2));
    }
    else if (list.size() >= 4) {
      processingTime = new ProcessingTime(facility, date, lineNo,
                             list.get(0), list.get(1), list.get(2), list.get(3));
    }
    else {
      if (log.isWarnEnabled()) {
        log.warn("invalid field number = " + list.size() + " for " + s);
      }
    }
    return processingTime;
  }

  public static Date parseDate(String s) {
    int n = s.indexOf(' ');
    int m = s.indexOf(',', n+1);
    int dd = Integer.parseInt(s.substring(n+1,m));
    int yyyy = Integer.parseInt(s.substring(m+2,m+6));
    int mm = parseMonth(s.substring(0,n));
    if (mm < 1 || mm > 12) {
      return null;
    }
    Calendar cal = Calendar.getInstance();
    cal.set(yyyy, mm-1, dd, 12, 0, 0);
    return cal.getTime();
  }

  private static final String[] months = {
    "jan", "feb", "mar", "apr", "may", "jun",
    "jul", "aug", "sep", "oct", "nov", "dec"
  };

  private static int parseMonth(String s) {
    s = s.toLowerCase();
    for (int i = 0; i < months.length; i++) {
      if (s.startsWith(months[i])) {
        return i+1;
      }
    }
    return -1;
  }
} 

Tags: immigration, programming

Spring Framework and Apache Commons Chain #2 - USCIS Processing Times #7 - KazMuzik Blog
2007-12-16 07:16

12/12 に、Spring Framework の IoC を用いて、Command を使用する方法を紹介しましたが、これを Chain に拡張して、さらに便利にします。12/11 に、5つの Command(s) からなる Chain を紹介したので、これを例に使います。

まずは、XML のリソースです。
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
      http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-2.5.xsd
    ">

  <bean id="chain" class="net.java.sampo.immigration.processingTime.command.spring.CommandChain">
    <property name="commands">
      <list>
        <ref bean="fetchCommand" />
        <ref bean="cutContentCommand" />
        <ref bean="parseContentCommand" />
        <ref bean="setFilenameCommand" />
        <ref bean="writeBytesCommand" />
      </list>
    </property>
    <property name="contextMap">
      <map>
        <entry key="url"
               value="https://egov.uscis.gov/cris/jsps/officeProcesstimes.jsp?selectedOffice=70" />
        <entry key="outPath" value="/tmp/pt" />
      </map>
    </property>
  </bean>

  <bean id="fetchCommand"
        class="net.java.sampo.immigration.processingTime.command.FetchCommand" />
  <bean id="cutContentCommand"
        class="net.java.sampo.immigration.processingTime.command.CutContentCommand" />
  <bean id="parseContentCommand"
        class="net.java.sampo.immigration.processingTime.command.ParseContentCommand" />
  <bean id="setFilenameCommand"
        class="net.java.sampo.immigration.processingTime.command.SetFilenameCommand" />
  <bean id="writeBytesCommand"
        class="net.java.sampo.immigration.processingTime.command.WriteBytesCommand" />
</beans>

"chain" bean では、List で Command の bean(s) を、Map で Context の entry を定義してあります。

次に、"chain" bean の CommandChian クラスです。main() で、上記のリソースを読み込み、実行しています。
package net.java.sampo.immigration.processingTime.command.spring;

import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
import org.apache.commons.chain.impl.ChainBase;
import org.apache.commons.chain.impl.ContextBase;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class CommandChain extends ChainBase implements InitializingBean {
  private static Log log = LogFactory.getLog(CommandChain.class);

  private List<Command> commands;
  private Map<String,String> contextMap;
  private Context context;

  public CommandChain() {
    context = null;
  }

  public void setCommands(List<Command> commands) {
    this.commands = commands;
  }

  public List<Command> getCommands() {
    return commands;
  }

  public void setContextMap(Map<String,String> contextMap) {
    this.contextMap = contextMap;
  }

  public Map<String,String> getContextMap() {
    return contextMap;
  }

  public Context getContext() {
    return context;
  }

  public void afterPropertiesSet() {
    // adding commands
    for (Command command : commands) {
      addCommand(command);
    }
    // setting context
    context = new ContextBase();
    for (String key : contextMap.keySet()) {
      String value = contextMap.get(key);
      context.put(key, value);
    }
  }

  public void execute() throws Exception {
    super.execute(context);
  }

  public static void main(String[] args) throws Exception {
    Resource resource = new ClassPathResource("chain.xml");
    XmlBeanFactory factory = new XmlBeanFactory(resource);
    log.info("getting chain ..");
    CommandChain chain = (CommandChain)factory.getBean("chain");
    Context context = chain.getContext();
    log.info("context=" + context);
    log.info("executing ...");
    chain.execute();
    //
    context.remove("bytes");
    context.remove("content");
    context.remove("processingTimes");
    log.info("context=" + context);
  }
} 

InitializingBean で定義されている afterPropertiesSet() メソッドを実装して、properties がセットされた後に、必要な処理を自動的に行うようにしています。このため、main() では、"chain" bean を get した後は、execute() メソッドを呼ぶだけです。
$ cat log4j.properties
log4j.rootCategory=WARN,A1
log4j.category.net.java.sampo=INFO
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %c{1} - %m%n
$ java -classpath .:lib/commons-logging-1.1.1.jar:lib/log4j-1.2.15.jar:lib/commons-chain-1.1.jar\
:lib/commons-io-1.3.2.jar:lib/spring-2.5.jar \
net.java.sampo.immigration.processingTime.command.spring.CommandChain
2007-12-16 07:39:34,508 [main] INFO  CommandChain - getting chain ..
2007-12-16 07:39:34,569 [main] INFO  CommandChain \
- context={outPath=/tmp/pt, url=https://egov.uscis.gov/cris/jsps/officeProcesstimes.jsp?selectedOffice=70}
2007-12-16 07:39:34,569 [main] INFO  CommandChain - executing ...
2007-12-16 07:39:36,012 [main] INFO  CommandChain \
- context={outPath=/tmp/pt, facility=San Jose CA, posted=Wed Nov 14 12:00:00 PST 2007,\
 url=https://egov.uscis.gov/cris/jsps/officeProcesstimes.jsp?selectedOffice=70,\
 outFile=/tmp/pt/San_Jose_CA-20071114.html}
$ 

CommandChain 自体は、今回の USCIS Processing Times の処理と独立しているので、リソースファイルで、Chain で実行する Command の List と、Context の Map を記述すれば、コンパイルせずに、任意の command chain と context を使って実行することができます。

Tags: immigration, programming

USCIS Processing Times #4 - fetcher - KazMuzik Blog
2007-12-10 21:55

USCIS のサイトは、予定より早く、昨晩には立ち上がっていました。まずは、Processing Times のページをすべて fetch して、ローカルに保存しておくことにします。

まずは、特定の URL を fetch してきて、byte 配列に格納して返すクラスです。
package net.java.sampo.immigration.processingTime;

import java.io.InputStream;
import java.io.IOException;
import java.net.URL;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class EgovFetcher {
  private static final long minimumFetchInterval = 1000; // 1 sec

  private static Log log = LogFactory.getLog(EgovFetcher.class);

  private static EgovFetcher fetcher = null;

  public static EgovFetcher getInstance() {
    if (fetcher == null) {
      fetcher = new EgovFetcher();
    }
    return fetcher;
  }

  private long lastFetchedTime;

  public EgovFetcher() {
    lastFetchedTime = -1L;
  }

  synchronized public byte[] fetch(String url) throws IOException {
    if (url == null) {
      log.error("url is null.");
      return null;
    }
    long now = System.currentTimeMillis();
    long t = minimumFetchInterval - (now - lastFetchedTime);
    if (t > 0L) {
      if (log.isInfoEnabled()) {
        log.info("sleeping " + t + "msecs ..");
      }
      try {
        Thread.sleep(t);
      }
      catch (InterruptedException e) {
      }
      now = System.currentTimeMillis();
    }
    lastFetchedTime = now;
    byte[] bytes = null;
    InputStream in = new URL(url).openStream();
    bytes = IOUtils.toByteArray(in);
    return bytes;
  }
} 

アクセスが集中しないように、fetch は、1秒間に 1回に制限してあります。また、このためと、使いやすさを考慮して、singleton になっています。

次は、Processing Times のトップページを parse して、facility (Field Office や Service Center)のリストと、それぞれの URL の Collection (List と Map) オブジェクトを準備するクラスです。
package net.java.sampo.immigration.processingTime;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class FacilityUrlMap extends HashMap<String, String> {
  private static final String ptimesUrl = " https://egov.uscis.gov/cris/jsps/ptimes.jsp";
  private static final String officeUrl
    = "https://egov.uscis.gov/cris/jsps/officeProcesstimes.jsp?selectedOffice=";
  private static final String centerUrl
    = "https://egov.uscis.gov/cris/jsps/Processtimes.jsp?SeviceCenter=";
  private static final String nbcUrl = "https://egov.uscis.gov/cris/jsps/NBCprocesstimes.jsp";

  private static Log log = LogFactory.getLog(FacilityUrlMap.class);

  private static FacilityUrlMap map;

  public static FacilityUrlMap getInstance() {
    if (map == null) {
      map = new FacilityUrlMap();
    }
    return map;
  }

  private String[] facilityNames;

  public FacilityUrlMap() {
    super();
    try {
      init();
    }
    catch (IOException e) {
      log.fatal(e);
    }
  }

  public String getUrl(String facility) {
    return get(facility);
  }

  public String[] getAllFacilityNames() {
    return facilityNames;
  }

  private void init() throws IOException {
    byte[] bytes = EgovFetcher.getInstance().fetch(ptimesUrl);   
    BufferedReader in
      = new BufferedReader(new InputStreamReader(
          new ByteArrayInputStream(bytes), "ISO-8859-1"));
    parse(in);
  }

  private void parse(BufferedReader in) throws IOException {
      List<String> list = new ArrayList<String>();
      int mode = 0;
      while (true) {
        String line = in.readLine();
        if (log.isDebugEnabled()) {
          log.debug("" + mode + " : " + line);
        }
        if (line == null) {
          break;
        }
        String s = line.toLowerCase();
        if (mode == 0) {
          if (s.indexOf("<select name=\"selectedoffice\">") >= 0) {
            mode = 1;
          }
          else if (s.indexOf("<select name=\"sevicecenter\">") >= 0) { // Sevice : "r" missing !!
            mode = 2;
          }
          continue;
        }
        if (s.indexOf("</select>") >= 0) {
          if (mode == 2) {
            break;
          }
          mode = 0;
          continue;
        }
        //
        int n = 0;
        while (true) {
          int m = s.indexOf("<option value=\"", n);
          if (m < 0) {
            break;
          }
          n = s.indexOf('"', m+15);
          String id = line.substring(m+15,n).trim();
          m = s.indexOf('<', n+2);
          String name = line.substring(n+2, m).trim();
          log.info(id + " : " + name);
          if (mode == 1) {
            int intId = Integer.parseInt(id);
            put(name, officeUrl + intId);
            list.add(name);
          }
          else if (mode == 2) {
            put(name, centerUrl + id);
            list.add(name);
          }
          n = m+8;
        }
      }
      String name = "National Benefits Center";
      put(name, nbcUrl);
      list.add(name);
      //
      int n = list.size();
      facilityNames = new String[n];
      list.toArray(facilityNames);
  }
} 

これも singleton です。

以上を利用して、すべての Processing Times のページを fetch して、ファイルに保存する Command クラスです。
package net.java.sampo.immigration.processingTime.command;

import java.io.File;
import java.io.IOException;
import java.util.Map;
import org.apache.commons.chain.Chain;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
import org.apache.commons.chain.impl.ChainBase;
import org.apache.commons.chain.impl.ContextBase;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import net.java.sampo.immigration.processingTime.FacilityUrlMap;

public class FetchAllCommand implements Command {
  private static Log log = LogFactory.getLog(FetchAllCommand.class);

  public boolean execute(Context context) {
    FacilityUrlMap urlMap = FacilityUrlMap.getInstance();
    if (urlMap == null) {
      log.fatal("facility to url map is null.");
      return true;
    }
    String outPath = (String)context.get("outPath");
    if (outPath == null) {
      log.error("outPath not set in context.");
      return true;
    }
    File outDir = new File(outPath);
    if (! outDir.exists()) {
      log.warn("outPath not exist. creating..");
      if (! outDir.mkdir()) {
        log.warn("outPath failed to create.");
        return true;
      }
    }
    Chain command = new ChainBase();
    command.addCommand(new FetchCommand());
    command.addCommand(new CutContentCommand());
    command.addCommand(new ParseContentCommand());
    command.addCommand(new SetFilenameCommand());
    command.addCommand(new WriteBytesCommand());

    for (String facility : urlMap.getAllFacilityNames()) {
      String url = urlMap.getUrl(facility);
      Context eachContext = new ContextBase();
      eachContext.put("url", url);
      eachContext.put("outPath", outPath);
      if (log.isInfoEnabled()) {
        log.info(facility + " : " + url + " to " + outPath);
      }
      try {
        command.execute(eachContext);
      }
      catch (Exception e) {
        log.error(e);
      }
    }
    return false;
  }

  public static void main(String[] args) throws Exception {
    String path = "orig";
    if (args.length > 0) {
      path = args[0];
    }
    Context context = new ContextBase();
    context.put("outPath", path);
    Chain command = new ChainBase();
    command.addCommand(new FetchAllCommand());
    command.execute(context);
  }
} 

いくつかの簡単な Command オブジェクトを Chain で使っていますが、これは後に紹介します。(2007-12-11 -> USCIS Processing Times #5 - Command(s) and Chain)

実行して、保存したファイルを加工したページのサンプルを載せておきます。今日(12/10)の時点では、Posted Date は、まだ 11/14 のままでした。



Tags: immigration, programming

USCIS Processing Times - Java parser - KazMuzik Blog
2007-12-09 00:58

USCIS の Processing Times ですが、San Jose だけではなく、参考のため、Los Angeles と San Francisco も載せておきます。
District Office Processing Dates for Los Angeles CA Posted November 14, 2007
FormForm NameProcessing Timeframe:
I-131Application for Travel Documents3 Months
I-485Application to Register Permanent Residence or Adjust Status6 Months
I-600Petition to Classify Orphan as an Immediate RelativeJuly 28, 2007
I-600AApplication for Advance Processing of Orphan PetitionJuly 28, 2007
I-765Application for Employment Authorization11 Weeks
N-400Application for Naturalization7 Months
N-600Application for Certification of CitizenshipMay 24, 2007

District Office Processing Dates for San Francisco CA Posted November 14, 2007
FormForm NameProcessing Timeframe:
I-131Application for Travel Documents3 Months
I-485Application to Register Permanent Residence or Adjust Status6 Months
I-600Petition to Classify Orphan as an Immediate RelativeJune 07, 2007
I-600AApplication for Advance Processing of Orphan PetitionJune 07, 2007
I-765Application for Employment Authorization11 Weeks
N-400Application for Naturalization7 Months
N-600Application for Certification of CitizenshipJuly 06, 2007

N-400 に関しては、San Jose は、"March 08, 2007" と処理している日付になっていますが、Los Angeles と San Francisco は、"7 Months" と期間になっています。昔は、すべて、日付による表示でしたが、いつからか、期間による表示も混在するようになったようです。

今日、USCIS の Processing Times のページをアクセスすると、次にようなメッセージが表示されました。
The Case Status Online, Processing Times, Office Locator, and Change of Address Online Systems \
will be experiencing a scheduled outage from 9:30 PM EST
on Friday, December 7 to 8:00 AM EST on Monday, December 10 due to scheduled maintenance. 

週末に、maintenance のためとはいえ、このような mission critical (!?)) なサービスを、丸 2日半(58.5時間)にわたって out of service にするとは、さすが、USCIS です。

Processing Time(s) を parse するクラスを書きましたが、本格的な fetch は、週明け、maintenance が完了してからになります。なお、上記の table(s) は、昨日、保存しておいたものから、テストを兼ねて作成したものです。
package net.java.sampo.immigration.processingTime;

import java.io.Serializable;

public class ProcessingTime implements Serializable {
  private String form;
  private String title; // name
  private String classification; // basis
  private String timeframe;

  public ProcessingTime(String form, String name, String timeframe) {
    this(form, name, null, timeframe);
  }

  public ProcessingTime(String form, String title, String classification, String timeframe) {
    this.form = form;
    this.title = title;
    this.classification = classification;
    this.timeframe = timeframe;
  }

  public String getForm() {
    return form;
  }

  public String getTitle() {
    return title;
  }

  public String getName() {
    return title;
  }

  public String getClassification() {
    return title;
  }

  public String getTimeframe() {
    return timeframe;
  }

  public String toString() {
    return "PT[" + form + "|" + title + "|"
         + ((classification==null)?"":(classification+"|"))
         + timeframe + "]";
  }
} 

package net.java.sampo.immigration.processingTime;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Formatter;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import static net.java.sampo.immigration.processingTime.ProcessingTimeUtils.parseDate;

public class ProcessingTimesPageParser extends BufferedReader {
  private static Log log = LogFactory.getLog(ProcessingTimesPageParser.class);

  private String facilityName;
  private Date date;
  private ProcessingTime[] processingTimes;
  private String content;

  public ProcessingTimesPageParser(Reader in) {
    super(in);
  }

  public ProcessingTime[] getProcessingTimes() {
    return processingTimes;
  }

  public String getFacilityName() {
    return facilityName;
  }

  public Date getPostedDate() {
    return date;
  }

  public String getContent() {
    return content;
  }

  public void parseAll() throws IOException {
    content = parseContent();
    if (log.isDebugEnabled()) {
      log.debug(content);
    }
    facilityName = parseFacility(content);
    date = parsePostedDate(content);
    processingTimes = parseTable(content);
  }

  private String parseContent() throws IOException {
    int postedCount = 0;
    int endTableCount = 0;
    StringBuilder sb = new StringBuilder();
    String tableTag = null;
    while (true) {
      String line = readLine();
      if (line == null) {
        break;
      }
      line = line.trim();
      String lineLowerCase = line.toLowerCase();
      if (lineLowerCase.indexOf("<table") >= 0 && postedCount < 2) {
        tableTag = line;
      }
      if (lineLowerCase.indexOf("<tr") >= 0 && postedCount < 2) {
        sb = new StringBuilder();
        sb.append(tableTag);
        if (line.indexOf("<tbody") < 0) {
          sb.append("<tbody>");
        }
      }
      sb.append(line);
      if (lineLowerCase.indexOf("posted ") >= 0) {
        postedCount ++;
      }
      if (lineLowerCase.indexOf("</table>") >= 0 && postedCount >= 2) {
        endTableCount ++;
        if (endTableCount >= 2) {
          break;
        }
      }
    }
    return sb.toString();
  }

  private String parseFacility(String content) {
    String contentLowerCase = content.toLowerCase();
    int n = contentLowerCase.indexOf("<big>");
    if (n < 0) {
      if (log.isWarnEnabled()) {
        log.warn("\"<big> \" tag not found.");
      }
      return null;
    }
    int m = contentLowerCase.indexOf("</big>", n+5);
    if (m < 0) {
      if (log.isWarnEnabled()) {
        log.warn("\"</big> \" tag not found.");
      }
      return null;
    }
    return content.substring(n+5, m);
  }

  private Date parsePostedDate(String content) {
    int n = content.toLowerCase().indexOf("posted ");
    if (n < 0) {
      if (log.isWarnEnabled()) {
        log.warn("\"Posted \" not found.");
      }
      return null;
    }
    return parseDate(content.substring(n+7));
  }

  private ProcessingTime[] parseTable(String content) {
    String contentLowerCase = content.toLowerCase();
    int n = contentLowerCase.indexOf("processing timeframe");
    List<ProcessingTime> list = new ArrayList<ProcessingTime>();
    while (true) {
      n = contentLowerCase.indexOf("<tr", n);
      if (n < 0) {
        break;
      }
      int m = contentLowerCase.indexOf("</tr>", n+4);
      list.add( parseLine( content.substring(n, m+5) ) );
      n = m;
    }
    ProcessingTime[] array = new ProcessingTime[ list.size() ];
    list.toArray(array);
    return array;
  }

  private ProcessingTime parseLine(String s) {
    if (log.isDebugEnabled()) {
      log.debug(s);
    }
    String sl = s.toLowerCase();
    int m = sl.indexOf("<b>");
    int n = sl.indexOf("</b>", m+3);
    List<String> list = new ArrayList<String>(4);
    list.add(s.substring(m+3, n).trim()); // form
    if (log.isDebugEnabled()) {
      log.debug(list);
    }
    while (true) {
      n = sl.indexOf("</td>", n+5);
      if (n < 0) {
        break;
      }
      m = sl.lastIndexOf(">", n);
      list.add( s.substring(m+1, n).trim() );
      if (log.isDebugEnabled()) {
        log.debug(list);
      }
    }
    ProcessingTime processingTime = null;
    if (list.size() == 3) {
      processingTime = new ProcessingTime(list.get(0), list.get(1), list.get(2));
    }
    else if (list.size() == 4) {
      processingTime = new ProcessingTime(list.get(0), list.get(1), list.get(2), list.get(3));
    }
    else {
      if (log.isWarnEnabled()) {
        log.warn("invalid field number = " + list.size());
      }
    }
    return processingTime;
  }

  public static void main(String[] args) throws Exception {
    ProcessingTimesPageParser parser
      = new ProcessingTimesPageParser(new InputStreamReader(System.in, "ISO-8859-1"));
    parser.parseAll();
    System.out.printf("%s : %tF%n", parser.getFacilityName(), parser.getPostedDate());
    for (ProcessingTime pt : parser.getProcessingTimes()) {
      System.out.println(pt.toString());
    }
    System.out.println(parser.getContent());
  }
} 

package net.java.sampo.immigration.processingTime;

import java.util.Calendar;
import java.util.Date;
import java.util.Formatter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class ProcessingTimeUtils {
  private static Log log = LogFactory.getLog(ProcessingTimeUtils.class);

  public static Date parseDate(String s) {
    int n = s.indexOf(' ');
    int m = s.indexOf(',', n+1);
    int dd = Integer.parseInt(s.substring(n+1,m));
    int yyyy = Integer.parseInt(s.substring(m+2,m+6));
    int mm = parseMonth(s.substring(0,n));
    if (mm < 1 || mm > 12) {
      return null;
    }
    Calendar cal = Calendar.getInstance();
    cal.set(yyyy, mm-1, dd);
    return cal.getTime();
  }

  private static final String[] months = {
    "jan", "feb", "mar", "apr", "may", "jun",
    "jul", "aug", "sep", "oct", "nov", "dec"
  };

  private static int parseMonth(String s) {
    s = s.toLowerCase();
    for (int i = 0; i < months.length; i++) {
      if (s.startsWith(months[i])) {
        return i+1;
      }
    }
    return -1;
  }
} 

一部、不自然なコードもありますが、これは、Field Office (District Office) のページだけではなく、Service Center のページも parse できるようにしたためです。


2007-12-17 update
-> USCIS Processing Times Tracking Project #6 - Processing Time & ParserUtils
このエントリのコードは、12/17/2007 に、大幅にアップデートしました。

Tags: immigration, programming

USCIS - Advisory on Processing Times - KazMuzik Blog
2007-12-07 22:06




今朝、久しぶりに、USCIS (U.S. Citizenship and Immigration Services) のホームページを見たところ、トップのニュースが、Advisory on Processing Times (*) で、次のような summary が載っています。

USCIS has received a significant increase in the number of applications filed; nearly double the number received in the same period last year. The agency is working to improve processes and focus increased resources, including hiring approximately 1,500 new employees, to address this workload.

As a result, average processing times for certain applications may grow longer. Naturalization applications filed after June 1, 2007 may take approximately 16-18 months to process.

リンクのページには、もう少し詳しい数字もあるので、引用しておきます。
...
USCIS has received a significant increase in the number of applications filed. In July and August, nearly 2.5 million applications and petitions of all types were received. This compares to 1.2 million applications and petitions received in the same time period last year. This fiscal year, we received 1.4 million applications for naturalization; nearly double the volume we received the year before. The agency is working to improve processes and focus increased resources, including hiring approximately 1,500 new employees, to address this workload.

As a result, average processing times for certain application types may become longer. In particular, naturalization applications filed after June 1, 2007 may take approximately 16 - 18 months to process.
...

これは、この夏に申請料を大幅に値上げしましたが、たぶん、その影響だと思われます。特に、Naturalization (N-400) は、ある条件が整えば、いつでも申請できるので、値上げ前に、駆け込みで申請した人が多かったのでは、と予想されます。

せっかく、だいたいの application で、processing time が 6ヶ月~1年未満となってきたところでしたが、ここにきて、また面倒なことになってきました。来年中には、バックログが解消されればいいのですが、USCIS のことなので、ただ期待するだけでは、だめかもしれません。

一応、今日の時点での、San Jose District Office の Processing Time(s) を保存しておきます。



District Office Processing Dates for San Jose CA Posted November 14, 2007

Form Form Name Processing Timeframe:
I-131 Application for Travel Documents 3 Months
I-485 Application to Register Permanent Residence or Adjust Status 6 Months
I-600 Petition to Classify Orphan as an Immediate Relative July 05, 2007
I-600A Application for Advance Processing of Orphan Petition July 05, 2007
I-765 Application for Employment Authorization 11 Weeks
N-400 Application for Naturalization March 08, 2007
N-600 Application for Certification of Citizenship October 12, 2006

Tags: immigration
Current Mood: angry

DV-2009 #2 - Photo - KazMuzik Blog
2007-10-10 18:47

DV-2009 の申請には、デジタル写真を upload しなければいけません。DV-2009 の公式サイトには、Photo Validation のページがあり、事前にチェックすることができます。試しに、昨日、日本のパスポート申請のために準備した U.S. Passport 用の正方形の写真で確認しようとしたところ、62,500 bytes を超えているため、Your photo must be less than 62.5KB in size となりました。Instructions のドキュメントが PDF であるので、よく読むと、いろいろな条件が書いてあり、そのひとつにこのファイルサイズの制限があります。

その下には、解像度の指定があり、320 pixels high by 240 pixels wide とあります。これにけっこう苦労する人がいるみたいです。私は Linux で GIMP を使いますが、次のような手順がわかりやすいと思います。
  1. 解像度は気にしないで、U.S. Passport の基準を満たすように、正方形のイメージを作成する。今回はすでに作成済みでした。
  2. 320x320 に縮小(あるいは拡大)する。ただし、拡大しなければいけないようだと、鮮明さに欠ける恐れがあり、元の解像度が小さ過ぎたということになります。
  3. 左右をカットして、320x240 にサイズ変更する。
これで試したところ、Your picture is valid となりました。私は DV-2009 には申請できないので、今回は写真のチェックだけです。


2007-10-10 update
Instructions をよく読むと、300x300 の正方形でもいいみたいです。これならば、上記のステップ 2 で、300x300 にすればよく、ステップ 3 を省略できます。試しにやってみましたが、Your picture is valid と、無事にパスしました。

320x240

300x300

Tags: immigration

DV-2009 - KazMuzik Blog
2007-10-10 08:13




10/3/2007 から、DV-2009 (the 2009 Diversity Immigrant Visa Program) の受付が始まりました。これは、U.S. Department of State (DOS) が毎年行っているプログラムで、U.S. の永住権(グリーンカード) を抽選で、毎年、5万人に与えることになっています。昔は、郵送による申請だったのですが、最近では、時代を反映してインターネットでの申請になりました。よく、間際らしい代行業者が、なんとか .ORG などと、あたかも正式サイトのように見せかけて立ち上げているのをよく見ますが、自分でも簡単に、そしてなにより安心して申請できるので、代行業者に頼らず、自分で申請する方がいいと思います。たぶん、このページにも、そのような業者の広告が出ると思いますが、間違ってもクリックしないように、気をつけてください。仮にそのようなサイトへ行ってもだまされいように気をつけて、DOS の正式サイトから申請しましょう。

Tags: american_life, immigration