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.
אם יש משחק ששווה קניה השנה, זה המשחק.

דרכון קנדי ב20 דקות, או : VPN לכל שרת

אחד המשחקים המצופים של השנה – Dragon age: Origins – יצא לפני אתמול, ואחרי שראיתי את הציונים והביקורות שהוא קיבל החלטתי לקנות אותו.

חיש מהר קניתי אותו בSteam, חנות המשחקים שלValve.
בזמן שקניתי אותו היה נראה כאילו אני מבצע הזמנה לפני שהמשחק יצא (Pre order), אבל מה שקורה בדרך כלל זה שאפשר להוריד את המשחק מראש, וברגע שהוא משתחרר (מה שהיה אמור להיות אתמול) קבצי המשחק המוצפנים עוברים תהליך של פענוח ואז אפשר לשחק.
אבל מה? מסתבר שבארצנו הקטנטונת – וגם באירופה, המשחק ישוחרר רק ביום שישי או שבת.
סתם כדי להתעצבן, בדקתי באתר הטורנטים הקרוב לביתי, ואכן – המשחק כבר שם.
שלחתי אימייל לתמיכה של Valve, בו מחיתי על כך שהם מסרו מידע שגוי שגרם לי ולאחרים לקנות את המשחק ולהצטער.
אז המשחק כבר אצלי, מוצפן – ושילמתי עליו, אבל מסיבות עלומות ומציקות אני לא מורשה לשחק בו למרות ששחקנים אחרים בעולם כן.
מעצבן מספיק כדי לפעול.
משתמשים בפורום של Steam כתבו שהם הצליחו לשחק אחרי שהתחברו לSteam תוך שימוש בVPN שמחובר לארצות הברית.
חיפשתי קצת, ולא מצאתי משהו שלא ביקש ממני כרטיס אשראי בשביל לנסות, אז חשבתי לעצמי:
השרת שמריץ את הבלוג נמצא בקנדה, רוב הסיכויים שהמשחק שוחרר בקנדה באותו תאריך כמו בארצות הברית.
החלטתי להרים שרת VPN על השרת בעזרת ההוראות פה.
ההוראות פשוטות למדי, אבל במקום לאתחל את השרת כמו שהם הציעו אחרי ההגדרות הפעלתי מחדש את pptpd:
[code]
/etc/init.d/pptpd restart
[/code]

כדי להפעיל את קידום הפקטות בקרנל בלי לאתחל, הרצתי את:
[code]
echo 1 > /proc/sys/net/ipv4/ip_forward
[/code]

פתחתי חור TCP בפיירוואל בשרת בפורט 1723, שהוא הפורט הסטנדרטי של העניין הזה, וכמובן בחרתי סיסמא חזקה עם gpw שמייצר סיסמאות שאפשר להגות (Generate pronounceable passwords), ניסיתי להתחבר דרך מכונת המשחקים שלי שמריצה חלונות 7 (מערכת מומלצת), והעסק התחבר בלי בעיה.
בדקתי את כתובת הIP שלי בwhatismyip.com ולשמחתי ראיתי שהיא הכתובת של השרת.
הפעלתי מחדש את Steam, נכנסתי מקנדה – והפלא ופלא, בתור קנדי הצלחתי להפעיל את המשחק.

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