שידרוג נפח אכסון ZFS על גבי OpenSolaris

לפני קצת יוצר מחצי שנה קניתי מכונת אכסון, כשהתוכנית היתה להריץ עליה אופן סולאריס כדי להנות מפירות הZFS.
נהנתי מאוד, עד שהתחלתי להרגיש שקצת צפוף לי, אז החלטתי להרחיב את נפח האכסון.
מכיוון שהתצורה של הדיסקים דומה לRAID10 – גם MIRROR וגם STRIP, כל הרחבה צריכה לבוא בזוגות.
קניתי שני דיסקים של של סיגייט, בנפח של 2TB כל אחד, ובפוסט זה אתאר את התהליך של השדרוג.
אחרי הקטע המלכלך של לחבר את הדיסקים, הרצתי את הפקודה הבאה:
[code]
root@iron:~# zpool add storage mirror c10d0 c11d0
[/code]

זהו, השדרוג הסתיים.
הפקודה הזו אומרת, תוסיף לבריכת האיכסון שנקראת storage יחידה וירטואלית חדשה מסוג ראי, שבנויה מהדיסקים c10d0 וc11d0.
הפקודה לקחה שניה, ובתום השניה נוספו לי כ2TB נלנפח האכסון במכונה. לא צריך fdisk ולא צריך לפרמט.
ככה נראה הpool הראשי שלי כרגע, הוא מורכב מארבעה דיסקים מלאים ומשתי מחיצות שתופסות את רוב הנפח של שני הדיסקים הנותרים.
למעשה, אין לי מקום לעוד דיסקים במכונה, מה שאומר שבשדרוג הבא אני אעשה משהו שעדיין לא יצא לי לעשות: להחליף דיסקים קטנים בדיסקים יותר גדולים.

[code lang="bash"]
root@iron:~# zpool status storage
pool: storage
state: ONLINE
scrub: none requested
config:

NAME STATE READ WRITE CKSUM
storage ONLINE 0 0 0
mirror ONLINE 0 0 0
c8d0p2 ONLINE 0 0 0
c9d0p2 ONLINE 0 0 0
mirror ONLINE 0 0 0
c9d1 ONLINE 0 0 0
c8d1 ONLINE 0 0 0
mirror ONLINE 0 0 0
c10d0 ONLINE 0 0 0
c11d0 ONLINE 0 0 0
[/code]

ZFS זה כיף.

אבטחת מידע רגיש נגד מדליפים

הרבה מילים נכתבו ויכתבו על ענת קם שהדליפה מסמכים מלשכת הרמטכל אלוף פקוד מרכז.
אני רוצה לכתוב קצת על ההיבט האבטחתי של הפרשה.
אני אהיה בוטה ואומר שלדעתי ברגע שסומכים על מישהו שיעבוד בסביבה בה יש מידע רגיש, אין אפשרות למנוע ממנו ב100% להדליף החוצה.
יש אין סוף דרכים שאדם עם גישה למידע יכול להדליף אותו, ונסיון ליצור סביבה הרמטית שממנה לא יכול לדלוף מידע הוא נסיון עקר שנועד להכשל.
אז מה כן אפשר לעשות?
סיווג בטחוני של העובדים במתקנים רגישים, ובדיקות ביטחון שוטפות כחלק מהשגרה.
מידור גם הוא חשוב מאוד כדי למנוע מאנשים גישה מיותרת למידע רגיש, כי כאמור ברגע שהם נחשפו למידע הרגיש הם יכולים להדליף אותו.
השאלה היא האם ענת קם היתה צריכה גישה למידע, והתשובה היא שזה לא ברור.
לכאורה אין ספק שפקידה לא צריכה גישה לכל המידע, אבל יתכן מאוד שהיא עצמה הקלידה חלקים ממנו או שהיא שלחה אותו לכל מני גורמים בהוראת אלוף הפיקוד, ואז בהגדרה היא צריכה גישה כלשהי.
אפשר לטעון מהיום ועד מחרתיים שהיא היתה צריכה להיות ממודרת, שהמסמכים היו צריכים להיות מוצפנים וכו' וכו', ואולי אפילו זה המצב לגבי רוב החומר הרגיש, אבל יש מקרים לגיטימיים שבהם פקידה בלשכת האלוף תחשף לחומרים רגישים.
ואם לא היא, אז מישהו אחר.
ומה אם אלוף הפיקוד בעצמו ידליף מידע?
"מה, אתה טיפש? ברור שהוא לא ידליף", אני שומע אותכם אומרים.
ואתם צודקים, אנחנו סומכים עליו שהוא לא ידליף, וזה העניין.
אלוף הפיקוד סומך על הפקידות שלו, אחרת הוא לא יכול היה לעבוד.
ענת קם הפרה את האמון שניתן בה, התקלה היא שהיא הגיעה למקום שהיא הגיעה אליו ולא שהיא הצליחה להדליף מידע משם.

חלון מהיר

לפני כמה פוסטים שאלתי את השאלה הבאה:

נתון מערך בגודל NxN של פיקסלים כאשר כל הפיקסלים שחורים חוץ מאחוז מסויים מהם שאינו שחור ומפוזר באופן אקראי,
בהינתן קואורדינטה (x,y) מסויימת בתמונה, מצא במהירות את כל הנקודות שנמצאות בתוך חלון בגודל K על K (כאשר K קבוע בבעיה) שמרכזו (x,y), משהו כזה:

פעולת המציאה עצמה צריכה להיות מהירה מאוד, אבל מותר לעבד מראש את התמונה פעם אחת (בזמן סביר).

אז הנה הפתרון שלי:
נחלק את התמונה למשבצות בגודל KxK, ונשמור רשימה של כל הנקודות בכל משבצת.
כאשר מבקשים מאיתנו לתת את רשימת הנקודות בחלון מסויים, נסתכל בארבעת החלונות שהחלון הזה חותך ונסנן את כל הנקודות בארבעת החלונות שלא נמצאות בתוך החלון המבוקש.
זה הכל בעצם.
הביצועים של הפתרון הזה מעולים, כדי להכין את הגריד (Grid) נעבור על כל הפיקסלים בתמונה, ולכל נקודה נמצא בזמן קבוע את המשבצת שאליה היא שייכת.
כשממש מחפשים את הנקודות בחלון מסויים, נבדוק במקרה הגרוע 2K*2K פיקסלים (אם כל הנקודות לבנות) אבל במקרה הרגיל נבדוק הרבה פחות (ואם החלון לא מכיל נקודות כלל נדע את זה מהר מאוד).
זה הקוד של העיבוד המקדים:
[code lang="java"]
private static int [][][] buildgrid(byte[][] image, int width, int height, int gridSize)
{
int grid[][][] = new int[width / gridSize][height / gridSize][];
// count the number of points in each grid cell
int numpoints[][] = new int[width / gridSize][height / gridSize];
for(int x=0;x Byte.MIN_VALUE)
{
numpoints[x/gridSize][y/gridSize]++;
}
}
}

for(int x=0;x Byte.MIN_VALUE)
{
int gy = y/gridSize;
int gx = x/gridSize;
int list[] = grid[gx][gy];
if (list == null)
{
int np = numpoints[gx][gy];
list = new int[np * 2];
grid[gx][gy] = list;
numpoints[gx][gy] = 0;
}

list[numpoints[gx][gy]++] = x;
list[numpoints[gx][gy]++] = y;
}
}
}
return grid;
}
[/code]

הקוד הבא סופר את המספר הנקודות בתוך החלון שמרכזו (x,y)' שימו לב שהלולאות עוברות על ארבעה ריבועים בגריד בלבד:
[code lang="java"]
// window boundaries:
int rx1 = x – grid_size/2;
int ry1 = y – grid_size/2;
int rx2 = rx1 + grid_size;
int ry2 = ry1 + grid_size;

// top left grid cell (out of 2×2 group to be checked)
int gx = rx1 / grid_size;
int gy = ry1 / grid_size;

for(int grid_x=gx;grid_x= 0 && grid_x < gwidth;grid_x++) { for(int grid_y=gy;grid_y= 0 && grid_y < gheight;grid_y++) { int list[] = grid[grid_x][grid_y]; if (list == null) continue; for(int i=0;i= rx1 && dx < rx2 && dy >= ry1 && dy < ry2) { c++; } } } } [/code] יתכן שאפשר לשפר את הביצועים אם נחלק את הגריד לריבועים יותר קטנים ונכלול ריבועים שלמים שנופלים בתוך החלון בלי לבדוק כל נקודה באופן פרטני, אבל לא ניסיתי. הביצועים של הפתרון הזה די מטורפים. על Q6600 במהירות 2.4GHZ, עם תמונה בגודל 500X500 פיקסלים וחלון של 20X20, בדיקה של כמה זמן לוקח לספור את הפיקסלים בכל 250,000 החלונות האפשריים לקחה כ160 מילישניות, מה שנותן מהירות בדיקה של מעל 1500 חלונות במילישניה (או יותר ממליון וחצי חלונות בשניה), בלי תלות בגודל התמונה שנבדקת (על תמונה של 1000X1000 המהירות היתה דומה). האפלט הבאה מדגימה את האלגוריתם. אפשר להוריד אותה מפה. הקוד כלול בתוך הJAR (אפשר לפתוח את הJAR עם תוכנה לפתיחת קבצי ZIP).
בנוסף, האפלט יכולה לרוץ כתוכנית רגילה : java -jar fast_window.jar
אפשר ללחוץ בתוך האפלט כדי לסמן את הנקודות בחלון.


הדפדפן שלך לא תומך בג'אווה, ככה האפלט ניראית (רק שהיא אינטראקטיבית) :


JNotify 0.92

לפני כמה שנים טובות עבדתי בסטארטאפ קטן בשם Content Objects שנסגר זה מכבר.
בתקופתי שם פיתחתי ספרית ג'אווה בשם JNotify שמאפשרת קבלת ארועים על שינויים במערכת הקבצים בלינוקס ובחלונות (ואולי עוד בהמשך).
דאגתי שהקוד ישוחרר ברשיון קוד פתוח כפרוייקט סורספורג'.
החברה נסגרה (אחרי שעזבתי), אבל הקוד נשאר. לא ממש תחזקתי אותו, אבל נראה שאנשים השתמשו בו בכל זאת – למרות שהיו כמה בעיות די חמורות בגרסאת החלונות.

כדי לתת מה שהספריה נותנת, חייבים להשתמש בקריאה לפונקציות של מערכת ההפעלה.
בלינוקס העניין היה פשוט יחסית: קטע הקוד המקומי (native code) הוא מינימלי ביותר ומסתמך על inotfiy. הAPI שלו מאוד פשוט אבל הוא לא תומך בהאזנה ריקורסיבית ולכן רוב הקוד כתוב בג'אווה ונועד להוסיף יכולת לקבלת ארועים על ספריות באופן ריקורסיבי (צפיה בתת ספריה על כל בניה).

בחלונות העניין הפוך, קריאת המערכת ReadDirectoryChangesW תומכת בהאזנה ריקוסיבית, אבל השימוש בה מורכב ברמות שלא יאמנו והתיעוד של מייקרוסופט מחורבן ביחס ישר למורכבות הAPI. ולכן על חלונות רוב הקוד כתוב בC++ (כי אין דרך פשוטה להתממשק אל הAPI המקומי מג'אווה) אבל קוד הג'אווה הספציפי לחלונות פשוט מאוד.

מכיוון שהרבה יותר קל לכתוב ולדבג קוד ג'אווה מאשר קוד C++, המימוש ללינוקס היה הרבה יותר יציב מזה של חלונות – שנטה להתרסק או להתקע לעיתים נדירות בכל מני סיטואציות שלא הצלחתי לשחזר.

לפני כמספר שבועות פנה אלי משתמש של הספריה, והציע שאני אפתור בתשלום את הבאגים בגרסאת החלונות.
לאחר משא ומתן קצר הסכמנו על $100, וניסיתי את מזלי.
זה היה די קשה, אבל לבסוף הצלחתי לתקן את  הבאגים החמקמקים, ובנוסף לשפר את הביצועים של הספריה כך שלא תפספס אירועים גם על מחשבים חלשים.
אחרי שכמות השעות ההשקעתי בעניין עברה את מה שנראה לי מוצדק בעבור $100 הסכמנו גם להגדיל את הסכום ל$250 והיום שחררתי את הגרסא המתוקנת

$250 זה לא סכום שבאמת מכסה את כמות השעות שהשקעתי בתיקון הבאגים (אם הייתי לוקח סכום סביר לשעה), אבל זה בכל זאת פרוייקט קוד פתוח ואני מרוצה שתיקנתי את הבאגים האלו.

נודע לי מאותו משתמש שמישהו ביצע fork לספריה והוסיף לה תמיכה בMac.
פניתי אליו ונראה שהוא יצטרף לפרוייקט וישלב את התוספת שלו בקוד (שנכתב כך שיהיה קל מאוד להוסיף תמיכה במערכות הפעלה חדשות), ואולי גם יעזור עם באגים אחרים.

JNotify התעורר.

בעיית החלוקה ההוגנת (*למדיי)

אז הזכרתי באחר הפוסטים האחרונים את הבעיה הבאה:

בהנתן קבוצת S של n מספרים שלמים, איך נחלק אותה לk קבוצות כך שסכום המספרים בכל קבוצה הוא קרוב לסכום המספרים בקבוצות האחרות.
למשל:
אם

[code]
S = {2,2,3,2,3}
k=2
split(S,k)={{2,2,2},{3,3}}

S1={1,5,11,2,10}
k1=3
split(S1,k1)={{5,2,1},{10},{11}}
[/code]

עבור k=2 הבעיה היא בעצם בעיית תיק הגב (Knapsack)
.
בבעיה זו יש לנו תיק גב בגודל מוגבל, וערמת חפצים במשקלים שונים ובערכים שונים ועלינו לבחור תת קבוצה של החפצים שנכנסים כולם לתיק וערכם מקסימלי.
אם הערך של כל חפץ שווה למשקל שלו (נניח כל החפצים עשויים מזהב טהור), ונפח התיק הוא חצי מסכום המשקל של כל החפצים אז הבעיה שקולה לגמרי לבעיה שלנו עבור K=2, כי רשימת החפצים שבתיק שקולה לחלוקה של החפצים לשתי קבוצות (אלו שבתיק ואלו שמחוץ לתיק).

עבור k גדול מ2, הבעיה קשה יותר.
הפתרון שמצאתי פותר את הבעיה בצורה קרובה לאופטימלית (החלוקה לא תמיד הטובה ביותר, אבל קרובה מאוד), והוא גם פשוט למימוש ויעיל במיוחד.
בשמיעה ראשונה הוא ישמע פשוט מדי מכדי להיות נכון, ואתם יותר ממוזמנים להוכיח לי שאני טועה:
1. מיינו את רשימת המספרים בסדר יורד.
2. צרו k קבוצות ריקות
3. לכל איבר ברשימה הממוינת (בסדר יורד) הכניסו אותו לקבוצה הריקה ביותר.

זה הכל.
לא היה קל מדי למצוא דוגמא שבה האלגוריתם הפשוט הזה נותר תשובה שאינה אופטימלית, אבל למעשה הדוגמא הראשונה שלי למעלה היא דוגמא כזו. בחלוקה האופטימלית שתי הקבוצות בגודל שש. בחלוקה לפי האלגוריתם שלי הגדלים יהיו שבע וחמש.
ובכל זאת, השגיאה פה היא השגיאה המינימלית האפשרית בדוגמא הזו (Off by one).

אז מה אתם אומרים, יש לכם פתרון יותר טוב?
יש לכם דוגמא שמראה לי שהפתרון שלי הוא בעצם לא טוב?

והנה בעיה נוספת עליה אני ארחיב באחד הפוסטים הקרובים:
יש לכם תמונה שחורה בגודל N על N פיקסלים ועליה מפוזרים נקודות באופן אקראי. נניח משהו דומה כזה:


הבעיה היא כזו. בהינתן קואורדינטה (x,y) מסויימת בתמונה, מצא במהירות את כל הנקודות שנמצאות בתוך חלון בגודל K על K (כאשר K קבוע בבעיה) שמרכזו (x,y), משהו כזה:

הדרישה היחידה פה היא המהירות של הפעולה הזו. מותר לכם להשתמש בכמה זכרון שתרצו ולעבד את התמונה מראש כאוות נפשכם (כמובן, העיבוד מראש לא יכול להיות איטי מדי)
כשאני אומר מהר, אני מתכוון ממש מהר, גם עבור תמונות גדולות.

חיבור לתהליך ג'אווה מרוחק עם VisualVM למחשב שמוגן על ידי פיירוואל

עם השנים נוספו לג'אווה כלים סטנדרטיים שמאפשרים חיבור למכונה וירטואלית חיה, ובחינה של מה שקורה שם ככלי למציאת בעיות בזמן הריצה של תוכניות.

  • jps : מראה תהליכי ג'אווה
  • jstack : מציג את רשימת הת'רדים בתהליך ג'אווה, ומה כל אחד מהם עושה.
  • jmap: מאפשר שמירה לקובץ של תמונת הזכרון (heap dump) של תהליך ג'אווה. אפשר לבחון את הקובץ עם jhat או עם VisualVM.
  • jhat : מאפשר ניתוח קבצי heap dump שנוצרו בעזרת jmap.
  • jconsole : ממשק פשוט שמאפשר בחינה של שימוש הזכרון, שימוש בזמן מעבד ועוד.
  • visualvm: כלי חזק יותר מjconsole, שהחל מעדכון 18 של JDK 1.6.0 מגיע עם הJDK. ויז'ואל VM מאפשר גם ניתוח ביצועים פשוט (cpu and memory profiling).

כל הכלים האלו תומכים גם בגישה למכונה מרוחקת בצורה זו או אחרת, הבעיה היא שכמעט בלתי אפשרי להתחבר איתם למכונה שמוגנת בפיירוואל כי הם עובדים עם פורטים אקראיים.
אם עם כלי שורת הפקודה עוד אפשר להסתדר על שרת מרוחק (קל יותר להריץ jps ישירות על השרת מאשר לנסות לעשות את זה מרחוק), עם הכלים הגראפיים הסיפור כבר אחר.

VisualVM

אז איך בכל זאת אפשר להתחבר לתהליך ג'אווה מרוחק עם VisualVM?
התהליך קצת מורכב, ולכן אני אתעד אותו כאן:

על המחשב המרוחק:

1. צרו קובץ permissions.txt שיכיל את זה:

[code]
grant {
permission java.security.AllPermission;
};

[/code]

2. הריצו את jstatd (שמאפשר לתהליכים מרוחקים לקבל רשימה של מכונות ג'אווה שרצות על המכונה ולהתחבר אליהן) :

[code]

jstatd -J-Djava.security.policy=permissions.txt
[/code]

3. הריצו את התוכנית שלהם עם הפרמטר הבא:

[code]
java -Dcom.sun.management.jmxremote MainClass
[/code]

על המחשב המקומי:

1. צרו תעלות SSH לשרת כך:

[code]
ssh -D9696 -L1101:localhost:1099 your_server
[/code]
שימו לב שיש פה שתי 'תעלות':

  • תעלת TCP מ1101 אל 1099 בשרת המרוחק. זו תעלה שמאפשרת להתחבר אל הjstatd ישירות.
  • פרוקסי SOCKS5 שמאזין על פורט 9696

2. הפעילו את visualvm עם הפרמטרים הבאים :

[code]
visualvm -J-Dnetbeans.system_socks_proxy=localhost:9696 -J-Djava.net.useSystemProxies=true
[/code]

שאומרים לו להשתמש בפרוקסי SOCKS5 שהקמנו.

3. מתוך VisualVM, הוסיפו לחיבור המקומי חיבור לjstatd בפורט 1101.

זהו. הרבה יותר מסובך ממה שהייתי רוצה, אם מישהו מכיר דרך יותר פשוטה אני אשמח לשמוע.

מגה פוסט – שרת חדש, טיפוסי אישיות ועוד

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

שרת חדש

הגיעה התקופה הזו, שבה אני פחות מרוצה מההוסיטנג שלי ועברתי להוסיטנג חדש.

למעשה הייתי מרוצה מספיק מeSecureData (אליהם עברתי מHCOOP לפני פחות משנה וחצי).
מהירות התקשורת היתה קצת מאכזבת אבל לא היו יותר מדי תקלות.
אז למה עברתי?
במסגרת העבודה שלי בface.com (כן, אני עובד בface.com, לא חושב שיצא לי להזכיר את זה פה עד עכשיו) אני עובד מול חברת אכסון בשם CentralHost בסן דייגו, ומחזיק אצלם מספר לא מבוטל של שרתים. בשנה וחצי בשנה חצי שאני עובד שם, הייתי מאוד מרוצה מהם ומרמת התמיכה שלהם – אם כי המחיר שלהם הוא גבוה משמעותית מזה של eSecureData, לפחות למכונות החזקות שאני מחזיק שם במסגרת העבודה.
בכל אופן, יש לי יחסים מצויינים עם בעל החברה, וכששאלתי אם יש לו הצעה אלטרנטיבית שתאפשר לי להעביר את השרת שלי אליו הוא הסכים לתת לי מחשב באותו מחיר שאני מקבל בeSecureData – שזה $79 לחודש, עם יותר זכרון (4 ג'יגה במקום 2 ג'יגה), ושני הרדיסקים של 500 בתצורת רייד 1 (ראי, אם הרדיסק אחד מת לא קורה כלום ופשוט מחליפים אותו) לעומת הרדיסק אחד בלבד בשרת הישן.
העברתי בעזרתו את השרת למכונה החדשה, ולמעט שינויי הגדרות קטנים בשרת הDNS שאני מריץ, ובהגדרות הDNS ברשת הדומיינים שלי הכל פשוט עובד.
אני בטוח שיהיו עוד חבלי לידה, אבל אם אתם קוראים את זה, אתם עובדים מול השרת החדש.
אז כמו תמיד, יש לי מקום לאורחים. מי שחושב לעבור שרת למשהו יותר רציני מאיכסון משותף בגודדי שיצור קשר. (רק לאנשים שמרגישים בנוח עם SSH).

BoneCP

השתמשתי בProxool בתור Connection pool לבסיס הנתונים במשך די הרבה זמן, ועם הזמן גיליתי בעיות – שאומנם די נדירות אבל מספיק חמורות כדי שאני אחפש פתרון.
חשבתי לפתור אותן בעצמי, וגיליתי שהוא לא מתקמפל על JDK מודרני. שלחתי מייל לרשימת התפוצה שלו לגבי העניין, וחודשים עברו בלי שום תגובה ובלי הודעות נוספות.
היה ריח של פרוייקט מת באוויר, וכשנתקלתי בבעיה נוספת (100% CPU בקוד של פרוקסול לעיתים נדירות), החלטתי לחפש Connection pool אחד.
בסוף הגעתי לBoneCP שאומנם מוגדר כבטא, אבל עובד היטב – וחשוב יותר – המפתח שלו עונה לאימיילים ומתקן באגים.

טיפוסי אישיות

מי שלמד פסיכולוגיה (לא אני) מכיר את העניין הזה לעומק כנראה, אבל אני מניח שרוב הקוראים פה לא למדו פסיכולוגיה אני אכנס לעניין:
במהלך שיטוטי באינטרנט בחיפוש אחרי ספרייה לDecoding של תמונות בC או C++ (יש מילה בעברית לDecoding? פענוח? פרישה?) נתקלתי בCxImage, וראיתי בדף האודות של המפתח שהוא טוען שהאישיות שלו היא מסוג INTJ.
אני די בטוח שנתקלתי בסוג הקטלוג הזה למחלקות אישיות בעבר, אבל הפעם הסתקרנתי, אם הוא INTJ אז מה אני? וכמה הדבר הזה בכלל עובד?

התחלתי לחקור, מסתבר שמדובר במבחן פסיכומטרי שמבוסס על העבודה של קארל יאנג מ1920 ופותח על ידי קתרין קוק בריגס וביתה איזבל בריגס מיירס, והמבחן קרוי על שמן: Myers-Briggs Type Indicator או MTBI.
בגדול, הרעיון הוא שהאישיות של בני אדם נקבעת על ידי ארבעה תכונות, כאשר לכל תכונה יש שני צדדים (מוחצן – מופנם, חושב – מרגיש) וכו', ואצל כל אחד תכונה אחת מכל זוג היא יותר דומיננטית מהשניה.

הזוגות הם:

  • התנהגות – מוחצן או מפונם :  האם רוב המחשבה של האדם מופנית החוצה או פנימה
  • תפיסה – חש או אינטואיטיבי : איך האדם קולט מידע חדש, האם הוא סומך יותר על תחושות פנימיות או על מידע קונקרטי
  • החלטה – חושב או מרגיש : איך האדם  מבצע החלטות רציונליות בניתוח של המידע שהוא קיבל באמצעי התפיסה, האם הוא מעדיף חשיבה וניתוח לוגי או החלטה לפי הרגשה והזדהות עם המצב.
  • סיגנון חיים – שיפוטי או תפיסתי : האם האדם מעדיף להשתמש בבהחלטה (חושב/מרגיש) או בתפיסה (חש/אינטואיטיבי) כשהוא מתייחס אל העולם החיצוני.

קצת מבלבל, ואולי התרגום שלי לא מאוד מדוייק (יש הרבה מאוד חומר מדוייק על זה באינטרנט).

סך הכל יש ארבע 'ביטים' כשלכל ביט יש שתי אפשרויות, מה שיוצר 16 קומבינציות.

מצאתי מבחן עם כ-70 שאלות כן/לא שמוצא את הטיפוס שלכם, וקיבלתי שגם אני INTJ.
קראתי קצת על INTJ, ונראה שלפחות לגבי – המבחן יצא מאוד מדוייק.

בעיית החלוקה

שוב ושוב אני נתקל בבעיה הבאה:
בהנתן קבוצת מספרים, איך מחלקים אותה לשתי קבוצות כך שסכום המספרים בכל קבוצה יהיה קרוב ככל האפשר לסכום המספרים בקבוצה השניה.
במילים אחרות, שאף קבוצה לא תהיה 'כבדה' הרבה יותר מהשניה בצורה שניתנת לתיקון על ידי סידור מחדש של האיברים בקבוצות.

הרחבה טבעית של השאלה הזו, היא איך מחלקים את הקבוצה לk קבוצות, לאו דווקא רק לשתיים.
הנה כמה דוגמאות למצבים שבהם אלגוריתם כזה יהיה שימושי:

דמיינו משחק מרובה משתתפים שעובד בסיבובים. בכל סיבוב יש שתי קבוצות שנלחמות אחת בשניה. חלוקה אקראית של השחקנים לשתי קבוצות תגרום למצב שבו כל השחקנים החזקים נופלים בקבוצה אחת ואז המשחק לא יהיה מהנה במיוחד לאף אחת מהקבוצות.
חלוקה אידיאלית תהיה כזו שההפרש בין סכומי היכולת בכל קבוצה יהיה נמוך (קבוצות מאוזנות). נניח שיש לנו מדד ליכולת של שחקן (יחס נצחונות/הפסדים ב20 המשחקים האחרונים, או דרגה או כל דבר אחר) נוכל להשתמש באלגוריתם חלוקה כזה כדי למצוא חלוקה טובה של הקבוצות.

דוגמא נוספת: נניח שיש לכם ערמת עבודות, וכמה מחשבים שיכולים לבצע את העבודות. איך תחלקו את העבודות בין המחשבים כך שעבודות יסתיימו בהקדם? אם אחד המחשבים יקבל את כל העבודות הכבדות אז הוא יסיים הרבה אחרי כולם, אז שוב אנחנו מחפשים חלוקה מאוזנת (הפעם לk מחשבים).

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

Java with authenticated urls

התקן של HTTP כולל קביעה של שם משתמש וסיסמא ישירות בURL, למשל:
[code]
http://user:password@site.com/file.txt
[/code]

מסיבה לא ברורה, ג'אווה לא מסתדר עם URLים כאלו ונראה שהוא לא מעביר את שם המשתמש והסיסמא לאתר.
הנה פתרון לעניין (עקום אך גנרי) :
[code lang="java"]
Authenticator.setDefault(new Authenticator()
{
@Override
protected PasswordAuthentication getPasswordAuthentication()
{
URL url = getRequestingURL();
String userInfo = url.getUserInfo();
String user;
String password;
int i = userInfo.indexOf(':');
if (i == -1)
{
user = userInfo.substring(0);
password = "";
}
else
{
user = userInfo.substring(0, i);
password = userInfo.substring(i+1);
}
PasswordAuthentication ps = new PasswordAuthentication(user, password.toCharArray());
return ps;
}
});
[/code]

עוגיה למי שסביר למה המימוש הסטנדרטי של ג'אווה לא תומך בדבר הטריויאלי הזה.

protobuf

לפני קצת יותר משנה גוגל שחררו ברשיון קוד פתוח פרוייקט בשם Protocol Buffers, ובקיצור protobuf.
protobuf מגדיר שפה להגדרת מבני נתונים (IDL), ויודע לייצר קוד יעיל שקורא וכותב את אותם מבני נתונים בC++, JAVA או פייתון.
יש תמיכה חיצונית לפורמט בשפות נוספות, C#, D, רובי PHP* ועוד.
הדוגמאות שאני אתן יהיו בג'אווה, אבל השתמשתי בו גם עם C++ והוא עובד היטב גם שם.
כל מפתח מגיע מתי שהוא לשלב שבו תוכנית שהוא כותב צריכה להעביר נתונים לתוכנית אחרת (או למופע אחר של עצמה) דרך הרשת, או לשמור נתונים לקובץ כדי לקרוא אותם אחר כך.
מקובל לקודד את הנתונים בתוך הודעות, כשיש הרבה מאוד דרכים לכתוב את ההודעות, ובדרך כלל מדובר בקוד די סיזיפי שחוזר על עצמו וכתיבתו היא די משעממת (בפעם העשירית שעושים משהו כזה).
נניח שאנחנו רוצים להעביר אובייקט שמייצג אימייל על גבי הרשת (ונתעלם רגע מהפרוטוקולים המקובלים להעברת אימיילים).
לאובייקט אימייל שלנו יש שדה של שולח, אחד או יותר שדות של מקבלים, נושא, טקסט, ואפס או יותר קבצים נלווים ואפילו עדיפות.
אפשר לייצג אותו במבנה הלוגי הזה:
[code lang="java"]
package messages;
message Email
{
enum Priority
{
LOW = 1;
NORMAL = 2;
HIGH = 3;
}

required string from = 1;
repeated string to = 2;
required string subject = 3;
required string message = 5;
repeated Attachment attch = 4;
optional Priority priority = 6;
optional string date = 7;

message Attachment
{
optional string data = 1;
required string name = 2;
}
}
[/code]

מה שיש לנו פה זה הגדרת הודעה תקינה בשפת הIDL של protobuf.
השפה תומכת בהגדרת חבילה (שמתורגמת לpackage בג'אווה ולnamespace בC++), וכן בהגדרות מקוננות של הודעות.
המספרים אחרי כל שורה נקראים טאגים ומשמשים לזיהוי של השדות בפרוטוקול הבינארי, ולכן אחרי שהם נקבעים אי אפשר לשנות אותם.
אפשר לראות שהשפה תומכת בהגדרה של enum, וכן ברשימות של אובייקטים (שיכולים בעצמם להכיל אובייקטים וכן הלאה).
חוץ מטיפוסים שאתם מגדירים, השפה תומכת גם בטיפוסים פנימיים למשל מחרוזת, משתנה בוליאני, מספר ברוחב קבוע (למשל ארבעה בתים), מספר ברוחב משתנה ועוד.
המספרים ברוחב משתנה מקודדים בצורה דומה קצת לקידוד של UTF8, אבל בצורה קצת יותר פשוטה:

הביט השמאלי (MSB) בכל בייט מוגדר כך: 1 אם המספר המועבר כולל בייטים נוספים, או 0 אם זה סוף המספר.
7 הביטים האחרים בכל בייט משמשים להעברת 7 ביטים של המספר עצמו. בצורה כזו, מספרים קטנים מ128 יתפסו בייט אחד בלבד, מספרים קטנים מ65000 בקירוב יתפסו שני בתים וכן הלאה. אם התוכנית שלכם מעבירה מספרים קטנים שיכולים להיות גדולים לעיתים נדירות – הקידוד הזה הוא אידיאלי כי בדרך כלל המספרים לא יתפסו הרבה מקום, בניגוד לקידוד ברוחב קבוע שבו כל מספר תופס למשל ארבעה בתים.

חלק מהטיפוסים הנתמכים בשפה הם ברוחב קבוע, למשל מספרים בנקודה צפה (Floating point) ושלמים שמוגדרים כFIXED, למשל FIXED64 יהיה תמיד 64 ביטים או 8 בתים.
עוד על השפה אפשר לקרוא פה.

את הקובץ שמכיל את הגדרת ההודעות "מקמפלים" עם protoc, שמייצר ממנו קוד בג'אווה C++ או פייתון:
[CODE]
$ protoc messages.proto –java_out src/
[/CODE]

הנה דוגמא לקוד ג'אווה שמייצר הודעה, כותב אותה לקובץ, קורא אותה ומדפיס אותה בפורמט טקסטואלי:
[CODE LANG="JAVA"]
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import test.Messages.Email;
import test.Messages.Email.Attachment;
import test.Messages.Email.Builder;

class Test
{
public static void main (String args[]) throws FileNotFoundException, IOException
{
Builder b = Email.newBuilder();
b.addTo("test@abc.com");
b.addTo("test@loogle.com");
b.setFrom("someone@there.com");
Attachment aa = Attachment.newBuilder().setName("viruts.exe").build();
b.addAttch(aa);
b.setSubject("A present for you");
b.setMessage("Please open the attached Virus");
Email email = b.build();
System.out.println(email.toString());
FileOutputStream out = new FileOutputStream("email.dat");
email.writeTo(out);
out.close();

System.out.println(Email.parseFrom(new FileInputStream("email.dat")));
}
}
[/CODE]
נקמפל ונריץ:
[code lang="bash"]
$ javac -cp lib/protobuf-java-2.2.0.jar src/Test.java src/test/Messages.java
$ java -cp lib/protobuf-java-2.2.0.jar:src Test
from: "someone@there.com"
to: "test@abc.com"
to: "test@loogle.com"
subject: "A present for you"
attch {
name: "viruts.exe"
}
message: "Please open the attached Virus"
[/code]

אפשר לראות שבמפתיע הפלט הטקסטואלי הוא כמעט קובץ Swush תקני, אני נשבע שלא הסתכלתי עליו כשהגדרתי את Swush 🙂
זו דוגמא לשימוש בprotobuf בג'אווה, השימוש בC++ בשפות אחרות פשוט בצורה דומה.
כל העניין מאוד קל לשימוש, ואני ממליץ מאוד לכל מי שצריך לכתוב אובייקטים לקובץ או לרשת לבדוק את protobu.
אגב, הקוד המחולל נראה טוב מאוד, כמעט כאילו כתבתם אותו בעצמכם.

* PHP : הספריה לתמיכה בPHP היא pb4php, והיא לא מאוד מוצלחת. למרות שיתכן שבקרוב הפרוייקט יקבל PATCH משמעותי שהופך את הספריה ליותר שמישה (לפחות לצרכים שלי).

Dragon age : Origins

דרגון אייג' הוא משחק RPG לשחקן יחיד, עם עומק דמויות ועלילה באמת יוצא דופן.
כמו בכל המשחקים מסוג זה, המשחק מתחיל ביצירה של הדמות הראשית.
BioWare החליטו לא להשתמש בחוקי הAD&D המקובלים, אז למרות שהעניינים די מוכרים הם מספיק שונים כדי שיהיה מעניין.
אפשר לבחור אחד משלושה גזעים:בני אדם, אלפים או גמדים, ואחד משלושה מקצועות :לוחם, קוסם או גנב (המגבלה היחידה היא שגמד לא יכול להיות קוסם).
למרות שאין מה לדאוג, לכל אחד משלושת המקצועות הראשיים יש ארבעה התמחויות אפשריות, מתוכם תוכלו לבחור שתיים במהלך המשחק.
המשחק מתחיל באחד משישה פתיחות שנקבעת לפי המקצוע או הגזע של השחקן. בסוף סיפור הרקע העלילות מתלכדות.
הסיפור הכללי הוא ששוב כוחות השחור מאיימים להשמיד את הכל, ואתם מצטרפים למסדר בשם השומרים האפורים (Grey Wardens) שנלחמים
בכוחות השחור (Darkspawn) כל כמה מאות שנים מחדש.
מהר מאוד דברים משתבשים והופכים למאוד נואשים עבור השומרים האפורים.

יש במשחק עשרות שעות של דיאלוגים, שמוקראים על ידי שחקנים מקצועיים ולא ובדרך כלל מאוד מעניינים.
אתם מסתובבים בעולם של פרלדן בקבוצה של עד ארבעה חברים.
בדומה למערכת הקרב של באלדר'ס גייט, אפשר לעצור את הקרב בכל רגע ולחלק הוראות לשחקנים, אבל הם עצמאיים ואם לא תגידו להם מה לעשות הם כבר יחליטו לבד.
דבר חדש הוא שאפשר להגדיר מערכת חוקים טקטיים לפיה הדמויות פועלות כאשר אתם לא שולטים בהם ישירות. השליטה יכולה להיות כללית כמו למשל להגדיר שקוסם מסויים יהיה על תקן מרפא ולוחם מסויים יעדיף לתקוף מרחוק (חץ וקשת למשל) או ממש להכנס להגדרות מפורטות של מה לעשות כשתנאי מסויים מתקיים, למשל :
אם הכוח שלך יורד מתחת ל50% תשתה שיקוי כוח או אם השחקן הראשי מותקף, תגן עליו וכו'
כמובן, עם הזמן הדמויות עולות בדרגות ומקבלות נקודות שאתם יכולים להשקיע ביכולות שונות.

בניגוד לרוב המשחקים מסוג זה שבו הבחירות של השחקן רק מקדמות עלילה לינארית פה את רוב המשימות הראשיות אפשר לגמור בשתיים או יותר צורות שונות משמעותית.
ההחלטות שלכם יקבעו את היחס של חברי הקבוצה אליכם, ומה יהיה בהמשך המשחק.
למשל, בשלב מסוים אחד מחברי הקבוצה שאספתי בדרך שלי תקף אותי כי הוא החליט שבמקום להתרכז במשימה הראשית וללכת להדביר את הרוע אני מתרוצץ בכל מני מקומות שלא קשורים לדעתו.
נלחמנו באחד על אחד, ואחרי שהבסתי אותו וזכיתי מחדש בכבוד שלו החלטתי להרשות לו להשאר.
אם תהיו ביחסים טובים עם החברים בקבוצה, תקבלו מהם קווסטים שקשורים לרקע שלהם.
המשחק רחב יריעה במיוחד, ומושקע מאוד לכל האורך. להערכתי יש בו בין 50 ל100 שעות משחק (תלוי כמה אתם סוטים מהעלילה הראשית), שלא כוללים משחק כדמות אחרת עם מצפן מוסרי שונה (לגמרי שווה לשחק את המשחק שוב הפעם כדמות חסרת מוסר שעושה מה שטוב לה ולמעשה התחלתי בדיוק בזה אחרי שסיימתי את המשחק).

אני חייב להזהיר:
המשחק שואב אתכם לתוכו, ורוב הסיכויים הם שאחרי שתתחילו, לא תוכלו להפסיק לשחק עד הסוף (המר?).
חוץ מהכמות האדירה של תוכן שיש במשחק הזה, BioWare שיחררו איתו ערכה ליצירת תוכן נוסף, ובנוסף משחררים חבילות נוספות בתשלום כתוכן להורדה מתוך המשחק. למשל, לפני כמה ימים הם שחררו פרק נוסף ב$5.
אם יש משחק ששווה קניה השנה, זה המשחק.