פונקציות שימושיות בכל השפות - עמוד 3 - תכנות - HWzone פורומים
עבור לתוכן
  • צור חשבון

פונקציות שימושיות בכל השפות


Pure-Gold

Recommended Posts

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

לסקריפט שלי, בגלל שהם מאוד פשוטים ובגלל שיש ב autoit פונקציה מאוד מגניבה בשם IniRead .

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

לא מצאתי אחת, אז בניתי אחת משלי ועוד 2 פונקציות שקוראות לה ומשנות את הערך המוחזר, הנה ה prototypes שלהם:

char *IniReadKey ( FILE *ini_file, char *key, char *section, char *default_string )

int IniReadInt ( FILE *ini_file, char *key, char *section, int default_value )

short IniReadBool ( FILE *ini_file, char *key, char *section, short default_value )

והנה הקוד:

#define BUFFER_SIZE		1000

char *IniReadKey ( FILE *ini_file, char *key, char *section, char *default_string )
{
char buffer[BUFFER_SIZE];
short i;
short section_found = 0, key_found = 0 ;
char *value;
char *default_value = NULL;


if (default_string)
{
default_value = malloc ( strlen(default_string) +1 );
if (default_value)
strcpy (default_value, default_string);
}



if ( !ini_file || !key || !section ) return default_value;

fseek (ini_file, 0, SEEK_SET);


while ( fgets (buffer, BUFFER_SIZE, ini_file) )
{
if (buffer[0] == '#') continue; /* Comment */


if (section_found)
{
if (buffer[0] == '[') break; /* If a new section starts and no key was found, break and return */


for (i = 0, key_found = 1; key_found && !( buffer[i] == '=' && i != 0); i++)
key_found = ( toupper (buffer[i]) == toupper (key[i]) );

if (key_found)
{
buffer[strlen(buffer) - 1] = '\0'; /* Remove the new line character */

value = malloc ( (strlen(buffer)-i) );
if (!value) break;

strcpy (value, buffer + (i+1) );

free (default_value); /* We found the value, so we dont need a default value anymore... */

return value;
}

else continue;
}

if (buffer[0] == '[') /* new section */


for (i = 0, section_found = 1; section_found && !( buffer[i+1] == ']' && i != 0 ) ; i++)
section_found = ( toupper(buffer[i+1]) == toupper(section[i]) );



}

return default_value;

}


int IniReadInt ( FILE *ini_file, char *key, char *section, int default_value )
{
char *tmp_ptr;
int x;

tmp_ptr = IniReadKey ( ini_file, key, section, NULL );
if (tmp_ptr == NULL)
return default_value;

x = atoi (tmp_ptr);
free (tmp_ptr);


return x;
}


short IniReadBool ( FILE *ini_file, char *key, char *section, short default_value )
{
char *tmp_ptr;

tmp_ptr = IniReadKey ( ini_file, key, section, NULL );
if (tmp_ptr == NULL)
return default_value;

switch ( toupper(tmp_ptr[0]) )
{
case '1' :
case 'T' : /* True */
case 'Y' : /* YES */

free (tmp_ptr);
return 1;

case '0' :
case 'F' : /* False */
case 'N' : /* NO */

free (tmp_ptr);
return 0;

default:

free (tmp_ptr);
return default_value;
}
}

הרעיון הוא ש IniReadKey מקבלת pointer לקובץ, את ה key וה section שבו הוא נמצא, וערך שהיא תחזיר (שיכול להיות גם NULL )

אם היא לא תמצא, או תתרחש שגיאה מסויימת.אם IniReadKey תמצא את ה key והכל יעבוד כמו שצריך, IniReadKey תעתיק את הערך

של ה key ל heap ותחזיר pointer לשם. אגב, גם אם היא לא תמצא את ה key היא תקצה ב heap ותעתיק את default_string

לשם, היא כמובן לא תעשה את זה אם הוא יהיה NULL .

2 המיני פונקציות האחרות התפקיד שלהם הוא לקרוא ל IniReadKey ולהפוך את הערך של ה key ממחרוזת למשהו אחר.

IniReadInt משתמשת ב atoi להפוך את המחרוזת ל int ו IniReadBool משתמשת ב switch ומנסה לנחש האם זה

true או false . כן, אני יודע ש 2 הפונקציות האלה מאוד פשוטות וכנראה לא אמורות להופיע כאן... אבל כמות הפעמים שהייתי

צריך להפוך את הערך של IniReadKey ל int כבר עשתה לי בחילה.

אם מישהו מצא באגים או יש לו עצות לשפר את הקוד אני מאוד אשמח לשמוע

קישור לתוכן
שתף באתרים אחרים

  • תגובות 43
  • נוצר
  • תגובה אחרונה

בלולאות for שאתה עושה להשוואת מחרוזות כדאי לבדוק שהאות הנוכחית ב buffer לא 0 ושאתה לא חורג מ BUFFER_SIZE.

כמו כן ב malloc אתה צריך להוסיף 1 בשביל ה null termination.

קישור לתוכן
שתף באתרים אחרים

תודה שעברת על הקוד, אני מיד מתקן את הבאג עם strlen ו malloc .

לגבי לבדוק האם:

buffer[i] != '\0'

לדעתי זה מיותר כי אם הוא null terminator אז המשפט הבא יהיה 0:

toupper (buffer[i]) == toupper (key[i])

ואז הלולאה תפסיק לרוץ.

לגבי לבדוק האם I לא גדול מ BUFFER_SIZE .

שוב, אני לא בטוח... כי אם BUFFER_SIZE הוא בגודל סביר (100+ בייטים), מה הסיכוי שכל התווים יהיו זהים

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

ל '=' והערך עצמו, תזכור שברגע שהלולאה נתקלת ב '=' או באות שלא תואמת את [buffer[i היא יוצאת.

קישור לתוכן
שתף באתרים אחרים

  • 5 חודשים מאוחר יותר...

פתרון לגילוי אותיות בC# בעת פיתוח משחקים או סתם textboxים(למי שמנסה לעשות את זה עם direct input - זה לא הפתרון).

כאשר רוצים לגלות איזה מקש נלחץ ב- DirectInput זו לא בעיה. אך מה קורה כאשר מנסים לבדוק אילו אותיות המשתמש הקליד? לא ניתן הרי ליצור פונקציה שממירה מ- Key של DirectInput ל- char, מכיוון שיש מספר שפות במחשב(אצלנו זה בדרך כלל עברית ואנגלית), יש אותיות ראשיות וקטנות ע"י CAPS LOCK, יש אותיות ראשיות וקטנות ע"י SHIFT ועוד מלא מצבים שלא ניתן לבדוק אותם בקלות דרך DirectInput. הפתרון הוא פשוט - בטופס מעמיסים את 2 הפונקציות הבאות:


protected override bool ProcessKeyPreview(ref Message m)
{
bool flag = base.ProcessKeyPreview(ref m);

if (m.ToString().Contains("WM_CHAR"))
{
SendChar((char)m.WParam);
}
return flag;
}

protected override bool ProcessKeyEventArgs(ref Message m)
{
bool flag = base.ProcessKeyEventArgs(ref m);

if (m.ToString().Contains("WM_CHAR"))
{
SendChar((char)m.WParam);
}
return flag;
}

כאשר הראשונה נקראת כאשר יש פקדים בטופס, והשניה כאשר אין.

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

יש נתונים נוספים שאפשר להשיג ע"י lparam(לדוגמא - האם alt נלחץ באותו זמן).

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

אני מקווה שתמצאו את זה שימושי.

עריכה: עכשיו מצאתי את זה: http://www.codeproject.com/cs/miscctrl/validatingtextbox.asp

כנראה שהטיפ שלי לא כל כך חדשני.

קישור לתוכן
שתף באתרים אחרים

  • 1 חודש מאוחר יותר...

דפדפן בפייטון לטלפונים סלולריים:



#Created By Ofir Tadmor

import os
import appuifw
import e32

class MenuFileBrowser:
def __init__(self):
self.dir_stack = []

def show(self):
selected_file = None
focused_item = 0

while 1:
#show the list
if len(self.dir_stack) == 0:
entries = e32.drive_list()

index = appuifw.popup_menu(entries)

if index == None:
break
else:
self.dir_stack.append(entries[index])
else:
old_path = os.sep.join(self.dir_stack).encode('utf-8')
entries = [x.decode('utf-8') for x in os.listdir(old_path)]
entries.insert(0, u"..")
entries.insert(1, u".")

index = appuifw.popup_menu(entries)

if index == None or index == 0: #go up one directory
focused_item = self.dir_stack.pop()
elif index == 1: #select current directory
selected_file = old_path
focused_item = self.dir_stack.pop()
break
else:
short_path = entries[index]
new_path = ("%s%s%s" % (old_path.decode('utf-8'), os.sep, short_path)).encode('utf-8')
if os.path.isdir(new_path):
self.dir_stack.append(short_path)
else:
selected_file = new_path
focused_item = self.dir_stack.pop()
break

return selected_file

קישור לתוכן
שתף באתרים אחרים

  • 2 שבועות מאוחר יותר...
  • 4 שבועות מאוחר יותר...

כתבתי מחלקה קטנה ב PHP שיוצרת גרף בצורת פאי בעזרת GD.

יש מגוון של פרטמטרים שניתן לשנות כך שיש גמישות רבה ביצירת הגרף.

בסוף יש דוגמה בסיסית מאוד שמדגימה איך עושים שימוש במחלקה.

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

תהנו:

<?php
Class PieSlice {
var $Value; // Slice Vvlue;
var $NormalColor; //Slice color
var $Color3D; //Height color for slice at 3D mode
}

Class PieGraph {
var $TotalSum; //Total value of the pei
var $ImageWidth;
var $ImageHeight;
var $PieSlices; // Array
var $BGColor;
var $IsTransparent;
var $DefaultColors; // Array of default colors is no color set for the Slice
var $Height3D; // Set the pei height at 3D mode
var $Enable3D; // Enable 3D mode
var $GraphOffset;

function PieGraph($w,$h,$sum) {
$this->ImageWidth = $w;
$this->ImageHeight = $h;
$this->TotalSum = $sum;
$this->IsTransparent =true;
$this->DefaultColors = Array("ff0000","0000ff","00ff00","fff000","ffa800","1bbbf6","d41bf6","1beef6","f0eca4","ad7e18");
$this->BGColor = Array(0,0,0);
$this->Height3D = 10;
$this->Enable3D = true;
$this->GraphOffset = 45;
}

function SetBGColor($RGB) {
$this->BGColor = $this->Hex2RGB($RGB);
}

function Hex2RGB($hex_color = "") {
// Convert hexadecimal to format { FFFFFF --> (255,255,255) }
// If no color supplied the function generates a random color
if (!empty($hex_color)) {
$R = hexdec(substr($hex_color,0,2));
$G = hexdec(substr($hex_color,2,2));
$B = hexdec(substr($hex_color,4,2));
}else{
$R = rand()%255;
$G = rand()%255;
$B = rand()%255;
}
$RGB = Array($R,$G,$B);
return $RGB;
}

function Gen3DColor($RGB) {
// Set the color for Slice height for 3D effect
if ($RGB[0] > 50) $R = $RGB[0]-50; else $R = 0;
if ($RGB[1] > 50) $G = $RGB[1]-50; else $G = 0;
if ($RGB[2] > 50) $B = $RGB[2]-50; else $B = 0;
$RGB = Array($R,$G,$B);
return $RGB;
}

function AddSlice($vlaue, $color_rgb_1 = "", $color_rgb_2 = "") {
//Add Slice to the Slice array
$slice =& new PieSlice();
$slice->Value = $vlaue;
if (empty($color_rgb_1)) {
if (count($this->PieSlices) < 10) {
$slice->NormalColor = $this->Hex2RGB($this->DefaultColors[count($this->PieSlices)]);
}else{
$slice->NormalColor = $this->Hex2RGB();
}
}else{
$slice->NormalColor = $this->Hex2RGB($color_rgb_1);
}
if ($this->Enable3D) {
if (empty($color_rgb_2)) {
$slice->Color3D = $this->Gen3DColor($slice->NormalColor);
}else{
$slice->Color3D = $this->Hex2RGB($color_rgb_2);
}
}
$this->PieSlices[] =& $slice;
return $slice;
}

function DrawGraph() {
$image = imagecreatetruecolor($this->ImageWidth, $this->ImageHeight);
$bgcolor = imagecolorallocate($image, $this->BGColor[0], $this->BGColor[1], $this->BGColor[2]);
imagefill($image,0,0,$bgcolor);
if ($this->Enable3D) {
for ($i = (($this->ImageWidth/2)+$this->Height3D); $i > ($this->ImageWidth/2); $i--) {
$tmp_start = 0;
foreach ($this->PieSlices as $key => $val) {
$SliceColor = imagecolorallocate($image, $val->Color3D[0], $val->Color3D[1], $val->Color3D[2]);
$tmp_val = $tmp_start+(($val->Value/$this->TotalSum)*360);
imagefilledarc($image, $this->ImageWidth/2, $i, $this->ImageWidth-20, $this->ImageHeight/2, $this->GraphOffset+$tmp_start, $this->GraphOffset+$tmp_val , $SliceColor, IMG_ARC_PIE);
$tmp_start = $tmp_val;
}
}
}
if ($this->Enable3D) $GraphHeight = $this->ImageHeight/2; else $GraphHeight = $this->ImageHeight-20;
$tmp_start = 0;
foreach ($this->PieSlices as $key => $val) {
$SliceColor = imagecolorallocate($image, $val->NormalColor[0], $val->NormalColor[1], $val->NormalColor[2]);
$tmp_val = $tmp_start+(($val->Value/$this->TotalSum)*360);
imagefilledarc($image, $this->ImageWidth/2, $this->ImageHeight/2, $this->ImageWidth-20, $GraphHeight, $this->GraphOffset+$tmp_start, $this->GraphOffset+$tmp_val , $SliceColor, IMG_ARC_PIE);
$tmp_start = $tmp_val;
}
header('Content-type: image/png');
if ($this->IsTransparent) imagecolortransparent($image,$bgcolor);
imagepng($image);
imagedestroy($image);
}
}

//------- Using ---
$Graph = new PieGraph(500,500,300);
$Slice = $Graph->AddSlice(100);
$Slice = $Graph->AddSlice(100);
$Slice = $Graph->AddSlice(100);

$Graph->DrawGraph();
?>

[attachment deleted by admin]

קישור לתוכן
שתף באתרים אחרים

מצטער שאני נכנס פה, אבל רק רציתי להדגיש שפוינטר שערכו 0 (מושווה לאפס או ע"י השמה p = 0) הערך האמיתי שלו (כלומר הביטים, ערך הרגיסטר, או השמה ל-int) אינו חייב להיות 0 על פי הגדרת השפה. כלומר פוינטר שאותחל ל-0 או NULL, אינו בהכרח מצביע לכתובת 0x00000000.

נוח לחשוב על זה כאילו "0" של פוניטרים היא מילה שמורה כמו ""null ב-C# או משהו כזה. הכוונה למצביע שלא מצביע על כלום, אבל הערך אינו חייב ליהות 0.

אבל בגלל ש-א) נוח להעשות את זה. ב) כתובת 0 היא באמת לא שימושי במיוחד בשפת C לרוב המעבדים. ג) יש חוקים שקשורים בהמרות פוינטרים מאחד לשני ולערכים מספריים (int). נדמה לי שיותר קל למלא אותם אם פשוט מחליטים ש-0 זה 0.

קישור לתוכן
שתף באתרים אחרים

  • 1 שנה מאוחר יותר...

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

בפורמט של: יום שישי, ה-5 ביוני, 2009

<?php

function hebDate( $date ) {

$Days = array('ראשון','שני','שלישי','רביעי','חמישי','שישי','שבת');

$Months = array('ינואר','פברואר','מרץ','אפריל','מאי','יוני','יולי','אוגוסט','ספטמבר','אוקטובר','נובמבר','דצמבר');

return "יום " . $Days[date('w',$date)] . " ה-". date('d',$date) ." ב" . $Months[date('n',$date)-1] . ", " . date('Y',$date);

}

print hebDate( time() ); // יום שישי, ה5- ביוני, 2009

?>

תהנו.

קישור לתוכן
שתף באתרים אחרים

  • 1 חודש מאוחר יותר...

מחלקה סטאטית בc# שמריצה שאילתות הוספה או עידכון על SQL Server. ההרצה של השאילתות היא ממוקבלת (מספר הthreads נקבע ב initialize שלה) ככה שהיא מתאימה גם במקרים שרוצים ביצועים טובים על כמה וגם אם פשוט רוצים משהו שיריץ את השאילתות ברקע ולא יפריע לthread הראשי (במקרה הזה מומלץ לעשות ל initialize עם thread אחד).

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

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

אני מניח שאפשר לגרום לזה לעבוד גם על DB אחר, נגיד MySql או Access (רק ב thread אחד כמובן, זה Access אחרי הכל) אני יכול להסביר בפרטי.

public static class DBQueuer
{
public static void Initialize()
{
Initialize(DEFAULT_NUMBER_OF_THREADS);
}

public static void Initialize(int numberOfThreads)
{
if (_isInitialized)
return;
_isInitialized = true;
_numOfThreads = numberOfThreads;
_queue = new List<Queue<string>>(_numOfThreads);
_threadList = new Thread[_numOfThreads];
InitializeThreadsAndQueues();
}

private static void InitializeThreadsAndQueues()
{
for (int i = 0; i < _numOfThreads; ++i)
{
_queue.Add(new Queue<string>(MAX_QUEUE_SIZE + 1));
}
for (int i = 0; i < _numOfThreads; ++i)
{
_threadList[i] = new Thread(Start);
_threadList[i].Start(i);
}
}

private static void Start(object threadNumerObject)
{
int threadNumber = (int)threadNumerObject;
SqlConnection connection = GetConnection(); // You must implement this method yourself!
SqlCommand cmd = connection.CreateCommand();
while (_appRunning)
{
while (_queue[threadNumber].Count > 0)
{
string query;
lock (_queue[threadNumber])
{
query = _queue[threadNumber].Dequeue();
}
cmd.CommandText = query;
for (int i = 0; i < TRIES_TO_RUN_QUERY; ++i) // Give TRIES_TO_RUN_QUERY tries to executing the query
{
try
{
cmd.ExecuteNonQuery();
break;
}
catch (SqlException)
{
continue;
}
}

}
if (_queue[threadNumber].Count == 0)
Thread.Sleep(100);
}
cmd.Dispose();
connection.Close();
connection.Dispose();
}



public static void QueueQuery(string query)
{
if (string.IsNullOrEmpty(query))
throw new Exception("Problem with query");
unchecked
{
_queryCount++;
}
int currentQueue = _queryCount % _numOfThreads;
lock (_queue[currentQueue])
{
if (_queue[currentQueue].Count < MAX_QUEUE_SIZE)
{
_queue[currentQueue].Enqueue(query);
return;
}
}
while (true)
{
for (int i = 0; i < _numOfThreads; ++i)
{
if (null == _queue[i])
continue;
lock (_queue[i])
{
if (_queue[i].Count < MAX_QUEUE_SIZE)
{
_queue[i].Enqueue(query);
return;
}
}
}
Thread.Sleep(100);
}
}

public static void WaitForQueuesToEmpty()
{
for (int i = 0; i < _numOfThreads; ++i)
{
while (_queue[i].Count > 0)
Thread.Sleep(100);
}
}

public static void Die()
{
_appRunning = false;
}

private static int _numOfThreads;
private static List<Queue<string>> _queue;
private const int MAX_QUEUE_SIZE = 1000;
private const int TRIES_TO_RUN_QUERY = 5;
private const int DEFAULT_NUMBER_OF_THREADS = 10;
private static int _queryCount;
private static Thread[] _threadList;
private static bool _appRunning = true;
private static bool _isInitialized;
}

קישור לתוכן
שתף באתרים אחרים

  • 4 חודשים מאוחר יותר...

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

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

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

הנה התקציר של החלק ה"חשוב" של הפונקציה עצמה:

int userInput(char *fieldName, char *defaultValue, unsigned int flags, char *outStr, int length)
{
int c;
int index = 0, i;
unsigned short x, y;
.
.
.
for (c = getch(); c != '\n' && c != '\r'; c = getch())
{
// If user pressed on backspace, delete last char from string and screen.
if (c == '\b')
{
if (index > 0)
{
printf("\b_\b");
index--;
}
}
// Else print char to screen and copy it to string.
else if (index < length)
{
// Ignore any non-standard ascii
if (!isprint(c))
continue;
// If Numeric-Only flag is on, make sure we only allow the input of numeric values.
if ((flags & UIF_NUMERIC) && !isdigit(c))
{
// Position cursor behind the closing Field bracket.
getxy(&x, &y);
gotoxy(x + (length - index) + 2, y);
puts("- This field is numeric "); // Spaces are added to make text the same length as other warnings, so that old warninngs are overwritten
gotoxy(x, y);
continue;
}
if (flags & UIF_PASSWORD)
putch('*');
else
putch(c);
outStr[index] = (char)c;
index++;
}
}
.
.
.
return index;

לפונקציה המלאה וכל מה שמסביב:

http://pastebin.ca/1688865

קישור לתוכן
שתף באתרים אחרים

  • 5 חודשים מאוחר יותר...

מיון וחיפוש על דיסק © מצורף קובץ שהכנתי עם תוכנית הדגמה.

מציאת אורך של מספר ©:

number_length = (int)floor(log10((double)program_number))+ 1; 

מציאת כמות המבנים הרשומים בקובץ:

int GetTotalEntreis(FILE* db, int struct_size) {
fseek(db, 0, SEEK_END);
return ftell(db)/struct_size;
}

האם קובץ קיים:


enum bool {False,True};
typedef enum bool bool;

bool FileExists(const char* filename) {
FILE* file;
if (file = fopen(filename, "r")) {
fclose(file);
return True;
}
return False;
}

צבעים עם C:

#include <windows.h>

#define CONSOLE_TEXT_COLOR_GREEN 10
#define CONSOLE_TEXT_COLOR_RED 12
#define CONSOLE_TEXT_COLOR_WHITE 7

HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

SetConsoleTextAttribute(hConsole, CONSOLE_TEXT_COLOR_RED);
puts("some text");
SetConsoleTextAttribute(hConsole, CONSOLE_TEXT_COLOR_WHITE);

[attachment deleted by admin]

קישור לתוכן
שתף באתרים אחרים

ארכיון

דיון זה הועבר לארכיון ולא ניתן להוסיף בו תגובות חדשות.


×
  • צור חדש...