ארכיון עבור הקטגוריה Java
נכתב על ידי עמרי בנושא Java, קוד פתוח, תכנות
שחררתי גרסא חדשה של IP2C, מהירה מתמיד וגם תומכת בבסיס הנתונים של Software77.
All tests done on an Intel(R) Core(TM)2 Duo CPU E8400 @ 3.00GH
PHP:
* No cache: 5000 searches/sec (Fast startup, slow query)
* Memory cache: : 5700 searches/sec (Slow startup, fastest query)
Java:
* No cache: 13900 searches/second. (Fast startup, slow query)
* Memory mapped file: 265k searches/second. (Fast startup, fast query)
* Memory cache: 281k searches/second. (Slow startup, fastest query)
אין תגובות »
נכתב על ידי עמרי בנושא Java, קוד פתוח
הPreprocessror שפיתחתי במסגרת העבודה של בVollee, שנכלל בפרוייקט הקוד הפתוח אנטנה (פרוייקט שעוזר בפיתוח ובבניה של ישומי ג’אווה למכשירים סלולריים), אושר על ידי Eclipse Legal, ויכלל בMTJ.
MTJ הוא פרוייקט Eclipse רשמי שמטרתו להוסיף לEclipse תמיכה בפיתוח ישומי ג’אווה למכשירים סלולריים. כבר היום יש את EclipseME, פלאגין שפותח במשך שנים על ידי קרייג סטרה, שעושה את אותה עבודה - למעשה וקרייג עובד עם צוות MTJ, וMTJ מיועד להיות תחליף רשמי של EclipseME.
תהליך הקליטה של הPreprocessor לא היה קל:
הקוד המקורי הסתמך על ANTLR 2.7 (שמייצר אוטומטית קוד לפענוח קוד לפי הגדרה פורמלית - Parser generator) - הבעיה עם ANTLR 2.7 היתה שהרשיון שלו לא תאם את הרשיון של Eclipse (מסתבר שPublic domain זה לא תמיד טוב מספיק). למרבה המזל, ANTLR 3.0 כבר שוחרר ברשיון BSD שתאם את הרשיון של Eclipse, אבל הוא לא תאם את הקוד של הPreprocessor.
החב’רה בMTJ שאלו אם אני מוכן להמיר את הקוד כך שישתמש בANTLR 3.0: בינתיים עזבתי את Vollee ואת כל העולם של הפיתוח לסלולריים (בשעה טובה ומוצלחת) אז סירבתי, אבל אמרתי שאשמח לייעץ להם ולעזור מרחוק.
הם הרימו את הכפפה, וכמעט בלי עזרה מפתח אחד - דייגו סנדין - המיר את העסק לANTLR 3.0 תוך כשבועיים.
הזמן עבר, ולפני חודשיים צוות MTJ קיבל אישור למסור לי את הקוד, כדי שאקלוט אותו לתוך Antenna.
מכיוון שהקוד כלל בדיקות יחידה מקיפות, שדייגו הקפיד להשתמש בהן כדי לבדוק את ההמרה - התוצאה היתה טובה מאוד.
עוז זמן עבר, והיום הקוד קיבל אישור מEclipse Legal ויכנס לענף הראשי של MTJ.
2 תגובות »
נכתב על ידי עמרי בנושא Java, קוד פתוח, תכנות
כשכותבים בדיקת יחידה (Unit test) לקוד שקשור לבסיס נתונים, צריך לאתחל את בסיס הנתונים לאיזה שהוא מצב ידוע ויציב לפני כל בדיקה.
מול MySQL, אפשר להשתמש בmysql עצמו כדי ליבא סקריפט SQL מוכן, אבל זה לא נחמד במיוחד:
צריך לפתוח תהליך חדש, ויש כל מני בעיות מעצבנות עם זה (בג’אווה למשל, חובה לקרוא את הפלט של התהליך, אחרת הוא יתקע בכתיבה לפלט הסטנדרטי כשיתמלא הבאפר).
הרבה יותר נחמד יהיה ליבא את הקובץ ישירות מתוך ג’אווה, בשימוש בJDBC, לא?
הנה קוד שעושה בדיוק את זה, הוא מקבל זרם קלט (InputStream) שיכול להיות כל דבר, וגם Connection JDBC שחיברתם מבעוד מועד, וקולט את הSQL לתוך בסיס הנתונים.
הקוד מתמודד עם הפלט הסטנדרטי של mysqldump.
public static void importSQL(Connection conn, InputStream in) throws SQLException
{
Scanner s = new Scanner (in );
s. useDelimiter(“(;(\r)?\n)|(–\n)”);
Statement st = null;
try
{
st = conn. createStatement();
while (s. hasNext())
{
String line = s. next();
if (line. startsWith(“/*!”) && line. endsWith(“*/”))
{
int i = line. indexOf(‘ ‘);
line = line. substring(i + 1, line. length() - ” */”. length());
}
if (line.trim().length() > 0)
{
st.execute(line);
}
}
}
finally
{
if (st != null) st.close();
}
}
2 תגובות »
אם יש משהו שאני אוהב בפרוייקטי קוד פתוח, זה שאנשים מוכנים לפעמים לעבוד די קשה כדי לשפר אותם.
את IP2C, ספריה למציאת המדינה של כתובת IP שחררתי לפני כמעט שנתיים, וכתבתי גם פוסט שמספר על המימוש שלה פה.
IP2C ממומשת בPHP ובג’אווה. מה שמיוחד בה זה שהיא מסוגלת לחפש ישירות על הקובץ, מה שאומר שחיפוש בודד הוא מאוד מהיר כי לא צריך להעלות את כל הקובץ לזכרון.
הייתי לגמרי מרוצה מהביצועים של הספריה בPHP (כ1200 חיפושים בשניה במחשב האחרון שמדדתי), אבל הביצועים בג’אווה היו טובים יותר משמעותית - כ8000 חיפושים בשניה על אותו מחשב בעבודה ישירות על קובץ הנתונים.
ההבדל בביצועים בין PHP לג’אווה לא הטריד אותי, כי היה לי ברור שPHP תהיה יותר איטית מג’אווה, אבל הוא כן הטריד את תומס רומר שהתיישב על העסק לילה שלם ושיפור את הביצועים של גרסאת הPHP ב150%.
תומס כתב פוסט מעניין על השינויים שהוא עשה, ושלח לי את השינויים. שבמבט ראשון נראים טובים ואני אקלוט אותם לפרוייקט אחרי בדיקה מעמיקה יותר.
בנוסף דיברנו קצת בIRC, והוא יעבוד על תמיכה בבסיס הנתונים של software77 :
software77 מספקים בסיס נתונים של IP למדינה, שאמור להיות יותר איכותי מבסיס הנתונים שIP2C משתמשת בו כרגע (webhosting.info), אבל יש להם קצת בעיות בעקביות המידע.
התחלתי לעבוד על תמיכה בבסיס הנתונים שלהם לפני כמה חודשים טובים, אבל כשראיתי שזה נמשך יותר מדי הקפאתי את העסק (שעדיין נמצא בTODO שלי, קבור איפשהו )
תומס ימשיך מאיפה שהפסקתי.
אין תגובות »
נכתב על ידי עמרי בנושא Java, קוד פתוח, תכנות
הפוסט הזה מיועד למתכנתי ג’אווה שעובדים עם Eclipse.
אז אתם מתחילים פרוייקט, מפתחים, משתמשים בכל מני JARים מפרוייקטים אחרים בתוך הסביבת עבודה, מוסיפים פרוייקטים אחרים לרשימת התלויות של הפרוייקט שלכם, והכל עובד בתוך Eclipse.
ואז אתם צריכים לשחרר JAR שירוץ מחוץ לסביבת הפיתוח שלכם.
פה יש כמה אפשרויות:
1. להשתמש באופצית הExport JAR של Eclipse.
2. ליצור build.xml לפרוייקט
לפרוייקטים פשוטים, האפשרות הראשונה תספיק, אבל היא בהחלט לא עושה נעים בבטן. כדי ליצור את הJAR חייבים את Eclipse, וזה לא מאוד מיקצועי.
האפשרוית השניה היא מה שכמעט כולם עושים:
בדרך כלל מעתיקים build.xml מהפרוייקט השכן, ומתחילים לעקם אותו עד שיתאים לפרוייקט הנוכחי.
על הדרך עוד פעם מוסיפים - הפעם לbuild.xml החדש - את המסלול לJARים שהפרוייקט צריך כדי להתקמפל, ואולי גם את המסלול לספריות הbin של פרוייקטים אחרים שהפרוייקט הזה צריך, או אולי פשוט קריאה לקובץ הbuild.xml של הפרוייקטים האלו, ואז שימוש בתוצרים שלו.
אחרי זמן שיקח בין חצי שעה לחצי יום, תלוי בבלאגן שיש לכם בפרוייקט, כנראה תהיה לכם מערכת build עובדת לפרוייקט, שעושה בדיוק מה שאתם רוצים.
תהיה לכם תחושה נעימה בבטן, כי תוכלו לבנות את הפרוייקט שלכם מחוץ לEclipse (וככה גם אחרים אם בניתם את העסק נכון).
אבל מה, הפרוייקט ממשיך לחיות:
עם הזמן, נוספים לו תלויות בJARים נוספים, תלויות בפרוייקטים נוספים בסביבת העבודה וכו’, ואז מערכת הבילד המדוגמת שלכם נשברת, ואתם מרגישים פיכס, כי שוב אי אפשר לבנות את העסק מחוץ לEclipse עד שתתקנו את הבילד.
הפעם בדרך כלל העידכון של הבילד הוא יותר פשוט, כמה דברים קטנים והכל עובד שוב.
עכשיו, תכפילו את כל העסק הזה במספר הפרוייקטים שאתם מפתחים אקטיבית על פני כמה שנים, ומתחיל להיות פה משהו די מעצבן.
הרבה קבצי build.xml שעושים כמעט אבל לא בדיוק את אותו דבר, והרבה התעסקות איתם ברגע שמשהו משתנה.
המפתח העצלן כבר מזמן שאל את עצמו: “מה, אין דרך אחרת?”
הרי לרוב הפרוייקטים, Eclipse מכיל את כל המידע שצריך בשביל לבנות אותם.
מעבר לזה, המידע הזה תמיד נכון בהגדרה כי אחרת לא תוכלו לפתח כלום וזה יהיה הדבר הראשון שתתקנו ברגע שתעשו איזה שינוי.
Eclipse שומר את רוב המידע בתוך קבצי ה.claspath בתוך כל פרוייקט (וגם קצת בתוך קבצי ה.project). הקבצים האלו הם קבצי XML פשוטים למדי, שלא השתנו משמעותית מאז ימי Eclipse הראשונים.
אז הנה רעיון:
מה אם במקום לשכפל את המידע גם בEclipse וגם בbuild.xml, ניצור build.xml אחד שקורא את המידע על הפרוייקטים מEclipse, מבין מה סדר הבניה הנכון של הפרוייקטים, איזה JARים צריך לכל פרוייקט ובונה את העסק לפי זה?
אותו build.xml קסום ומופלא יעבוד כמעט לכל פרוייקט Java שפותח בתוך Eclipse בצורה שקופה, בלי שום התעסקות ותחזוקה של קובץ build.xml ספציפי לפרוייקט.
נשמע טוב מכדי להיות אמיתי?
ובכן, שחררתי מערכת כזו בדיוק, ולמערכת קוראים ebuild.
התחלתי לפתח אותה לפני שנים, והיא ליוותה אותי דרך ארבע מקומות עבודה עד עכשיו (למעשה דרך כל מקומות העבודה שהיו לי בתחום ההיטק).
המערכת משוחררת תחת רשיון FreeBSD (רשיון תעשו מה שבזין שלכם, לא מזיז לי) ודף הבית שלה הוא http://ebuild.firefang.net.
בגדול, כדי להשתמש בה, מה שצריך לעשות זה:
- לקחת את הקוד שלה ולהכניס לפרוייקט נפרד בסביבת העבודה.
- להעתיק את example-common.properties לcommon.properties (הוא מכיל הגדרות ספציפיות למחשב שלכם, למרות שכרגע אין מה להתעסק איתו ברוב המקרים).
- ליצור קובץ build.properties בתוך הפרוייקט שאתם בונים (מאוד פשוט ומינימלי)
- להריץ עם ant -Dproject=YOUR_PROJECT, כאשר YOUR_PROJECT הוא השם שם הפרוייקט שלכם בסביבת העבודה.
- לקחת את התוצרים האיכותיים מספרית הbuild שנוצרה תחת הפרויקט.
התוצר יהיה JAR שניתן להריץ בעזרת java -jar file.jar, וכן זיפ שכולל את הJAR ואת הספריות הדרושות כדי להפיץ את התוכנית.
נכון לכרגע, המערכת די בסיסית ומסוגלת לבנות פרוייקטי Eclipse בתוך סביבת העבודה (Workspace) שלכם.
בהמשך אני מתכנן להוסיף אפשרות לתייג פרוייקטם ולבנות ישר מCVS/SVN בלי לגעת בקוד בסביבת העבודה (זה דרוש כדי לשחרר גרסאות בצורה מסודרת).
בנוסף, אני מתכנן להוסיף אפשרות לebuild-hook.xml אופציונלי שיהיה ספציפי לפרוייקט שיכיל כל מני דברים שבאמת ספציפיים לפרוייקט מסויים.
יש כמה דברים שכדאי לדעת:
באופן כללי, עדיף לעבוד עם JARים שנמצאים בתוך בworkspace כי אז החיים של מי שרוצה לבנות את העסק הם יותר קלים.
- ebuild תומך בזה בצורה טובה, אבל לא ברור לי אם הוא יתמודד עם JARים חיצוניים.
- ebuild לא תומך בכל מני הרחבות מוזרות של eclipse, שמסתמכות על מידע שלא מופיע בקבצי ה.classpath. למשל ‘user libraries’. אם אתם רוצים שהוא יעבוד בשבילכם, תעבדו פשוט.
זהו.
אני אשמח אם הרבה אנשים ישתמשו בebuild, ידווחו על בעיות ואולי אפילו ישלחו תיקונים.
2 תגובות »
נכתב על ידי עמרי בנושא Java, מחשבים, תכנות
כולם יודעים שC יותר מהירה מג’אווה, נכון?
פרוייקטים רציניים של גריסת מספרים (Number crunching) כמו עיבוד תמונה בזמן אמת, זיהוי קול, רינדור, דחיסה, קידוד ווידאו וכו בדרך כלל נכתבים בC (או C++).
בהינתן שתי פיסות קוד שעושות בדיוק את אותו דבר, מעניין לראות את במה מתבטא היתרון של C על ג’אווה.
למה אפשר לצפות ליתרון?
כי ג’אווה רצה מעל JVM, והJVM מוסיף תקורה, ברור שC תרוץ יותר מהר כי היא רצה ישר על הCPU ולא דרך הJVM.
הנה שתי פיסות קוד, אחת בג’אווה ואחת בC. שתי התוכניות מאתחלות שתי מטריצות גדולות ומכפילות אותן אחת בשניה, הקוד בהחלט לא יעיל במיוחד ברמת האלגוריתם, אבל הוא זהה מבחינה מימושית.
הנה הקוד:
תוכנית C:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int i,j,k;
int N = 2500;
printf(“N = %d\n“, N);
double *A = malloc(N*N*sizeof(double));
double *B = malloc(N*N*sizeof(double));
double *C = malloc(N*N*sizeof(double));
double *bj = malloc(N*sizeof(double));
for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
{
int n = i*N+j;
A[n] = i * j;
}
for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
B[i*N+j] = i * j * j;
// order 7: jik optimized ala JAMA
for (j = 0; j < N; j++) {
for (k = 0; k < N; k++)
bj[k] = B[k*N+j];
for (i = 0; i < N; i++) {
double s = 0;
for (k = 0; k < N; k++) {
s += A[i*N+k] * bj[k];
}
C[i*N+j] = s;
}
}
printf(“done\n“);
return 0;
}
תוכנית ג’אווה:
public class Matrix
{
public static void main (String[] args )
{
int i,j,k;
int N = 2500;
System. err. println(“N = “ + N );
double A [] = new double[N*N ];
double B [] = new double[N*N ];
double C [] = new double[N*N ];
double bj [] = new double[N ];
for (i = 0; i < N; i++ )
for (j = 0; j < N; j++ )
{
int n = i*N+j;
A [n ] = i * j;
}
for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
B[i*N+j] = i * j * j;
// order 7: jik optimized ala JAMA
for (j = 0; j < N; j++) {
for (k = 0; k < N; k++)
bj[k] = B[k*N+j];
for (i = 0; i < N; i++) {
double s = 0;
for (k = 0; k < N; k++) {
s += A[i*N+k] * bj[k];
}
C[i*N+j] = s;
}
}
System.err.println(“done”);
}
}
מי לוקח התערבות של בכמה C עוקפת את ג’אווה בזמן הריצה של זה?
נקמפל ונבדוק:
$javac Matrix.java
$gcc Matrix.c -o matrix
$ date;java Matrix;date;./matrix;date
Thu Jun 26 08:42:10 IDT 2008
N = 2500
done
Thu Jun 26 08:42:54 IDT 2008
N = 2500
done
Thu Jun 26 08:44:31 IDT 2008
לתוכנית בג’אווה לקח לקח 44 שניות ולתוכנית בC לקח 107 שניות.
מש”ל.
אה, רגע. רצינו להראות שC יותר מהירה!
טוב, מסתבר שלא כדאי לקחת דברים כמובנים מאליהם, גם אם כולם יודעים שהם נכונים.
אם אתם חושבים שרימיתי, תריצו בעצמכם. בדקתי על שני מחשבים, אחד עם שתי ליבות של 3GHZ, ואחד עם ארבע ליבות של 2.4GHZ (כמובן שהראשון הוביל בכמה אחוזים טובים, אבל היחס נשמר).
השתמשתי בJava 1.6.06.
לדעתי התופעה הזו נובעת מההתקדמות המדהימה של סביבת הריצה של ג’אווה בתחום הHotspot.
Hotspot היא טכנולוגיה שמקמפלת חלקים “חמים” בתוכנית בזמן, אבל בזמן ריצה. מכיוון שזמינות לHotspot סטטיסטיקות בזמן הריצה הממשי של התוכנית היא יכולה לשנות את הקוד ככה שירוץ בצורה אופטימלית לאור התנהגות של התוכנית ולא כנסיון מלומד לנחש מה יהיה יותר מהר מהתבוננות ושינוי הקוד, מה שעושה קומפיילר סטאטי.
עדכון:
קימפלתי את התוכנית C עם אופטימיזציה מקסימלית והתוצאה שלה השתפרה פלאים:
gcc -O3 Matrix.c
$ date;./matrix;date
Thu Jun 26 11:26:00 IDT 2008
N = 2500
done
Thu Jun 26 11:26:29 IDT 2008
הפעם התוצאה של C היא 29 שניות.
טוב משמעותית מקודם, וגם יותר מהיר בכ30% מג’אווה.
עדכון 2:
שמתי לב שקוד שקומפל עם javac איטי מקוד שקומפל בeclipse. נחשתי שeclipse מקמפל עם jikes (אני לא בטוח בזה).
ניסיתי עם jikes והתוצאה השתוותה, תיקו 29 שניות.
$ javac Matrix.java ; time java Matrix
N = 2500
done
real 0m42.854s
user 0m55.335s
sys 0m26.214s
$ jikes –bootclasspath /usr/lib/jvm/java-6-sun-1.6.0.06/jre/lib/rt.jar Matrix.java ; time java Matrix
N = 2500
done
real 0m29.463s
user 0m29.366s
sys 0m0.108s
אגב, זו תוצאה מדהימה שכדאי שכל מפתח ג’אווה יכיר.
מי רוצה לשפר את התוצאות עוד?
14 תגובות »
נכתב על ידי עמרי בנושא Java, קוד פתוח, תכנות
אחרי ניג’וסים ונדנודים, החברים בTorrentLeech בדקו את TorrentLeech2RSS ואישרו אותו לשימוש (כאילו, יכלתי לשחרר אותו בלי לומר להם, אבל אז הם היו משעים לי שוב את החשבון).
אז בקיצור, מי שרוצה להוריד, שיתכבד ויפנה לבלוג של הפרוייקט.
7 תגובות »
לפני כמה שבועות הפיד RSS של TorrentLeech (להלן TL), ספק הסדרות העיקרי שלי, התחיל להחזיר 404 (דף לא נמצא).
אין פה שום דבר חדש, הפיד הזה אף פעם לא היה יציב במיוחד, לכן חיכיתי בסבלנות כשבוע, ואז התלוננתי בערוץ הIRC שהלינק של הפיד לא עובד.
גורם “רשמי” מסר לי שהפיד לא יחזור כי השתמשו בו לרעה.
ניסיתי לברר את פשר השימוש הפוחז, ואפילו הצעתי את עזרתי במציאת פיתרון, אך לשוא:
הילדון זב החוטם מסר שלא משנה מה אני אגיד או אעשה, הפיד לא חוזר.
הסברתי לו בדרכי נועם שאם המידע זמין באתר, אין שום הבדל כי אפשר להפוך אותו לפיד, אבל זה לא עזר.
אז החלטתי לעשות בדיוק את זה, וכך נולדה תוכנה חדשה - TorrentLeech2RSS.
בגדול, הרעיון הוא כזה:
שרת מקומי דוגם את TL, נניח פעם בחצי שעה.
השרת נכנס לTL, מזדהה עם שם המשתמש והסיסמא של המשתמש בTL, מוריד את דף הHTML שמכיל את רשימת הטורנטים בכל אחת מהקטגוריות הנבחרות, מפענח את הדף, ומחלץ ממנו את השם, הלינק, המזהה והתאריך של כל טורנט, ושומר אותם בזכרון.
במקום להשתמש בכתובת הRSS של TL (שאינה עימנו עוד), המשתמש מכניס כתובת של TorrentLeech2RSS, שמכין דף RSS ומחזיר אותו למבקש.
TorrentLeech2RSS גם משכתב את הלינקים בתוך הRSS שיעברו דרכו, כדי שיוכל להוסיף פרטי הזדהות שיעברו לשרת של TL ברגע שהמשתמש מנסה להוריד טורנט (אחרת הTracker של TL לא משתף פעולה עם המשתמש).
בחרתי לכתוב את tl2rss בשפת ג’אווה.
הצעד הראשון, וכנראה הכי קשה בתהליך, הוא להכנס תכנותית לאתר, התהליך מורכב יחסית וכולל כמה שלבים.
כדי להבין מה אני אמור לשלוח ומתי, השתמשתי בWireShark, וניטרתי את התעבורה שנוצרת כשאני מבצע לוגין בעזרת הדפדפן.
שימו לב במיוחד לאפשרת של Follow TCP Stream, שמציגה שיחת HTTP שלמה בצורה ברורה.
ברגע שהקוד הצליח להזדהות מול השרת, לבקש דף שמתאים לקטגוריה רלוונטית זה קל. אבל מה עושים עם הדף?
הדפים של TorrentLeech הם דוגמא לאיך נראה קוד HTML מבולגן ולא תקני, ערבוביה של תגיות HTML שכוללות תוכן, עיצוב ועימוד.
בקיצור, לא משהו שכיף במיוחד לחפוש בתוכו אחרי מידע.
הגישה הנאווית לבעיות כאלו היא שימוש בביטוי רגולרי, אבל זה לא יעבוד טוב בכל המקרים (מה קורה למשל אם יש HTML בתוך התאור של הטורנט?).
בחרתי ללכת לגישה טיפה יותר חזקה, והיא פירוק מלא של הHTML למבנה נתונים בזכרון, וניתוח של אותו מבנה.
ספרית ג’אווה שמאפשרת parsing כזה לHTML היא htmlparser הוותיקה.
אבל גם אם htmlparser מחזירה לנו עץ אובייקטים נוח, איך מוציאים ממנו את מה שמעניין? הוא ענק וסבוך ויותר מכל מסובך.
למזלי מצאתי בונה פילטרים ויזואלי עם htmlparser. אפשר להריץ אותו עם Java web start:
javaws http://htmlparser.sourceforge.net/samples/filterbuilder.jnlp
או פשוט להריץ את הקוד ישירות (org.htmlparser.parserapplications.filterbuilder.FilterBuilder). עורך הפילטרים מאפשר ליצור פילטרים מורכבים בהדרגתיות תוך בדיקה מתמדת של התוצאה על דף הHTML שאתם רוצים לבדוק.
אזהרה: הוא לא הכי ידידותי בעולם, לוקח זמן להתרגל אליו - אבל הוא עובד.
לדוגמא, נניח שאנחנו רוצים לחלץ את רשימת השחקנים מהסרט ביוולף בIMDB.
קודם נכניס בשורה התחתונה את הURL, אחר כך נלחץ על fetch page, ואז נקבל את הHTML כעץ בחלק הימני.

ברגע שיש לנו את הHTML, נתחיל לפלטר. חיפוש קצר אחרי שם של אחד השחקנים (Musician #2) מצא את הטבלא, ולמרבה הנוחות אפשר לראות שclass הCSS שלה הוא cast. זה מצויין, כי זה יאפשר לנו לדוג את הטבלא בקלות:
נוסיף פילטר של תכונות (attributes), נכניס בו את התכונה class עם הערך cast.
קליק ימני על הפילטר, execute filter, ונקבל חלון קטן בצד ימין עם התוצאות.
בינגו, יש לנו את הטבלה.

אבל אנחנו רוצים רק את רשימת השחקנים, אז צריך לעדן את הפילטר.
נוסיף שאנחנו רוצים רק טגים בשם TR, שיש להם הורה שהוא טבלא עם תכונה של class שערכו cast:

אפשר להמשיך, אבל הרעיון - אני מקווה - ברור.
ברגע שאנחנו מרוצים מהפילטר שיצרנו, אפשר לשמור אותו.
זה מה שיוצא (גרסא מקוצרת):
// Generated by FilterBuilder. http://htmlparser.org
// [aced0005737200206f.......17374]
import org.htmlparser.*;
import org.htmlparser.filters.*;
import org.htmlparser.beans.*;
import org.htmlparser.util.*;
public class imdb
{
public static void main (String args[])
{
TagNameFilter filter0 = new TagNameFilter ();
filter0.setName (“TR”);
HasAttributeFilter filter1 = new HasAttributeFilter ();
filter1.setAttributeName (“class”);
filter1.setAttributeValue (“cast”);
HasParentFilter filter2 = new HasParentFilter ();
filter2.setRecursive (false);
filter2.setParentFilter (filter1);
NodeFilter[] array0 = new NodeFilter[2];
array0[0] = filter0;
array0[1] = filter2;
AndFilter filter3 = new AndFilter ();
filter3.setPredicates (array0);
NodeFilter[] array1 = new NodeFilter[1];
array1[0] = filter3;
FilterBean bean = new FilterBean ();
bean.setFilters (array1);
if (0 != args.length)
{
bean.setURL (args[0]);
System.out.println (bean.getNodes ().toHtml ());
}
else
System.out.println (“Usage: java -classpath .:htmlparser.jar:htmllexer.jar imdb <url>”);
}
}
בראש הקובץ יש קידוד של הפילטר, מה שמאפשר לנו לטעון את הקובץ ולהמשיך לעבוד עליו מאותה נקודה.
כדי לקמפל את זה צריך כמובן את htmlfilter.jar בclasspath.
טוב, אז נניח שכתבנו פילטר מתאים, וגיבינו אותו בקצת קוד שמוציא את הנתונים לרשימה נוחה.
איך הופכים את זה לRSS?
בקלות, בעזרת ספרית ג’אווה בשם Rome.
השימוש ברומא פשוט מאוד, הנה דוגמא:
public String getListRSS () throws FeedException
{
SyndFeed feed = new SyndFeedImpl ();
feed. setFeedType(“rss_2.0″);
feed. setTitle(“My RSS!”);
feed. setLink(“http://firefang.net/blog/768″);
feed. setDescription(“A feed for you!”);
List entries = new ArrayList();
feed. setEntries(entries );
Vector v = new Vector();
v. add(“item1″);
v. add(“item2″);
v. add(“item3″);
for (int i = 0; i < v. size(); i++ )
{
SyndEntry entry = new SyndEntryImpl ();
entry. setTitle((String) v. elementAt(i ));
entry. setLink(“http:://imdb.com/”);
entries. add(entry );
}
SyndFeedOutput output = new SyndFeedOutput();
return output.outputString(feed);
}
שמפיקה את הRSS הזה:
<?xml version=“1.0″ encoding=“UTF-8″?>
<rss xmlns:content=“http://purl.org/rss/1.0/modules/content/” xmlns:taxo=“http://purl.org/rss/1.0/modules/taxonomy/” xmlns:rdf=“http://www.w3.org/1999/02/22-rdf-syntax-ns#” xmlns:dc=“http://purl.org/dc/elements/1.1/” version=“2.0″>
<channel>
<title>My RSS!</title>
<link>http://firefang.net/blog/768</link>
<description>A feed for you!</description>
<item>
<title>item1</title>
<link>http:://imdb.com/</link>
<guid>http:://imdb.com/</guid>
</item>
<item>
<title>item2</title>
<link>http:://imdb.com/</link>
<guid>http:://imdb.com/</guid>
</item>
<item>
<title>item3</title>
<link>http:://imdb.com/</link>
<guid>http:://imdb.com/</guid>
</item>
</channel>
</rss>
אז עכשיו שאנחנו יודעים לקחת דף HTML ולהוציא ממנו טקסט של RSS, נשאר רק לאפשר לקורא RSS רגילים לגשת אליו.
הדרך הטבעית תהיה להריץ שרת ווב קטן, שיגיש את קובץ הRSS למי שמבקש.
בחרתי להשתמש בJetty, שהוא שרת ווב קטן וגמיש בג’אווה, שמאפשר גם שילוב פשוט וקל בתוך אפליקציות אחרות.
לא להבהל מגודל ההורדה שלו, כדי להשתמש בו בתוך האפליקציה שלכם מספיק לקחת שלושה Jarים בגודל כולל של כ700K.
ככה משלבים את Jetty בתוך הישום שלכם, שימו לב כמה שזה פשוט.
Handler handler= new AbstractHandler ()
{
public void handle (String target, HttpServletRequest request, HttpServletResponse response, int dispatch )
throws IOException, ServletException
{
response. setContentType(“text/html”);
response. setStatus(HttpServletResponse. SC_OK);
response. getWriter(). println(“<h1>Hello</h1>”);
((Request)request ). setHandled(true);
}
}
Server server = new Server(8080);
server.setHandler(handler);
server.start();
כדי לגשת אליו, נפתח את הדפדפן על http://localhost:8080 במקרה שלנו.
עכשיו רק נשאר לקשור את החוטים ביחד.
פתחתי בלוג קטן לפרוייקט, וחיש מהר החשבון שלי בTorrentLeech הושעה. כשביררתי מה הסיפור נאמר לי שהם חוששים שאני אגנוב למשתמשים סיסמאות.
הצעתי להם לבדוק את הקוד, ושעד אז אני אוריד את הלינק, וכך עשיתי, והחשבון שלי שוחזר.
בינתיים הם עדיין לא חזרו אלי, והסבלנות קצת פקעה.
מי שרוצה להוריד את הקוד יכול להוריד אותו מפה עם לקוח Subversion.
מי שרוצה להוריד את הבינארי מוזמן להוריד אותו מפה.
יש הוראות שימוש בתוך קובץ הREADME.
tl2rss משוחרר תחת רשיון GPL-3.0.
10 תגובות »
נכתב על ידי סשה בנושא Java, אינטרנט, מחשבים, תכנות
לאחר חודשים של עבודה מפרכת שחררתי היום את ספרית המפות מבוססת ה-Google Web Toolkit שלי. הספריה מאפשרת פיתוח אפליקציות web עם מפות בשפת Java (החביבה עלי וכן על עמרי עד מאוד), כשם ש-Google Maps API מאפשר זאת למפתחי JavaScript.
לאחר נסיוני המר עם ה-GPL פרסמתי את ספרית המפות תחת ה-CC BY-NC-SA.
יום הולדת שמח, עמרי, ותהנה מהאוגרים!
12 תגובות »
מפתחי ג’אווה שמפתחים למכשירים סלולאריים הם עם די מסכן, יש בעיות שונות ומשונות במכשירים מסויימים, ואם אתם רוצים שהישום שלכם יעבוד בכל המכשירים צפויה לכם דרך קשה ומייגעת.
ללא ספק, החברה שמייצרת את המכשירים השנואים ביותר עלי אישית היא מוטורולה.
למרות שהמכשירים החדשים של מוטורולה (RAZR2-V9 שמריץ לינוקס, V6 ואפילו V3) הם מכשירים חזקים, עתירי זכרון ועם תקשורת נתונים מהירה מאוד, הם עדיין שנואים במיוחד.
איך זה?
הבעיה עם מוטורולה, היא שלמרות שהם מייצרים מכשירים עם חומרה מצויינת, התוכנה שלהם היא לא פחות מפיגוע רב נפגעים.
הבעיות מתחילות בממשק מעצבן ולא אינטואיטיבי (נסו לקבוע דף בית לדפדפן, או להעלות אפליקציית ג’אווה דרך הכבל USB), וממשיכות במגוון באגים במכשירים.
HTTP 100
HTTP 1.1 תומך בקוד תגובה 100, שאומר לקליינט להמשיך לקרוא הלאה. השרת יכול לשלוח את זה אם הוא רוצה אחרי שהוא קרא את הכותרות של הבקשה, והלקוח אמור להמשיך את הבקשה אוטומטית בצורה שקופה למתכנת.
הבעיה היא שמוטורולה לא עובדים לפי הפרוטוקול, ומחזירים לאפליקציה את הקוד 100, ומשם התגובה האמיתית של השרת כבר אבודה.
יש פתרון שמצליח לעקוף את הבעיה הזו, והוא האק בקנה מידה בין לאומי. לא משהו שהייתם מכניסים לאפליקציה (ולשרת) אם לא היו מאיימים עליכם שיחליפו את המכשיר האישי שלכם למוטורולה.
כתיבה של קבצים בRAZR2
RAZR2 הוא המכשיר החדש ביותר של מוטורולה, והוא מריץ לינוקס. לכאורה, הזדמנות פז למוטורולה להוציא תוכנה פחות מסריחה.
איכשהו, מוטורולה הצליחו ליצור באג בכתיבה של קבצים בשימוש בFileConnection.
הבאג ממש ביזארי, וגרם לכך שלפעמים קבצים שתכתבו לא יכתבו כמו שצריך למערכת הקבצים.
הבאג מופיע בעיקר כשוכתבים “הרבה” נתונים במכה, למשל:
byte buf [] = new byte[20000]; // create buffer
for (int i = 0; i < buf. length; i++ ) buf [i ] = (byte) i; // populate with some crap
FileConnection conn = (FileConnection ) Connector. open(“file:///…”); // open file connection
OutputStream out = conn. openOutputStream(); // open output stream
out. write(buf ); // write buffer to file
// cleanup
out. close();
conn. close();
conn = (FileConnection) Connector.open(“file:///…”); // open file connection again
InputStream in = conn.openInputStream();
// read, you are in for a surprise
פתרון שעובד לבעיה המוזרה הזו הוא לכתוב את הקובץ בכמה חתיכות יותר קטנות, למשל:
private void writeChunked (byte[] buffer, OutputStream out ) throws IOException
{
final int MAX = 4096;
int offset = 0;
while (offset < buffer. length)
{
int chunkSize = (buffer. length - offset > MAX ? MAX : buffer. length - offset );
out. write(buffer, offset, chunkSize );
offset += chunkSize;
out. flush();
}
}
ממשק לעיון בקבצים
מוטורולה לא מספקים ממשק לעיון במערכת הקבצים על הפלאפון, רק משהו מוגבל שמאפשר גישה לתמונות ומדיה בלבד.
זה מראה שהם מפחדים מהמשתמשים שלהם, ולא סומכים על מערכת ההפעלה שלהם שתעמוד בפני משתמש חקרן.
אם במכשירים מהדור הקודם אפשר איכשהו לעיין בקבצים באמצעות MIDWay הזוועתית (תוכנה לניהול של מכשירי מוטורולה), בגרסאות החדשות (לינוקס) זה לא עובד עדיין.
הגבלות משאבים מגוחכות
במוטורולות למיניהן, אין אפשרות לפתוח יותר מארבעה חיבורי רשת בו זמנית. זה אולי נשמע הרבה, אבל זה לא.
הרבה ישומים נאלצים להתעקם בגלל המגבלה הזו.
בעיה נוספת היא שאי אפשרת לפתוח יותר מ14 קבצי קול בו זמנית (ליתר דיוק, 14 Players).
אפליקציות שמנגנות אפקטים קוליים טוענות בדרך כלל את הצלילים מראש כדי לנגן אותם מהר בעת הצורך. במוטורולה החליטו ש14 זה מספיק, מה שמכריח אפליקציות עתירות סאונד לקפוץ דרך חישוקי אש נוספים.
חוסר יציבות
זה אולי ישמע כמו התבכיינות, במיוחד למפתחי סלולארי שרגילים לקריסות (BREW, Symbian), אבל קל מאוד לגרום למכשירי מוטורולה לקרוס.
מספיק לפתוח ולא לסגור יותר מדי קבצים. במקום לקבל איזו שגיאה סבירה, המכשיר זורק במקרה הטוב “IOException : native error” ובמקרה הפחות טוב פשוט נתקע לחלוטין.
תמיכה במקשים
שינאה מיוחדת גורמת התמיכה במקשים במכשירי מוטורולה.
הקודים של המקשים שונים מהקודים של יצרני סלולאר אחרים, ואם על זה אני מוכן לסלוח, אני הרבה פחות סלחן כשמדובר בהבדלים בקודי הלחיצה בין מכשירי מוטורולה שונים, כשלפעמים ההבדל היחיד בינהם הוא מאיזה ספק נרכש המכשיר.
זה בהחלט גורם לצער ויגון לא מבוטל למפתחי משחקים.
בעית מקשים נוספת היא התמיכה הצולעת במצב שהמשתמש לוחץ על שני כפתורים בו זמנית.
במכשירים מסויימים, למשל V9m, האפליקציה מקבלת שני ארועי “מקש נלחץ” וארוע יחיד של “מקש שוחרר”, במכשירים אחרים בכלל לא מקבלים ארועים על הכפתור השני שנלחץ.
התממשקות למחשב
מוטורולה עדיין לא הבינו שחיבור בממשק של מודם (פקודות AT) פס מהעולם, וישום הניהול שלהם - MIDWay (המשוקץ) מתחבר למכשיר ממש כאילו הוא מודם. מי שזוכר את המחלות של מודמים (מה הערוץ הCOM? מה הBaud rate? שיט, העכבר לא זז, שיט הCOM נתקע וצריך לאתחל את המחשב) ירגיש כמו בבית.
ההתקנה של ישומי ג’אווה היא ממש מציקה:
כדי להתקין, צריך לחפור בתפריטי המכשיר למצוא אפשרות נסתרת שמעבירה את המכשיר למצב טעינת ג’אווה, להפעיל אותה, ורק אז לחבר את הכבר נתונים (אם הוא היה מחובר כבר, צריך לנתק אותו! Serenity now!).
דבר מעצבן נוסף הוא שברגע שמחברים את המכשיר למחשב עם הכבל, ישום הג’אווה הפעיל - אם יש כזה, מושהה מיד ואי אפשר להריץ אותו.
למה? כי מוטורולה עושים כל מה שהם יכולים כדי לעלות למפתח הנואש על העצבים.
בלוטות’
התמיכה בבלוטות’ במכשירי מוטורולה חלקית ביותר, ולא מאפשרת פעולות טרויאליות כמו התקנה של תוכנת ג’אווה דרך בלוטות’, או עיון בקבצים שעל המכשיר.
כמיטב המסורת, לקראת שנת 2008, מוטורולה עדיין חוסמים את המשתמשים ואת המפתחים מכל דבר שמזכיר נוחות עבודה מול מכשירים אחרים.
יש לציין שיצא לי לעבוד עם מכשירי מוטורולה לראשונה לפני ארבע או חמש שנים, וכבר אז שנאתי אותם פחות או יותר מאותן סיבות.
מוטורולה הוציאו כמות מפחידה של מכשירים מאז, אבל לא תיקנו תקלות שמישות בסיסיות בשיטת העבודה עם המכשירים.
סיכום
אין ספק בליבי שמוטורולה מנסים, אבל משום מה הם לא מצליחים.
אולי המפתחים שלהם לא יוצלחים, ואולי יש בעיה בתרבות הארגונית שלהם שמונעת מאנשים לזהות או להגיב לחרא שהם מייצרים.
בכל מקרה, התוצאה זהה.
אני שונא את מוטורולה.
6 תגובות »
|