لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 08/05/21 في كل الموقع
-
الإصدار 1.0.0
11238 تنزيل
التصميم هو مهنة العصر الحالية، هذا العصر الذي يولي أهميةً كبيرةً منقطعة النظير للعامل البصري، فيدخل مجال التصميم في كل مناحي حياتنا اليومية فكل شيء تراه حولك بدءًا من صور أغلفة المنتجات وحتى الإعلانات والملصقات والشعارات وأغلفة الكتب وكل شيء تقريبًا قد مرَّ على يدي مصمم وعولج داخل أحد تطبيقات الرسم والتصميم فسوق التصميم كبيرٌ يزداد فيه الطلب على المصممين يومًا بعد يوم. تمثلت رؤيتنا للكتاب في أن يكون المرجع الأول للمصمم العربي أو من يريد تعلم مجال التصميم الجرافيكي وذلك بجعله شاملًا لكل ما يحتاج إليه المتعلم في بداية رحلته التعليمية في هذا المجال وليتضمن العناصر الأساسية في هذا التخصص سواء كان ذلك في الأساسيات أو البرامج والتطبيقات أو أفكار التصميمات. يهدف الكتاب لإخراج أفراد متمكنين من أساسيات مجال التصميم الجرافيكي ولديهم المعلومات والخبرة الأساسية اللازمة لدخول سوق العمل وتحقيق دخل مادي عبر سوق الإنترنت الكبير وذلك من خلال تنفيذ أعمال التصميم الجرافيكي عبر منصات العمل الحر العربية مثل مستقل وخمسات. يتكون الكتاب من خمسة أقسام رئيسية: الأساسيات والمبادئ البرامج والتطبيقات مجالات التصميم الجرافيكي قواعد التصميم المسار المهني والتطوير الذاتي دخول سوق العمل هذه النقاط الخمس نعدها شاملة لما يحتاج إليه المصمم الجديد ليكون قادرًا على إنتاج تصميم وبيعه في السوق. يستهدف الكتاب جمهور المصممين المبتدئين أو من يريدون دخول هذا المجال، وعليه فإن الكتاب ليس موجهًا للمصممين المتقدمين أو المحترفين فهؤلاء في الغالب يتعلمون مباشرة من مصادر متقدمة سواءً عربية أو أجنبية ولكن قد يكون لدى البعض منهم نقص في معرفة أساسيات التصميم الفنية والأكاديمية، لذا يمكنهم آنذاك الرجوع إلى فصول بعينها من هذا الكتاب أي أنَّ فصول هذا الكتاب قد تفيد حتى من كان متقدمًا في مجال التصميم التطبيقي ولكن دون أساس أكاديمي سليم. هذا الكتاب مرخص بموجب رخصة المشاع الإبداعي Creative Commons «نسب المُصنَّف - غير تجاري - الترخيص بالمثل 4.0». يمكنك قراءة فصول الكتاب على شكل مقالات من هذه الصفحة، «أساسيات تصميم الرسوميات»، أو تجدها مسردة بالترتيب التالي: مقدمة إلى تصميم الرسوميات (التصميم الجرافيكي) عناصر تصميم الرسوميات مبادئ تصميم الرسوميات الألوان في تصميم الرسوميات ونظرية الألوان تعرف على أشهر برامج وتطبيقات تصميم الصور والرسوميات مقدمة إلى برنامج أدوبي فوتوشوب Adobe Photoshop مقدمة إلى برنامج أدوبي إليستريتور Adobe Illustrator والتعرف على واجهته مساحات وقياسات العمل التصميمي النص وأسلوب الطباعة Typography في تصميم الرسوميات قواعد التعامل مع الصور والرسوميات قواعد تصميم الأيقونات والشعارات قواعد تصميم المطبوعات والإعلانات قواعد تصميم الواجهات قواعد تصميم الرسوم البيانية قواعد تصميم الهوية البصرية دليل المسار المهني لمصمم الرسوميات مواقع العمل الحر والعمل عن بعد لتصميم الرسوميات2 نقاط -
1 نقطة
-
لدي كود مشابة للتالي: import numpy as np avgDists = np.array([2, 9, 7, 10, 5, 3]) ids = avgDists.argsort()[:3] print(ids) # Output: array([0, 5, 4], dtype=int64) هل من الممكن استخدام نفس دالة argsort بترتيب تنازلي للحصول على مؤشرات indices أعلى ثلاثة العناصر؟1 نقطة
-
لدي مصفوفة NumPy ثنائية الأبعاد وأريد استبدال كل القيم الأكبر أو تساوي عتبة محددة T بالقيمة 255.0 import numpy as np arr = np.array([[1,2,3,4,5,6,7,8,9,0], [11,22,33,44,55,66,77,88,99,110]]) هل يجب أن أقوم بالمرور على كل عنصر في المصفوفة وأقوم بإستبداله يدويًا أم أن هناك دالة جاهزة أو طريقة أسرع في مكتبة Numpy تقوم بهذا الأمر؟ وكيف أقوم بهذا الأمر في حالة كان حجم المصفوفة مختلفًا (أي لم تكن المصفوفة ثنائية الأبعاد على سبيل المثال)؟1 نقطة
-
أريد التحقق مما إذا كانت مصفوفة numpy فارغة أم لا، لقد استخدمت الشرط التالي، لكن هذا يفشل إذا كانت المصفوفة كالتالي: import numpy as np a = np.array([[]]) if len(a) == 0: print('empty') else: print('not empty') ما الطريقة التي تجعل الشرط يتحقق ويتم طباعة empty؟1 نقطة
-
أرجو الاطلاع على الروابط بالترتيب، سوف تأخذ فكرة جيدة جداً عن كل مايتطلبه الأمر، لبدء بتعلم Django عليك البحث عن دورة للمبتدئين، أكاديمية حسوب لاتوفر دورات لتعمل إطار العمل هذا حالياً. بالتوفيق1 نقطة
-
1 نقطة
-
ليتم إرسال البيات للمخدم، علينا استعمال بروتوكول http والذي يتكفل بنقل البيانات عبر الانترنت، وفي صفحة HTML يتطلب وضع عنصر form اي الاستمارة، ويتم تحديد الخاصية action والتي هي مسار ملف بايثون الذي سيستجيب للطلبية، والخاصية method والتي هي http method التي تحدد نوع الطلبية المراد إرسالها للخادم، هل هي لجلب البيانات من قاعدة البيانات أي get أو إرسال ملفات و استمارات post او حذف بيانات delete.. أي عليك الاطلاع على كل من: HTML form http protocol python request مكتبة بعد فهم الاساسيات، انتقل لتعلم إطار عمل Django وهو اشهر back end للغة بايثون1 نقطة
-
هذه المراحل روتينية ويقوم فريق الدعم الفني بالتأكد من الخطوات و تفعيل الدورات على حسابك، وسيتم فتح الدورات في حسابك بأقرب وقت وقد تاخذ بعض الوقت، شكرا لصبرك.1 نقطة
-
السلام عليكم ورحمة الله وبركاته. انا عندي سؤال بالنسبة لshared preference. انا لم افهم طريقة عمل shared preference بشكل كامل لكن أعرف بأنه هو طريقة لحفظ الملفات في التطبيق حتى تكون مثل ماهي اذا دخلت التطبيق مرة اخرى، لكن هل هنالك طريقة لتغيير القيمه المحفوظه في المفتاح الموجود في shared preference بشكل تلقائي؟. بمعنى لو لدي متغير var او val رقمي دائما يرتفع من مثلا 10 الى 11 ثم الى 12 ثم ينزل الى11.. الخ انا مثلا اريد من shared pref ان يحفظ اولا الرقم 10 واذا تغير الى 11 تتغير القيمة المحفوظه معه بشكل تلقائي الى نفس الرقم فهل هنالك طريقة لعمل هذا الشيء؟ اتمنى اكون وفقت في شرح سؤالي بأفضل طريقة ممكنه.1 نقطة
-
سؤال ممتاز، لا يمكن تشغيل كود بايثون داخل المتصفح، ولهذا الغرض بالضبط يتم إرسال البيانات إلى الserver، يقوم الserver بمعالجة المدخلات، وثم إرسال الرد. يمكن للserver أن يقوم بتشغيل أي لغة تختارها، وتقوم بتهيئته كما تريد، ويكون التواصل بين المتصفح والserver من خلال الrequests.1 نقطة
-
يمكنك التواصل مع الدعم (من هنا) أو عبر الرابط التالي: https://support.academy.hsoub.com/ وإخبارهم بأي مشكلة تواجهك وهم سيقومون بمساعدتك.1 نقطة
-
الكود يعمل بشكل جيد بعد تعديل الإصدار1 نقطة
-
نعم ولكن يوجد حل بديل مجاني باستخدام الحزمة laravel-websockets المقدّمة من beyondcode وستجد في التوثيق الرسمي للارافيل شرح ورابط لهذه الحزمة وجميع التفاصيل المتعلّقة بكيفية استخدامها وتضمينها ضمن مشروعك.1 نقطة
-
لدي الكود التالي: r = numpy.zeros(shape = (width, height, 2)) // Width و height قيم عددية يقوم السطر السابق بتوليد مصفوفة حجمها width * height* 2، بدلاً من ذلك، أود معرفة ما إذا كانت هناك دالة أو طريقة لتهيئتها باستخدام NaN بدلًا من الأصفار، لتكون النتيجة كالتالي على سبيل المثال: # في حالة كان # width = 2 # height = 2 array([[[nan, nan], [nan, nan]], [[nan, nan], [nan, nan]]])1 نقطة
-
هناك دالتين في numpy يمكنهما فعل ذلك بسهولة وهما numpy.empty() و numpy.nan() ، حيث تستخدمان سويا في انشاء المصفوفة الفارغة، عن طريق انشاء مصفوفة في البداية باستخدام ا numpy.empty() ثم ملئها بقيم nan باستخدام numpy.nan(). يمكن استخدامها عن طريق تمرير أبعاد المصفوفة المراد انشاءها بدالة numpy.empty() ثم استخدام الدالة numpy.nan() كالتالي: an_array = np.empty((4,3)) an_array[:] = np.NaN print(an_array) OUTPUT [[nan nan nan] [nan nan nan] [nan nan nan] [nan nan nan]] خيار أخر عن طريق استخدام الدالة Numpy.full وذلك لملئ المصفوفة بالقيم nan كالتالي: a = np.full([height, width], np.nan) حيث أن height هي عدد الصفوف في المصفوفة التمراد انشاءها بينما width هو عدد الاعمدة.1 نقطة
-
كما تم الشرح في التعليقات السابقة فالمشكلة أن العناصر بداخل overlayer تأخذ نفس ال opacity من الأب وهو overlayer لذلك الحل لهذه المشكلة ببساطة هو جعل العناصر بداخل ال overlayer بنفس المستوى وهذه الطريقة هي المفضلة لعمل ال overlay لاحظ التعديل <div class="homeSection"> <div class="overlayer"></div> <div class="home-content"> <!--ووضعه بنفس المستوى overlayer قمت بإخراج هذا العنصر من --> <div> <h1 class="title">we are creative agency</h1> <p class="p"> <span class="nr">Nawwar</span> is an Egyptian IT-Training Center founded in 2012 We have identified the unique challenges people may face in learning a new technology and have exerted efforts in providing strategies to overcome them. We welcome your participation in our training </p> <button class="btn btn-start">Get started</button> <button class="btn btn-learn">Learn more</button> </div> </div> </div> وباستخدام هذه الطريقة لن تحتاج للتعديل في التنسيقات1 نقطة
-
يمكننا استخدام الدالة empty لإنشاء مصفوفة ثم القيام بتعبئتها بالقيمة المطلوبة من خلال التابع fill كما يلي: def fill(n): arr = np.empty(n) return arr.fill(np.nan) fill(5) # array([nan, nan, nan, nan, nan]) def fill(n): arr = np.empty(n) arr.fill(np.nan) return arr print(fill((3,2))) """ [[nan nan] [nan nan] [nan nan]] """ أو يمكنك أن تقوم يتعبئتها بشكل يدوي: def c(n): a = np.empty(n) a[:] = np.nan return a print(c((3,2))) """ [[nan nan] [nan nan] [nan nan]] """ وكطريقة سهلة يمكنك استخدام التابع full بحيث نمرر له أبعاد المصفوفة والقيمة المراد تعبئتها: def full(n): return numpy.full(n, np.nan) print(c((3,2))) """ [[nan nan] [nan nan] [nan nan]] """ أو من خلال التابع التالي حيث سنعتمد على مفهوم القوائم ثم تحويلها لمصفوفة نمباي: def list(n,row,col): return np.array(n * [np.nan]).reshape(-1,col) print(list(12,3,4)) """ [[nan nan nan nan] [nan nan nan nan] [nan nan nan nan]] """ لكن هنا نمرر عدد عناصر المصفوفة المطلوبة وعدد أسطر وأعمدة المصفوفة المطلوبة. ويمكنك أيضاً تنفيذ ماتريده بالشكل التالي: np.nan * np.zeros(shape=(3,2)) """ array([[nan, nan], [nan, nan], [nan, nan]]) """ كما ويمكنك من خلال الدالةtile حيث نمرر لها القيمة ثم الأبعاد كما في المثال التالي : np.tile(np.nan, (2, 3)) """ array([[nan, nan, nan], [nan, nan, nan]]) """ وبشكل عام فإن أسرع طريقة هي استخدام الدالة fill.1 نقطة
-
أولاً يجب أن نفهم المشكلة. ال unit vector أو متجه الوحدة هو متجه طويلته (magnitude) تساوي ال 1. وبالتالي فإن الشعاع التالي لايمثل متجه وحدة: import numpy as np # تعريف الشعاع التالي v = np.array([1,3]) # حساب الطويلة np.linalg.norm(v) #3.1622776601683795 # إذاً ليس متجه وحدة حيث أن التابع np.linalg.norm(x) يقوم بحساب الطويلة للشعاع. الآن إذا أردنا أن نقوم بتحويل هذا الشعاع إلى متجه وحدة فيجب أن نقوم بعملية normalizing. رياضياً فإنه لتحويل أي شعاع إلى شعاع وحدة يجب أن نقوم بقسمة جميع عناصره على طويلته، أي لتحويل الشعاع السابق يجب أن نقوم بقسمة قيمه على 3.16227766. import numpy as np v = np.array([1,3]) magnitude =np.linalg.norm(v) # نقسم كل عنصر على الطويلة v=v/magnitude # نختبر إذا أصبح متجه وحدة np.linalg.norm(v) # 1.0 # نجحنا حسناً إذا أردت أن لاتستخدم np.linalg.norm(v) يمكنك استخدام الصيغة التالية، فكما نعلم أن الطويلة هي الجذر التربيعي لمجموع مربعات قيم الشعاع: import numpy as np v = np.array([1,3,5,6,33]) magnitude =np.sqrt(np.sum(v**2)) # نقسم كل عنصر على الطويلة v=v/magnitude # نختبر إذا أصبح متجه وحدة np.linalg.norm(v) # 1.0 # نجحنا كما ويمكنك استخدام مكتبة Sklearn حيث تحتوي على طرق فعالة متاحة للمعالجة المسبقة للبيانات وأدوات التعلم الآلي الأخرى. عادةً ما يستخدم التابع normalize في هذه المكتبة مع المصفوفات ثنائية الأبعاد وتوفر خيار تسوية L1 و L2. سنستخدم في الكود التالي هذه التابع مع مصفوفة 1D حيث سنقوم باستخدام الدالة ravel لتسطيح المصفوفة : import numpy as np from sklearn.preprocessing import normalize v = np.array([1,3,5,6,33]) v = normalize(v[:,np.newaxis], axis=0).ravel() # نختبر إذا أصبح متجه وحدة np.linalg.norm(v) # 1.0 # نجحنا ,وأخيراً يمكنك استخدام الدالة الجاهزة لتحويل الشعاع إلى شعاع وحدة بشكل مباشر من خلال المكتبة transformations: # لتحميلها : pip install transformations import numpy as np import transformations as trafo v = np.array([1,3,5,6,33]) unit_v = trafo.unit_vector(data, axis=1) # نختبر إذا أصبح متجه وحدة np.linalg.norm(unit_v) # 1.01 نقطة
-
1 نقطة
-
السلام عليكم احاول جمع وارسال البيانات من نموذج بصفحةhtml بعد التحقق من ادخال البيانات بالحقول باستخدام jquery validation الى google sheet وتمكن بطريقة ما من منع ارسال حقول فارغة الا انني اواجه مشكلة.ففي النموذج يظهر جدول يبين ما تم شراءة من الصفحة وتحديد العدد المطلوب مع امكانية حذف الطلب، ويفترض انه يمنع ارسال البيانات في حال كان جدول الطلب فارغا .. الا انه يتم الارسال. حاولت حل المشكلة كتالي: serverlessForm.addEventListener('submit', e => { //للتاكد من الكمية المختارة ليست صفر if ($('[data-product-quantity]').val() === "1" || $('[data-product-quantity]').val()==="2") { console.log($('[data-product-quantity]').val()) $('[data-product-quantity]').addClass("success") } //عندما تصبح الحقول محققة من قبل jquery vlidation ارسل البيانات ل google sheet if(Name.hasClass("success") && phone.hasClass("success") && address.hasClass("success") && $('[data-product-quantity]').hasClass("success") ){ e.preventDefault(); spinner.show(); fetch(scriptURLC, { mode: 'no-cors', method: 'POST', body: new FormData(serverlessForm) }) .then(res => { console.log(res); spinner.hide(); swal("تم ارسال طلبك بنجاح!", "سنتواصل معك قريبا.احظى بتسوق ممتع!", "success"); modal.modal('hide'); serverlessForm.reset(); Name.removeClass("success") phone.removeClass("success") address.removeClass("success") return true; }) .catch(error => { swal("حدث خطأ ما!", `ارجو معاودة المحاولة لاحقا: ${error}`, "error"); // todo enable submit button }) } }); ولم تعمل، فقمت باستخدام دالة addMethod التابعه لjquery validation ولم تعمل ايضا... jQuery.validator.addMethod("orders", function (value, element) { var numberOfOrders= $('[data-product-quantity]').val(); return this.optional(element) || numberOfOrders !=="0"; },'لطفا اختيار العدد المطلوب من فرشاة ايمي') كما انه بالشاشات الصغيرة عند تحديد العدد المطلوب يتم حذف المنتج تلقائيا فما السبب رابط العمل على github ---> https://github.com/aishazaki/aishazaki-emibrush.github.io وشكرا1 نقطة
-
بما أنك تستخدم إطار العمل express، يمكنك الحصول على محتوى app من خلال req.app التي يتم تضمينها مع كل طلب. بحيث يتم إضافة أي بيانات إضافية من خلال app.set: app.set('anykey', {}) والحصول عليها ضمن الكود يكون من خلال المتغير req الذي سيكون موجود مع كل طلب يتم ربطه بالمتحكّم الخاص به بالشكل التالي: req.app.get('anykey') كما يمكنك تعديل كود الملف الرئيسي لديك وجعل app متغيّر عام بهذا الشكل: var app = module.exports = express(); app.use(app.router); وعندها يمكنك تضمين app في الأجزاء المتفرقة من الكود لديك كالتالي: var app = require('../app'); app.get('/', function(req, res, next) { res.render('index'); }); وبشكل مشابه يمكنك بباسطة تمرير المتغيرات إلى المتحكمات لديك بهذا الشكل: var controllers = require('./controllers')({app: app}); وإنشاء واجهة عامة للمتحكمات تستقبل هذه المتغيرات: // controllers.js module.exports = function(params) { return require('controllers/index')(params); } ثم الوصول إليها يكون بهذا الشكل: // controllers/index.js function controllers(params) { var app = params.app; controllers.users = require('./users'); controllers.index = function(req, res) { ... }; } module.exports = controllers; ويمكنك الإطلاع على طريقة مشابهة من خلال استخدام locals في node.js موجودة هنا:1 نقطة
-
إذا قام المستخدم بتسجيل الدخول، سيتم إنشاء الغرض user ضمن نسخة الطلب req وإرساله مع كل طلب في express.js والذي يتيح لك التأكد من وجوده أو التحقق من المعلومات الموجودة فيه من خلال أي وسيط: if (req.user) { //قام المستخدم بتسجيل الدخول } else { ... } كما يمكنك فصل عملية التحقق إلى وسيط خارجي واستدعائه عند اللزوم بالشكل التالي: function isLoggedIn(req, res, next) { if (req.user) { next(); } else { res.redirect('/login'); } } بحيث سيتم إعادة توجيه المستخدم إلى صفحة تسجيل الدخول في حال حاول الوصول إلى أي جزء من الكود البرمجي لديك يحتاج توثيق. ويمكنك استخدام الوسيط السابق بالشكل التالي: app.get('/testLogin', isLoggedIn, function(req, res, next) { ... }); بحيث سيتم الدخول إلى الوسيط والتأكد من تسجيل الدخول قبل الوصول إلى هذا الكود1 نقطة
-
أستخدم إطار العمل express مع node.js، كيف يمكنني تضمين ملف نصي ضمن الكود بحيث يكون بهذا الشكل: var mytext = require("test.txt"); لاستعادته لاحقاً ضمن الكود أي: modules.exports = function(){ return mytext; } هل العملية السابقة صحيحة؟ وهل يمكنني تخزين محتوى كامل ضمن متغيّر واستعادته بهذا الشكل في node.js ؟1 نقطة
-
في حال كان المحتوى بسيط وغير معقّد يمكنك استخدام handler خاص وتضمينه بالشكل التالي: var fs = require('fs'); require.extensions['.txt'] = function (module, filename) { module.exports = fs.readFileSync(filename, 'utf8'); }; var test = require("./mytext.txt"); console.log(typeof words); حيث سيتم تخزين المحتوى النصي ضمن المتغيّر test ويمكنك استعماله في أماكن أخرى من الكود البرمجي. كما يمكنك استخدام كل من fs.readFile و require.resolve بالشكل التالي: var fs = require('fs'); function readModuleFile(path, callback) { try { var filename = require.resolve(path); fs.readFile(filename, 'utf8', callback); } catch (e) { callback(e); } } readModuleFile('./mytext.txt', function (err, result) { console.log(result); }); أو من خلال readFileSync: const fs = require('fs') const path = require('path') const mytext = fs.readFileSync(path.resolve(__dirname, 'testfile.txt'), 'utf8') وعموماً أنت لا تقوم بتخزين المحتوى النصي في المتغيّر، بل يتم الإشارة إليه ضمن ذاكرة التخزين العشوائي إلى هذا المتغيّر بشكل مشابه عندما تقوم بعملية نسخ ولصق لمحتوى ما في جهازك.1 نقطة
-
كطريقة ثانية، يمكن تقسم الشعاع vector (المصفوفة الأحادية) على طولها import numpy as np normalized_v = v / np.sqrt(np.sum(v**2)) حيث تم حساب الطول (جذر مجموع مربعات قيم الشعاع)1 نقطة
-
من إصدار +NumPy 1.8 يمكن استعمال الدلة numpy.full ونملأ المصفوفة بالقيم التي تريدها مثلا np.nan: a = np.full([height, width, 9], np.nan) وفي إصدارات أقدم يمكن عمل ذلك بخطوتين، إنشاء المصفوفة ثم ملؤوها بقيمة NaN a = numpy.empty((3,3,)) # مصفوفة فارغة a[:] = numpy.nan # ملأ المصفوفة بقيم محددة >>> a array([[ NaN, NaN, NaN], [ NaN, NaN, NaN], [ NaN, NaN, NaN]]) ويمكن أيضا باستخدام عملية الضرب: np.nan * np.ones(shape=(3,2)) array([[ nan, nan], [ nan, nan], [ nan, nan]])1 نقطة
-
إذا كنت تستخدم scikit-learn فيمكنك استخدام import numpy as np from sklearn.preprocessing import normalize x = np.random.rand(1000)*10 norm1 = x / np.linalg.norm(x) norm2 = normalize(x[:,np.newaxis], axis=0).ravel() print np.all(norm1 == norm2) # True صائب1 نقطة
-
يمكن استعمال دريفر Pusher لتحقيق الغرض . لنقم بإتباع الخطوات التالية : 1. تثبيت حزمة خادم Pusher في تطبيق الللارافل : composer require pusher/pusher-php-server 2, إنشاء تطبيق Pusher : نحتاج في هاته الخطوة إلى التسجيل في pusher.com و تسجيل تطبيق جديد . بعد ذلك سنحتاج نسخ معلومات التوثيق و نقوم بوضعها في ملف الإعداد env. كما يلي : PUSHER_APP_ID=PUT_YOUR_PUSHER_ID_HERE PUSHER_APP_KEY=PUT_YOUR_PUSHER_KEY_HERE PUSHER_APP_SECRET=PUT_YOUR_PUSHER_SECRET_HERE PUSHER_APP_CLUSTER=PUT_YOUR_PUSHER_CLUSTER_HERE كما أنه يجب تغيير قيمة BROADCAST_DRIVER: BROADCAST_DRIVER=pusher 3. نقوم بإنشاء حدث معين : php artisan make:event NewTemperatureRecord سنلاحظ إضافة ملف NewTemperatureRecord.php داخل مجلد events . لنقم بتعديله : <?php namespace App\Events; use Illuminate\Broadcasting\Channel; use Illuminate\Queue\SerializesModels; use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Broadcasting\PresenceChannel; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Contracts\Broadcasting\ShouldBroadcast; class NewTemperatureRecord implements ShouldBroadcast { use Dispatchable, InteractsWithSockets, SerializesModels; public $data; /** * هنا يتم التقاط أية بيانات و تسجيلها ضمن هذا الكائن * * @return void */ public function __construct($passed_data) { $this->data = $passed_data; } /** * هنا يتم تعريف القنوات التي من المفترض أن ينتمي إليها هذا الحدث * * @return \Illuminate\Broadcasting\Channel|array */ public function broadcastOn() { return new Channel('temperature-channel'); } } إنشاء متحكم يختص بالعملية : php artisan make:controller TemperatureController ثم لنتأكد من وضع المحتوى التالي به : <?php namespace App\Http\Controllers; use Illuminate\Http\Request; class TemperatureController extends Controller { public function update(Request $request) { // تحضير مصفوفة بيانات لتمريرها $data['temp'] = $request->temp; // Notify إثارة الحدث event(new App\Events\NewTemperatureRecord($data)); } } و لتأكد من تعريف المسارات اللازمة , واحد لعرض الصفحة وواحد لإرسال طلبات التحديث : // web.php Route::post('temperature','TemperatureController@update'); Route::view('temperature', 'temperature'); ثم بملف ما بالواجهة الأمامية سيكون علينا فقط : الإشتراك في هاته القناة + الإستماع لأحداث هاته القناة : <!-- temperature.blade.php --> <!DOCTYPE html> <head> <title>مثال </title> <script src="https://js.pusher.com/4.1/pusher.min.js"></script> <script> // الإشتراك ضمن نفس تطبيق البوشر var pusher = new Pusher('{{env("MIX_PUSHER_APP_KEY")}}', { cluster: '{{env("PUSHER_APP_CLUSTER")}}', encrypted: true }); // الاشتراك في نفس القناة var channel = pusher.subscribe('temperature-channel'); // Notify الاستماع للحدث channel.bind('App\\Events\\NewTemperatureRecord', function(data) { // إن تم اثارة الحدث قم بعرض البيانات document.querySelector('#temp').textContent = data.temp; }); </script> </head> <body> <div id="temp"> 35 </div> </body> بدون تحديث الصفحة سيكون علينا إرسال طلبات أجاكس إلى المسار temp/ بالفعل POST و سنلاحظ تحدث القيمة في صفحة العرض temp/ .1 نقطة
-
تحديث البيانات من طرف المتصفح يمكن من خلال إما استخدام web sockets لفتح اتصال مع الخادم وإرسال هذه البيانات الجديدة عند استقبالها بشكل فوري ومباشر إلى المستخدم وذلك سيتطلب تهئية مناسبة للخادم لديك ووضع الإعدادات المناسبة (بحيث يتم استقبال بيانات API عند الخادم لديك وإعادة إرسالها إلى المستخدم). أما الحل الثاني والذي لا ينصح به في حال كانت الموارد محدودة على استضافة خادم الويب لديك، وهو طلب هذه البيانات بشكل مباشر من المتصفح كل مدة زمنية معيّنة من خلال استخدام AJAX أو axios مثلاً مع set interval، بحيث يتم إرسال طلب إلى الخادم كل 5 دقائق للتحقق من وجود بيانات جديدة، وفي حال وجودها يتم استقبالها في المتصفح وتحديثها ضمن الصفحة. لا أعلم إن فهمت سؤالك بالشكل الصحيح، ولكن يمكنك إرفاق أجزاء الكود وما تحاول تحقيقه بالتفصيل لنتمكّن من مساعدتك بشكل أفضل.1 نقطة
-
في البداية انصحك بإستخدام اطار عمل مثل vue.js أو React.js لتسهيل العمل ولكن في حالتك إن اردت فعل ذلك بإمكانك فعلها بإستخدام الجافاسكريبت الفكرة هنا هي تعريف متغييرين اثنين الأول ستسميه مثلاً ar والآخر ستسميه مثلاً en وبداخل كل متغيير ستضيف كائن وفي كل كائن ستضيف عدة Properties ستضيف فيها جميع النصوص الكلمات التي تريدها بعدها سنقوم بتعريف متغيير اخر وهذا المتغيير سيتم فيه تحديد اللغة التي تريدها واخيراً بعدها ستقوم بإنشاء دالة من خلالها ستقوم بتغيير هذا المتغيير دعنا نأخذ المثال للتضح لك الصورة بشكل افضل اولاً HTML <h2 id="hello"></h2> <!-- هنا سيظهر النص --> <p id="text"></p> <!-- هنا لتتغير اللغة عند الضغط --> <button onclick="setLang('en')">English</button> <button onclick="setLang('ar')">عربي</button> ثانياً : الجافاسكريت // هنا حيث نقوم بتخزين الكلمات والعبارات التي نريدها لكل لغة في متغيير منفصلين var ar = { hello: "مرحباً!!", text: 'تغيير اللغة' }; var en = { hello: 'Hello!!', text: 'Change language' }; var language = ar; // تحديد اللغة // تغيير نص HTML function changeText(){ for (const key in language) { document.getElementById(key).innerText = language[key]; } } changeText(); // تغيير اللغة عند الضغط على ازرار تغيير اللغة var setLang = function (lang){ lang === 'ar' ? language = ar : language = en; changeText(); }1 نقطة
-
del تستخدم مع القوائم وليس مصفوفات نمباي على ما اعتقد، لذالك يظهر الخطأ. هناك عدة طرق للحذف من نمباي، فيمكنك استخدام التابع setdiff1d من نمباي، حيث نمرر له المصفوفة الأصلية والقيم التي نريد حذفها موضوعة ضمن مصفوفة: import numpy as np arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9]) # مصفوفة بالقيم التي نريد حذفها b = np.array([1,2,4]) arr = np.setdiff1d(arr,b) arr # array([3, 5, 6, 7, 8, 9]) أو من خلال التابع delete لكن هنا نمرر له ال index المراد حذفها وليس القيم: import numpy as np arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9]) b = np.delete(arr, [2,3,6]) #index هنا نمرر له ال b #array([1, 2, 5, 6, 8, 9]) # لحذف عنصر واحد من خلال الفهرس array = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100] index = 2 array = np.delete(array, index) array # array([ 10, 20, 40, 50, 60, 70, 80, 90, 100]) أيضاً هنا يتم الحذف من خلال تحديد الفهرس عن طريق استخدام itertools.compress وهي الطريقة الأسرع: import numpy as np arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9]) import itertools index=[2,3,6] arr = np.array(list(itertools.compress(arr, [i not in index for i in range(len(arr))]))) arr # array([1, 2, 5, 6, 8, 9]) حسناً الطرق السابقة كانت من أجل مصفوفات نمباي، لكن هناك طرق أخرى خاصة بالقوائم، فمثلاً يمكنك تحويل المصفوفة إلى قائمة ثم حذف العنصر من القائمة بإحدى الطرق التالية، ثم إعادة تحويلها لمصفوفة. استخدام Remove لحذف عنصر محدد: array = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100] array.remove(40) #[10, 20, 30, 50, 60, 70, 80, 90, 100] أو pop لحذف عنصر من خلال تمرير ال index: array = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100] index = 2 array.pop(index) array # [10, 20, 40, 50, 60, 70, 80, 90, 100] أو من خلال del وأيضاً من خلال ال index: array = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100] index = 2 del array[index] array # [10, 20, 40, 50, 60, 70, 80, 90, 100]1 نقطة
-
بالإضافة للطريقة الأولى، يمكن استعمال: slicing: a = a[i:j] تمرير مصفوفة ب indexes لاستخلاص العناصر المطلوبة: a = a[[1, 2, 3, ...]] بهتين الطريقتين يمكن حذف مجال (مستمر أو متقطع من العناصر في مصفوفة ما)1 نقطة
-
يمكنك استخدام دالة استخدم numpy.delete () numpy.delete(a, index) لسؤالك المحدد: import numpy as np a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9]) index = [2, 3, 6] new_a = np.delete(a, index) print(new_a) # `يطبع `[1, 2, 5, 6, 8, 9] لاحظ أنه numpy.delete() يُرجع مصفوفة جديدة نظرًا لأن المصفوفة غير قابل للتغيير ، مثل السلاسل النصية في Python ، لذلك في كل مرة يتم إجراء تغيير عليها ، يتم إنشاء كائن جديد : من توثيق delete()1 نقطة
-
من كيراس باستخدام التابع to_categorical import numpy as np a = np.array([1, 0, 3]) from keras.utils.np_utils import to_categorical one_hot_train = to_categorical(a) one_hot_train """ array([[0., 1., 0., 0.], [1., 0., 0., 0.], [0., 0., 0., 1.]], dtype=float32) """ أو يمكنك القيام بذلك من خلال تشكيل تابع: import numpy as np a = np.array([1, 0, 3]) # dimension: أكبر عنصر في بياناتك+1 def vectorize_sequences(sequences, dimension=a[max(a)]+1): results = np.zeros((len(sequences), dimension)) for i, sequence in enumerate(sequences): results[i, sequence] = 1. return results OneHOT = vectorize_sequences(a) OneHOT """ array([[0., 1., 0., 0.], [1., 0., 0., 0.], [0., 0., 0., 1.]]) """ أيضاً بشكل يدوي من خلال استخدام عدة توابع في نمباي : import numpy as np a = np.array([1, 0, 3]) b = np.zeros((a.size, a.max()+1)) b[np.arange(a.size),a] = 1 b أيضاً طريقة أخرى، عبر الاستعانة بتوابع نمباي: import numpy as np a = np.array([1, 0, 3]) def one_hot(a, dimension=a[max(a)]+1): return np.squeeze(np.eye(dimension)[a.reshape(-1)]) one_hot(a) """ array([[0., 1., 0., 0.], [1., 0., 0., 0.], [0., 0., 0., 1.]]) """ يمكنك أيضاً استخدام مكتبة باندا من خلال التابع get_dummies: import numpy as np import pandas a = np.array([1, 0, 3]) one_hot_encode=pandas.get_dummies(a) one_hot_encode """ 0 1 3 0 0 1 0 1 1 0 0 2 0 0 1 """ أو من مكتبة sklearn استخدام التابع OneHotEncoder: import numpy as np import pandas a = np.array([1, 0, 3]) from sklearn.preprocessing import OneHotEncoder enc = OneHotEncoder(handle_unknown='ignore') o=enc.fit_transform(a.reshape(-1, 1)) onehot=o.toarray() onehot """ array([[0., 1., 0.], [1., 0., 0.], [0., 0., 1.]]) """ لكن في آخر طلريقتين سيكون حجم الشعاع لكل قيمة يساوي عدد العناصر المختلفة. أي لن يقوم بعملية تمثيلهم حسب ال index انظر: import numpy as np import pandas a = np.array([1, 0, 4]) from sklearn.preprocessing import OneHotEncoder enc = OneHotEncoder() one_hot = enc.fit_transform(a.reshape(-1, 1)) one_hot.toarray() """ array([[0., 1., 0.], [1., 0., 0.], [0., 0., 1.]]) """1 نقطة
-
تيح لنا طبقة التضمين تحويل كل كلمة إلى متجه بطول ثابت وبحجم محدد. المتجه الناتج هو متجه كثيف "Dense" له قيم حقيقية بدلاً من 0 و 1 فقط كما في الترميز One-Hot. يساعدنا الطول الثابت لمتجهات الكلمات على تمثيل الكلمات بطريقة أفضل وأكثر فعالية مع أبعاد مخفضة. وهذه المتجهات تكون ممثلة في فضاء Vector space مهيكل ويعكس المعاني الدلالية لكل كلمة وهذا مايجعل هذا التمثيل فعال للغاية. إن أفضل فهم لطبقة التضمين هو اعتبارها كقاموس يقوم بربط أعداد صحيحة (كل كلمة ترمز في البداية كعدد صحيح) بمتجه كثيف. أي أنها تأخذ كدخل أعداد صحيحة ثم تبحث في هذا القاموس على المتجه الذي يقابله في القاموس الداخلي، ويعيد هذا القاموس. Word index --> Embedding layer --> Corresponding word vector في كيراس نستخدمها كأول طبقة من طبقات النماذج التي تتعامل مع مهام NLP. هذه الطبقة تأخذ وسيطين على الأقل الأول هو عدد ال tokens (المفردات) الموجودة في بياناتك أي (1 + maximum word index) والثاني هو dimensionality of the embeddings أي أبعاد التضمين. وفي حالة كانت الطبقة التالية هي طبقة flatten ثم Dense فيجب عليك استخدام وسيط ثالث هو input_length أي طول مدخلاتك أو بمعنى أوضح، طول السلاسل النصية التي تعالجها. وفي كيراس لها الشكل التالي: keras.layers.Embedding( input_dim, output_dim, input_length=None, ) هذه الطبقة تأخذ كمدخلات مصفوفة 2D من الشكل:(batch_size, input_length) وتعيد مصفوفة من الشكل: (batch_size, input_length, output_dim) مثال: >>> model = tf.keras.Sequential() # طول السلاسل هو 120 وأبعاد التضمين 128 وعدد الكلمات 10000 >>> model.add(tf.keras.layers.Embedding(10000, 128, input_length=120)) >>> input_array = np.random.randint(1000, size=(32, 10)) >>> model.compile('rmsprop', 'mse') >>> output_array = model.predict(input_array) >>> print(output_array.shape) # (32, 10, 64)1 نقطة
-
عادةً يمكن حذف المكتبات التي يمكن إعادة تحميلها من الطرف الآخر للمشروع، مثلا: إن اعتمد المشروع على node أو npm يمكن ضغط المشروع بدون المجلد node_module نثبت المكتبات ب (npm install) إن اعتمد المشروع على Laravel يمكن حذف المجلد vendor منه نثبت المكتبات ب (composer install) وهكذا بالنسبة لأي مشروع برمجي، كما يمكن اعتماد github + gitlab وغيرها من التقنيات التي تعتمد على git وهي source version controle تسمح بتحديث المشاريع بين المبرمجين و تتبع التغييرات فيها ويفضل تعلمها. يمكن مراجعة أساسيات git من مقالات أكاديمية حسوب:1 نقطة
-
في عام 1993، جلب أبي إلى البيت هاتفًا محمولًا كبيرًا على شكل حجر من الطوب، كنا جميعًا متحمسين جدًا لهذه التكنولوجيا الجديدة، ولم يخطر ببال أحد منا أنه سيكون لها تأثيرٌ ضخم على حياتنا. إنني في الواقع لا زلت أعتبره أداة سحرية، وقد قام بعض أصدقائي بشرائه بعد عدة سنوات. أما اليوم، فهناك ستة مليارات مؤيد للهواتف المحمولة حول العالم؛ مما يعني أنه إذا امتلك كل واحد منهم هاتفًا، فسيمتلك 87% من سكان العالم هواتفًا محمولة، وهذا عدد ضخم جدًا مقارنة بأن هناك أقل من ثلاثة مليارات شخص فقط يمتلكون حواسيبًا مكتبية. من الواضح جدًا أن الهواتف النقالة سوف يستمر بقاؤها لفترة طويلة؛ وتبقى معها أيضًا مجموعة من القيود (والفرص) الجديدة للمصممين؛ لذا دعونا نلقي نظرة عن كيف يمكننا تطوير نهجنا في التعامل. كيف تختلف الهواتف عن غيرها؟ إن أول شيء علينا فهمه حول تصاميم الهواتف هو أنها مختلفة، ليس فقط بشأن الحجم؛ فبِنْية ومواصفات الجهاز المحمول تعطينا تصاميمَ مختلفة القدرات والمتطلبات. ونحن نجد أن الهواتف المحمولة أنسب في الاستخدام لكونها خفيفة وسهلة الحمل والتنقل، ومع استخدامها المنتظم تتكون لدينا معها رابطة عاطفية مميزة. البنية والمواصفات تمتلك معظم الهواتف المحمولة شاشات لمسية، حيث يتفاعل معها المستخدمون معتمدين على الإيماءات، بالإضافة إلى واجهة ذات عناصر بسيطة. ونظرًا لصغر أبعاد هذه الأجهزة، نتوقع أيضًا أن تكون بنية المحتوى بسيطة وصغيرة. أيضًا لمحدودية عرض النطاق الترددي والاتصال (bandwidth and connectivity) لهذا الأجهزة، فإنها تتطلب تصميمًا يجمع بين المثالية في وقت التحميل، والانخفاض في استهلاك بيانات الهاتف. كيف، أين ومتى نميل لاستخدام هواتفنا المحمولة في كثير من الأحيان؛ ولذلك لأن لدينا وصولًا مستمرًا إليها، فهي معنا في وسائل المواصلات، وحين نتمشى في الشارع، أو حين نشاهد التلفاز، بل نحن غالبًا ما نستخدمها بينما نقوم بعمل آخر، وهذا يعنى أن بعضنا ربما يستخدم جهازه تحت ظروف عرض صعبة، أو بين العديد من المشتتات. كيف نتصرف ونشعر لدينا طرقًا وسلوكيات وأولويات مختلفة في استخدامنا للهواتف المحمولة؛ ففي جزء من دراسة Going Mobile 2012، وجدت وكالة User Experience Design agency Foolproof أن الهواتف أعطتنا شعورًا جديدًا من الحرية والتحكم؛ لذا يشعر بعض المستخدمين بمودة حقيقية بينهم وبين هواتفهم! فقد وجدت وكالة Foolproof أن 63% من الناس يفتقدون هواتفهم إذا لم يستطيعوا الوصول إليها بسهولة، ووصفوا هواتفهم بأنها (على قيد الحياة)، وأنها جزء من أجسامهم وشخصياتهم. ولأن الهواتف المحمولة قد غيرت توقعات المستخدم جذريًا، فمن المهم جدًا لنا- نحن المصممين- أن نتبع عملية التصميم التي تركز على المستخدم للوصول إلى حلول، فالمشكلة الوحيدة هي أن أفضل ممارساتنا التقليدية قد لا تفلح دائمًا. كيف تؤثر الهواتف على المصممين إن اختلافات الهواتف المحمولة تؤثر بشكل مباشر على جميع أجزاء عملية التصميم التي تركز على المستخدم، بداية من أبحاث المستخدم وحتى التطوير النهائي واختبار الحلول، وأكبر الأجزاء المؤثرة في العملية هي: طرق التقديم والعرض، وهندسة المعلومات. طرق التقديم والعرض على عكس مواقع الإنترنت التقليدية، هناك أربع طرق شائعة لتقديم محتوى الهواتف المحمولة: بالنسبة للمستخدمين الذين يفضلون عرض المحتوى على المتصفح، فتناسبهم المواقع المخصصة للهواتف (mobile-specific site)؛ أو المواقع المتجاوبة (responsive site) التي تعيد ترتيب واجهتها بحيث تتناسب مع أبعاد الهاتف. أما بالنسبة للذين يفضلون تحميل التطبيقات على هواتفهم المحمولة، فيناسبهم إما تحميل التطبيقات المخصصة (native app)؛ أو التطبيقات الهجينة (hybird app). التطبيقات المخصصة مستقلة بذاتها؛ فكل صفحة من صفحات التطبيق محددة في تصميمها من الألف إلى الياء. أما التطبيقات الهجينة ففيها بعض المرونة؛ إذ أنها تستطيع عرض المحتوى من الإنترنت كالمتصفحات، مع الاحتفاظ بواجهة مستخدم شبيهة بواجهة التطبيقات. إن كل طريقة من طرق تقديم المحتوى لديها إيجابيات وسلبيات. اختر ما تراه مناسبًا لك بِناءً على متطلبات تصميم المشروع. (في الجدول التالي مقارنة بين الطرق الأربعة المذكورة أعلاه، وكلما زادت عدد النجوم كلما كان أفضل). المأخوذ في الاعتبار المواقع المخصصة للهواتف المواقع المتجاوبة التطبيقات المخصصة التطبيقات الهجينة ملاحظات مصممة خصيصًا لأولويات المستخدم ★★★ ★★ ★★★ ★★★ يمكن للمواقع المخصصة أن تزيد من تقييم استجابة التصميم إلى ثلاث نجوم تقديم المحتوى ★★ ★★★ ★★ ★★★ من السهل فهرسة المواقع المتجاوبة (والتطبيقات الهجينة) في محركات البحث الوظائف ★★ ★★ ★★★ ★★★ تُوفر التطبيقات المخصصة إمكانية الدخول إلى مميزات الجهاز (مثل نظام تحديد المواقع، والكاميرا) مما يسمح بتجربة أكثر فاعلية وجاذبية التوافق ★★ ★★★ ★ ★ من السهل عرض التصميم المتجاوب على أي شاشة؛ أما المواقع والتطبيقات المخصصة فهي معتمدة بالأساس على الجهاز الذي صُممت من أجله تكاليف التطوير ★★ ★★★ ★ ★★ بالاعتماد على كونك تطور موقعًا كاملًا من الصفر، فإن التصميم المتجاوب يحتاج بناؤه لمزيد من الوقت، لكن ليس بقدر التصميم التقليدي المخصص تكاليف الصيانة ★★ ★★★ ★ ★★ في التطبيقات المخصصة، تلزمك صيانة كل تطبيق منها على حدة؛ بينما في التصميم المتجاوب فلا يلزمك إلا صيانة الموقع المحتاج لذلك، وستُعمم النتائج هندسة معلومات الهواتف المحمولة تمتلك الهواتف المحمولة مجموعتها الخاصة من أنماط هندسة المعلومات أيضًا؛ وبينما تُبنى المواقع المتجاوبة باتباع أنماط معيارية؛ توظِّف التطبيقات المخصصة- على سبيل المثال- هياكل متنقلة مستندة على علامات التبويب. ليست هناك طريقة (صحيحة) لهندسة مواقع أو تطبيقات الهواتف المحمولة؛ بدلًا من ذلك، دعونا نلقي نظرة على بعض الأنماط الشائعة: نمط التسلسل الهرمي (Hierarchy)، المحور والعجلة (Hun & Spoke)، الدمية المنزلية (Nested doll)، العرض المُبوّب (Tabbed view)، صندوق بينتو (Bento box)، والعرض المُصفّى (Filtered view): التسلسل الهرمي (Hierarchy) يعد نمط التسلسل الهرمي بناءً معياريًا للموقع، مع صفحة فهرس ومجموعة من الصفحات الفرعية. إذا كنت تصمم موقعًا متجاوبًا فربما ستُضطر لاتباع هذه النمط؛ بينما إدخال أنماط أخرى سوف يسمح لك بتفصيل التجربة على الهاتف المحمول. إن مبادرة Luke Wroblewski في كتابه Mobile First تساعدنا في التركيز على الأمور المهمة أولًا: المميزات، ورحلات المستخدم (user journeys)؛ حيث ستساعدنا تلك الأمور على إيجاد نماذج أفضل لتجارب المستخدم. الإيجابيات: يستطيع التسلسل الهرمي ترتيب هيكل مواقع معقدة، مثل تلك التي تحتاج إلى اتباع هياكل مواقع سطح المكتب. السلبيات: يمكن أن تمثل هياكل التنقل متعددة الأوجه (Multi-faceted navigation structures) مشكلة لمن يستخدمون الشاشات الصغيرة. المركز هو المحور (Hub)، والفرعيات هي العجلة (Spoke) المحور والعجلة (Hub & Spoke) يعطيك نمط المحور والعجلة فهرسًا في المركز يمكنك التنقل من خلاله إلى المحتويات، وهذا هو النمط الافتراضي في أجهزة Apple’s iPhone. لا يستطيع المستخدمون التنقل بين العجلات، بل عليهم العودة إلى المحور؛ هذا النمط مستخدم منذ فترة طويلة في سطح المكتب حيث يتم وضع قيود على سير العمل (غالبًا ما تقود قيودًا تِقَنية، مثل الموجودة في نموذج لعملية شراء)؛ ومع ذلك، فبمرور الوقت يصبح هذا النمط أكثر انتشارًا على الهاتف المحمول؛ لأن المستخدم صار يركز على مهمة واحدة، كما أن عامل تكوين الجهاز يجعل التنقل الشامل أصعب في الاستخدام. الإيجابيات: وجود أدوات متعددة الوظائف، لكل منها مهمة وتنقل داخلي مستقل. السلبيات: غير مناسب لمن يفضل القيام بمهام متعددة. الدمية المنزلية (nested doll) إن نمط الدمية المنزلية يقود المستخدم في شكل خَطيّ إلى محتوى فيه المزيد من التفاصيل. هذه طريقة سهلة وسريعة للتنقل حين يكون المستخدم في ظروف صعبة، كما أنها تعطي المستخدم شعورًا قويًا حول مكانهم في هيكل المحتوى؛ بفضل إمكانية التحرك للأمام ثم الرجوع للخلف. الإيجابيات: يمكن لهذا النمط أن يُستخدم كقسم فرعيّ داخل نمط من الأنماط الأساسية، مثل نمط الهرم التسلسلي أو نمط المحور والعجلة؛ وذلك في المواقع أو التطبيقات ذات الموضوعات الأحادية أو وثيقة الصلة ببعضها. السلبيات: لن يستطيع المستخدمون التنقل سريعًا بين الأقسام، لذا من الجيد النظر فيما إذا كان هذا سيكون مناسبًا، أم عائقًا أمام استكشاف المحتوى. العرض المُبوّب (Tabbed view) هذا النمط سيكون مألوفًا لمن يستخدم التطبيقات بانتظام؛ إنه عبارة عن أقسام فرعية مرتبطة ببعضها عبر قائمة شريط الأدوات، وهذا يسمح للمستخدم أن يفصح ويفهم سريعًا وظيفة التطبيق كاملة من أول مرة يفتحه فيها. الإيجابيات: مناسب للتطبيقات المتفقة الموضوع والمعتمدة على الأدوات، ولديه القدرة على القيام بمهام متعددة. السلبيات: التعقيد؛ فهذا النمط مناسب جدًا للمحتويات ذات البنية البسيطة. مربع بينتو (Bento box) إن نمط مربع بينتو أو لوحة القيادة يجلب المزيد من المحتوى التفصيلي مباشرة إلى شاشة الفهرس باستخدام مكونات لعرض أجزاء من الأدوات المترابطة أو المحتوى. هذا النمط يناسب الجهاز اللوحي (Tablet) أكثر من الهاتف المحمول لكونه- أي النمط- أكثر تعقيدًا. أنه مميز حقًّا؛ إذ يتيح للمستخدم أن يفهم المفاتيح الأساسية في لمحة واحدة، لكنه يعتمد بشكل كبير على امتلاك واجهة ذات تصميم جيد مع معلومات مقدمة بشكل واضح. الإيجابيات: مناسب للأدوات متعددة الوظائف، وللمحتوى المعتمد على تطبيقات الشاشات اللوحية والتي لها مواضيع مماثلة. السلبيات: إن شاشة الجهاز اللوحي تعطيك مساحة أكبر لاستخدام هذا النمط جيدًا؛ ومع ذلك، فمن المهم فهم كيف سيتفاعل المستخدم مع وبين كل جزئية من المحتويات؛ وذلك للتأكد من كون هذا التطبيق سهلًا، فعالًا وممتعًا للاستخدام. العرض المُصَفّى (Filtered view) وأخيرًا، يسمح نمط العرض المُصفى للمستخدم بالتنقل ضمن مجموعة من البيانات عبر تحديد خيارات التصفية لإنشاء طريقة عرض بديلة للمحتوى؛ فالتصفية (Filtering) وطرق البحث متعددة الأوجه (faceted search methods)، تعتبر خيارات ممتازة تسمح للمستخدم باستكشاف المحتوى بالطريقة التي تناسبه. الإيجابيات: مناسب للتطبيقات والمواقع ذات الكميات والمحتويات الكبيرة، مثل: المقالات، الصور وأشرطة الفيديو. يمكن أن يكون أساسًا جيدًا لتطبيق لموقع أو مجلة، أو كنمط فرعيّ ضمن نمط تنقليّ آخر. السلبيات: يمكن أن يكون من الصعب عرض نظام التصفية وطرق البحث متعددة الأوجه على شاشة صغيرة نظرًا لكون هذه الأنماط معقدة. الخطوات القادمة لقد مر تقريبًا عقدين من الزمن منذ رأيت هذا الهاتف الحجريّ الكبير أول مرة، وحوالي عشرين سنة منذ اشتريت أول هاتف محمول لي، والآن نمتلك أنا وأبي وتقريبًا كل من أعرف هواتف محمولة؛ حيث نستخدمها أكثر الوقت في التفاعل والتواصل وإدارة حياتنا. في كل عام تقفز التكنولوجيا قفزة جديدة، ومن الواضح أن علينا أن نواكبها جنبًا إلى جنبٍ. إن تطوير هندسة معلومات صديقة للهواتف المحمولة والأجهزة اللوحية، هي الخطوة الأولى في تقديم تجربة رائعة للهواتف. في الجزء الثاني: متطلبات التصميم، سوف أشرح كيف أن الاختلافات في سياق الهاتف المحمول سوف يؤثر على كيفية تطوير حل التصميم النهائي الخاص بك. ترجمة -وبتصرّف- للمقال Designing for Mobile, Part 1: Information Architecture لصاحبته Elaine McVicar حقوق الصورة البارزة محفوظة لـ Freepik1 نقطة