Make a schedule to book appointments for visiting schools by the supervisors.

How to make a schedule for booking appointments to visit schools by supervisors. So that no more than one supervisor can visit the specified school in one day

Solved Solved
0 35 771
4 ACCEPTED SOLUTIONS

You should have at least the following table:

- ِAppointments table

- Schools table

- Supervisors table

- Agenda table

They will be "combined" in the Appointments table that would contains reference columns to each of the three other tables. 

Once you have this established, it will be easy to write an expression to exclude already-booked schools in a particular day. 

Please read this: References Between Tables | AppSheet Help Center 

أهلاً بك

View solution in original post

السلام عليكم,

I don't see a single reference in any of your tables. It is important that you study the first link I posted carefully: References Between Tablesnot just for this simple task, but because as you progress with your app, you'll keep running into obstacles and possibly unsolvable problems without establishing correct references between your tables. 

Anyway, based on your current table, it seems that your room booking form is based on the Schedule table. So in this table you should add at least a Ref column to the Schools table. 

When a user is inside this form, and chooses a certain date, then the "School" column should show only the schools not already booked for a visit during this day. For this you should put the expression below in the Valid if  field in the "School" column:

School Data[NUM] - SELECT(Schedule[School], [date-m] = [_ThisRow].[date-m])

If the user instead selects the school first, then the Date column should not allow dates booked already for the selected school. For this you should use this expression in the Valid if field of the "date-m" column:

ISBLANK(
  FILTER(Schedule, AND(
    [School] = [_ThisRow].[School],
    [date-m] = [_ThisRow].[date-m]
  ))
  - LIST([_ThisRow])
)

And add an error msg here something like: "Date already booked for this school. Please choose another date or another school."

In both expressions above we have used List Subtraction

_______

Is your "date-h" column for هجري dates? If so, what method you are using for the date conversion please? شكراً جزيلاً!

View solution in original post

Thanks my friend, this is kind of you. 

Actually I was just curious about the method you might be using. I know of three methods:

  1. A not so accurate complex formula; would give you an error margin of a day or two. I don't like it, so I won't write it 🙂

  2. Write a simple JSON parser in Apps Script, and use it to call a free API like the one offered by aladhan.com.

  3. My preferred method: I used the API above to generate a lookup table that you can add to your app. Here it is. Feel free to copy to your own Drive. The advantage of using a lookup table is having immediate calculations showing you the date before saving the form. Also you can retrieve the corresponding Hijri date with a simple Dereference Expression.

    Convertisseur de dates Grégorienne Hijri - Google Sheets 

View solution in original post

عليكم السلام ورحمة الله وبركاته

ln this case we must have a log of schools visited twice during a given week. One way to do this is to create a slice on the Schedule table. Let's name it twiceWeeklyVisits. The slice's Row filter condition would be:

COUNT(
  FILTER(Schedule,
AND(

    [School] = [_ThisRow].[School],
    ISOWEEKNUM([date-m]) = ISOWEEKNUM([_ThisRow].[date-m])
  ))
) >= 2

The twiceWeeklyVisits slice will contain all Schedule records, visiting the same school during the same week, at least twice. From now on, the form will not allow more than two visits, but the slice has to accommodate for earlier records, that's why we used ">= 2" instead of "= 2".

Now back to our earlier expressions. The Valid if  field of the School column should have the following formula:

School Data[NUM]
- SELECT(Schedule[School], [date-m] = [_ThisRow].[date-m])
- SELECT(twiceWeeklyVisits[School], 
    ISOWEEKNUM([date-m]) = ISOWEEKNUM([_ThisRow].[date-m])
)

The Valid if field of the date-m column, should in turn have this formula:

ISBLANK(
  FILTER(Schedule, AND(
    [School] = [_ThisRow].[School],
    [date-m] = [_ThisRow].[date-m]
  ))
  - LIST([_ThisRow])
  + FILTER(twiceWeeklyVisits, AND(
      [School] = [_ThisRow].[School],
      ISOWEEKNUM([date-m]) = ISOWEEKNUM([_ThisRow].[date-m])
  ))

)

 

View solution in original post

35 REPLIES 35

You should have an Appointments table referencing both a Schools table and an Agenda table containing booked dates. 

In your Appointment Form, after choosing a date, your form should display a list of schools to the user, excluding the schools that have appointments for the chosen day. 

Very nice
Could you explain to me more?
Do I create two schedules, one for appointments and one for schools
How are they combined?
Are there functions?

With thanks

You should have at least the following table:

- ِAppointments table

- Schools table

- Supervisors table

- Agenda table

They will be "combined" in the Appointments table that would contains reference columns to each of the three other tables. 

Once you have this established, it will be easy to write an expression to exclude already-booked schools in a particular day. 

Please read this: References Between Tables | AppSheet Help Center 

أهلاً بك

Wonderful
Already i have created the four tables.
Can you help me write an expression to exclude schools already booked on a particular day.

best wishes

Please show the column of your tables. 

The expression would be based on a SELECT() statement operating on the Agenda table, and would be used inside the Valid if field of your Ref column to the Schools table. 

Now that you have read the first guide, please also read the following guides:

SELECT() | AppSheet Help Center 

IN() | AppSheet Help Center 

Dereference Expressions | AppSheet Help Center 

List Dereference | AppSheet Help Center 

I read the guide
I wrote this formula
But it didn't work

 

SELECT(School data [schoolname], ([schoolname] = [shcoolname]), TRUE)

Please post screenshots showing the columns of your tables from the app editor. Thank you.

These are the pictures of the tables

schedule.pngsupervisor.pngschool.pngAgenda.png

Thank you.

السلام عليكم,

I don't see a single reference in any of your tables. It is important that you study the first link I posted carefully: References Between Tablesnot just for this simple task, but because as you progress with your app, you'll keep running into obstacles and possibly unsolvable problems without establishing correct references between your tables. 

Anyway, based on your current table, it seems that your room booking form is based on the Schedule table. So in this table you should add at least a Ref column to the Schools table. 

When a user is inside this form, and chooses a certain date, then the "School" column should show only the schools not already booked for a visit during this day. For this you should put the expression below in the Valid if  field in the "School" column:

School Data[NUM] - SELECT(Schedule[School], [date-m] = [_ThisRow].[date-m])

If the user instead selects the school first, then the Date column should not allow dates booked already for the selected school. For this you should use this expression in the Valid if field of the "date-m" column:

ISBLANK(
  FILTER(Schedule, AND(
    [School] = [_ThisRow].[School],
    [date-m] = [_ThisRow].[date-m]
  ))
  - LIST([_ThisRow])
)

And add an error msg here something like: "Date already booked for this school. Please choose another date or another school."

In both expressions above we have used List Subtraction

_______

Is your "date-h" column for هجري dates? If so, what method you are using for the date conversion please? شكراً جزيلاً!

You are so amazing and so beautiful 💃👍 
All expressions work very well
Thank you very much 😘

For the Hijri date
I'm converting the date and entering it manually as text

I will look for a way to convert it and maybe ask in the APPSHEET community

If I find a way, I will send it to you.

Thanks my friend, this is kind of you. 

Actually I was just curious about the method you might be using. I know of three methods:

  1. A not so accurate complex formula; would give you an error margin of a day or two. I don't like it, so I won't write it 🙂

  2. Write a simple JSON parser in Apps Script, and use it to call a free API like the one offered by aladhan.com.

  3. My preferred method: I used the API above to generate a lookup table that you can add to your app. Here it is. Feel free to copy to your own Drive. The advantage of using a lookup table is having immediate calculations showing you the date before saving the form. Also you can retrieve the corresponding Hijri date with a simple Dereference Expression.

    Convertisseur de dates Grégorienne Hijri - Google Sheets 

ما شاء الله

you are creative
Thanks, my friend
I learned a lot from you
I hope to cooperate in the future

بإذن الله، يكون لي الشرف

السلام عليكم

hello joseph
If you want to write an expression, to make a maximum visit to the school twice a week from all supervisors.
What can I add to the previous expression?

عليكم السلام ورحمة الله وبركاته

ln this case we must have a log of schools visited twice during a given week. One way to do this is to create a slice on the Schedule table. Let's name it twiceWeeklyVisits. The slice's Row filter condition would be:

COUNT(
  FILTER(Schedule,
AND(

    [School] = [_ThisRow].[School],
    ISOWEEKNUM([date-m]) = ISOWEEKNUM([_ThisRow].[date-m])
  ))
) >= 2

The twiceWeeklyVisits slice will contain all Schedule records, visiting the same school during the same week, at least twice. From now on, the form will not allow more than two visits, but the slice has to accommodate for earlier records, that's why we used ">= 2" instead of "= 2".

Now back to our earlier expressions. The Valid if  field of the School column should have the following formula:

School Data[NUM]
- SELECT(Schedule[School], [date-m] = [_ThisRow].[date-m])
- SELECT(twiceWeeklyVisits[School], 
    ISOWEEKNUM([date-m]) = ISOWEEKNUM([_ThisRow].[date-m])
)

The Valid if field of the date-m column, should in turn have this formula:

ISBLANK(
  FILTER(Schedule, AND(
    [School] = [_ThisRow].[School],
    [date-m] = [_ThisRow].[date-m]
  ))
  - LIST([_ThisRow])
  + FILTER(twiceWeeklyVisits, AND(
      [School] = [_ThisRow].[School],
      ISOWEEKNUM([date-m]) = ISOWEEKNUM([_ThisRow].[date-m])
  ))

)

 

You are really creative
Expressions are already working.

Just
If I wish to add a phrase

SCHEDULE[date-m]
The date is automatically inserted
to express
ISBLANK(
FILTER(Schedule, AND)
[School] = [_ThisRow].[School],
[date-m] = [_ThisRow].[date-m]
))
- LIST([_ThisRow])
+ FILTER(twiceWeeklyVisits,
ISOWEEKNUM([date-m]) = ISOWEEKNUM([_ThisRow].[date-m])
)
)
So what do I use?

I'm sorry, I don't understand. Would you please explain further? Thanks.

I apologize that I cannot pass the information on to you

I mean:

That the [date-m] field I already put the statement in :

SCHEDULE [date-m]

The date will be added automatically

If I add to it the expression you sent me, which is:

ISBLANK(
FILTER(Schedule, AND)
[School] = [_ThisRow].[School],
[date-m] = [_ThisRow].[date-m]
))
- LIST([_ThisRow])
+ FILTER(twiceWeeklyVisits,
ISOWEEKNUM([date-m]) = ISOWEEKNUM([_ThisRow].[date-m])
)
)

How do I combine the two expressions?

I hope I have made it more clear

Sorry again I can't make sense of this, how would Schedule[date-m] automatically add the dates? this would rather restrict you to dates already registered and prevent you from adding new dates.

Let's forget about the expressions. Please just explain in plain language what do you want to do. You want the date to be automatically filled, based on what criteria? 

ممكن تكتب بالعربي لو تحب..

بالفعل أرغب الكتابة باللغة العربية بدل استخدام الترجمة 😁

 

حقل (التاريخ الميلادي) لدي مرتبط بالجدول الزمني ويأخذ البيانات من الجدول (SCHEDULE)

للتوضيح أكثر في الصور المرفقة

alfakeah_1-1652793603386.png

أرغب في إضافة التعبير الذي أرسلته انت والذي يبدأ بـ (ISBLANK) 

مع الصيغة الأولى 

جربت AND  ولم تعمل

alfakeah_2-1652793851173.png

اعذروني على الأزعاج..

السلام عليكم، لا يوجد إزعاج أبداً، الهدف من هذا المنتدى هو تقديم المساعدة لبعضنا البعض..

أولاً: ما هو الفرق بين الجدولين؟ 
Agenda و Schedule?
أرى أنهما يحتويان على نفس أسماء الأعمدة بالضبط مع ترجمة الأسماء. إذا كان الهدف هو إظهار الأسماء المترجمة في التطبيق، فيمكنك بدلاً من هذا استخدام حقل
Display Name
ًإذا كان الهدف غير ذلك، فرجاءً توضيح السبب وراء وجود الجدولين سويا

ثانياً: حقل
Valid if
وظيفته هو استبعاد القيم التي لا تحقق الشروط المدرجة في التعبير المدرج داخل الحقل، ولكن لا يمكن استخدامه لأجل الملء التلقائي لقيمة العمود

بشكل عام، بعيداً عن التطبيق، بحسب ما فهمت، فأنت تريد ملء التاريخ تلقائياً حين حجز موعد جديد لزيارة المدرسة.. السؤال هو: ما هي القاعدة التي تريد ملء التاريخ على أساسها؟ ما الذي كنت لتفعله باستخدام الورقة والقلم بدون وجود التطبيق؟ شكراً

شكرا جزيلا لك

- الجدول (1)
Schedule
يحتوي على الأسابيع والأيام و التواريخ الثابتة للعام الدراسي


- الجدول (2)
Agenda 
هو الجدول الزمني للمشرف حيث سنقوم بإدخال الزيارات فيه.

القاعدة هي :  جلب الأسبوع واليوم والتاريخ الهجري والميلادي من الجدول (1) وإضافتها للجدول (2)  

----

ملاحظة : الطريقة التي أرسلتها لك في الصورة الأولى تعمل معي بشكل جيد، لكن المشكلة عند إضافة تعبير آخر عليها لا يعمل التعبير.

ممممم.. شكراً

طيب مبدئياً للأسف كل ما سبق لن يعمل بصورة صحيحة لأن التعبيرات يجب وضعها في نفس الجدول الذي يتم من خلاله تسجيل الزيارات وفي  حالتنا هذا الجدول هو:
Agenda
وليس:
Schedule

التعبيرات سيتم قبولها من خلال التطبيق ولن تظهر أية أخطاء حين إدخال التعبيرات، لأنها لغوياً صحيحة.. لكنها لن تعطي النتيجة المرجوة.. على سبيل المثال، إذا كنا نبحث عن الزيارات السابقة لمعرفة هل تمت زيارة نفس المدرسة في نفس اليوم أو مرتين خلال نفس الأسبوع، فالتعبير يقوم بالبحث في جدول التواريخ الثابتة للعام الدراسي, وليس جدول الزيارات، وبالتالي حين استخدام التطبيق لن تظهر لك التواريخ المطلوبة بطريقة صحيحة، لأن البحث لا يتم في المكان الصحيح.. 

لا توجد مشكلة، سنقوم بضبط التعبيرات السابقة من جديد مع تغيير الجدول داخل التعبير.. 

أولاً: إذا كنت قد أضفت عموداً للمدرسة داخل جدول التواريخ الثابتة بناءً على نصيحتي السابقة فيجب عليك الآن إزالته.. ربما لم تفعل ذلك بل أضفت العمود إلى جدول الزيارات، وهو الإجراء الصحيح..

ثانياً: يجب إجراء التغييرات التالية، وسنقوم أيضاً بإضافة تعبير إضافي للسماح فقط بالزيارات خلال التواريخ الثابتة للعام الدراسي، فلا يمكن مثلاً إجراء زيارة لمدرسة خلال العطلات أو نهاية الأسبوع

1. The Slice

يجب إنشاؤها من جدول الزيارات وليس جدول التواريخ الثابتة للعام الدراسي

Create a slice on the Agenda table. Let's name it twiceWeeklyVisits. The slice's Row filter condition would be:

COUNT(
  FILTER(Agenda,
AND(

    [School] = [_ThisRow].[School],
    ISOWEEKNUM([
التاريخ الميلادي]) = ISOWEEKNUM([_ThisRow].[التاريخ الميلادي])
  ))
) >= 2

2. The Agenda Table 

The Valid if  field of the School column, should have the following formula:

School Data[NUM]
- SELECT(Agenda[School], [
التاريخ الميلادي] = [_ThisRow].[التاريخ الميلادي])
- SELECT(twiceWeeklyVisits[School], 
    ISOWEEKNUM([التاريخ الميلادي]) = ISOWEEKNUM([_ThisRow].[التاريخ الميلادي])
)

The Valid if  field of التاريخ الميلادي column, should in turn have this formula:

AND(
  IN(
[_This], Schedule[date-m]),
  ISBLANK(

    FILTER(Agenda, AND(
      [School] = [_ThisRow].[School],
      [التاريخ الميلادي= [_ThisRow].[التاريخ الميلادي]
    ))
    - LIST([_ThisRow])
    + FILTER(twiceWeeklyVisits, AND(
        [School] = [_ThisRow].[School], 
        ISOWEEKNUM([
التاريخ الميلادي]) = ISOWEEKNUM([_ThisRow].[التاريخ الميلادي])
    ))

  )
)

رائع

بالفعل أنا كنت أغير في التعبيرات حسب ما أريد فكانت تعمل معي
وهي متطابقة لكل ما كتبت  في رسالتك الأخيرة

كل ما كنت أريده هو هذا التعبير ولكنه لا يعمل ربما يكون ناقصاً وقد قمت أنا بتعديله فأرجو منك مراجعته
AND(
  IN(
[_This], Schedule[date-m]),
  ISBLANK(

    FILTER(Agenda, AND(
      [School] = [_ThisRow].[School],
      [التاريخ الميلادي= [_ThisRow].[التاريخ الميلادي]
    ))
    - LIST([_ThisRow])
    + FILTER(twiceWeeklyVisits, AND(
        [School] = [_ThisRow].[School],
        ISOWEEKNUM([
التاريخ الميلادي]) = ISOWEEKNUM([_ThisRow].[التاريخ الميلادي])
       )
    )

  )
)

طيب مثلما يقولون إذا عرف السبب بطل العجب 😁 شكراً

عذراً هذه غلطة مني نسيت إضافة هذا الجزء وأنت قمت بإضافة المطلوب وبالطريقة الصحيحة.. أحسنت!! 👏 ما شاء الله

مرحبا جوزيف
كيف أخبارك؟

استبدلت 
IN
في العبارة السابقة بـ
SELECT
فأصبحت هكذا

AND(
SELECT(schedule[date-m],
[date-h] = [_ThisRow].[التاريخ الهجري]),
ISBLANK(
FILTER(Agenda, AND(
[المدرسة] = [_ThisRow].[المدرسة],
[التاريخ الميلادي] = [_ThisRow].[التاريخ الميلادي]
))
- LIST([_ThisRow])
+ FILTER(twiceWeeklyVisits, AND(
[المدرسة] = [_ThisRow].[المدرسة],
ISOWEEKNUM([التاريخ الميلادي]) = ISOWEEKNUM([_ThisRow].[التاريخ الميلادي])
))
)
)

لكنه يعطيني خطأ هل من الممكن مراجعتها؟

لك تحياتي

حياك الله،

لماذا؟ ما الهدف من هذا الاستبدال؟

الخطأ طبيعي لأن كل التعبيرات المشمولة داخل
AND()
يجب أن يُرجِع كل منها قيمة منطقية: صحيح أم خطأ، في حين أن القيم التي يتم إرجاعها من التعبير الذي أدخلتَه هي تاريخ..

التعبير داخل 
IN
لا يعمل بشكل صحيح فهو لا يجلب التاريخ تلقائيا من الجدول 
schedule
لذلك قمت باستبداله 

الهدف من التعبير لم يكن جلب التاريخ تلقائياً من الجدول، بل قصر التواريخ المتاحة لاختيار ميعاد الزيارة، على التواريخ المشمولة ضمن الأيام الدراسية في العام الدراسي..

بالإضافة إلى أن حقل 
Valid if 
لا يمكن استخدامه إلا لهذا الغرض: التأكد من صلاحية القيم المدخلة أو قصرها على قائمة محددة

هل هناك طريقة لجلب التاريخ تلقائيا
بالإضافة إلى إلى قصر التواريخ المتاحة لاختيار ميعاد الزيارةعلى التواريخ المشمولة ضمن الأيام الدراسية

هذا التعبير
SELECT(schedule[date-m],
[date-h] = [_ThisRow].[التاريخ الهجري])
يعمل معي جيداً في حقل
Valid if 
لكن لم استطع أن أجمع بينه وبين التعبير الذي كتبته أنت

نعم ذلك ممكن، ولكن ما هي القاعدة التي تريد جلب التاريخ على أساسها؟ لديك قائمة من التواريخ الصالحة للاختيار، وتريد جلب أحدها تلقائياً، أي تاريخ من تلك القائمة تود جلبه؟ 

بغض النظر عن صحة التعبير الذي كتبتَه، ربما يمكنني استنتاج أنك تريد أن يقوم المستخدم بكتابة التاريخ الهجري، فيقوم التعبير بجلب التاريخ الميلادي المقابل له تلقائياً.. هل هذا هو الغرض؟ 

(ربما يمكنني استنتاج أنك تريد أن يقوم المستخدم بكتابة التاريخ الهجري، فيقوم التعبير بجلب التاريخ الميلادي المقابل له تلقائياً)

بالفعل هذا هو المطلوب 👌

ما فعلناه حتى الآن:

  1. استبعاد الأيام التي تمت فيها زيارة نفس المدرسة
  2.  استبعاد الأيام التي ستتسبب في زيارة نفس المدرسة أكثر من مرتين الأسبوع
  3.  قصر أيام الزيارات على التواريخ الثابتة للعام الدراسي

 النتيجة النهائية هي الحصول على قائمة من التواريخ الصالحة للاختيار، وهذه التواريخ هي تواريخ ميلادية..

إذا قام المستخدم بكتابة التاريخ الهجري يدوياً فربما يكون التاريخ الميلادي المقابل ضمن القائمة الصالحة للاختيار، أو لا، وفي هذه الحالة إذا كان التاريخ الميلادي المقابل غير صالح للاختيار ستظهر رسالة خطأ وسيتوجب عليه تكرار المحاولة مراراً حتى تختفي رسالة الخطأ.. لا أرى هذه الطريقة حلاً عملياً لواجهة المستخدم.. 

ولكن يمكنك المحافظة على التعبيرات كما هي بحيث تعمل على التواريخ الميلادية، بينما يتم إظهار قائمة التواريخ الهجرية الصالحة للاختيار للمستخدم.. في الواقع سيكون المستخدم قد قام باختيار تاريخ ميلادي، ولكن ما سيظهر له هو التاريخ الهجري.. 

هل هذا هو الغرض؟ 

الغرض كما ذكرت

لكن في ترتيبي أنا سيقوم المستخدم بالاختيار على النحو التالي 
الفصل الدراسي
بعد ذلك سيظهر له 
الأسابيع
ثم تظهر له
الأيام
ثم يظهر له
التاريخ الهجري
ثم يظهر له التاريخ الميلادي

alfakeah_0-1654612381884.png

 

حسناً.. استمراراً لما طبقناه في السابق، كما شرحتُ، لن نقوم بإجراء تغييرات على التعبيرات، ولكن ما سنقوم بتغييره هو إظهار التواريخ الصالحة للاختيار من التواريخ الهجرية بدلاً من التواريخ الميلادية، وبعد اختيار التاريخ الهجري سيقوم التطبيق بإظهار التاريخ الميلادي المقابل..

أولاً:

سنقوم بإضافة جدول تحويل التواريخ الذي أرفقتُه في تعليق سابق لي، بعدما سألتك عن الطريقة التي تقوم بها بتحويل التواريخ بين التقويم الميلادي والهجري، إلى التطبيق.. 

Key  في هذا الجدول، حقل التاريخ الميلادي سيكون من نوع تاريخ وسيكون هو مفتاح الجدول
Label أما حقل التاريخ الهجري فسيكون هو الوسم

ثانياً:

Ref  سنقوم بتغيير نوع كل حقول التاريخ الميلادي في كل الجداول الأخرى إلى نوع مرجع
مشيراً إلى جدول تحويل التواريخ

وهكذا ستظهر التواريخ الهجرية محل التواريخ الميلادية في كل صفحات التطبيق، في حقل التاريخ الميلادي، وهنا سيتوجب علينا إظهار اسم جديد يراه المستخدم بدلاً من اسم "التاريخ الميلادي".. لن نقوم بتغيير اسم الحقل بل سنقوم فقط بتغيير الاسم الذي يراه المستخدم.. أيضاً في الواقع سيتم الاختيار بناءً على التواريخ الميلادية وليست الهجرية، ولكن المستخدم سيرى بدلاً عنها التواريخ الهجرية.. 

Display Name  لذلك، داخل حقل التاريخ الميلادي سنقوم بالذهاب إلى خانة
ونضع بداخلها عنوان "التاريخ الهجري"، وهذا ما سيراه  المستخدم.. 

ثالثاً: 

نتيجة التغيير الذي قمنا به هو ظهور التواريخ الهجرية (الوسم) بدلاً من الميلادية (المفتاحفي كل حقول التواريخ الميلادية التي قمنا بتغيير نوعها إلى (مرجع)، في جميع الجداول..

 لإظهار التاريخ الميلادي، سنقوم بإضافة حقل جديد يمكن أن يكون افتراضياً من نوع تاريخ 
App Formula وسنقوم داخله بوضع التعبير التالي في خانة 

[التاريخ الميلادي].[التاريخ الميلادي]

Top Labels in this Space