لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 08/02/21 في كل الموقع
-
أريد أن أقوم بعمل مصفوفة بأبعاد معينة وتكون كل العناصر في المصفوفة عبارة عن نرقم معين، حاولت أن أستخدم الكود التالي: >>> import numpy as np >>> a = np.empty(5) >>> for i in range(5): ... a[i] = 9 ... >>> a array([9., 9., 9., 9., 9.]) لكن المشكلة أنه لا يمكنني عمل مصفوفة متعددة الأبعاد بشكل سهل، وسأحتاج إلى أستخدام حلقات متعددة، هل توجد طريقة أسهل في Numpy لعمل مصفوفة كالتالي على سبيل المثال: array([[3, 3, 3, 3], [3, 3, 3, 3], [3, 3, 3, 3]])2 نقاط
-
دخل إلى مجال الويب مؤخرًا العديد من الأفكار والتقنيات والإضافات لغاية خدمة تجربة المستخدم في تطبيقات الويب، مثل دعم الإشعارات وتوافر أيقونة على سطح المكتب وإتاحة التحكم بالـ API والعمل بشاشة كاملة وأهم عناصر وأركان هذه التقنيات والإضافات "عامل أو منجز خدمة" Service Worker وما يقدمه من عمل التطبيق بدون الاتصال في الشبكة والتخزين المؤقت وغيرها مما ساهم بإنجاح تجربة المستخدم لهذه التطبيقات. مفهوم Service Worker منجز خدمة هو سكريبت (script) ينفذ في خلفية مشروع الويب (موقع أو تطبيق)، غير مرتبط بصفحة معينة. مسؤول عن الأحداث التي تجري بالمشروع مثل طلبات الشبكة الصادرة من الصفحة المسؤول عنها والاستجابات لهذه الطلبات، له عدة غايات من أهمها اتاحة استخدام التطبيق مع الشبكة أو بانقطاعها أو ببطئها. فلو افترضنا شخصًا يستخدم موقعًا وكان متصلًا بالشبكة وأثناء تصفحه للموقع انقطع اتصاله بالشبكة ولكن أراد الرجوع للصفحة السابقة عند إذٍ لن تفتح الصفحة السابقة وستظهر له شاشة تعلمه بإنقطاعه عن الشبكة، لكن إن كان ذلك الموقع يملك Service Worker فلن يحدث هذا، بل ستظهر الصفحة السابقة أو على الأقل جزء منها. ومن اللطيف ذكره أن أي موقع ويب بإمكانه أن يمتلك Service Worker وأن يُفعله مستفيدًا من مزاياه الرائعة، لكن في حالة تطبيقات الويب التقدمية PWA يجب أن تمتلكه وأن يكون مسجلًا وفعالًا فهو من شروط عملها. أهم الميزات التي يضفيها على مشروعك سرعة كبيرة يركز ال Service Worker في فكرته بشكل كبير على السرعة والأداء المثالي في التحميل وذلك في حالة اتصال الشبكة أو بدونها أو ببطئها وتكون أطول فترة تحميل في المرة الأولى وأما في الزيارات المتكررة يتم تحميلها بشكل أسرع. انظر المثال في الصورة حيث كان وقت التحميل في المرة الأولى 2.5 ثانية وفي الزيارات الأخرى 0.8 ثانية أي انخفضت إلى أقل من الثلث وهذا مثال بسيط. (بإمكانك اختبار أداء فاعلية مشروعك من خلال هذه الأداة WEBPAGETSET). العمل بدون شبكة كانت تتميز التطبيقات (العادية) عن الويب إمكانية عملها من غير اتصال شبكة، لكن الآن مع الـ Service Worker يمكن لمواقع وتطبيقات الويب أن تعمل بدون اتصال شبكة والذي يقوم بتخزين الموارد والعناصر التي ترتبط بالأحداث والتفاعل لاستخدامها بدون اتصال شبكة أو ببطئها. التحديث المستمر للتطبيق يعتبر Service Worker المسؤول عن التحديثات في تطبيقات الويب، بل يتميز عن تحديثات أنواع البرامج والتطبيقات الأخرى بالسلاسة والاستمرارية والسهولة وذلك من خلال تخزين وتثبيت الموارد المحدثة فقط وبشكل تلقائي ويظهر شارة صغيرة للمستخدم عند فتح التطبيق بأن التطبيق تم تحديثه. سيطرة أعلى يمنح Service Worker لمطورين المواقع والتطبيقات سيطرة كاملة وأفضل على تجربة المستخدم للتطبيق. تجربة تطبيقات حقيقية يدعم Service Worker ويحسن تجربة المستخدم في التطبيقات ومحاكاتها من خلال ما يوفر من السرعة والعمل بدون اتصال الشبكة والتخزين المؤقت وهيكل التطبيق (الذي سنفصل فيه) وغيرها. وكذلك يمنح تجربة تطبيقات حقيقية ويحسنها للجوال حيث تكون منفصلة ومستقلة عن المتصفحات لا يشترط أن تكون مبنية عليها. بنية هيكل التطبيق application shell architecture عند تكرار زيارة الموقع أو عند تحميل التطبيق يتم تخزين حد معين من الشيفرات المصدرية HTML، و CSS، و JavaScript مؤقتًا ليتم استعمالها بدون اتصال الشبكة أو حتى مع اتصالها ولكن بشكل فوري وأسرع. وصلب الفكرة هنا أننا نملك هيكل يمثل جزءًا معينًا من التطبيق أو الموقع موجود على جهاز المستخدم يُحمل ويُبنى فورًا عند فتحه سواء مع اتصال شبكة أو بدون ثم يبدأ إضافة المحتوى غير المشمول فيها من الشبكة على هذا الهيكل إذ هو بمثابة الوعاء الفارغ الذي يوضع فيه شيء ما.(يعني نحافظ على واجهة المستخدم الأساسية على جهاز المستخدم ولا داعي لتحميلها كل مرة). وبهذا فإنها تخدم التجربة كثيرًا بغض النظر عن اتصال الشبكة أو سرعتها. وحتى إن كانت فكرة التطبيق/الموقع تعتمد بشكل كامل على اتصال الشبكة فإن المستخدم سيحصل على هيكل وشكل جذاب ومناسب بعدم اتصال الشبكة ويتوافق مع شكل التطبيق الأصلي ولن تظهر له شاشة عدم الاتصال، فهذا الهيكل يلعب دورًا عظيمًا في الأداء المثالي للموقع أو التطبيق من سرعة وخفة وتجربة مثالية. بعد فتح الموقع في المرة الأولى وتحميل الـ Service Worker لهذا الهيكل تظهر شارة أن البرنامج جاهز للعمل بدون اتصال شبكة. والمسؤول عن هذا الهيكل هو Service Worker وفي حال عدم دعم المتصفح لـ Service Worker لا داعي للقلق، فإن الهيكل والصفحة كاملة ستعتمد في تحميلها على استراتيجية الويب الشهيرة Progressive Enhancement بدون مشاكل. ومن الأمثلة الناجحة في استخدام فكرة هذا الهيكل: Google’s Inbox و offline Wikipedia app ومعظم مشاريع نقاية. آلية عمل الـ Service Worker وحدود إمكانياته عند الزيارة الأولى للموقع أو عند تثبيت التطبيق يتم بناء الـ Service Worker وأخذ المحتوى والهيكل وكل البيانات والموارد من الخادم، وفي المرات التالية يتم سحب بيانات وعناصر محددة من الخادم ولكن كيف يتم تنظيم هذا السحب؟ كيف يتم تحميل بعض العناصر من Service worker وأخرى من الخادم؟ يعترض Service Worker طلبات الشبكة الصادرة من الصفحة وهنا يقوم بالاستجابة لهذه الطلبات بواحدة مما يلي: جلب المطلوب من الخادم عبر الشبكة. جلب المطلوب من الذاكرة المؤقتة على جهاز المستخدم، يتم جلب من الذاكرة المؤقتة العناصر والموارد المحددة مسبقًا لتجلب منها (مثل الهيكل الذي تحدثنا عنه). بناء المطلوب برمجيًا. والرائع هنا أن هذا كله يحدث دون أن يظهر مصدر الإستجابة ولا حتى أن الـ Service Worker قد تدخل. فلو تتبعنا دورة حياة الـ Service Worker لوجدنا أنه يتم بناءه عند أول دخول ويُحمل بعض الموارد عليه، ثم يُفعل ويَستيقظ عند وجود أي حدث، ويستجيب لهذا الحدث إن لزم الأمر مؤديًا دوره، ثم يُحذف من الذاكرة بمحتواه عند مرور الزمن دون أن ينشط، وتم إنشائه هكذا محدود العمر عن قصد. ومن الجيد معرفته أن Service Worker يحتوي على API محدودة مقارنة بما تحتويه الـ JavaScript في الصفحة العادية، بإمكانك أن تعرف تفاصيل API له هنا. واعلم بأن Service worker لا يمكنه الوصول إلى الـ DOM ولكن يمكنه الوصول إلى ذاكرة التخزين. ويمكنه أيضًا ارسال طلبات الشبكة، كذلك يمكنه أن يتواصل وأن يتبادل البيانات مع الصفحة المسؤول عنها عن طريق IndexedDB API و postMessage. لا تفوت ميزاته مع مشاريعك القادمة لكن بحدود يتبين مما سبق البون الشاسع الذي يُحدِثه الـ Service Worker في أداء مشاريع الويب معه، لذا يُنصح وبشدة استخدامه في تطبيقات ومواقع الويب، لكن بشكل معقول، فليس من المنطق أن تضيفه إلى مواقع صغيرة الحجم أو لا تقدم خدمة وتفاعل وتميل للمحتوى الثابت الخفيف فلا فائدة أو معنى من إضافته لمثلها. تسهيل الحصول على Service Worker مع Workbox يعتبر Workbox مجموعة من المكتبات والأدوات المستخدمة لإنشاء Service Worker والتخزين المؤقت وغيرها وتسهيل ذلك. مراجع Instant Loading Web Apps With A Service Worker Application Shell Architecture Service Workers: an Introduction Using Web Workers Cache Fetch API IndexedDB API Client.postMessage() Application Shell Architecture workbox What Are Service Workers and How They Help Improve Performance1 نقطة
-
كيفية عمل كود التفعيل مثل قالب سكويز لمنع سرقة قوالب بلوجر.1 نقطة
-
لتجنب مشاكل AJAX التابعة لنفس اسم النطاق، أود جعل طرف الخادم من node.js بتحويل جميع الطلبات من مسار محدد (مثال: /api/xxx) إلى خادم آخر (مثال: anotherwebsite.com:5000/xxx) ,ويعيد نفس النتائج التي قد يعيدها الخادم الأول الأساسي دون أن يحدث أي فارق من طرف المستخدم ودون أن يشعر بالفرق. أما بقية المسارات (مثل: api/*) يتم تخديمها من الخادم الأول ولا يتم تحويلها إلى الخادم الثاني. أي فقط مجموعة طلبات محددة سيتم تحويلها وليس جميع الطلبات. فكيف يمكنني إضافة هذه الطبقة كـ proxy والتي ستقوم بدورها بتحويل هذه الطلبات إلى الخادم الآخر ضمن express.js ؟ هل يوجد كود مباشر أستطيع تضمينه أم أحتاج لتثبيت حزم إضافية لتحقيق ذلك؟1 نقطة
-
لقد قمت بإنشاء مشروع express.js جديد باستخدام الأوامر التالية: express -e myBlog npm install ejs --save npm install ولكن عندما أحاول تشغيل المشروع بهذا الأمر: node app.js يظهر لي هذا الخطأ: events.js:72 throw er; // Unhandled 'error' event ^ Error: listen EADDRINUSE at errnoException (net.js:884:11) at Server._listen2 (net.js:1022:14) at listen (net.js:1044:10) at Server.listen (net.js:1110:5) at Object.<anonymous> (myBlog/app.js:33:24) at Module._compile (module.js:456:26) at Object.Module._extensions..js (module.js:474:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Function.Module.runMain (module.js:497:10) كيف يمكنني حل هذه المشكلة؟1 نقطة
-
ما هو الفرق بين المصفوفة من نوع ndarray والمصفوفة العادية array في Numpy؟ عرفت مؤخرًا أن دوال مثل asanyarray وغيرها قد تعيد مصفوفة من نوع ndarray لكن لم أفهم ما الفرق بين هذا النوع من المصفوفات والمصفوفات العادية1 نقطة
-
لنفترض أن لدي مصفوفة بسيطة تحتوي على عناصر مكررة كالتالي: >>> import numpy as np >>> x = np.array([1,1,1,2,2,2,5,25,1,1]) >>> freq_count(x) # pseudo code [(1, 5), (2, 3), (5, 1), (25, 1)] >>> كيف يمكنني الحصول على نفس النتيجة السابقة في Numpy؟1 نقطة
-
1 نقطة
-
اقدر ازيد دخل عبر شغل ك فريلانسر (مطور ويب)1 نقطة
-
منصة بلوجر لا توفر طريقة مباشرة لعمل كود تفعيل لقوالب بلوجر، لكن يمكنك عمل كود للتأكد من أن الشخص الذي يستعمل القالب قد قام بشراءه بشكل سليم، وذلك من خلال JavaScript حيث يتم تجهيز Widget أثناء برمجة القالب، وتكون عبارة عن حقل إدخال ليقوم العميل (من أشترى القالب) بوضع كود معين (نص عبارة عن رموز وأرقام مثل: ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad) ومن خلال لغة JavaScript يتم إحضار هذا الكود وإرساله إلى خادم معين (تم إعداده من قبل مبرمج القالب نفسه)، ليتم التأكد من أن هذا الكود مسجل في قاعدة البيانات، وأن المدونة التي تحمل الرابط example.blogspot.com قد أشترت القالب بالفعل. في حالة لم يتم إيجاد الكود في قاعدة البيانات أو أن نطاق domain المدونة غير مسجل في قاعدة البيانات، فيتم عمل إعادة توجيه من المدونة لصفحة شراء القالب على سبيل المثال. بالطبع هذه الطريقة ليس آمنة 100% لأن أي شخص يمكنكه أن يبحث عن كود JavaScript الذي يقوم بعمل تحقق من الكود، ويقوم بحذفه أو إيقافه بأي شكل، لذلك لا يوجد حل واضح لهذه المشكلة غير تشويش/تعميم Obfuscation كود JavaScript من خلال أداوات مثل Javascript Obfuscato (أي جعل الكود غير قابل للقراءة)، وبالتالي لن يستطيع أحد عمليًا من إيجاد الكود الذي يقوم بعملية التحقق، يمكنك الإطلاع على هذه الإجابة لمعلومات أكثر حول تشويش كود JavaScript. أيضًا إن لم يكن القالب يعتمد على JavaScript بشكل أساسي، فيمكن أن يقوم أي أحد بحذف كل أكواد JavaScript وحينها سيعمل القالب بشكل سليم (لأنه لا يحتاج JavaScript لأن يعمل من الأساس).1 نقطة
-
أحاول إضافة خصائص أخرى إلى الطلب req من خلال وسطاء middlewares باستخدام typescript، مثلاً بهذا الشكل: app.use((req, res, next) => { req.newKey = setProperty(); next(); }); بحيث يتم عبر typescript من خلال هذا الوسيط إضافة بعض القيم إلى الغرض req والوصول إليها ضمن التوابع الأخرى. كيف يمكنني تنفيذ مايشبه ذلك؟1 نقطة
-
أقوم باستخدام حزمة التوثيق passport.js في خادم node.js، والكود لدي بهذا الشكل: 'use strict'; var express = require('express'); var passport = require('passport'); var LocalStrategy = require('passport-local').Strategy; var app = express(); module.exports = function setupServer(){ app.use(express.bodyParser()); app.use(express.cookieParser()); app.use(express.session({ secret: 'secretKeyHere' })); app.use(passport.initialize()); app.use(passport.session()); passport.use(new LocalStrategy(function(username, password, result) { if (username === 'test' && password === 'test') { console.log('Success'); result(null, {username}); } else { result(null, false); } })); app.post('/login', passport.authenticate('local', { successRedirect: '/loggedIn', failureRedirect: '/guest' })); app.listen(5000); console.log('Server listening on port 5000'); }(); ولكن يظهر لي الخطأ التالي دوماً: Error: failed to serialize user into session كيف يمكنني تجاوز هذا الخطأ؟1 نقطة
-
لقد قمت بكتابة كود بسيط لتشغيل خادم node.js، ولكن عندما أقوم بتنفيذ الأمر التالي لتشغيل الخادم: npm start يظهر لي الخطأ التالي: npm ERR! Windows_NT 6.3.9600 npm ERR! argv "C:\\Program Files\\nodejs\\\\node.exe" "C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js" "start" npm ERR! missing script: start npm ERR! npm ERR! If you need help, you may report this error at: npm ERR! <https://github.com/npm/npm/issues>npm ERR! Please include the following file with any support request: كيف يمكنني حل هذه المشكلة؟1 نقطة
-
في النسخ السابقة يمكنك كما تمت الإشارة في التعليق السابق تعريف متغيّر express عام لأي خصائص إضافية: declare global { namespace Express { interface Request { context: Context } } } بحيث يصبح الكود الكامل عندما تريد استخدامه بالشكل التالي: import * as express from 'express'; export class Context { constructor(public newVariable) { } log(message: string) { console.log(this.newVariable, { message }); } } declare global { namespace Express { interface Request { context: Context } } } const app = express(); app.use((req, res, next) => { req.context = new Context(req.url); next(); }); app.use((req, res, next) => { req.context.log('returning from the context') res.send('Hi There!'); }); app.listen(5000, () => console.log('Server is listening on port: 5000')) أما في النسخ الحديثة من express 4.17.1 وما فوق أصبح يجب عليك استخدام وتضمين express-serve-static-core مع المودل بهذا الشكل: import {Express} from "express-serve-static-core"; declare module 'express-serve-static-core' { interface Request { newProperty?: string } interface Response { anotherProperty?: string }1 نقطة
-
يجب عليك إنشاء تعريف مخصص ، واستخدام ميزة في Typescript تسمى دمج الإعلان Declaration Merging . هذا شائع الاستخدام ، على سبيل المثال في method-override. قم بإنشاء ملف custom.d.ts وتأكد من إدراجه في ملفات tsconfig.json إن وجدت. يمكن أن تبدو المحتويات على النحو التالي: declare namespace Express { export interface Request { tenant?: string } } سيسمح لك ذلك ، في أي مكان في الكود الخاص بك ، باستخدام شيء مثل هذا: router.use((req, res, next) => { req.tenant = 'tenant-X' next() }) router.get('/whichTenant', (req, res) => { res.status(200).send('This is your tenant: '+req.tenant) })1 نقطة
-
التابع predict يقوم فقط بتمرير بيانات الدخل إلى النموذج فتحصل على الخرج (القيمة المتوقعة بناءان على أوزان التدريب التي تم حفظها في الملفات). لذا لايعطيك أي مشكلة. أما عند استخدام evaluate ، فهذا التابع يقوم بحساب الخطأ loss و ال metrics، ودالة التكلفة التي نحسب من خلالها ال loss لايكون لدينا معلومات عنها حتى تقوم بتجميع النموذج compile. فهم وسطاء لتابع ال compile: model.compile(optimizer=.., loss=.., metrics=..) إن كل مايهمنا من تدريب النموذج هو استخلاص الأوزان المدربة: إن مخرجات النموذج النهائية هي عبارة عن أوزان هذه الأوزان تكون مدربة لتنفيذ المهمة التي قمنا بتدريبها من أجل حلها، في البداية نقوم بتهيئتها بقيم عشوائية (بين ال 0 و 1). ثم عن طريق النموذج الذي بنيناه وعن طريق خوارزمية Backbropagation يتم تحديث قيم هذه الأوزان (تدريبها لحل المشكلة)، وبعد انتهاء التدريب نقوم بإدخال العينة التي نريد تجربتها أو اختبار الأداء عليها، فيحسب النموذج الناتج لنا بناءان على قيم هذه الأوزان. وهذا هو كل ما يهمنا (بناء نموذج قادر عتلى تصنيف الصور مثلاً بحيث نعطيه صورة ويعطينا الخرج أما التفاصيل الأخرى لاتهمنا كمستخدمين). حسناً إن التكلفة "loss" هي دالة نقوم باستخدامها خلال عملية التدريب حيث تستلم هذه الدالة القيم المتوقعة من النموذج والقيم الحقيقية ثم تقارنهما وتعطي قيمة تعبر عن مدى اختلاف القيمتين (الفرق بينهما). وطبعاً يكون الهدف هو تصغير قيمة التكلفة (الخطأ) لأنه كلما قل الاختلاف بين القيم التي يتوقعها النموذج والقيم الحقيقية يصبح نموذجك أفضل. إذاً ال loss ليست مفيدة للغرض النهائي للنموذج، لكنها ضرورية للتدريب. وهذا هو السبب في أنه يمكنك الحصول على توقعات من النموذج لكن دون ال loss. لكن إذا أردت لسبب ما أن تحسب ال loss أيضاً فيجب عليك تنفيذ ال compile لنموذجك، انظر للمثال التالي الذي سأقوم فيه بحفظ نموذج ثم سأعيد تحميله وأنفذ عليه التابع evaluate: from keras.models import Sequential from keras.layers import Dense from keras.models import model_from_yaml import numpy import os dataset = numpy.loadtxt("pima-indians-diabetes.csv", delimiter=",") X = dataset[:,0:8] Y = dataset[:,8] # بناء النموذج model = Sequential() model.add(Dense(16, input_dim=8, activation='tanh')) model.add(Dense(1, activation='sigmoid')) # تجميع النموذج model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['acc']) # تدريب النموذج model.fit(X, Y, epochs=120, batch_size=10, verbose=0) # تقييم النموذج scores = model.evaluate(X, Y, verbose=0) print("%s: %.2f%%" % (model.metrics_names[1], scores[1]*100)) # acc: 78.78% # حفظه model_j = model.to_json() with open("model.json", "w") as f: f.write(model_j) model.save_weights("model.h5") # الآن إعادة تحميله json_file = open('model.json', 'r') loaded_model_json = json_file.read() json_file.close() model = model_from_json(loaded_model_json) # تحمبل الأوزان model.load_weights("model.h5") #نقوم الآن بتجميع النموذج model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['acc']) # قم بتحديد دالة التكلفة والمعيار # على بيانات الاختبار evaluate score = model.evaluate(X, Y, verbose=0) # حساب ال loss print('Test loss:', score[0]) #metrics حساب ال print('Test accuracy:', score[1])1 نقطة
-
Write a C++ program that takes as input six numbers (x, x1, x2, x3, x4, x5) then the program finds and prints the result of the following equation1 نقطة
-
document.getElementsByClassName("col") تقوم بإرجاع HTMLCollection وهي أشبه بالمصفوفة عند التعامل معها فمثلا لجلب أول عنصر يحتوي على الكلاس .col فنقول في الكود document.getElementsByClassName("col")[0] لاحظ ال [0] في النهاية (لأن المصفوفة تبدأ من 0) الآن نحن نريد أن نجلب العنصر الذي تم الضغط عليه لذلك سنعدل في كود ال HTML ليتم اضافة ال index الخاص بكل عنصر، وسنعدل في كود الجافاسكربت لكي نستطيع جلب ال index ايضاً كالتالي: <div class="container"> <div class="row"> <div class="col" onclick="ik(0)"> Column </div> <div class="col" onclick="ik(1)"> Column </div> <div class="col" onclick="ik(2)"> Column </div> <div class="col" onclick="ik(3)"> Column </div> </div> <div class="row"> <div class="col" onclick="ik(4)"> Column </div> <div class="col" onclick="ik(5)"> Column </div> <div class="col" onclick="ik(6)"> Column </div> <div class="col" onclick="ik(7)"> Column </div> </div> </div> <script> function ik(index){ var y = document.getElementsByClassName("col")[index]; var t = alert("this is column" + "=" + Math.round(Math.random() * 10)); if(y >= 8){ alert("YOU WON"); } else{ alert("YOU LOST"); } } </script> الآن تبقى شئ أخير وهو المقارنة بأن الرقم العشوائي أكبر من أو يساوي 8، لعمل ذلك علينا حفظ الرقم العشوائي في متغير والمقارنة هل هو أكبر من أو يساوي 8 كالآتي: <script> function ik(index){ var y = document.getElementsByClassName("col")[index]; var randomNumber = Math.round(Math.random() * 10)) var t = alert("this is column" + "=" + randomNumber; if(randomNumber >= 8){ alert("YOU WON"); } else{ alert("YOU LOST"); } } </script> نلاحظ هنا بعد التعديل في الكود أنه لا حاجة إلى المتغير الذي يسمى y أصلاً لذلك يمكننا حذفه ويصبح كود الجافاسكربت النهائي: <script> function ik(index){ var randomNumber = Math.round(Math.random() * 10)) var t = alert("this is column" + "=" + randomNumber; if(randomNumber >= 8){ alert("YOU WON"); } else{ alert("YOU LOST"); } } </script>1 نقطة
-
سأعطيك بعض الملاحظات: y هي عبارة عن مصفوفة تحوي جميع العناصر التي لها class يساوي col أي جميع الأسطر لديك للوصول لسطر محدد استخدم محدد المصفوفة [ i ] أي هكذا document.getElementsByClassName("col")[0] أي للوصول للعنصر الذي تم النقر عليه يجب تمرير المعرف ضمن الدالة ()ik عند الاستدعاء <div class="col" onclick="ik(0)"> .. </div> <script> function ik(id) { let element = document.getElementsByClassName("col")[id] } </script> الشرط غير محقق لأنك لا تقارن قيمة عددية مع الرقم 8 حسب الفكرة في الصفحة لا تحتاج y لايمكن تخزين العنصر alert في متغير فهو undefined علينا تخزين القيمة التي يولدها التابع العشوائي في متغير ثم نستعمله نفسه في alert ثم اختبار الشرط <script> function ik() { // var y = document.getElementsByClassName("col"); var t = Math.round(Math.random() * 10) alert('this is column' + '=' + t) if (t >= 8) { alert('YOU WON') } else { alert('YOU LOST') } } </script>1 نقطة
-
شكرا لك , افهم من جوابك انه ليس مهم لكنه يساعد فقط في البدء , يعني لن يأتي في امتحان الاخير في الشهاده فقط وضيفته انه يساعد وليس شيء اساسي في البرمجه لتعلم هل هذا صحيح ؟!1 نقطة
-
لإضافة عمود إلى مصفوفتك استدعي numpy.append(arr, values, axis=1) ، انظر للمثال التالي: import numpy as np arr = np.zeros((3,2)) print(arr) """ [[0. 0.] [0. 0.] [0. 0.]] """ new_column = [[3],[3], [6]] arr = np.append(arr, new_column, axis=1) arr """ array([[0., 0., 3.], [0., 0., 3.], [0., 0., 6.]]) """ ولإضافة أسطر، فقط نغير المحور: import numpy as np arr = np.zeros((3,2)) print(arr) """ [[0. 0.] [0. 0.] [0. 0.]] """ new_row = [[3,2]] arr = np.append(arr, new_row, axis=0) arr """ array([[0., 0.], [0., 0.], [0., 0.], [3., 2.]]) """ أو يمكنك استخدام numpy.insert(arr, idx, values, axis=1): import numpy as np arr = np.zeros((3,2)) print(arr) """ [[0. 0.] [0. 0.] [0. 0.]] """ new_column = [[3,2,1]] arr=np.insert(arr, 1, new_column, axis=1) print(arr) """ [[0. 3. 0.] [0. 2. 0.] [0. 1. 0.]] """1 نقطة
-
التطبيقات التي تنقل الصور عبر الانترنت أغلبها يقوم بعملية ضغط للصور، وواتساب هو أحد التطبيقات التي تقوم بذلك عند مشاركة المحتوى عليه، لذا تبدو الصور أقل دقة.1 نقطة
-
يجب عليك تخزين numpy.ndarray بتنسيق JSON أو أي تركيب من ال nested-list: import json import numpy as np class NumpyEncoder(json.JSONEncoder): # مشفر جيسون خاص للنوع نمباي def default(self, obj): if isinstance(obj, np.integer): return int(obj) elif isinstance(obj, np.floating): return float(obj) elif isinstance(obj, np.ndarray): return obj.tolist() return json.JSONEncoder.default(self, obj) dumped = json.dumps(data, cls=NumpyEncoder) with open(path, 'w') as f: json.dump(dumped, f) حيث أن JSON هو "Javascript Object Notation" وبالتالي يمكنه فقط تمثيل التركيبات الأساسية من لغة جافا سكريبت: كائنات (مماثلة لل dict ببايثون) ، ومصفوفات (مماثلة لقوائم بيثون) ، وأرقام ، وبيانات بوليانية، وسلاسل ، و nulls. أما المصفوفات Numpy ليست أياً من هذه الأشياء، وبالتالي لا يمكن تحويلها إلى تسلسل "serialised" في JSON. لذلك نلجأ للطريقة السابقة1 نقطة
-
المشكلة في التعليمات البرمجية الخاصة بك هي أنك تريد تطبيق العملية على كل صف. الطريقة التي كتبتها بها تأخذ عمودي "bar" و "foo" بالكامل ، وتحولها إلى سلاسل وتعطيك سلسلة واحدة . لذا يمكنك حل المشكلة بالشكل التالي: from pandas import * import numpy df = DataFrame({'foo':['a','b','c'], 'bar':[1, 2, 3]}) df.apply(lambda x:'%s is %s' % (x['bar'],x['foo']),axis=1) ومن خلال نمباي يمكنك القيام بذلك باستخدام الكلاس numpy.chararray حيث نقوم بتحويل الأعمدة إلى تسلسل على هيئة chararrays، ثم نقوم بدمجهم معاً كالتالي: from pandas import * import numpy d = DataFrame({'foo':['a','b','c'], 'bar':[1, 2, 3]}) def join(d): a = numpy.char.array(d['bar'].values) b = numpy.char.array(d['foo'].values) bar=(a + b' is ' + b).astype(str) return DataFrame({'bar':bar}) join(d) """ bar 0 1 is a 1 2 is b 2 3 is c """1 نقطة
-
هذه تصنيفات تتبع لتصنيف فلين الكلاسيكي Flynn's Classical Taxonomy وهو تصنيف يميز بين الحواسيب متعددة المعالجات ويتم التصنيف على أساس بعدين مستقلين: الأول: مجرى التعليمات Instruction Stream والثاني Data Strem مجرى البيانات، حيق أن كل بعد من هذه الأبعاد يمكنه فقط أن يأخذ إحدى الحالتين : (مفرد) single أو Multiple (متعدد). إذاً لدينا بعدين وحالتين وبالتالي يكون لدينا 2*2=4 وبالتالي نحصل على الأصناف الأربعة التالية: 1.SISD: Single Instruction strem Single Data stream 2.SIMD: Single Instruction strem Multiple Data stream 3.MISD: Multiple Instruction strem Single Data stream 4.MIMD: Multiple Instruction strem Multiple Data stream 1.تعليمة مفردة،بيانات مفردة: تمثل حالة حاسب تسلسلي(وليس تفرعي أبداً).بحيث تعليمة مفردة تعني أن مجرى واحد للتعليمات يتم استخدامه من قبل المعالج في كل نبضة ساعة. وبيانات مفردة تعني أن مجرى واحد للبيانات يتم استخدامه كدخل للمعالج في كل نبضة ساعة. وهذا النمط يمثل الحواسيب الأقدم. 2. تعليمة مفردة، بيانات متعددة: عبارة عن حاسب تفرعي (التفرعية هنا من وجهة نظر البيانات)، وفي هذا النمط يظهر تعدد المعالجات. بحيث تعليمة مفردة تعني أن كل وحدات المعالجة تنفذ نفس التعليمة في كل نبضة ساعة. وبيانات متعددة تعني أن كل وحدة معالجة تستطيع التعامل مع عنصر بيانات مختلف (لها ممر خاص بها) مثال: في عملية جمع عناصر مصفوفة يمكن أن يتم تقسيم المصفوفة إلى عدة أقسام 4 أقسام مثلاً وكل معالج يأخذ قسم وينفذ عليه عملية الجمع+، ثم في النهاية تجمع نواتج الأقسام الأربعة. 3. تعليمات متعددة، بيانات مفردة: تمثل حالة حاسب تفرعي أيضاً (التفرعية هنا من وجهة نظر التعليمات )، وبصراحة لايوجد الكثير من الأمثلة لهذا النمط لكن ينطبق على الحالات التي يكون فيها من الممكن تطبيق أكثر من عملية (جمع وضرب مثلاً) بنفس الوقت على نفس البيانات لكن أشهر أمثلتها هو خوارزميات التشفير المتعددة التي تحاول فك شيفرة رسالة مشفرة مثلاً إذا كان لدينا رسالة نود تشفيرها ولدينا مرحلتين الأولى جعل الأحرف كبيرة والثانية إضافة 35 حسب جدول الآسكي، هنا نلاحظ أنه لدينا نوعين من التشفير (نوعين من التعليمات) والبيانات نفسها (الرسالة) إذاً MISD فهنا الرسالة تتألف من عدة أحرف --> كل حرف يمر أولاً على p1 ويشفر، ثم هو نفسه يمر على p2 ويشفر (لكن بعد فاصل زمني قصير لكي يتم التشفير بشكل صحيح). وطبعاً تعليمات متعددة تعني أن كل حاسب يعمل على البيانات بشكل مستقل عن الوحدات الأخرى عبر مجاري تعليمات مستقلة "Separate instruction streams". وبيانات مفردة تعني أن مجرى بيانات وحيد يستخدم لتغذية كل وحدات المعالجة. 4. تعليمات متعددة، بيانات متعددة: حاسب تفرعي (التفرعية هنا من جانب التعليمات والبيانات). بحيث كل معالج ينفذ تعليماته الخاصة على مجرى تعليمات مختلف. وكل معالج يعمل على مجرى بيانات مختلف. والتنفيذ هنا يكون متزامن أو غير متزامن، وحالياً الأجهزة الشائعة من الحاسبات تستخدم هذا النمط.1 نقطة
-
الكثير من التخصصات لقد عملت سابقا في العديد من الشركات المختلفة كمصمم منفرد مع العديد من الفئات المختلفة من المصممين. وقبل 5 سنوات، كان الاتجاه السائد هو التخصص في التصميم؛ المصممون البصريون، مصممو تجربة المستخدم، مصممو واجهة الاستخدام، مهندسو المعلومات، ومصممو المنتجات. وأنا متأكد أنّ بعضكم يعرف من الألقاب المبهمة أكثر مما ذكرته. لم أفهم تماما لماذا كل هذا الكم من تخصّصات التصميم. ربما يكون هذا الأمر منطقيا لو كنا نتحدث عن المهندسين بحكم وجود الهياكل والمنصات، فمهندسو iOS يختلفون عن مهندسي Rails رغم أن المبرمج الحذق يُمكنك أن يعبر من لغة برمجية إلى أخرى بكل سهولة ويُسر. مصدر الصورة: Christian Manzella إنّ تصنيف الناس حسب التخصصات لا ينفع في شيء ولا يحل أي مشكلة. وعندما تعزل أحدهم فقط لأنّه متخصص في تصميم تجربة المستخدم لا يعني أنّه لا يعرف شيئا عن مهارات التصميم البصري أو تصميم المنتجات. وعلى الأرجح يملك كل مصمم بعض المعلومات عن التخصصات الأخرى، فمصمم واجهة المستخدم يمكن أن يملك خلفية ومهارات مصمم تجربة المستخدم. ويمكنني أن أقول أنّ معظمنا يملك نقاط قوة واهتمامات في مجالات معيّنة، ولا يمكن أن ننمي مهاراتنا كمصممين إذا كنّا نركّز على الأجزاء التي نبرع فيها فقط. كيف تم تحديد التخصصات عندما نتحدث من الناحية التنظيمية، من المنطقي تحديد الأدوار في الشركات. ففي العادة تضمن الممارسة القائمة على توظيف العديد من التخصصات في الشركات الكبيرة خلق مزيج جيّد من المصممين والأفكار. والفكرة هي امتلاك تعاون متكامل بين مختلف التخصصات مما يتيح للجميع تبادل الأفكار وتنفيذ المشاريع على نحو أسرع من ذي قبل. لماذا لا يصلح تصنيف المصممين إلى تخصصات على الرغم من أنني أؤيد وجهة النظر النّظرية القائلة إنّ العديد من عقول التصميم المختلفة يمكن أن تجتمع معا لخلق شيء عظيم، إلا أنني لم أشهد قط حالة لا ينهار فيها هذا التنظيم عمليًا. والمشكلة هي في الحواجز التي تخلقها. من هو المسؤول وعن ماذا؟ لماذا تكون الكلمة الأخيرة للمصممين البصريين حول الأمور المتعلّقة بالجماليات أكثر من غيرهم؟ من الواضح أنّ هذا الأمر يمكن معالجته بالفريق المتكامل والقيادة المناسبة، لكنني نادرا ما أرى ذلك يحدث في الواقع. يبدو المصممون البصريون وكأنّهم حماة "العلامة التجارية" الأسطورية، بينما مصممو تجربة المستخدم هم حماة التجربة ولا يرغبون في تشويشها بالعناصر البصرية الرديئة. ولذلك أعتقد أنّ التصنيف إلى تخصصات خلق المزيد من المشاكل أكثر مما عالج. المشكلة الأخرى هي أنّ تعليمات المشروع تصبح هلامية وغير واضحة المعالم. من هو المسؤول عن ماذا؟ كيف نجدول المشروع بحيث يتدفق العمل بصورة مثالية من الإطارات الشبكية wireframes إلى التصميم البصري في حين يلتزم العديد من الناس بإنهاء ما بأيديهم من أعمال؟ حسب تجربتي، الأمر يصبح أكثر صعوبة بإشراك العديد من الناس. ولادة مصطلح "مصمم المنتجات" لقد نشأ مصطلح "مصمم المنتجات" في عالم الشركات الناشئة في وادي السيليكون. والفكرة وراء هذا اللقب كانت أن يصبح دورا شاملا وملما بجميع التخصصات. يُفترض بمصمم المنتج أن يكون خبيرًا بجميع تخصصات التصميم، وفي نفس الوقت يكون خبيرًا بالمنتج أيضًا. في هذه الحالة، أصبح بإمكان مصمم واحد أو أكثر من مصممي المنتجات السيطرة على كامل التجربة الرقمية من البداية وحتى النهاية، دون الحاجة إلى تسليم أعمالهم إلى مصممين آخرين. إنّ إشراك العديد من مصممي المنتجات للعمل على نفس المُنتج لا يضمن طرح العديد من الأفكار فحسب، وإنّما يُوفّر عدّة مهارات لأشخاص من مستويات مُتقاربة وُمتكاملة تسمح بخلق تجربة رائعة. كما سيتعزز الشعور بالثقة عند إزالة الحواجز والمشاكل المُتعلقة بالملكية (من المسؤول عن ماذا)، ولن يقلق أحدهم بعد ذلك من التقليل من شأن عمله، لكن سيكون التركيز أكثر على أفضل الأفكار المطروحة. مع ذلك، ليس من المثالي استخدام "المنتج" كوصف للمصمم (أي نقول "مصمم منتجات")، فهذا يوحي بأنّه يُعنى بكيفية عمل الشيء وأدائه أكثر من مظهره، بينما يجب أن يشمل التصميم كل ما يتعلّق بالتجربة التي تخلقها: كيف يعمل المنتج، كيف يبدو، لماذا قمت ببنائه، وما هي المشاكل التي يحلها أو الأهداف التي يحققها. مصدر الصورة: Boston Interactive لماذا يجب ألا تتخصص لقد طُرح علي هذا السّؤال العديد من المرات من قبل طلاب الجامعات حول التخصصات، وعلى وجه التحديد كيف أختار ما أريد العمل عليه. ودائما ما أخبرهم أنّه كلما كانت مهاراتهم عامة أكثر، سيصبحون في وضع أفضل وستتاح لهم فرص أكثر. وهذا يعني امتلاك المعرفة بجميع الفنون التصميمية التي تجعلك مصمما عظيما، وليس التميّز في تخصص واحد، وامتلاك خبرة متوسطة في التخصصات الأخرى. وبذلك ستصبح مطلوبا أكثر من قبل أصحاب العمل، وكذلك من طرف الزملاء. ماذا بعد الآن؟ لا تهتم أفضل الشركات التي عملت لديها بمفهوم الملكية آنف الذّكر. ربما يشعر أحدهم بالغضب والانزعاج إذا قام زميل برتبة أقل بالتعديل على تصميمه، لكن في الواقع، ليست هذه هي الكيفية التي تعمل بها الفرق العظيمة. وفي نهاية المطاف، هذا هو ما يعرّف التصميم. التصميم يعني معرفة أفضل طريقة يمكن أن ينفّذ فيها أحدهم شيئا على موقعك، سواء كان تطبيقا أو صفحة تسويقية. وهذا لا يمكن حلّه بواسطة مصمم يعمل على جانب واحد فقط من المشروع، كما يجب ألّا يُحل بواسطة العديد من الأطراف مما يغيّر العمل الأصلي. وبذلك عندما نقوم بتقسيم التصميم إلى تخصصات مختلفة، فإننا بذلك نلحق الضرر بصناعتنا من خلال خلق تجارب مفككة في أغلب الأحيان. لنعد إلى لقبنا العام، "مصممون"، ولنعمل على ما نحن شغوفون به ونبني تجربة رائعة. ترجمة -وبتصرّف- للمقال The Versatile Designer لصاحبه: Ryan Scherf.1 نقطة
-
تصميم تجربة المستخدم ليس هو نفس الشيء عندما تقارنه بتصميم واجهات الاستخدام. تجربة المستخدمين تحصل وراء الشاشات وبين الفجوات. كمصممي ويب وواجهات استخدام محمولة فإنّ عملنا يتركّز في بناء واجهاتٍ أنيقة. واجهاتٍ تكون عناصر أساسية في تجربة المستخدم. واجهات تسمح للمستخدمين بأن يحصلوا على أجوبة لأسئلتهم أو إكمال مهام أساسية بالنسبة لهم. عملنا هو أن نساعدهم في تحقيق أهدافهم. لكن إيّاك أن تخطئ وتعتقد أنّ هذه التفاعلات هي كلّ شيءٍ عن تجربة المستخدم. تجربة المستخدمين الرائعة تحصل دومًا خلف الشاشات وفي الفجوات. الفجوات التي تقع بين القنوات، الأجهزة وشركات الأعمال. تحصل تلك التجربة دومًا عندما تقوم المنظّمات بالاهتمام بالتفاصيل الدقيقة لتفاعلاتها مع العملاء. بسبب أنّ تصميم تجربة المستخدم يتعلّق بأكثر من أمر فإنّه من الصعب وصفه عادةً. لذا عوضًا عن ذلك، دعني أعطيك بعض الأمثلة على تفاعلاتٍ تساعد على إنشاء تجربة أفضل للمستخدمين. تفادي إزعاج دعم الهواتفتطبيق Barclays للهواتف الذكية مثال جيّد على تصميم جيّد لتجربة المستخدم. يمتلك التطبيق بذات نفسه واجهة جميلة. ولكنّ هذا ليس هو السبب وراء تجربة المستخدم الجيّدة الخاصّة به. يمتلك Barclays تطبيقًا ممتازًا للهاتف المحمول، ولكن السحر الحقيقي يحصل عندما تحاول الاتصال بهم. إذا أردت الاتصال بـBaraclays فإنّه يمكنك القيام بذلك عبر التطبيق. يسمح لك هذا بتخطّي الحاجة إلى الاستيثاق عبر الهاتف لأنّك قمتَ بهذا بالفعل عندما قمتَ بتسجيل الدخول إلى التطبيق. هذا مثال رائع على تجربة مستخدم مميّزة. أنا متأكّد من أنّ جلب نظام الهاتف والتطبيق ليتحدثا مع بعضهما البعض مباشرةً دون تدخل المستخدم لم يكن أمرًا سهلًا. ولكن بلا شكّ، فإنّه سيساعد المستخدمين على تجنّب الكثير من الإزعاج يوميًا. جعل عمليات الإرجاع أقل صعوبةإذا قمتَ من قبل بإرجاع منتج اشتريته عبر الشبكة فحينها أنت تعرف أنّ الأمر ليس سهلًا دومًا. يجب عليك كتابة طلب إرجاع، الذهاب إلى مكتب البريد والانتظار لأيّام قبل أن يعود المبلغ إلى حسابك الشخصي. وفوق كلّ هذا فهناك ذلك الأمر الذي تقلق حوله دومًا من أنّهم لن يعيدوا لك أموالك. على العكس مما سبق فقد كان لي تجربة حديثة في القيام بعملية إرجاع منتج. بعد أن أخبرت الشركة بأنني أريد إرجاع منتج خاصّ بهم، أخبروني بأنّ المال سيعود مباشرةً إلى حسابي، دون أيّ حاجة لانتظار عودة الطرد إليهم ومن ثمّ التحقق منه مجددًا. عند إرجاع منتج ما فهناك دومًا خوف من ألّا يعيدوا إليك نقودك. هذه فرصة سانحة لتحسين تجربة المستخدم. بعدها سألوني متى أريد أن يتم أخذ الطرد منّي. لم أحتج إلى توضيب الطرد وإغلاقه مجددًا أو تعبئة استمارة إرجاع ولصقها عليه والذهاب إلى البريد أو ما شابه. قام أحدهم فجأة بطرق باب منزلي حاملًا صندوقًا لكي يأخذ المنتج الذي أريد إرجاعه منّي. وضعت المنتج في ذلك الصندوق وأخذه لاحقًا. الآن، هذه تجربة مستخدم مميّزة. مساعدة الزبائن على أن يشعروا بالأمانعملت مرة مع زبون قام ببيع وجبات جاهزة مثلّجة لكبار السنّ. إنّه أمرٌ مثير للقلق بالنسبة لهم عندما يشترون المنتجات عبر الشبكة، ولا يحبّون فكرة أن يقوم شخص غريب بأن يطرق الباب عليهم. للتعامل مع هذه المشكلة، تمّ جعل اسم السائق وهويته واضحين لهم عندما يقومون بطلب عملية توصيل عبر الشبكة. بهذه الطريقة، سيتمكنون من تمييز الشخص الذي سيطرق الباب عليهم لاحقًا ليوصل الطلب إليهم. من الممكن لتجربة مستخدم جيّدة أن تقوم بزيادة أرباحك وأن تميّزك عن منافسيك. ولكنّهم لم يتوقّفوا هناك، بل يقومون بعمل فحص بواسطة الشرطة على جميع السائقين لكي يتمكّن الزبون من التأكّد من أنّ الأمر آمن. كان هذا مكلفًا واستغرق الكثير من الجهد، ولكنّه في المقابل زيادةً ملحوظةً في المبيعات. كان شيئًا لم يتمكّن منافسوهم (مثل Tescos) من تقديمه. الحفاظ على وقت المستخدمبالحديث عن عمليات التوصيل. هل قمت من قبل بالحصول على أيّ طرد عبر شركة DPD؟ أكره عمليات التوصيل، غالبًا ما لا يكون لديك أيّ فكرة عن متى سيصل الطرد الخاصّ بك وهل يجب عليك أن تقوم بمهامك وفقًا لهذا في الصباح أم في المساء. فهذا يعني أنّه يجب عليك أن تكون موجودًا ومستعدًا لرجل تسليم الطرود. لاشيء أبشع من اكتشاف وجود بطاقة تخبرك بالذهاب للمركز البريدي لاحقًا لتسلّم الطرد لأنّك اخترت اللحظة الخاطئة للذهاب إلى الحديقة. تسمح لك DPD بمعرفة موعد وصول الطرد الخاصّ بك بالضبط. تتعامل شركة DPD مع هذا. في يوم التوصيل سيقومون بمراسلتك قبل ساعةٍ من الموعد المتوقّع لوصول الطرد الخاصّ بك. كما وسيقومون أيضًا بالسماح لك بتعقّب طردك في الوقت الحقيقي ومعرفة مكانه عبر الخريطة. هذا يعني أنّه يمكنك معرفة مكان السائق وأن تقرر ما إذا كنت تمتلك 10 دقائق للذهاب إلى المتجر أم لا. بسبب تجربة المستخدم هذا، فإنني أتحمّس بشدّة عندما أكتشف أنني سأستلم طردًا عبر DPD! توفير الإلهاموأخيرًا أريد أن أذكر Etsy. يدرك المدراء في Etsy أنّه هناك الكثير من الأمور التي يمكن الاستفادة منها من قنوات التواصل الإجتماعي غير كونها مجرّد قناة تسويق. يعرفون أنّ العديد من زبائنهم يبحثون عن هديةٍ جيّدة ويحتارون في ماذا يشترون. لهذا قاموا ببناء تطبيق يقوم بالاتصال بحسابات المستخدمين على موقع Facebook. تقوم Etsy بدمج تجربة فيسبوك مع موقعهم عبر عرض اقتراحات الهدايا على المستخدمين عبر تحليل اهتمامات أصدقاء المستخدمين، يقوم التطبيق بتقديم الاقتراحات للمستخدمين عن ماهيّة الهدايا التي يجب عليهم شراؤها. استخدموا التكنولوجيا لتوفير مصدرٍ للإلهام لتجربة الشراء. أليس هذا هو نفسه خدمة العملاء؟ربّما تعتقد أنّ التفكير بهذه الطريقة هو أقرب إلى ما يشبه تصميم خدمة العملاء أكثر منه إلى تصميم تجربة المستخدم. ربّما تكون محقًا. تجربة المستخدمين ليست محدودة بقناةٍ واحدة، جهاز أو قطعة من مشروعك. الحقيقة هي أننا قمنا بتجزئة توصيفات أعمالنا بحيث تتداخل مع بعضها البعض غالبًا. أؤمن أنّ تصميم تجربة المستخدم مهمّ لأكثر من مجال. مجالات تتضمن كلا من تصميم واجهة الاستخدام وخدمة العملاء. مهما كان الاسم الذي تدعوها به، هناك درسٌ مهمّ لتعلّمه، وهو أنّ تجربة المستخدمين ليست محدودة بقناةٍ واحدة، جهاز أو قطعة من مشروعك. ترجمة -وبتصرّف- للمقال User experience design is not what you think لصاحبه Paul Boag. حقوق الصورة البارزة: Designed by Freepik.1 نقطة
-
إن آخر ما تريد سماعه من المستخدم لديك عند دخوله إلى موقعك لأول مرة هو "لحظة، ما الذي علي أن أفعله هنا بالضبط؟!" يمكن أن يكون تصميم عناصر الانتقالات أمرًا شائكًا، وخاصة إذا تركته للأخير بجعلها العنصر الأخير الذي ستقوم بتحسينه عند الاقتراب من الانتهاء من المشروع بأكمله. إنّ توجّهًا كهذا لا يمكن أن ينتهي نهاية حيدة، وهو بالتأكيد ليس الطريق السليم لتصميم عناصر التنقلات. إن التحدي هنا هو أنّ تصميم عناصر التنقلات لا يتعلق فقط بالقوائم التي ستستخدمها وأين ستضع تلك القوائم. يجب أن يبدأ هذا التوجه قبل ذلك بكثير. في الواقع، يفترض أن تعمل عليها منذ اليوم الأول في الوقت الذي تخطط فيه لتصميمك التالي. ولهذا، فما ستقرأه هنا هو دليل موجز: أساسيّات تصميم عناصر التنقلات. أول ما سنركز عليه هنا هو فصل الأشياء الضرورية للتنقل السليم عن غير الهامّة. ونبدأ بما يلي: إن الانطباع الأول هو ما يحدد النجاح أو الخسارةلدى كل منا موقع في العلامات (bookmarks) نستمتع بزيارته رغم سوء تصميم عناصر التنقلات فيه، أليس كذلك؟ لقد تعلمنا بطريقة ما أن نتنقل فيه وأن نحصل على محتواه، رغم صعوبة التنقلات. ما أحاول قوله هنا هو أن الزائر العادي لديك سيتعلم كيف يتعامل مع موقعك مع الوقت، بغض النظر عن مدى سوء تصميم عناصر التنقلات. أما عن زوارك الجدد، فهم فئة أخرى مختلفة تمامًا، ومن شبه المؤكد أنهم لن يتمتعوا بهذا القدر من التفاني والدافعية لتخطي هذه العقبات. ولهذا، فعند العمل على تصميم عناصر التنقلات لديك، عليك أن تركّز على التجربة الأولى للمستخدم قبل أيّ شيء آخَر. إن الانطباع الأول هو ما سيدعو المستخدم لأن يرجع، أو سيخيفه ويبعده بعيدًا عن الموقع. يبدأ التنقل الجيد بهيكلية جيدة للمحتوىفي الواقع الأمر سهل: المحتوى أولًا، ثم القوائم. يجب ان لا يكون تصميم عناصر التنقلات فكرة متأخرة، بل أن يكون نتيجة مباشرة لهيكلية المعلومات التي على الموقع. وبعبارة أخرى فإن الطريقة التي تصمم بها هيكلية المحتوى للموقع ستؤثر على الطريقة التي ستصمم بها عناصر التنقلات، وليس العكس. إن أحد الاحتمالات طريقة فرز البطاقات وهي طريقة لبدء تصميم هيكلية المعلومات وفرزها حسب الأولوية. إن طريقة فرز البطاقات طريقة يتم عملها دون استخدام الحاسوب، ويستخدم فيها المشاركون بطاقات حقيقيّة (قطع من الورق) لترتيب الموضوعات في مجموعات. دائما فكر بأهدافك أنتتُعلمُنا إحدى مدارس تصميم عناصر التنقلات أن نركز دائمًا على ما يريد المستخدم عمله أولًا: اهتم بأهداف المستخدمين أولًا. قد تكون هذه استراتيجية حكيمة في بعض الحالات، ولكنها ليست دائمًا الأفضل من وجهة نظر تجارية. يتعلق الأمر بعلاقته بأهدافك (أو أهداف عميلك) التجارية للموقع. بدلًا من ذلك، رتب تنقلاتك اعتمادًا على المكان الذي ترغب أن يذهب مستخدموك إليه، وليس بالضرورة أن يكون هذا هو ما يريدون هم الذهاب إليه. ربما علي أن أعيد صياغة ذلك. لا يتعلق الأمر بعمل الأشياء بما يخالف نيّة المستخدِم، بل بربط أهداف المستخدم بأهدافك أنت. فمثلًا، قد يرغب مستخدموك بترشيح (فلترة) قائمة التنزيلات لديك ليروا العروض المجانية فقط، ولكن هل الخيار الأفضل من وجهة نظر تجارية أن تسمح لهم بعمل ذلك؟ بدلًا من ذلك، يمكنك أن تجد حلًّا وسطًا بعرض قائمة كاملًا للتنزيلات، مع إعطاء التنزيلات المجانية تركيزًا إضافيًّا (بحيث يتمكن المستخدم من تمييز الأشياء المجانية، ولكن ستُعرض عليهم عروض أخرى مدفوعة). خمن طريقة تفكير المستخدميتعلق هذا القسم من المقال بتخمين طريقة تفكير المستخدِم عند زيارته لموقعك. بشكل عام، هل يعرف الزوار ما يبحثون عنه؟ أم عليك أن تساعدهم في ذلك؟ دعني أعرض عليك مثالين هنا: المثال الأول: جوجل. كل من يذهب إلى موقع جوجل يعرف تمامًا ما يبحث عنه. كل ما يحتاجه الزائر هو حقل إدخال للبحث يمكنه أن يضع فيه الموضوع الذي يبحث عنه وحسب. المثال الثاني: المدونات العاديّة. الزائر العاديّ للمدونة قد لا يعرف ما يبحث عنه بالتحديد. يعرف الزائر أنه يرغب بتلقي محتوىً جيّد، لكن عندما يتعلق الأمر بمقال معين سيقدم إليه، فهنا يأتي دورك بأن تقدم إليه المقال المناسب. ستحتاج في هذه الحالة إلى هيكلية تنقلات أكثر تطورًا من مجرد شريط بحث. تحتاج إلى قوائم، وإلى تصنيفات، وربما تحتاج إلى أرشيف، وما إلى ذلك. ولهذا، فعليك أن تصمم عناصر التنقلات في موقعك بناءً على توقعاتك لطريقة تفكير الزائر. إذا كان هناك انفصال (أيّ، لم تكن هناك تنقلات وروابط مناسبة)، فلن تكون لدى الزائر أدنى فكرة عن ما عليه فعله في موقعك، أو لن يكون بإمكانه تلقي أيّ من المحتوى. يجب أن تكون التنقلات مألوفةمن أكثر الأخطاء التي يقع فيها المصممون شيوعًا عند بنائهم لموقع هو أن يكونوا مبدعين أكثر من اللازم في توجهاتهم المتعلقة بالتنقلات. رغم صعوبة مقاومة الإبداع -خاصة أنّ أغلب أجزاء بناء الموقع تتطلبه- إلّا أنه من الأفضل العمل بأساليب مجرّبة عندما يتعلق الأمر بتصميم التنقلات. وفوق كل شيء، يجب أن لا يكون التنقل مُربكًا. يجب أن يتمكن جميع المستخدمين من تمييز القوائم بمجرد رؤيتها، دون أن يضطروا للبحث عنها. وبمناسبة الحديث عن ذلك، فهذا ليس رأيي وحدي. لقد طلبت من Robert Hapiuc -وهو مصمم في CodeinWP blog- أن يشاركني رأيه فيما يراها الأخطاء الأكثر شيوعًا التي يقع فيها مصممو المواقع عندما يتعلق الأمر بتصميم التنقلات. وفيما يلي ما قال: باختصار، اجعل بنية التنقلات لديك سهلة الفهم، ولا تحاول أن تذهب بعيدًا بإبداعك. اجعل القوائم وعناصر الموقع التي تشكّل التنقلات واضحة قدر الإمكان. إضافة إلى ذلك، لا تبدع أكثر من اللازم في إبراز التنقلات في موقعك. فمثلًا، لا بأس بحركات لتصاميم المسطحة، لكن جعلها متقدّمة ومعقدة جدًّا سيبعد المستخدمين وسيقلل من قابلية الاستخدام. والأهم من هذا كلّه: لا تتجاهل الأعراف المتبعة في الشبكة العنكبوتيةالعديد من أعراف الشبكة العنكبوتية قد رافقتنا لسنوات لسبب. ومن هذه الأشياء سلّة أو عربة التسوق في الزاوية اليمنى العليا للصفحة، أو روابط الولوج/الملف الشخصي في نفس المكان. لقد اعتاد المستخدمون على أن يروها في ذلك المكان، ومحاولة الخروج بمفهوم مختلف لن ينتج عنه إلا إرباك المستخدم. لذا، فالقاعدة الرئيسيّة هي الالتزام بالأعراف الموجودة، وجعلها توافق تصميمك، ولا تعد اختراع العجلة دون داعٍ. أظهر المحتوى الرئيسي بما يكفيبناء تنقلاتك حول المحتوى الرئيسيّ للموقع بداية جيدة. إن تجربة فرز البطاقات المذكورة أعلاه ستعطيك لمحة عامة عن تصنيفات المحتوى الرئيسيّ ومدى أهمية الدور الذي تلعبه في الموقع بأكمله. ستحتاج أيضًا لأن تنظر في أجزاء المحتوى الرئيسيّة المتعلقة بما يقدمه الموقع. فمثلًا، ليس عيبًا أن تضع رابطًا لجزئيّة معينة من المحتوى في القائمة العليا للموقع إذا كان هذا المحتوى هامًّا بما يكفي. لا تقع في فخّ بناء تنقلاتك حول القطاعات أو التصنيفات الرئيسيّة للمحتوى. قد يكون توجه كهذا قد يكون جيدًا لموقع دليل (مثل Alltop)، ولكنه لن يكون فعالًا على المدى البعيد لمواقع من نوع آخر. وهذا لأن تصميم عناصر التنقلات بناء على التصنيفات وحدها يتطلب أن يكون الزائر على اطلاع على ما يُتوقَّع أن يجد في كل تصنيف. (هناك مشكلة مشابهة في القوائم المنسدلة، والتي سنأتي على ذكرها لاحقًا في هذا المقال). أي نوع من عناصر التنقلات أستخدم؟هل نوع عناصر التنقلات التي تستخدمها مهم؟ هل هناك ميزة هامّة لاستخدام شريط التنقل العلوي (top nav. menus) بدلًا من القوائم المنسدلة الكبيرة (mega menus)؟ هل القوائم المنسدلة هي الطريقة السليمة؟ كالعادة -وكم أكره أن أقولها- هذا يعتمد على عدة أمور. الأنواع المختلفة لعناصر التنقلات مناسبة لحالات مختلفة، ولكن عليك أن تعرف خصائصها لتتمكن من اختيار النموذج المناسب لك بدقة. أشرطة التنقل العلوية (top nav bars)هي أداة التنقل الأكثر شيوعًا وربما الأكثر عمليّة. وأما عن عيبها الوحيد، فهو أنها تتسع فقط لقدر محدّد من العناصر. ولكن لا يشترط أن يكون هذا عيبًا. يتطلب استخدامك لشريط الانتقال العلويّ أن تراجع أولوياتك، بحيث تختار فقط أهم العناصر لتعرضها في الشريط العلويّ. كما وتجعل هذه الأشرطة اختيارات المستخدم أسهل. وفي النهاية، يذكرني هذا الكلام بالمثل العربيّ القائل "خير الكلام ما قلّ ودلّ"، والمثل الأجنبي القائل "less is more”. ويشير Dragos Bubu -وهو مصمم في ThemeIsle- أيضًا إلى قضية وجود أشياء أكثر من اللازم ضمن عناصر التنقلات الأساسيّة في حديثه عن الأخطاء الأساسيّة التي يقع فيها مصممو المواقع عند العمل على عناصر التنقلات في المواقع، إذ يقول: القوائم الجانبيةمن خيارات التنقلات الأقرب للموضة هذه الأيام وضع قائمة على الجانب. وبشكل عام، قد يكون هذا حلًّا جيدًا لبعض المواقع، ولكن هذا بشكل رئيسيّ للمواقع التي فيها تصنيفات كثيرة للمحتوى بحيث تتحول هذه التصنيفات نفسها إلى محتوى. وينطبق هذا أيضًا على المواقع التي فيها مرشّحات (فلاتر) يمكن للمستخدم ضبطها باستمرار أثناء تصفّح الجزء الخاص بالمحتوى الرئيسيّ. إن موقعًا صغيرًا يُدعى eBay مثال جيد على هذا. الجانب السلبي لهذه القوائم هو أنها يمكن أن تجذب قدرًا كبيرًا من اهتمام الزائر وتحدّ من ظهور وجاذبيّة الجزء الخاصّ بالمحتوى الرئيسيّ. وفي النهاية، لدينا نوع القوائم الأكثر إثارة للجدل، وهو القوائم المنسدلة (drop-down)مبدئيًّا، لا يوجد ما يعيب القوائم المنسدلة كأداة انتقال. المشكلة هي أن العديد من مصممي المواقع يلجؤون إليها عندما تنفد المساحة في شريط التنقل الرئيسيّ. هذا ليس الحلّ الأنسب. هذا يقلل قابليّة الاستخدام للموقع بأكمله لأن المستخدم لا يستطيع تخمين ما سيجد في هذه القوائم، ولهذا فلن يكون لديه دافع لينقر عليها. وكقاعدة رئيسيّة، القوائم المنسدلة بشكل عام جيدة فقط للقوائم التي يستطيع المستخدم أن يتنبأ بما في داخلها 100% دون أخطاء. فمثلًا، إذا كنت تريد من المستخدم أن يختار المحافظة أو المدينة أو الدولة التي يسكن فيها، فالقوائم المنسدلة خيار مثاليّ. ولكن عندما ترغب بعرض مجموعة قياسية من عناصر القائمة، فلن تكون خيارًا جيدًا. إضافة إلى هذا، ضمِّن تلميحات بصريّة إضافية عند استخدامك قوائم منسدلة، فمثلًا استخدم رمز المثلث الذي يوحي للمستخدم بوجود المزيد عند تمريره مؤشر الفأرة فوق القائمة. اسع إلى النجاح على المدى البعيدكما بالنسبة لمعظم نواحي تصميم المواقع، فمن المرجح أنك لن تصمم هيكلية التنقل الصحيحة في تجربتك الأولى مقارنة بما ستحققه عند رجوعك إلى التصميم والعمل على تحسينه. باختصار، تحقق من الأنماط، وتتبّع سلوك المستخدمين في موقعك والطريق الذي يتبعونه. ستتمكن مع الوقت من تحسين كفاءة التنقلات بجعل العناصر الأكثر استخدامًا مرئيّة أكثر، وبنقل الأقل استخدامًا إلى مكان أقل بروزًا. ما التالي؟تصميم عناصر التنقلات موضوع واسع إذا كنت ترغب باحترافه. وما تزال هناك الكثير من الأشياء التي لم نناقشها في هذا الدليل، ومنها: طريقة التعامل مع تنظيم المعلومات في صفحات المحتوى كلًّا على حدة (أين تضع الصور والنصوص والروابط)، واستخدام آليّات متقدمة للتنقلات، كالصفحات المنفصلة، وخرائط المواقع، والوسوم، والتنقلات الثابتة، وما إلى ذلك. أرى أن ندع الباقي إلى يوم آخَر، ونتوقف هنا لنسمح لعقلنا أن يتشرّب هذه المعلومات. ما رأيك؟ وما هي استراتيجيتك في تصميم عناصر تنقلات فعالة تقوم بمهمتها على أكمل وجه؟ ترجمة -وبتصرف- للمقال: Navigation Design 101 لصاحبته Karol K.1 نقطة