ריבוי מילים בפלקס (או… מה שמובן מאליו למתכנתי רובי און ריילס)

SingularPluralSort.pdf.00

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

בעצם זה נשכח, עד השבוע.

השבוע קיבלתי באג במערכת של לקוח שאומר שכאשר הוא בוחר מודול למחיקה הוא רואה (are you sure you want to delete the selected module) והוא רואה את אותה ההודעה בדיוק כאשר הוא בוחר מספר מודולים.

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

 

var module:String = "module";

			if(list.selectedItems.length > 1)
				module = "modules";

			Alert.show(StringUtil.substitute("are you sure you want to delete the selected {0}", module);

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

מה עשיתי?
1. חיפשתי בגוגל ומצאתי שמישהו עשה porting לקוד של מחלקת Pluralization מריילס ועשה אותה בas3
2. שכתבתי את הקוד וחשפתי החוצה פעולה אחת בלבד

הנה הקוד המלא (לשימושכם החופשי):

		public function PluralizationHelper()
		{
		}

		static:{
			PluralizationHelper.initPluralization();
		}

		private static var pluralWords : Array =
			[
				[/$/, 's'],
				[/s$/i, 's'],
				[/(ax|test)is$/i, '$1es'],
				[/(octop|vir)us$/i, '$1i'],
				[/(alias|status)$/i, '$1es'],
				[/(bu)s$/i, '$1ses'],
				[/(buffal|tomat)o$/i, '$1oes'],
				[/([ti])um$/i, '$1a'],
				[/sis$/i, 'ses'],
				[/(?:([^f])fe|([lr])f)$/i, '$1$2ves'],
				[/(hive)$/i, '$1s'],
				[/([^aeiouy]|qu)y$/i, '$1ies'],
				[/(x|ch|ss|sh)$/i, '$1es'],
				[/(matr|vert|ind)ix|ex$/i, '$1ices'],
				[/([m|l])ouse$/i, '$1ice'],
				[/^(ox)$/i, '$1en'],
				[/(quiz)$/i, '$1zes']
			];

		private static var singularWords : Array =
			[
				[/s$/i, ''],
				[/(n)ews$/i, '$1ews'],
				[/([ti])a$/i, '$1um'],
				[/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, '$1$2sis'],
				[/(^analy)ses$/i, '$1sis'],
				[/([^f])ves$/i, '$1fe'],
				[/(hive)s$/i, '$1'],
				[/(tive)s$/i, '$1'],
				[/([lr])ves$/i, '$1f'],
				[/([^aeiouy]|qu)ies$/i, '$1y'],
				[/(s)eries$/i, '$1eries'],
				[/(m)ovies$/i, '$1ovie'],
				[/(x|ch|ss|sh)es$/i, '$1'],
				[/([m|l])ice$/i, '$1ouse'],
				[/(bus)es$/i, '$1'],
				[/(o)es$/i, '$1'],
				[/(shoe)s$/i, '$1'],
				[/(cris|ax|test)es$/i, '$1is'],
				[/(octop|vir)i$/i, '$1us'],
				[/(alias|status)es$/i, '$1'],
				[/^(ox)en/i, '$1'],
				[/(vert|ind)ices$/i, '$1ex'],
				[/(matr)ices$/i, '$1ix'],
				[/(quiz)zes$/i, '$1']
			];

		private static var irregularWords : Array =
			[
				['person', 'people'],
				['man', 'men'],
				['child', 'children'],
				['sex', 'sexes'],
				['move', 'moves']
			];

		private static var uncountableWords : Array =
			[
				'equipment', 'information', 'rice', 'money', 'species', 'series', 'fish', 'sheep'
			];

		private static function makePlural (singular : String) : String
		{
			if (uncountableWords.indexOf(singular) != -1)
				return singular;

			var plural : String = new String();
			for each (var item : Array in pluralWords)
			{
				var p : String = singular.replace(item[0], item[1]);
				if (p != singular)
					plural = p;
			}
			return plural;
		}

		private static function makeSingular (plural : String) : String
		{

			if (uncountableWords.indexOf(plural) != -1)
				return plural;

			var singular : String = new String();
			for each (var item : Array in singularWords)
			{
				var s : String = plural.replace(item[0], item[1]);
				if (s != plural)
					singular = s;
			}
			if(singular == "")
				return plural
			else
				return singular;
		}

		[Bindable(event="pluralizationChangedEvent")]
		public static function pluiralize(count:int, word:String):String
		{
			if(count == 1)
				return makeSingular( word );

			return makePlural( word );
		}

		static private function initPluralization() : void
		{
			for each (var arr : Array in irregularWords)
			{
				pluralWords[pluralWords.length] = [arr[0], arr[1]];
				singularWords[singularWords.length] = [arr[1], arr[0]];
			}
		}
	}

איך מפעילים את הקוד מתוך האפליקציה? ובכן, כך:

PluralizationHelper.pluiralize(count, 'custom field')

הקוד הזה הוא חלק מספרייה שאני משחרר שהיא אוסף Helpers כלליים לאפליקציות פלקס.
את קוד המקור של כול הספרייה (שכרגע מכילה רק את הקלאס הזה אבל תתעדכן בהמשך) אפשר למצוא בgit בקישור הבא
http://github.com/KensoDev/Flex-Generic-Helpers

תהנו!

אם יש שאלות, תרגישו חופשי

תכנות מונחה התנהגות – רובי און ריילס (סקרינקאסט)

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

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

הערה: לחוויית צפיה מיטבית, מומלץ לבחור HD ולהגדיל את הוידאו למסך מלא.

זיהוי גרסת SQL Server בחיבור מרוחק

לעיתים קרובות מאוד (אולי מדי) אני מתחבר לבסיסי נתונים מרוחקים של לקוחות או על מכונות אחרות באותה רשת שעליה אני עובד כרגע.

אני באופן אישי מבצע את החיבור דרך Sql Server Management Studio 2008 אבל כמובן שאני יכול להתחבר לכול גרסה של בסיס נתונים קודמת מה שיכול להיות מאוד מבלבל.

כמו כן, על מכונת הפיתוח שלי אני מריץ שתי גרסאות של core, גם 2005 וגם 2008, כדי שאוכל לייצא את הנתונים בצורה תקינה לשרתי הproduction או הtest.

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

9-12-2010 12-06-29 PM

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

לכן, יש סקריפט t-Sql מאוד נחמד שנותן פרטים רבים (את כול מה שצריך בעצם) על בסיס הנתונים שאליו אתם מחוברים כעת דרך הAPI של Sql server לנושא ולא דרך מעקפים שונים ומשונים ובטח לא על ידי טלפונים ומיילים לחברת ההוסטינג לשאול אותם :-)

הנה הסקריפט

CREATE TABLE #SqlServerInformation(
editionText char(30),
versionText char(250),
productVersionText char(20),
levelText char(20))

INSERT INTO #SqlServerInformation (editionText, versionText, productVersionText, levelText)
VALUES (
CONVERT(char(30), SERVERPROPERTY('Edition')),
CONVERT(char(250), @@version),
CONVERT(char(20), SERVERPROPERTY('ProductVersion')),
CONVERT(char(20),SERVERPROPERTY('ProductLevel'))
)

SELECT * FROM #SqlServerInformation

drop table #SqlServerInformation

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

אשמח לתגובות

ניהול זכרון באפליקציות פלקס או איך לשמור על שפיות

צריכת זיכרון באפליקציות פלקסלאחרונה, יש המון דיבור ובאז ברשת ובקהילת הפלקס על ניהול זכרון בפלקס ועל שמירה של זכרון ברמות נמוכות וניתנות לניהול. אל לנו לסמוך רק על Adobe ועל ה SDK שינהלו לנו את הזכרון, זו בדיוק שיטת ה"יהיה בסדר" שלא עובדת לעולם בשום דבר טכני :-)

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

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

הדבר שתיארתי למעלה מתואר בהמון פוסטים שהכותרת שלהם היא "flex sucks" וכן הלאה, נחסוך תיאורים אחרים.

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

מה גם, שבעולם של היום שהוא עולם של mobile devices, חשוב לנו להבין שהזכרון הוא משאב עוד יותר מוגבל.

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

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

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

דליפות זכרון

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

אפליקציות פלקס מנהלות זכרון על ידי referances. כלומר, אם יש לי instanceA שיש לו referance דרך instanceB הוא לא ישוחרר מהזכרון עד שלא נשחרר את ההפניה.

Event Listeners

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

ניקח את פיסת הקוד הזו למשל

//objectX
objectY.addEventListener(some_event, some_function)

יש לנו כאן בעצם שני אובייקטים, יש לנו את אובייקט Y ויש את אובייקט X.

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

כן כן, תנו לזה לשקוע :-)

ניתן בevent Listeners לומר שהlistener  הוא weak, כלומר הוא לא נחשב כreference מאחורי הקלעים, יש ויכוח מאוד גדול כול פעם שהנושא הזה עולה ב StackOverflow או כול פורום אחר, הרבה אומרים שאדובי היו צריכים לעשות שevent listeners יהיו weak כברירת מחדל, אני חייב לומר שאני לא מסכים עם הקביעה הזו, אני חושב שאנחנו כמתכנתים צריכים לדעת לזרוק את ה listeners לפח בסיום השימוש

משתנים סטטיים

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

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

// static variable
public static var _foo:Foo;
//setting the value
_foo = new Foo();
//clean
_foo = null;

Dictionaries

Dictionaries זה בעצם אוסף של אובייקטים בצורה של מפתח-ערך, על כול שורה יש מפתח ולכות מפתח יש ערך.

אני אנסה להסביר את זה בצורה הטובה ביותר שניתן אבל אנא אמצו את עינכם, זה ממש קסמי Adobe ניהול הזכרון באובייקטים האלה :-)

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

אפשר לקבוע weak key כלומר במידה ואין הפניות (references) לאובייקט X, הוא יאסף על ידי הCollector אבל עכשיו יש לנו מצב מוזר, אפילו שיש לנו ערך בלי מפתח, הערך עדיין שם.

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

אשמח עם מישהו מצוות פיתוח פלקס יבהיר את המצב הזה…

נמשיך.

איך מנקים את המצב הזה?
יש האק, אם עושים לולאת For על הDictionary, כול הערכים שאין להם מפתחות ינוקו גם הם, כמובן בכול מגבלות הreferance הקיימות.

סיכום

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

כול ה"טיפים" האלה אולי יכולים להראות קטנוניים אבל כשמבינים מה קורה מאחורי הקלעים כשיש לנו למשל DataGrid שיש לו ItemRenderes שלכול אחד יש reference אחד שלא מנוקה יכול להבין שבסופו של יום מדובר בכמויות היסטריות לחלוטין של זיכרון.

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

שמירה על קבצי mxml מסודרים על ידי שימוש ב-ViewHelpers

כמתכנתי פלקס, אנחנו עובדים המון עם קבצי mxml. קבצים אלה נועדו להוות את הview שלנו בדיוק כמו ש-html מהווים את ה-markup של דפי אינטרנט.

היות ואפליקציות פלקס מכילות לוגיקה שקשורה ל-view, לוגיקה שקשורה ל-services וכן הלאה, אני תמיד בעד לשמור דברים מסודרים ונקיים, כחלק מהעקרונות של clean code. לכן, אני מאוד אוהב שקבצי ה-mxml שלי מכילים אך ורק קוד mxml ללא קוד actionscript כלל וכלל.

איך אני עושה את זה?

אני עושה שימוש במשהו שאני קורא לו ViewHelper. אין להתבלבל אגב עם המימוש של Cairngorm ל-ViewHelper מכיוון שזה לא אותו הדבר, אני עושה שימוש ב-custom class רק כדי לשמור על קוד מאורגן ונקי.

את השיטה הזו אפשר לממש ללא קשר לפריימוורק mvc שאתם עושים בו שימוש (אני אגב משתמש ב-RobotLegs).

מה השימוש לViewHelper?

השימוש הוא בעצם לשמור את כול קוד הActionScript מחוץ לקבצי הmxml שלנו. כמו כן, ליצור משהו גנרי שאנחנו יכולים להשתמש בו דרך כול האפליקציה ושתהיה שפה משותפת. כך למשל, אפשר שהViewHelper יכיל אוסף של ולידציות שאפשר להוסיף לView, כמו כן הוא יכיל Event Listeners שקשורים לאותו View וכו'.

אוקיי, אז איך נראית אפליקציה לדוגמא?

כך נראה מבנה הקבצים שלנו בתוך Flash Builder 4

Screen shot 2010-08-19 at 5.26.08 PM

ניתן לראות שיש לנו את האקליקציה המרכזית, יש לנו View component יש לנו את ה helper של ה view component הזה ויש לנו את הקלאס BaseViewHelper שמכיל את כול השדות והפקודות שכול ViewHelper יורש מהן.

אז בואו נראה איך נראה הקוד של BaseViewHelper

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

package com.kensodev.core
{
	import mx.core.UIComponent;

	public class BaseViewHelper
	{
		private var _view:UIComponent;

		public function BaseViewHelper()
		{

		}

		public function init():void
		{

		}

		public function set view(v:UIComponent):void
		{
			_view = v;
		}

		public function get view():UIComponent
		{
			return _view;
		}
	}
}

אז כמו שאפשר לראות יש לנו כאן referance לview שיכול להיות כול uiComponent וזה בערך הכול, אפשר להרחיב את הhelper לכול צורך שאתם רואים, למשל להצמיד לכול View מודל מסוים או dataProvider שצריך להיות bindable ועוד.

עכשיו, איך נראה ViewHelper שיורש מה base class שלנו?
כך


package com.kensodev.views.helpers
{
	import com.kensodev.core.BaseViewHelper;
	import com.kensodev.views.MyViewComponent;

	public class MyViewComponentHelper extends BaseViewHelper
	{
		public function MyViewComponentHelper()
		{
			super();
		}

		public function get myView():MyViewComponent
		{
			return MyViewComponent(this.view);
		}

		public override function init():void
		{
			//TODO Auto-generated method stub
			super.init();
		}

		public function myButton_clickHandler(event:MouseEvent):void
		{
			// TODO Auto-generated method stub
		}
	}
}

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

עכשיו לחלק האחרון, כך נראה הView שלנו

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"
		   width="400"
		   height="300"
		   creationComplete="helper.init()"
		   xmlns:helper="com.kensodev.views.helpers.*">

	<mx:Script>
		<![CDATA[

		]]>
	</mx:Script>

	<helper:MyViewComponentHelper view="{this}" id="helper" />

	<mx:Button id="myButton" click="helper.myButton_clickHandler(event)"

</mx:Canvas>

כמו שאפשר לראות, אנחנו כוללים את הhelper בתוך הview מה שגורם לו להיות "מופעל", כמו כן ניתן לראות שבקליק על הכפתור אני מפעיל פונקציה בתוך הhelper במקום לכתוב את הפונקציה ישירות על אותו הקובץ

דרך אגב, יש מוסכמה על השמות, כך שבעצם קל מאוד למצוא את הקבצים האלה במערכת
אם יש לכם view שנקרא myViewComponent אז הhelper שלו יקרא myViewComponentHelper והמודל שלו יקרא myViewComponentModel והקומנד יקרא myViewComponentCommand וכן הלאה.

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

Screen shot 2010-08-19 at 5.36.53 PM

קוד המקור של האפליקציה נמצא בgit, תרגישו חופשי להוריד ולראות איך זה בנוי.
http://github.com/KensoDev/view-helper-example

ולידציה לתעודת זהות ישראלית בC#

שלום חברים,

לאחרונה הייתי צריך לעשות ולידציה למספר תעודת זהות ישראלית.
הולידציה היא בטופס סליקת כרטיס אשראי ספציפית אבל זה לא משנה כלל לפונקציה :-)

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

תיהנו

   1: public static bool validateID(string idNumberString)

   2: {

   3:     if (idNumberString.Length < 9)

   4:         return false;

   5:

   6:     int int1 = Convert.ToInt32(idNumberString.Substring(0, 1)) * 1;

   7:     int int2 = Convert.ToInt32(idNumberString.Substring(1, 1)) * 2;

   8:     int int3 = Convert.ToInt32(idNumberString.Substring(2, 1)) * 1;

   9:     int int4 = Convert.ToInt32(idNumberString.Substring(3, 1)) * 2;

  10:     int int5 = Convert.ToInt32(idNumberString.Substring(4, 1)) * 1;

  11:     int int6 = Convert.ToInt32(idNumberString.Substring(5, 1)) * 2;

  12:     int int7 = Convert.ToInt32(idNumberString.Substring(6, 1)) * 1;

  13:     int int8 = Convert.ToInt32(idNumberString.Substring(7, 1)) * 2;

  14:     int int9 = Convert.ToInt32(idNumberString.Substring(8, 1)) * 1;

  15:

  16:     if (int1 > 9) int1 = (int1 % 10) + 1;

  17:     if (int2 > 9) int2 = (int2 % 10) + 1;

  18:     if (int3 > 9) int3 = (int3 % 10) + 1;

  19:     if (int4 > 9) int4 = (int4 % 10) + 1;

  20:     if (int5 > 9) int5 = (int5 % 10) + 1;

  21:     if (int6 > 9) int6 = (int6 % 10) + 1;

  22:     if (int7 > 9) int7 = (int7 % 10) + 1;

  23:     if (int8 > 9) int8 = (int8 % 10) + 1;

  24:     if (int9 > 9) int9 = (int9 % 10) + 1;

  25:

  26:     int sumOfAllInts = int1 + int2 + int3 + int4 + int5 + int6 + int7 + int8 + int9;

  27:

  28:     sumOfAllInts = sumOfAllInts % 10;

  29:     if (sumOfAllInts > 0)

  30:         return false;

  31:     else

  32:         return true;

  33: }

הקוד המקורי מאתר ASP תרגמתי אותו לc# והוספתי ולידציה לאורך של 9 תווים בהתחלה.

שיהיה בכיף!

אם אתם משתמשים בקוד שימו איזה תגובה כדי שאני אדע :-)