في هذا المقال ، ستتعلم كل شيء عن المكتبة البابلية ، والأهم من ذلك - كيفية إعادة إنشائها ، وأي مكتبة بالفعل.
لنبدأ باقتباسات من
المكتبة البابلية بقلم
لويس بورخيس .
اقتباس"يتكون الكون - يطلق عليه البعض على المكتبة - من عدد ضخم ، وربما لا حصر له من صالات العرض السداسية ، مع غرف تهوية واسعة محاطة بقضبان منخفضة. من كل مسدس ، يمكن رؤية طابقين علويين وطابقين سفليين - إلى ما لا نهاية. "
"المكتبة عبارة عن كرة ، مركزها الدقيق يقع في أحد السداسيات ، ولا يمكن الوصول إلى السطح. يوجد على كل جدار من كل مسدس خمسة رفوف ، يوجد على كل رف اثنان وثلاثون كتابًا من نفس التنسيق ، ولكل كتاب أربع مئة وعشر صفحات ، ولكل صفحة أربعون سطرًا ، ويحتوي كل سطر على حوالي ثمانين حرفًا أسود. هناك رسائل في العمود الفقري للكتاب ، لكنها لا تحدد أو تنبئ بما ستقوله الصفحات. هذا التناقض ، كما أعرف ، كان يبدو في السابق غامضًا. "
إذا قمت بإدخال مسدس عشوائي ، صعد إلى أي حائط ، وانظر إلى أي رف وأخذ الكتاب الذي يعجبك أكثر ، فمن المرجح أن تكون منزعجًا. بعد كل شيء ، كنت تتوقع معرفة معنى الحياة هناك ، لكنك رأيت مجموعة غريبة من الشخصيات. ولكن لا ينزعج بسرعة! معظم الكتب لا معنى لها ، لأنها عبارة عن بحث متجانس لجميع المتغيرات المحتملة من خمسة وعشرين حرفًا (
هذه الأبجدية هي التي استخدمها بورخيس في مكتبته ، ولكن بعد ذلك سوف يكتشف القارئ أنه يمكن أن يكون هناك أي عدد من الأحرف في المكتبة ). القانون الرئيسي للمكتبة هو أنه لا يوجد كتابان متطابقان تمامًا فيه ، وبالتالي فإن عددها محدود ، وستنتهي المكتبة في يوم من الأيام. يعتقد بورخيس أن المكتبة دورية:
اقتباس"ربما يخدعني الخوف والشيخوخة ، لكنني أعتقد أن الجنس البشري - الجنس الوحيد - يقترب من الانقراض ، وستبقى المكتبة: مضيئة ، غير مأهولة ، بلا حدود ، بلا حراك على الإطلاق ، مليئة بمجلدات ثمينة ، عديمة الفائدة ، غامضة ، غامضة. لقد كتبت فقط لا نهاية لها. أنا لم أضع هذه الكلمة من حب الخطابة ؛ أعتقد أنه من المنطقي افتراض أن العالم لا نهاية له. أولئك الذين يعتبرونها محدودة يعترفون أنه في مكان ما في ممرات المسافة ، والسلالم ، والسداسيات يمكن أن تنتهي لسبب غير معروف - مثل هذا الافتراض سخيف. أولئك الذين يتخيلون ذلك بلا حدود ينسى أن عدد الكتب الممكنة محدود. أجرؤ على اقتراح مثل هذا الحل لهذه المشكلة القديمة: المكتبة بلا حدود ودورية. إذا شرع المتجول الأبدي في رحلة في أي اتجاه ، فسيكون قادرًا بعد قرون على التحقق من تكرار نفس الكتب في نفس الفوضى (والتي ، عند تكرارها ، تصبح أمرًا - ترتيب). هذا الأمل الجميل يضيء الشعور بالوحدة ".
بالمقارنة مع هذا الهراء ، هناك عدد قليل جدًا من الكتب التي يمكن للشخص فهم محتوياتها على الأقل بطريقة أو بأخرى ، لكن هذا لا يغير حقيقة أن المكتبة تحتوي على جميع النصوص التي تم ابتكارها من قبل أي شخص. إضافة إلى ذلك ، منذ الطفولة اعتدت على النظر في بعض متواليات الرموز ذات مغزى ، في حين أن الآخرين لا يفعلون ذلك. في الواقع ، في سياق المكتبة ، لا يوجد فرق بينهما. لكن ما هو منطقي لديه نسبة أقل بكثير ، ونحن نسميها اللغة. هذه وسيلة للتواصل بين الناس. تحتوي أي لغة على بضع عشرات فقط من الكلمات ، والتي نعرف 70٪ من قوتها ، وبالتالي اتضح أننا لا نستطيع تفسير معظم البحث التوافقي للكتب. وشخص يعاني من
فقدان القدرة على الكلام وحتى في مجموعات عشوائية من الشخصيات يرى معنى خفيًا. لكن هذه فكرة جيدة عن
إخفاء المعلومات ! حسنًا ، أواصل مناقشة هذا الموضوع في التعليقات.
قبل الشروع في تنفيذ هذه المكتبة ، سأفاجئك بحقيقة مثيرة للاهتمام: إذا كنت ترغب في إعادة إنشاء المكتبة البابلية لويس بورخيس ، فلن تنجح ، لأن مجلداتها تتجاوز حجم الكون المرئي 10 ^ 611338 (!) مرات. وحول ما سيحدث في المكتبات الأكبر حجمًا ، أخاف حتى التفكير.
تنفيذ المكتبة
وصف الوحدة
مقدمة لدينا القليل قد انتهت. لكن الأمر لا يخلو من المعنى: الآن أنت تفهم شكل المكتبة البابلية ، والقراءة ستكون أكثر إثارة للاهتمام فقط. لكنني سأبتعد عن الفكرة الأصلية ، أردت إنشاء مكتبة "عالمية" ، والتي سيتم مناقشتها لاحقًا. سأكتب في JavaScript تحت Node.js. ما الذي يجب أن تفعله المكتبة؟
- العثور بسرعة على النص المطلوب وعرض موقعه في المكتبة
- تحديد عنوان الكتاب
- العثور على كتاب مع العنوان الصحيح بسرعة
بالإضافة إلى ذلك ، يجب أن تكون عالمية ، أي يمكن تغيير أي من معلمات المكتبة إذا أردت. حسنًا ، أعتقد أنني سأعرض أولاً الشفرة الكاملة للوحدة ، وسنقوم بتحليلها بالتفصيل ، ونرى كيف تعمل ، وسأقول بضع كلمات.
مستودع جيثبالملف الرئيسي هو index.js ، والمنطق الكامل للمكتبة موصوف هناك ، وسأشرح محتويات هذا الملف.
let sha512 = require(`js-sha512`);
نقوم بتوصيل الوحدة التي تنفذ
خوارزمية التجزئة
sha512 . قد يبدو الأمر غريبًا بالنسبة لك ، لكنه سيظل مفيدًا لنا.
ما هو الناتج من وحدة لدينا؟ تقوم بإرجاع دالة ، وهي مكالمة تُرجع كائن مكتبة بكل الأساليب اللازمة. يمكن أن نعيدها على الفور ، ولكن بعد ذلك لن تكون إدارة المكتبة مريحة للغاية عندما نمرر المعلمات إلى الوظيفة ونحصل على المكتبة "اللازمة". سيسمح لنا ذلك بإنشاء مكتبة "عالمية". نظرًا لأنني أحاول الكتابة بنمط ES6 ، فإن دالة السهم الخاصة بي تقبل كائنًا كمعلمات ، والتي سيتم إتلافها لاحقًا في المتغيرات الضرورية:
module.exports = ({ lengthOfPage = 4819, lengthOfTitle = 31, digs = '0123456789abcdefghijklmnopqrstuvwxyz', alphabet = ', .', wall = 5, shelf = 7, volume = 31, page = 421, } = {}) => {
الآن دعنا نذهب على المعلمات. كمعلمات رقمية قياسية ، قررت اختيار الأعداد الأولية ، لأنه بدا لي أنه سيكون أكثر إثارة للاهتمام.
- lengthOfPage - رقم ، عدد الأحرف في صفحة واحدة. الافتراضي هو 4819. إذا أخذنا هذا الرقم في الاعتبار ، فسنحصل على 61 و 79. 61 سطرًا من 79 حرفًا ، أو العكس ، لكنني أفضل الخيار الأول.
- lengthOfTitle - رقم ، عدد الأحرف في عنوان عنوان الكتاب.
- الحفريات - سلسلة ، أرقام محتملة من رقم مع قاعدة تساوي طول هذه السلسلة. ما هو هذا الرقم ل؟ سوف يحتوي على رقم (معرف) مسدس التي نريد أن نذهب إليها. بشكل افتراضي ، يكون صغير اللاتينية والأرقام 0-9. يتم تشفير معظم النص هنا ، لذلك سيكون عددًا كبيرًا - عدة آلاف من البتات (استنادًا إلى عدد الأحرف في الصفحة) ، ولكن سيتم معالجتها حرفًا بحرف.
- الأبجدية - السلسلة ، الأحرف التي نريد رؤيتها في المكتبة. سيتم ملؤها معهم. لكي يعمل كل شيء بشكل صحيح ، يجب أن يكون عدد الأحرف في الأبجدية مساويًا لعدد الأحرف في السلسلة مع أرقام محتملة من الرقم الذي يحدد السداسي.
- wall - رقم ، أقصى رقم للحائط ، افتراضي 5
- رف - رقم ، الحد الأقصى لعدد الرف ، الافتراضي 7
- حجم - رقم ، أقصى رقم للكتاب ، افتراضيًا 31
- الصفحة - الرقم ، الحد الأقصى لعدد الصفحات ، الافتراضي 421
كما ترون ، هذا يشبه إلى حد ما المكتبة البابلية الحقيقية لويس بورجيس. لكنني قلت أكثر من مرة أننا سننشئ مكتبات "عالمية" يمكن أن تكون بالطريقة التي نريد أن نراها (لذلك ، يمكن تفسير رقم ست عشري بطريقة مختلفة بطريقة مختلفة ، على سبيل المثال ، فقط معرف مكان ما حيث يتم تخزين الرقم المرغوب فيه المعلومات). المكتبة البابلية هي واحدة منها فقط. ولكن جميعها لديها الكثير من القواسم المشتركة - خوارزمية واحدة هي المسؤولة عن أدائها ، والتي سيتم مناقشتها الآن.
بحث الصفحة وعرض الخوارزميات
عندما نذهب إلى بعض العناوين ، فإننا نرى محتويات الصفحة. إذا ذهبنا إلى نفس العنوان مرة أخرى ، فيجب أن يكون المحتوى هو نفسه تمامًا. توفر خاصية المكتبات هذه خوارزمية لتوليد أرقام عشوائية مزيفة -
طريقة التطابق الخطي . عندما نحتاج إلى اختيار حرف لإنشاء العنوان أو ، على العكس من ذلك ، محتويات الصفحة ، فسوف يساعدنا ذلك ، وسيتم استخدام أرقام الصفحات ، والأرفف ، إلخ. config PRNG: m = 2 ^ 32 (4294967296) ، a = 22695477 ، c = 1. أود أيضًا أن أضيف أنه في تطبيقنا يبقى فقط مبدأ توليد الأرقام من طريقة التطابق الخطي ، الباقي يتم تغييره. ننتقل إلى قائمة البرنامج أكثر:
كود module.exports = ({ lengthOfPage = 4819, lengthOfTitle = 31, digs = '0123456789abcdefghijklmnopqrstuvwxyz', alphabet = ', .', wall = 5, shelf = 7, volume = 31, page = 421, } = {}) => { let seed = 13;
كما ترون ، تتغير حبيبة PRNG بعد كل إيصال للرقم ، وتعتمد النتائج بشكل مباشر على ما يسمى بالنقطة المرجعية - الحبة ، وبعدها سوف تهمنا الأرقام. (نقوم بإنشاء العنوان أو الحصول على محتويات الصفحة)
ستساعدنا وظيفة
getHash على إنشاء نقطة مرجعية. لقد حصلنا على علامة تجزئة من بعض البيانات ، ونأخذ 7 أحرف ، ونترجم إلى نظام رقمي عشري ، وقد انتهيت!
تتصرف وظيفة
mod مثل عامل٪. ولكن إذا كان العائد هو <0 (مثل هذه المواقف ممكنة) ،
فستُرجع الدالة
mod رقماً موجبًا بسبب البنية الخاصة ، نحتاج إلى ذلك لتحديد الأحرف من سلسلة
الحروف الأبجدية بشكل صحيح عند تلقي محتوى الصفحة على العنوان.
وآخر جزء من كود الحلوى هو كائن المكتبة المرتجعة:
كود return { wall, shelf, volume, page, lengthOfPage, lengthOfTitle, search(searchStr) { let wall = `${(Math.random() * this.wall + 1 ^ 0)}`, shelf = `${(Math.random() * this.shelf + 1 ^ 0)}`, volume = pad(`${(Math.random()* this.volume + 1 ^ 0)}`, 2), page = pad(`${(Math.random()* this.page + 1 ^ 0)}`, 3), locHash = getHash(`${wall}${shelf}${volume}${page}`), hex = ``, depth = Math.random() * (this.lengthOfPage - searchStr.length) ^ 0; for (let i = 0; i < depth; i++){ searchStr = alphabet[Math.random() * alphabet.length ^ 0] + searchStr; } seed = locHash; for (let i = 0; i < searchStr.length; i++){ let index = alphabetIndexes[searchStr[i]] || -1, rand = rnd(0, alphabet.length), newIndex = mod(index + parseInt(rand), digs.length), newChar = digs[newIndex]; hex += newChar; } return `${hex}-${wall}-${shelf}-${+volume}-${+page}`; }, searchExactly(text) { const pos = Math.random() * (this.lengthOfPage - text.length) ^ 0; return this.search(`${` `.repeat(pos)}${text}${` `.repeat(this.lengthOfPage - (pos + text.length))}`); }, searchTitle(searchStr) { let wall = `${(Math.random() * this.wall + 1 ^ 0)}`, shelf = `${(Math.random() * this.shelf + 1 ^ 0)}`, volume = pad(`${(Math.random()* this.volume + 1 ^ 0)}`, 2), locHash = getHash(`${wall}${shelf}${volume}`), hex = ``; searchStr = searchStr.substr(0, this.lengthOfTitle); searchStr = searchStr.length == this.lengthOfTitle ? searchStr : `${searchStr}${` `.repeat(this.lengthOfTitle - searchStr.length)}`; seed = locHash; for (let i = 0; i < searchStr.length; i++){ let index = alphabetIndexes[searchStr[i]], rand = rnd(0, alphabet.length), newIndex = mod(index + parseInt(rand), digs.length), newChar = digs[newIndex]; hex += newChar; } return `${hex}-${wall}-${shelf}-${+volume}`; }, getPage(address) { let addressArray = address.split(`-`), hex = addressArray[0], locHash = getHash(`${addressArray[1]}${addressArray[2]}${pad(addressArray[3], 2)}${pad(addressArray[4], 3)}`), result = ``; seed = locHash; for (let i = 0; i < hex.length; i++) { let index = digsIndexes[hex[i]], rand = rnd(0, digs.length), newIndex = mod(index - parseInt(rand), alphabet.length), newChar = alphabet[newIndex]; result += newChar; } seed = getHash(result); while (result.length < this.lengthOfPage) { result += alphabet[parseInt(rnd(0, alphabet.length))]; } return result.substr(result.length - this.lengthOfPage); }, getTitle(address) { let addressArray = address.split(`-`), hex = addressArray[0], locHash = getHash(`${addressArray[1]}${addressArray[2]}${pad(addressArray[3], 2)}`), result = ``; seed = locHash; for (let i = 0; i < hex.length; i++) { let index = digsIndexes[hex[i]], rand = rnd(0, digs.length), newIndex = mod(index - parseInt(rand), alphabet.length), newChar = alphabet[newIndex]; result += newChar; } seed = getHash(result); while (result.length < this.lengthOfTitle) { result += alphabet[parseInt(rnd(0, alphabet.length))]; } return result.substr(result.length - this.lengthOfTitle); } };
في البداية ، نكتب إليها خصائص المكتبة التي وصفتها سابقًا. يمكنك تغييرها حتى بعد أن تسمى الوظيفة الرئيسية (والتي ، من حيث المبدأ ، يمكن أن تُسمى مُنشئ ، لكن الكود الخاص بي مشابه بشكل ضعيف لتنفيذ الفصل في المكتبة ، لذا سأقصر نفسي على كلمة "رئيسي"). ربما هذا السلوك ليس كافيا تماما ، لكنه مرن. اذهب الآن على كل طريقة.
طريقة البحث
search(searchStr) { let wall = `${(Math.random() * this.wall + 1 ^ 0)}`, shelf = `${(Math.random() * this.shelf + 1 ^ 0)}`, volume = pad(`${(Math.random() * this.volume + 1 ^ 0)}`, 2), page = pad(`${(Math.random() * this.page + 1 ^ 0)}`, 3), locHash = getHash(`${wall}${shelf}${volume}${page}`), hex = ``, depth = Math.random() * (this.lengthOfPage - searchStr.length) ^ 0; for (let i = 0; i < depth; i++){ searchStr = alphabet[Math.random() * alphabet.length ^ 0] + searchStr; } seed = locHash; for (let i = 0; i < searchStr.length; i++){ let index = alphabetIndexes[searchStr[i]] || -1, rand = rnd(0, alphabet.length), newIndex = mod(index + parseInt(rand), digs.length), newChar = digs[newIndex]; hex += newChar; } return `${hex}-${wall}-${shelf}-${+volume}-${+page}`; }
إرجاع عنوان سلسلة
searchStr في المكتبة. للقيام بذلك ، حدد عشوائيًا
الحائط والجرف والحجم والصفحة .
حجم والصفحة مبطن أيضا مع الأصفار إلى الطول المطلوب. بعد ذلك ، قم
بتسلسلها في سلسلة لتمريرها إلى وظيفة
getHash .
locHash الناتج هو نقطة البداية ، أي الحبوب.
لمزيد من عدم القدرة على التنبؤ ،
نضيف عمق searchStr بأحرف شبه عشوائية من الأبجدية ،
ونضع بذرة
البذور على
locHash . في هذه المرحلة ، لا يهم كيف نضيف الخط ، لذلك يمكنك استخدام JavaScript PRNG المدمج ، فهذا ليس بالأمر الحاسم. يمكنك التخلي عنها تمامًا حتى تكون النتائج التي تهمنا دائمًا في أعلى الصفحة.
الشيء الوحيد المتبقي هو إنشاء معرف مسدس. لكل حرف من سلسلة
searchStr ،
نقوم بتنفيذ الخوارزمية:
- الحصول على رقم حرف الفهرس في الأبجدية من كائن alphabetIndexes . إذا لم يكن الأمر كذلك ، فقم بإرجاع -1 ، ولكن إذا حدث ذلك ، فأنت بالتأكيد تفعل شيئًا خاطئًا.
- قم بإنشاء راند عشوائي شبه عشوائي باستخدام PRNG لدينا ، في المدى من 0 إلى طول الأبجدية.
- احسب الفهرس الجديد ، الذي يتم حسابه على أنه مجموع عدد فهرس الرمز وراند الرقم العشوائي العشوائي ، مقسومًا على طول الحفريات .
- وبالتالي ، حصلنا على رقم معرف المسدس - newChar (أخذها من الحفريات ).
- إضافة newChar إلى معرف ست عشري
عند الانتهاء من الجيل
السداسي ، نرجع العنوان الكامل للمكان الذي يحتوي على الخط المرغوب فيه. يتم فصل مكونات العنوان بواسطة واصلة.
طريقة البحث
searchExactly(text) { const pos = Math.random() * (this.lengthOfPage - text.length) ^ 0; return this.search(`${` `.repeat(pos)}${text}${` `.repeat(this.lengthOfPage - (pos + text.length))}`); }
تقوم هذه الطريقة بنفس طريقة
البحث ، ولكنها تملأ كل المساحة الحرة (تجعل سلسلة
البحث searchStr بطول مسافات
lengthOfPage ). عند عرض هذه الصفحة ، سيظهر أنه لا يوجد شيء ما عدا النص الخاص بك.
طريقة البحث
searchTitle(searchStr) { let wall = `${(Math.random() * this.wall + 1 ^ 0)}`, shelf = `${(Math.random() * this.shelf + 1 ^ 0)}`, volume = pad(`${(Math.random()* this.volume + 1 ^ 0)}`, 2), locHash = getHash(`${wall}${shelf}${volume}`), hex = ``; searchStr = searchStr.substr(0, this.lengthOfTitle); searchStr = searchStr.length == this.lengthOfTitle ? searchStr : `${searchStr}${` `.repeat(this.lengthOfTitle - searchStr.length)}`; seed = locHash; for (let i = 0; i < searchStr.length; i++){ let index = alphabetIndexes[searchStr[i]], rand = rnd(0, alphabet.length), newIndex = mod(index + parseInt(rand), digs.length), newChar = digs[newIndex]; hex += newChar; } return `${hex}-${wall}-${shelf}-${+volume}`; }
إرجاع الأسلوب
searchTitle عنوان كتاب يسمى
searchStr . في الداخل ، إنه مشابه جدًا
للبحث . الفرق هو أنه عند حساب
locHash ، فإننا لا نستخدم الصفحة لربط اسمها بالكتاب. لا ينبغي أن تعتمد على الصفحة. يتم اقتطاع
searchStr إلى
lengthOfTitle ومبطنة بمسافات إذا لزم الأمر. وبالمثل ، يتم إنشاء معرف السداسي ويتم إرجاع العنوان المستلم. يرجى ملاحظة أنه لا توجد صفحة فيها ، كما كانت عند البحث عن العنوان الدقيق للنص التعسفي. لذلك إذا كنت تريد معرفة ما هو موجود في الكتاب بالاسم الذي صاغته ، فاختر الصفحة التي تريد الذهاب إليها.
طريقة GetPage
getPage(address) { let addressArray = address.split(`-`), hex = addressArray[0], locHash = getHash(`${addressArray[1]}${addressArray[2]}${pad(addressArray[3], 2)}${pad(addressArray[4], 3)}`), result = ``; seed = locHash; for (let i = 0; i < hex.length; i++) { let index = digsIndexes[hex[i]], rand = rnd(0, digs.length), newIndex = mod(index - parseInt(rand), alphabet.length), newChar = alphabet[newIndex]; result += newChar; } seed = getHash(result); while (result.length < this.lengthOfPage) { result += alphabet[parseInt(rnd(0, alphabet.length))]; } return result.substr(result.length - this.lengthOfPage); }
عكس طريقة
البحث . وتتمثل مهمتها في إرجاع محتويات الصفحة إلى العنوان المحدد. للقيام بذلك ، نقوم بتحويل العنوان إلى صفيف باستخدام الفاصل "-". الآن لدينا مجموعة من مكونات العنوان: معرف السداسي ، والجدار ، والجرف ، والكتاب ، والصفحة. نحسب
locHash بنفس الطريقة التي
اتبعناها في طريقة
البحث . نحصل على نفس الرقم الذي كان عند إنشاء العنوان. هذا يعني أن PRNG ستنتج نفس الأرقام ، فهذا السلوك هو الذي يضمن انعكاس تحولاتنا على النص المصدر. لحسابها ، نقوم بتنفيذ الخوارزمية على كل حرف (بحكم الأمر الواقع ، هذا رقم) من معرف مسدس:
- نحسب مؤشر في الحفريات سلسلة. أعتبر من digsIndexes .
- باستخدام PRNG ، نولد راندًا عشوائيًا عشوائيًا في النطاق 0 لقاعدة نظام الأرقام لعدد كبير ، مساويًا لطول السلسلة التي تحتوي على أرقام هذا الرقم الجميل. كل شيء واضح.
- نحسب موضع رمز النص المصدر newIndex على أنه الفرق بين الفهرس والراند ، مقسوما على طول الأبجدية. من الممكن أن يكون الفرق سالبًا ، عندئذٍ سيعطي معامل القسمة المعتاد فهرسًا سالبًا لا يناسبنا ، لذلك نستخدم نسخة معدلة من قسم المودولو. (يمكنك تجربة خيار أخذ القيمة المطلقة من الصيغة أعلاه ، وهذا يحل أيضًا مشكلة الأعداد السالبة ، لكن في الممارسة العملية لم يتم اختباره بعد)
- حرف نص الصفحة هو newChar ، نحصل على الفهرس من الأبجدية.
- إضافة حرف نص إلى النتيجة.
لن تملأ النتيجة التي تم الحصول عليها في هذه المرحلة دائمًا الصفحة بأكملها ، لذلك سنحسب الحبة الجديدة من النتيجة الحالية ونملأ المساحة الخالية بأحرف من الأبجدية. يساعدنا PRNG في اختيار الرمز.
هذا يكمل حساب محتوى الصفحة ، نعيده ، لا ننسى أن نقطع إلى الحد الأقصى للطول. ربما كان معرف السداسي كبيرًا في عنوان الإدخال.
طريقة GetTitle
getTitle(address) { let addressArray = address.split(`-`), hex = addressArray[0], locHash = getHash(`${addressArray[1]}${addressArray[2]}${pad(addressArray[3], 2)}`), result = ``; seed = locHash; for (let i = 0; i < hex.length; i++) { let index = digsIndexes[hex[i]], rand = rnd(0, digs.length), newIndex = mod(index - parseInt(rand), alphabet.length), newChar = alphabet[newIndex]; result += newChar; } seed = getHash(result); while (result.length < this.lengthOfTitle) { result += alphabet[parseInt(rnd(0, alphabet.length))]; } return result.substr(result.length - this.lengthOfTitle); }
حسنا ، القصة هي نفسها. تخيل أنك قرأت وصف الطريقة السابقة ، فقط عند حساب حبيبات PRNG التي لا تأخذها في الاعتبار رقم الصفحة ، وقم بإضافة
واقتصاص النتيجة إلى الحد الأقصى لطول اسم الكتاب -
lengthOfTitle .
اختبار الوحدة النمطية لإنشاء المكتبات
بعد أن درسنا مبدأ تشغيل أي مكتبة تشبه البابلية - حان الوقت لتجربة كل ذلك في الممارسة. سأستخدم التكوين في أقرب وقت ممكن للتكوين الذي أنشأه لويس بورخيس. سنبحث عن عبارة بسيطة "habr.com":
const libraryofbabel = require(`libraryofbabel`)({ lengthOfPage: 3200, alphabet: `abcdefghijklmnopqrstuvwxyz, .`,
تشغيل ، والنتيجة:

في الوقت الحالي ، لا يعطينا أي شيء. ولكن دعنا نعرف ما هو مخفي وراء هذا العنوان! الرمز سيكون مثل هذا:
const libraryofbabel = require(`libraryofbabel`)({ lengthOfPage: 3200, alphabet: `abcdefghijklmnopqrstuvwxyz, .`,
النتيجة:

وجدنا ما كنا نبحث عنه في عدد لا حصر له من صفحات (أراهن) بلا معنى!
ولكن هذا أبعد ما يكون عن المكان الوحيد الذي توجد فيه هذه العبارة. في المرة التالية التي يبدأ فيها البرنامج ، سيتم إنشاء عنوان آخر. إذا كنت تريد ، يمكنك حفظ واحدة والعمل معها. الشيء الرئيسي هو أن محتوى الصفحات لا يتغير أبدًا. لنلقِ نظرة على عنوان الكتاب الذي توجد فيه العبارة. سيكون الكود كما يلي:
const libraryofbabel = require(`libraryofbabel`)({ lengthOfPage: 3200, alphabet: `abcdefghijklmnopqrstuvwxyz, .`,
عنوان الكتاب هو شيء من هذا القبيل:

بصراحة ، لا تبدو جذابة للغاية. ثم دعونا نجد كتابًا به عبارة في العنوان:
const libraryofbabel = require(`libraryofbabel`)({ lengthOfPage: 3200, alphabet: `abcdefghijklmnopqrstuvwxyz, .`,

أنت الآن تفهم كيفية استخدام هذه المكتبة. اسمحوا لي أن أثبت إمكانية إنشاء مكتبة مختلفة تماما. الآن سيتم ملؤها بأخرى وأصفار ، وستحتوي كل صفحة على 100 حرف ، وسيكون العنوان رقم سداسي عشري. لا تنس ملاحظة حالة المساواة في أطوال الحروف الأبجدية وسلسلة الأرقام الخاصة بعدد كبير. سنبحث ، على سبيل المثال ، "10101100101010111001000000". نحن ننظر:
const libraryofbabel = require(`libraryofbabel`)({ lengthOfPage: 100, alphabet: `1010101010101010`,

دعنا نلقي نظرة على إيجاد تطابق كامل. للقيام بذلك ،
دعنا نعود إلى المثال القديم وفي الكود ،
استبدل libraryofbabel.search بـ
libraryofbabel.searchExactly :
const libraryofbabel = require(`libraryofbabel`)({ lengthOfPage: 3200, alphabet: `abcdefghijklmnopqrstuvwxyz, .`,

الخاتمة
بعد قراءة وصف خوارزمية تشغيل المكتبة ، ربما تكون قد خمنت بالفعل أن هذا نوع من الخداع.
عندما تبحث عن شيء ذي معنى في المكتبة ، يتم ترميزه ببساطة في شكل مختلف ويتم عرضه في شكل مختلف. ولكن يتم تقديمه بشكل جميل بحيث تبدأ في الاعتقاد بهذه الصفوف التي لا تنتهي من السداسي. في الواقع ، هذا ليس أكثر من مجرد تجريد رياضي. ولكن حقيقة أنه في هذه المكتبة يمكنك أن تجد أي شيء على الإطلاق ، أي شيء ، صحيح. الحقيقة هي أنه إذا قمت بإنشاء تسلسل عشوائي للأحرف ، يمكنك عاجلاً أم آجلاً الحصول على أي نص. لفهم أفضل لهذا الموضوع ، يمكنك دراسة نظرية القرد التي لا نهاية لها .يمكنك التوصل إلى خيارات أخرى لتنفيذ المكتبات: استخدم أي خوارزمية تشفير ، حيث سيكون نص التشفير العنوان في المكتبة الشاملة. فك التشفير - الحصول على محتوى الصفحة. أو ربما حاولbase64 ، م؟الاستخدام المحتمل للمكتبة هو تخزين كلمات المرور في بعض أماكنها. قم بإنشاء التكوين الذي تحتاجه ، واكتشف أين توجد كلمات المرور الخاصة بك في المكتبة (نعم ، إنها موجودة بالفعل. وكنت تعتقد أنه من أنت الذي اخترعها؟) ، احفظ العنوان. والآن ، عندما تحتاج إلى العثور على نوع من كلمة المرور ، ما عليك سوى العثور عليها في المكتبة. ولكن هذا النهج خطير ، لأن المهاجم يمكنه معرفة تهيئة المكتبة واستخدام عنوانك فقط. لكن إذا كان لا يعرف معنى ما وجده ، فمن غير المرجح أن تصل إليه بياناتك. وهل هي حقًا طريقة تخزين كلمة مرور رئيسية؟ لا ، لذلك لديه مكان ليكون.يمكن استخدام هذه الفكرة لإنشاء مجموعة متنوعة من "المكتبات". يمكنك تكرار ليس فقط الأحرف ، ولكن أيضًا الكلمات الكاملة ، أو حتى الأصوات! تخيل مكانًا يمكنك من خلاله الاستماع إلى أي صوت متاح للإدراك البشري أو للعثور على نوع من الأغاني. في المستقبل سأحاول بالتأكيد تنفيذ هذا.يتوفر إصدار الويب باللغة الروسية هنا ، ويتم نشره على الخادم الافتراضي الخاص بي. لا أعرف كل عمليات البحث الممتعة عن معنى الحياة في المكتبة البابلية ، أو ما الذي تريد إنشاؤه. وداعا! :)