תקלה קטנה שנתקלנו בה -
המערכת – VS 2012 עם פרוייקט DATA. בבסיס הנתונים ישנם מספר Views. בסיס הנתונים יושב על שרת 2008 R2 עם Management studio 2008.
כאשר משנים את הVIEW ומעבירים את השינוי דרך השוואת סכמות הוא מפסיק לעלות בDesigner של Management Studio.
לאחר פשפוש קל נמצא האשם – Extended properties.
כאשר גוררים בDesigner את הטבלאות נוצרים מאפיינים ששומרים את המיקום הזה לפעמים הבאות, ההשערה שלי היא שכאשר מבצעים השוואת סכמות בVS 2012 זה עובר שינוי ומותאם לSQL 2012 למרות שבסיס הנתונים הוא ב2008. לכן כאשר מתבצע Deploy הDesiger של 2008 לא יודע לזהות נכון את המאפיינים ולא מוכן לעלות, במחיקה שלהם הבעיה נפתרת.
מקווה שזה יעזור למישהו… 
גיט (Git בלע”ז) מאד מוצא חן בעיניי, הוא (היא?) גמיש, זריז, מתאים מאד לשיטת העבודה שלי שחלקה היא מול צוותים מבוזרים.
אז התחלתי להשתמש בכל מיני פרוייקטים קטנים, אחלה. קראתי מדריך מעולה – מומלץ בחום.
רק נקודה אחת נשאר לסגור, רוב הפרוייקטים יושבים על TFS…
אז הנה הפתרון צעד אחר צעד.
שלב מקדים – התקנת git. מחוץ למדריך זה, מומלץ להתקין GitExtensions.
1) התקנת git-tfs
הדרך הארוכה – להוריד את הקוד, לקמפל ולעבוד עם זה.
הדרך הקצרה –חתיכת שוקולד (ברצינות…
) ומיד אח”כ - cinst GitTfs. (מוזר לא? יותר מידיי פשוט
)
2) יצירת מחסן
מכינים את התיקייה בה ישב הפרוייקט, מנווטים לשם עם Git Bush (מותקן במחיצה של Git)
ומקלידים git tfs init http://tfs:8080/tfs/DefaultCollection $/some_project
(לעדכן כמובן לפרטים המתאימים – אם צריך להכניס שם משתמש וסיסמא)
3) לקחת את הקוד (יכול לקחת זמן – כפוף לגודל פרוייקט, גילו ותעבורה ברשת)
git tfs pull
תוך כמה שניות תתחילו לראות את הגרסאות יורדות.
ישנה אפשרות לעשות את 2 ו3 ביחד עם הפקודה
git tfs clone http://tfs:8080/tfs/defaultCollection $/some_project
העניין הוא שכשניסיתי את זה בפרוייקט בינוני זה נקטע באמצע ואז צריך להתחיל מחדש. השיטה עם הpull מאפשרת להמשיך גם אחרי קטיעות. (והיו לי לא מעט כאלו)
אפשרות שלישית זה quick-clone שמוריד רק את הגרסה האחרונה.
עד כאן הקמה. מקווה להספיק לכתוב בקרוב על דרך השימוש.
באחד הפוסטים הקודמים נתקלתי בבעיה עם רכיבים צד ג’ שעבדו באופן לא מובן מספיק ונאלצתי לפצח אותם ממש כדי להשתמש בהם כמו שצריך (מחסור בתיעוד ועוד)
הפעם נתקלתי ברכיב שמניח הנחה מאד בעייתית.
טלריק – חברה רצינית ביותר לרכיבים לדוט נט (ועוד ועוד ועוד…) מפתחת רכיבים לHTML 5 עם תמיכה ב MVC בשם
KendoUI.
שמתי גריד, חיברתי מקור AJAX הכל נראה מצויין בדיוק כמו בדוגמאות.
תוך כדי דפדפוף (Paging) אני שם לב שאני לא מצליח לעבור בין הדפים, לא שאין קריאות, יש קריאות והשרת מחזיר את אותו דף כל הזמן.
בקפיצה מאד גדולה קדימה ישנם שינויים אבל בעיקרון אותו דף חוזר כל הזמן.
אז התחלתי לנבור.
דבר ראשון - כדי לבצע דפדפוף עם EF חייבים מיון. אז ביצעתי מיון קשיח (מוגדר בקוד) – לא עבד.
דבר שני – בדקתי דפים אחרים – כן עובד.
דבר שלישי – פתחתי את הקוד של הדוגמאות – לא מצאתי הבדלים.
ואז התחלתי לחפור בקוד המקור (מזל שטלריק מספקים אותו…

)
נקודת הממשק שלי הייתה מתודה ToDataSourceResult שמקבלת את הבקשה ומבצעת את הפעולות של הגריד (מיון, סינון, דפדוף).
כמה קפיצות פנימה הובילו לקוד הבא -
1: if (!sort.Any() && queryable.Provider.IsEntityFrameworkProvider())
2: {
3: // The Entity Framework provider demands OrderBy before calling Skip.
4: SortDescriptor sortDescriptor = new SortDescriptor
5: {
6: Member = queryable.ElementType.FirstSortableProperty()
7: };
8: sort.Add(sortDescriptor);
9: temporarySortDescriptors.Add(sortDescriptor);
10: }
נחמד לא? כדי שלא נחטוף חריג עשו לנו טובה ובחרו עבורנו בצורה שרירותית את השדה לפיו יתבצע המיון (כמובן רק אם לא היה מיון מוגדר מראש מהגריד)
אגב זה הקוד שמחזיר את השם של השדה המבוקש -
1: internal static string FirstSortableProperty(this Type type)
2: {
3: PropertyInfo firstSortableProperty = type.GetProperties().Where(property => property.PropertyType.IsPredefinedType()).FirstOrDefault();
4:
5: if (firstSortableProperty == null)
6: {
7: throw new NotSupportedException(Exceptions.CannotFindPropertyToSortBy);
8: }
9:
10: return firstSortableProperty.Name;
11: }
אז מה רע?
שבמקרה הזה השדה הנבחר היה שם רחוב…
המשמעות הייתה שאילתה שנראית ככה (ותודה לIntelliTrace שחסך מלא זמן):
1: The command text "SELECT TOP 10
2: [Var_4].[Index@] AS [Internal_Index@],
3: [Var_4].[רחוב] AS [Internal_רחוב],
4: [Var_4].[EMAIL] AS [Internal_EMAIL],
5: [Var_4].[שם מלא] AS [Internal_שם מלא]
6: FROM [dbo].[PT] AS [Var_4]
7: WHERE NOT (EXISTS (SELECT [Var_6].[Internal_רחוב1] AS [Internal_רחוב1]
8: FROM ( SELECT TOP 30
9: [Extent1].[רחוב] AS [Internal_רחוב1]
10: FROM [dbo].[MainData] AS [Extent1]
11: ORDER BY [Extent1].[רחוב] ASC
12: ) AS [Var_6]
13: WHERE ([Var_4].[רחוב] = [Var_6].[Internal_רחוב1]) OR (([Var_4].[רחוב] IS NULL) AND ([Var_6].[Internal_רחוב1] IS NULL))))
14: ORDER BY [Var_4].[רחוב] ASC
או בעברית (אנסה לתרגם):
תן לי את ה10 הראשונים (מתוך כלל הנתונים) שהרחוב שלהם לא שווה לאף אחד בתוך ה30 הראשונים.
מכיוון שלהרבה מאד אנשים אין כתובת בבסיס הנתונים אותם עשרה חוזרים שוב ושוב…
הפתרון היה פשוט, להוסיף לכל מיון עוד שדה שמאפשר מיון (אינדקס למשל)
1: public ActionResult GetPeoples([DataSourceRequest] DataSourceRequest request)
2: {
3: var filterd = ApplyFilters();
4: request.Sorts.Add(new SortDescriptor() { Member = "Index" });
5: var res= Json( filterd.ToDataSourceResult(request));
6: return res;
7: }
זה למה כדאי שהקוד מקור של כל הרכיבים צד ג’ יהיו קרוב קרוב.
כדי להכניס זמן מקומי (נגיד של ישראל) לשדה תאריך/זמן במידה והשרת ממוקם בחו”ל ואין גישה לשעון שלו או שהמיקום הסופי לא מוחלט (אז’ור למשל) ניתן להחליט לפי איזה שעון יכתב הזמן.
לשם כך ניתן להשתמש ב TimeZoneInfo המאפשר בדיקה והשוואה מול שעון אחר.
הביטוי הבא מייצג את הזמן המקומי בישראל (כולל שעון/קיץ חורף)
1: DateTime.UtcNow +
2: TimeZoneInfo.FindSystemTimeZoneById("Israel Standard Time")
3: .GetUtcOffset(DateTime.UtcNow)
את המחרוזת של ישראל ניתן למצוא (כמו את שאר המחרוזות)
כאן
לעיתים די קרובות אני רוצה להמחיש בצורה פשוטה את המסלול של הקוד.
אז יש לוח לבן, נחמד אבל נדיף
(וגם צריך להגיע למשרד בשביל זה
)
יש ויזיו – ואז צריך תואר ראשון או לפחות סמסטר כדי לצייר משהו, לגרור חצים לראות שהם במקום בצבע והצורה וכו’
יש אפילו לויז’ואל סטודיו אבל – הקוד צריך להיות מוכן, אין שום שליטה על התוצאה וזה לוקח מלללללללא זמן.
ויש - http://www.websequencediagrams.com/
מהיר, פשוט, נחמד, קליל ומספיק עשיר כדי להציג דברים פשוטים ונחמדים.
-
אפשר להטמיע בכל אתר (או דף HTML).
-
הגרסה החינמית מספיק טובה לרוב הדברים.
-
ניתן לעצב בקלילות.
אהבתי.
באיזה כלים אתם משתמשים לדיאגרמות?
בעקבות ההכרזה של מיקרוסופט על Windows phone 8 לפיה הליבה תהיה משותפת עם חלונות 8 (הבעל”ט) אני תוהה (טרם מצאתי התייחסות רשמית) האם זה הסוף של סילברלייט.
בחודשים האחרונים ממילא היו שמועות עקשניות שסילברלייט 5 הוא האחרון ברשימה. כאשר חלונות 8 הוכרזה עם תמיכה מובנית בHTML 5 כבר חשתי שזה שאלה של זמן.
במידה ו WP8 יתמוך כמו חלונות 8 בWinRT זה אומר שניתן לעשות הכל ללא סילברלייט. זה יהיה בהחלט המסמר האחרון בארון.
יתרה מכך זה ייתן יתרון אדיר למיקרוסופט, מערכת הפעלה שמריצה על הליבה את HTML 5 פותחת למעשה למפתחים עולם שלם פיתוח אחיד. (מוזילה עובדת על משהו כזה)
אגב מבחינתי הסנונית הראשונה שסימנה את הנטישה של סילברלייט היתה המעבר של Skydrive מעריכת מסמכים בסילברלייט לHTML.
אגב לדעתי זו תהיה המגמה של כל הניידים (למורת הרוח של היצרניות) לעבור לHTML 5 עם שילוב כזה או אחר במערכת ההפעלה כדי לקבל יכולות נוספות.
מה דעתכם?
נ.ב. הפורטל החדש של אז'ור הפך גם הוא לHTML.
(בכוונה אני מעלים את הפרטים כדי לא לפגוע במי מהמעורבים בעניין)
בפרוייקט מסויים שאני מייעץ לו הוחלט לרכוש רכיבים צד ג כדי לנהל את נושא הרשיונות.
לאחר חיפוש ומחקר מסויים נבחרה חברה אשר המוצר שלה היה הקרוב ביותר לדרישות (יכולות + מחיר)
כאשר התחלנו לעבוד בפועל הסתבר שתסריט מסויים אשר היה נראה שהוא אפשרי ופשוט – הוא לא כ”כ פשוט ובמקום שהוא יהיה אוטמטי הוא ידני לחלוטין.
התיעוד על הרכיבים לא נתן פיתרון פשוט לבעיה, היא נכתבה והועברה למחלקת התמיכה.
למותר לציין שכחברה רצינית שעוסקת באבטחת מוצרים כל הרכיבים עברו Obfuscator. ואין כ”כ יכולת להבין איך הם עובדים כדי לנסות לעקוף את המגבלות.
חיפוש קל העלה את de4dot שמאפשר “טיפול” בבעיה, לאחר קצת נבירה וחפירה נמצא המתודה שדריסה שלה (8 שורות סה”כ) אפשרו פיתרון (לא הכי נקי אבל יעיל ועובד) של הבעיה.
“בעיה” נוספת הייתה הגנה שמצריכה אסמבלי חתום וכו’, שוב, “טיפול” (ilasm-ildasm) פתר את הבעיה לצורכי פיתוח.
תזכורת: הקוד הסופי רץ ללא בעיות על הרכיבים המקוריים, המוצר ברישיון חוקי והכל תקין.
אשמח לשמוע, מה אומרים האם זה נכון/ראוי?
האם קוד המקור צריך להיות מצורף לכל רכיב?

שבוע שעבר השתחררה גרסה 4 של NDepend.
למי שלא מכיר הכלי מאפשר תחקור של הקוד בכל מיני רמות, יצירת שאילתות על הקוד (החל משאילתות בסיסיות כגון – כמה מחלקות ישנן עם יותר מX שורות קוד)
הנקודה המשמעותית בשחרור הזה (לטעמי) הוא CQLing.
למעשה זהו מנגנון שאילתות שנראה בדיוק כמו Linq. הרבה יותר פשוט ואינטואיטיבי.
היכולות של הכלי מדהימות ובפרוייקטים גדולים הוא נותן עבודה מאד מהירה.
מקצת היכולות:
1. גרף תלויות (פי 100 יותר מהיר ממה שמובנה בVS)
2. יצירת “חוקים” לשימוש חוזר (למעשה הוא מגיע עם סט די עשיר)
3. יכולת אכיפה של חוקים, בזמן בנייה.
4. תאום “קוד מכוסה” עם כמה כלים.
ועוד ועוד.
בקיצור מומלץ בחום
צילומי מסך – מומלץ לעבור
למי שלא מכיר,
למי שנוהג לכתוב טסטים, (מי שלא – שלא יגלה…
)
כלי מדהים (קצת חבלי התקנה וקינפוג) תענוג לעבוד איתו.

הכלי מאפשר ריצה ברקע של הטסטים, מעדכן כל הזמן מה עובר ומה לא.
נותן חיווי ברור ליד כל שורה אם יש לה כיסוי.
טיפים:
קורה שמתבצע רישום כפול לאותו אירוע, ברוב המקרים זה לא הרצון המקורי…כמובן לא מדובר בכמה הנדלרים שונים אלא ברישום אותו הנדלר לאותו אירוע.
זה קורה ממספר סיבות:
- רישום ממתודה סטאטית שנקראת מספר פעמים.
- רישום ממקומות שונים בקוד. (לפעמים ע”י מתכנתים שונים, נתיבים שונים שכל אחד צריך את זה)
- רישום מתוך לולאה.
וכו’.
כדי להיפטר מזה ניתן לכתוב קוד שמוסיף לוגיקה לרישום/מחיקה לאירוע.
בעיקרון האירועים הינם מעטפת (נסתרת) כמו מאפיינים אוטמטיים (Auto properties) ויש להם מתודות נסתרות להוספה והורדה של הנדלרים.
בתוך הadd ניתן לבצע מעקב אחרי הנרשמים ולמנוע כפילויות.
זה מקרה קלאסי לAOP - aspect Oriented Programing.
ב-PostSharp ניתן לכתוב אספקט כגון זה די בקלות.
במקרה זה (אם יש צורך אז ניתן לשים נעילות כדי שזה יהיה Thread safe) .
עכשיו כל מה שצריך זה לשים UniqueHandlerAspect מעל הגדרת האירוע.
1: [Serializable]
2: public sealed class UniqueHandlerAspect : EventInterceptionAspect, IInstanceScopedAspect
3: {
4: #region Constants and Fields
5:
6: /// <summary>
7: /// The _handlers.
8: /// </summary>
9: private HashSet<Delegate> _handlers;
10:
11: #endregion
12:
13: #region Public Methods and Operators
14:
15: /// <summary>
16: /// The create instance method. run for every different instance of the aspect.
17: /// </summary>
18: /// <param name="adviceArgs">
19: /// The advice args.
20: /// </param>
21: /// <returns>
22: /// The create instance.
23: /// </returns>
24: public object CreateInstance(AdviceArgs adviceArgs)
25: {
26: return this.MemberwiseClone();
27: }
28:
29: /// <summary>
30: /// The on add handler.
31: /// </summary>
32: /// <param name="args">
33: /// The args.
34: /// </param>
35: public override void OnAddHandler(EventInterceptionArgs args)
36: {
37: var handler = args.Handler;
38: if (!this._handlers.Contains(args.Handler))
39: {
40: this._handlers.Add(handler);
41: args.ProceedAddHandler();
42: }
43: }
44:
45: /// <summary>
46: /// Method invoked <i>instead</i> of the <c>Remove</c> semantic of the event to which the current aspect is applied,
47: /// i.e. when a delegate is removed from this event.
48: /// </summary>
49: /// <param name="args">Handler arguments.</param>
50: public override void OnRemoveHandler(EventInterceptionArgs args)
51: {
52: if (this._handlers.Contains(args.Handler))
53: {
54: this._handlers.Remove(args.Handler);
55: args.ProceedRemoveHandler();
56: }
57: }
58:
59: /// <summary>
60: /// The runtime initialize instance.
61: /// </summary>
62: public void RuntimeInitializeInstance()
63: {
64: this._handlers = new HashSet<Delegate>();
65: }
66:
67: #endregion
68: }
69: }
בפרויקט מסוים עלתה דרישה לאפשר מערך הרשאות דינמית בתצוגה, כלומר לייצר מספר (דינמי) של פרופילי משתמש במערכת ולכל אחד לאפשר ביחד לרכיבים מסויימים במסך לאפשר גישה, להגביל לצפייה בלבד או להעלים לגמרי.
התצוגה מבוססת WPF וצד הלקוח כולו מבוסס PRISM ו MVVM והשאיפה היא למינימום קוד בתצוגה.
דרישות מהמערכת:
-
דינמיות בזמן ריצה של ההרשאות (לא לקודד אותן)
-
שליטה מהVM על ההרשאות (מינימום קוד בתצוגה)
-
יכולת לקבץ מספר מאפיינים עם אותה הרשאת גישה, עם זאת לאפשר שליטה ברמת השדה.
-
יכולת לקריאה בלבד/ הסתרה מלאה של מרכיבי תצוגה.
-
צימוד של רכיבים קשורים בתצוגה (תוית-> תיבת טקסט)
-
יצירת מספר פרופילים שונים שאינם קבועים מראש.
לטובת העניין כתבתי תשתית מאד פשוטה אבל יעילה המאפשרת עם Attribute פשוט בVM וBehavior בXAML לשלוט על העניין.
העיקרון פשוט – מצמידים תוית כלשהיא לשדות בVM. בBehavior מצמידים עם Binding מאפיינים בVM והוא דואג לשלוט בתצוגה.
הbehavior יכול להיות מוצמד למיכל של מספר נתונים למשל וכך לשלוט בכולם יחד. בVM התוית יכולה להיות מוצמדת למספר מאפיינים וכך לשלוט בהן כקבוצה.
המתכנת צריך לממש ממשק מאד פשוט שלמעשה שואל אותו לגבי תוית מסויימת מהי ההרשאה הנדרשת. את הProvider הזה מאתחלים עם העלייה של האפליקציה (bootstrapper in prism). מאחוריו ניתן להסתיר מימוש של קבצי XML, שירותים מקוונים וכו’.
חסרון מסויים זה שReadOnly למעשה מגדיר את רכיב התצוגה כIsEnable=false שזה לא ממש ReadOnly, ע”מ להתגבר על זה בחרתי לאפשר החלפה של DataTemplate מסויים.
דוגמא למורכבות של העניין – נניח שיש רשימה של אנשים וניתן לערוך את השם שלהם. במידה והוגדר לקריאה בלבד אם נהפוך את הרשימה לIsEnable=false לא נוכל לגלול או לבחור אנשים משם. ואם הרשימה הזו מקושרת בMaster/Detail לאובייקט אחר אז מאבדים את היכולת הזו.
אני מניח שככל שנתקדם ניתקל במקרים מורכבים יותר שידרשו עוד התאמות.
בכל אופן העליתי את התשתית הזו לcodeplex עם דוגמא פשוטה ניתן להגיע אליה – ב http://uiauth.codeplex.com/
אשמח לרעיונות נוספים… 
מיקרוסופט
הכריזה על גרסה של OneNote לאיפון.
לצערי זה עדיין לא זמין מישראל או מאיזשהו מקום מחוץ לארה”ב.
זו בערך הההערה הכי פופולארית שם (אפשר אירלנד? אוסטרליה וכו’…)
תופעה מטרידה שנתקלתי בה הרבה היא שבחיפוש בגוגל אני מקבל תוצאות מ expert-exchange שזה אתר דומה לStackOverflow רק בתשלום. זה מטריד כי יש אפשרות לראות את השאלה אבל בשביל התשובה צריך לשלם…
לא מעוניין שהאתר הזה יופיע בכלל אצלי על המפה.
אז מסתבר שיש תוספים שיפתרו את הבעיה עבורנו…
שניהם אגב יעבדו רק בגוגל רגיל ולא בחיפוש המהיר החדש.
לIE לא מצאתי.
למי שמשתמש במקלדת מיקרוסופט, יש את הכפתור המעצבן (לטעמי) F Lock (אי שם מימין למעלה).
הכפתור הזה נועד למעשה לשכפל את התפקוד של שורת הFים.
הכפתור הזה מעצבן כי ברירת המחדל שלו היא כבויה כלומר אין Fים. יש פונקציות אחרות (Open,New וכו’).
מה שמציק הוא שכאשר מכבים את המחשב הוא שוב מתאפס ונשאר כבוי, ואז אני מוצא את עצמי לוחץ F5 לדיבאג וזה לא זז עד שלוחצים עליו.
אז זהו שיש לזה פתרון. לא נכנסתי לעומק העניין אבל ניתן למצוא את ההסבר
כאן.
בכל אופן שינוי קטן ברגיסטרי פותר את העניין לתמיד, למעשה הכפתור נשאר כבוי אבל התפקוד מתהפך.
בכפוף לסוג המקלדת המדוייק יש להשתמש בקובץ הנכון.
כאשר עושים Add service reference לשירות נתונים נוצרים אובייקטים חדשים המייצגים את המודל. זאת בנוסף לפרוקסי (אותו אנחנו בעצם רוצים) המכיל את הנקודות קצה לכל האלמנטים במודל.
בWCF – ישנה אפשרות לשימוש חוזר באובייקטים כאשר הן לשרת והן ללקוח יש קישור אליהן.

עכשיו נניח תצורה מסויימת של פרוייקט.
- רוצים לעבוד N-tier והתבנית הנוחה ביותר היא Self tracking object
- רוצים למנוע תלויות ב Entity framework – אז מזיזים את הישויות לפרוייקט נפרד.
- רוצים להשתמש בWcf Data services ע”מ לקבל אובייקטים מהשרת.
- רוצים להשתמש גם בשירותים אחרים של WCF כדי להחזיר אובייקטים לשרת (עדכון וכו’)
התצורה הזו אינה דמיונית, היא מאד הגיונית, לתשאל עם Data Services זה תענוג, אולם שאר הפעולות (עדכון,הוספה,מחיקה) בד”כ דורשות קצת יותר לוגיקה ממה שנוח לעשות עם Data Services.
הבעיה כמובן היא שגם אם ללקוח יש קישור לפרוייקט של הישויות תהיה לו כפילות של ישויות תחת Namespace אחר.
ב Tip 52 מוצגת שיטה שלמעשה מיצרת פרוקסי ידנית כדי לעקוף את הבעיה הזו. רק שיש בעיה עם הגישה הזו. זה ידני – כל שינוי בשמות, הוספת/הורדת ישויות מחייב עריכה ידנית.
לכן הוספתי תבנית TT עם שינויים קלים שעושה את העבודה עבורי.
מצ”ב פרוייקט לדוגמא.
נקודות לתשומת לב -
- ב TT של הcontext יש תוספת של הNamespace של הישויות (החדש אם הוא שונה)
- ישנו override בDataService כדי לאפשר לMetadata של השירות לעלות בצורה תקינה. אבל זה נושא לפוסט אחר.
- ב TT של הישויות צריך לתקן את הנתיב ל Edmx.
- יש להוסיף רפרנס ל - System.Data.Services.Client מכיוון שהפרוקסי יורש מDataServiceContext
- ב TT של צד לקוח יש לעדכן נתיב ל Edmx והnamspace לישויות.
- אם נוצר קובץ כפול ואחד עם “1” בסוף – זו איזו תקלה לא ברורה שניתן לתקן (זה רק מעצבן ויזואלית) אם נכנסים לקובץ של הפרוייקט ומשנים שם את הערך של LastGenOutput שיהיה בלי 1.
More Posts
Next page »