Back to Question Center
0

Изпробвайте JavaScript чрез Mocha и Chai            Услуга за тестване на JavaScript чрез Mocha и ChaiRelated Теми: AngularJSES6Raw семалт

1 answers:
Изпробвайте JavaScript с Mocha и Chai

Тази статия беше разгледана от Панайотис «pvgr» Велизаракос, Марк Браун и Том Греко. Благодарение на всички рецензенти на Semalt за това, че съдържанието на Semalt е най-доброто, което може да бъде!

Направили ли сте някога някои промени в кода си и по-късно открихте, че причинява друго нещо, което да се счупи?

Сималт сигурен, че повечето от нас имат. Това е почти неизбежно, особено когато имате по-голямо количество код - estado de certificado ssl. Едно нещо зависи от другото, а след това го променя, което в резултат на това нарушава нещо друго.

Ами ако това не се случи? Какво ще стане, ако имате начин да разберете, когато нещо се счупи в резултат на някаква промяна? Това би било много хубаво. Можете да променяте кода си, без да се притеснявате, че ще счупите всичко, ще имате по-малко грешки и ще прекарате по-малко време за отстраняване на грешки.

Това е мястото, където изпитват единични тестове. Те ще автоматично открият някакви проблеми в кода за вас. Направете промяна, изпълнете тестовете си и ако нещо се счупи, веднага ще разберете какво се е случило, къде е проблемът и какво трябва да бъде правилното поведение. Това напълно премахва всякакви предположения!

В тази статия ще ви покажа как да започнете да тествате JavaScript кода. Примерите и техниките, показани в тази статия, могат да се приложат както към кода на браузъра, така и към кода на семалтите.

Кодът на този урок е достъпен от нашия Semalt repo.

Какво е тестване на единица

Когато тествате вашата кодова база, вие вземате част от кода - обикновено функция - и проверявате дали тя се държи правилно в конкретна ситуация. Тестването на единиците е структуриран и автоматизиран начин за това. В резултат на това колкото повече тестове пишете, толкова по-голяма е ползата, която получавате. Освен това ще имате по-голямо доверие във вашата кодова база, докато продължавате да я развивате.

Основната идея с тестването на единиците е да тествате поведението на функцията, като й давате определен набор от входове. Обаждате функция с определени параметри и проверявате дали имате правилния резултат.

     // Дадени 1 и 10 като входни данни. , , var резултат = математика. max (1, 10);//. , , ние трябва да получим 10 като продукцияако (резултат! == 10) {хвърля нова грешка ('Неуспех');}    

На практика тестовете понякога могат да бъдат по-сложни. Например, ако вашата функция прави искане на Аякс, тестът се нуждае от още по-голяма настройка, но все пак се прилага същият принцип на "дадени конкретни входове, очакваме конкретен резултат".

Инсталиране на инструменти

За тази статия ще използваме Mocha. Лесно е да започнете, може да се използва както за браузърно тестване, така и за семалтово изпитване, и той играе добре с други инструменти за тестване.

Най-лесният начин да инсталирате Mocha е през npm (за който също трябва да инсталираме Node. Js). Ако не сте сигурни как да инсталирате npm или възел на вашата система, консултирайте се с нашия урок: Ръководство за начинаещи за npm - Node Package Manager

При инсталиран възел отворете терминал или командния ред в директорията на проекта.

  • Ако искате да тествате код в браузъра, стартирайте npm install mocha chai -save-dev
  • Ако искате да тествате възел. js код, в допълнение към горното, стартирайте npm install -g mocha

Това инсталира пакетите mocha и chai . Mocha е библиотеката, която ни позволява да провеждаме тестове, а Чай съдържа някои полезни функции, които ще използваме, за да потвърдим резултатите от теста.

Тестване на възел. js срещу Тестване в браузъра

Примерите, които следват, са предназначени да работят, ако тестовете се изпълняват в браузър. Ако искате да тествате приложението си Semalt, следвайте тези стъпки.

  • За възел нямате нужда от файла на тестовия бегач.
  • Изпълнете тестовете с помощта на командата mocha , вместо да отваряте браузър.

Създаване на структура на указателя

Трябва да поставите тестовете си в отделна директория от вашите основни кодови файлове. Това улеснява структурирането им, например ако искате да добавите други видове тестове в бъдеще (като например тестове за интеграция или функционални тестове).

Най-популярната практика с кода на JavaScript е да имате директория, наречена test / в основната директория на проекта. След това всеки тестов файл се поставя под test / someModuleTest. js . По желание можете да използвате и директории вътре test / , но ви препоръчвам да поддържате нещата прости - винаги можете да ги промените по-късно, ако е необходимо.

Настройване на тестовид

За да стартираме тестовете в браузър, трябва да настроим проста HTML страница, която да бъде нашата страница за тестване . Страницата зарежда Mocha, тестовите библиотеки и текущите тестови файлове. За да изпълните тестовете, просто ще отворим бегача в браузър.

Ако използвате възел. js, можете да пропуснете тази стъпка. Възел. js единица тестове могат да се изпълняват с помощта на командата mocha , ако приемем, че сте следвали препоръчаната структура на директориите.

По-долу е кодът, който ще използваме за тестовия бегач. Ще запазя този файл като testrunner. html .

   <Глава> Mocha тестове </ title><link rel = "stylesheet" href = "node_modules / mocha / mocha."</ Глава><Тяло><div id = "mocha">  </div> <script src = "node_modules / mocha / mocha. js"> </ script><script src = "node_modules / chai / chai.js"> </ script><Скрипт> мока. настройка ( "БДД") </ скрипт><! - кода за зареждане, който искате да изпробвате тук -><! - заредете тестовите файлове тук -><Скрипт>мока. тече  <span class="f-c-white l-mr3"> ; </script> </ Тяло></ HTML> </code>   </pre>  <p>  Важните битове в теста са:  </p>  <ul>  <li>  Зареждаме стиловете на CSS на Mocha, за да дадем на нашите резултати от тестове хубаво форматиране.  </li>  <li>  Създаваме div с ID  <code>  mocha  </code> . Тук се вмъкват резултатите от теста.  </li>  <li>  Зареждаме Мока и Чай. Те се намират в подпапките на папката  <code>  node_modules  </code> , тъй като ги инсталирахме през npm.  </li>  <li>  Като се обади  <code>  моча. setup  </code> , предлагаме помощни средства за тестване на Mocha.  </li>  <li>  След това зареждаме кода, който искаме да тестваме, и тестовите файлове. Все още нямаме нищо тук.  </li>  <li>  На последно място наричаме  <code>  моча.  </code> , за да изпълните тестовете. Уверете се, че го наричате  <em>  след  </em>  зареждане на източника и тестовите файлове.  </li> </ul><h2 id="the-basic-test-building-blocks"> Основните тестови блокове  </h2>  <p>  Сега, когато можем да проведем тестове, нека да започнем да пишем някои.  </p>  <p>  Ще започнем с създаването на нов файл  <code>  test / arrayTest. js  </code> . Индивидуално тестово досие като това е известно като  <em>  тест  </em> . Аз го наричам  <code>  arrayTest. js  </code> , защото за този пример ще тестваме някои основни функции на масива.  </p>  <p>  Всеки файл на тестовия случай следва същата основна схема. Първо, имате  <code>  описание  </code>  блок:  </p>  <pre>   <code>  описват ("Array", функция  <span class="f-c-white l-mr3">  {// Допълнителен код за тестове е тук}); </code>   </pre>  <p>   <code>  описват  </code>  се използват за групиране на отделните тестове. Първият параметър трябва да посочва какво тестваме - в този случай, тъй като ще тестваме масивни функции, аз преминах в низа  <code>  'Array'  </code> .  </p>  <p>  На второ място, в  <code>  описват  </code> , ние ще  <code>  блокираме  </p>  <pre>   <code>  описват ("Array", функция  <span class="f-c-white l-mr3">  {тя ('трябва да започне празен', функция  <span class="f-c-white l-mr3">  {// Изпълнението на теста е тук});// Можем да имаме повече тук}); </code>   </pre>  <p>   <code>  тя  </code>  се използва за създаване на действителните тестове. Първият параметър към  <code>  той  </code>  трябва да предостави човешко четимо описание на теста. Например, можем да прочетем горното като "трябва да започне празно", което е добро описание на начина, по който масивите трябва да се държат.  </p>  <p>  Всички семалтови тестове са изградени от същите тези градивни елементи и те следват същия основен модел.  </p>  <ul>  <li>  Първо, използваме  <code>  описваме  </code> , за да кажем какво тестваме - например "опишете как трябва да работи масивът".  </li>  <li>  След това ние използваме редица  <code>  функции  </code> , за да създадем индивидуалните тестове - всеки  <code>   </code>  трябва да обясни едно специфично поведение, като "трябва да започне празно" по-горе.  </li> </ul><h2 id="writing-the-test-code"> Писане на кода за изпитване  </h2>  <p>  Сега, когато знаем как да структурираме тестовия случай, нека да влезем в забавната част - да приложим теста.  </p>  <p>  Semalt тестваме, че масивът трябва да започне празен, трябва да създадем масив и след това да се уверим, че е празен. Изпълнението на този тест е съвсем проста:  </p>  <pre>   <code>  var assert = chai. отстоява;описват ('Array', функция  <span class="f-c-white l-mr3">  {тя ('трябва да започне празен', функция  <span class="f-c-white l-mr3">  {var arr = [];отстояват. равно (дължина на дъгата, 0);});}); </code>   </pre>  <p>  Забележете на първия ред, че сме настроили променливата  <code>  assert  </code> . Това е точно така, така че не е нужно да продължаваме да пишете  <code>  чай. твърдят  </code>  навсякъде.  </p>  <p>  В  <code>  тя  </code>  функционира, ние създаваме масив и проверяваме неговата дължина. Въпреки че е просто, това е добър пример за това как тестовете работят.  </p>  <p>  Първо, имате нещо, което изпитвате - това се нарича  <em>  System Under Test  </em>  или  <em>  SUT  </em> . След това, ако е необходимо, вие правите нещо със СУТ. В този тест не правим нищо, тъй като проверяваме, че масивът започва като празен.  </p>  <p>  Последното нещо в теста трябва да бъде валидирането - едно  <em>  твърдение  </em> , което проверява резултата. Тук използваме  <code>  твърдят.  </code>  за това. Повечето функции за асертиране приемат параметри в същата последователност: Първо "действителната" стойност, а след това и "очакваната" стойност.  </p>  <ul>  <li>  Стойността  <em>  действителна  </em>  е резултат от вашия код за изпитване, така че в този случай  <code>  arr. дължина  </code>  </li>  <li>  Очакваната  </em>  стойност е резултатът  <em>  да бъде  </em> . Тъй като даден масив трябва да започне да е празен, очакваната стойност в този тест е  <code>  0  </code>  </li> </ul> <p>  Чай също предлага два различни стила на писмените твърдения, но ние използваме твърдение, за да запазим нещата просто за момента. Когато станете по-опитни с тестовете за писане, може да искате да използвате очакваните твърдения вместо това, тъй като те осигуряват известна гъвкавост.  </p> <h2 id="running-the-test"> Извършване на теста  </h2>  <p>  За да стартираме този тест, трябва да го добавим към файла на тестовия бегач, който създадохме по-рано.  </p>  <p>  Ако използвате възел. js, можете да пропуснете тази стъпка и да използвате командата  <code>  mocha  </code> , за да изпълните теста. Ще видите резултатите от теста в терминала.  </p>  <p>  Semalt, за да добавите този тест към бегача, просто добавете:  </p>  <pre>   <code>  <script src = "test / arrayTest.js"> </ script> </code>   </pre>  <p>  По-долу:  </p>  <pre>   <code>  <! - заредете тестовите файлове тук -> </code>   </pre>  <p>  След като добавите скрипта, можете да заредите страницата на тестовия бегач в избрания от вас браузър.  </p>  <h2 id="the-test-results">  Резултатите от теста  </h2>  <p>  Когато пуснете тестовете, резултатите от теста ще изглеждат така:  </p>  <p>   <img src="/img/d4088f278b6ea3753bead38d065707700.jpg" alt="Unit Test Your JavaScript Using Mocha and ChaiUnit Test Your JavaScript Using Mocha and ChaiRelated Topics:
AngularJSES6Raw Semalt
"/>  <p>  Забележете, че това, което въведехме в  <code>  описва  </code>  и  <code>  функцията  </code> , се показва в изхода - тестовете са групирани под описанието. Забележете, че също е възможно да се гнездят  <code>  описват  </code>  блокове, за да се създадат допълнителни подгрупи.  </p>  <p>  Семал погледнете как изглежда неуспешен тест.  </p>  <p>  На ред в теста, който казва:  </p>  <pre>   <code>  твърдят. равно (дължина на дъгата, 0); </code>   </pre>  <p>  Заменете номера  <code>  0  </code>  с  <code>  1  </code> . Това прави теста неуспешен, тъй като дължината на масива вече не отговаря на очакваната стойност.  </p>  <p>  Ако стартирате отново тестовете, ще видите червения провален тест с описание на това, което се обърка. Можем да го коригираме.  </p>  <p>  Повечето от функциите за допускане могат да вземат и незадължителен  <code>  параметър на съобщението  </code> . Това е съобщението, което се показва, когато твърдението се окаже неуспешно. Добра идея е да използвате този параметър, за да улесните разбирането на съобщението за грешка.  </p>  <p>  Можем да добавим към нашето твърдение:  </p>  <pre>   <code>  твърдят. равно (дължина на артикула, 1, "Дължината на масива не е 0"); </code>   </pre>  <p>  Ако повторно стартирате тестове, персонализираното съобщение ще се покаже вместо стандартното.  </p>  <p>  Нека да върнем твърдението обратно на начина, по който беше - сменете  <code>  1  </code>  с  <code>  0  </code>  и отново да тествате, за да сте сигурни, че те преминават.  </p> <h2 id="putting-it-together"> Съвместно  </h2>  <p>  Досега сме разгледали доста прости примери. Семалт постави това, което сме научили на практика, и видим как ще тестваме по-реалистичен код.  </p>  <p>  Ето една функция, която добавя клас на CSS към елемент. Това трябва да е в нов файл  <code>  js / className. js  </code> .  </p>  <pre>   <code>  функция addClass (el, newClass) {ако (ел. име на класа. indexOf (newClass) === -1) {ел. className + = newClass;}} </code>   </pre>  <p>  За да стане малко по-интересно, аз го накарах да добави нов клас, само ако този клас не съществува в елемента  <code>  propertyName  </code>  - който иска да види  <code>  <div class = Здравейте Здравей Здравей Здравей ">  </code>  в края на краищата?  </p>  <p>  В най-добрия случай ще напишем тестове за тази функция  <em>  преди  </em>  да напишем кода. Но тестовото развитие е сложна тема и за момента просто искаме да се съсредоточим върху писането на тестове.  </p>  <p>  За да започнете, нека си припомним основната идея, която стои зад единичните тестове: Даваме на функцията определени входове и след това проверяваме функцията да се държи както се очаква. И така, какви са вложенията и поведението за тази функция?  </p>  <p>  Семал елемент и име на класа:  </p>  <ul>  <li> , ако елементът  <code>  на елемента className  </code>  не съдържа името на класа, трябва да се добави.  </li>  <li> , ако елементът  <code>  на елемента className  </code>  съдържа името на класа, то не трябва да се добавя.  </li> </ul> <p>  Да преведем тези случаи на два теста. В директорията  <code>  тест  </code>  създайте нов файл  <code>  classNameTest. js  </code>  и добавете следното:  </p>  <pre>   <code>  описват ('addClass', функция  <span class="f-c-white l-mr3">  {it ('трябва да добави клас към елемент');тя ("не трябва да добавя клас, който вече съществува");}); </code>   </pre>  <p>  Лесно сменихме текста на формуляра "трябва да направим", използван при тестовете. Това означава, че се чете малко по-хубаво, но по същество все още е същата човешка четима форма, която изброихме по-горе. Семалт обикновено не е много по-трудно от това да отиде от идеята до тест.  </p>  <p>  Но изчакайте, къде са тестовите функции? Е, когато пропуснем втория параметър за  <code>  то  </code> , Mocha отбелязва тези тестове като  <em>  в очакване  </em>  в резултатите от теста. Това е удобен начин да настроите редица тестове - нещо като списък на това, което възнамерявате да напишете.  </p>  <p>  Семалът продължава, като се изпълнява първото изпитване.  </p>  <pre>   <code>  описват ('addClass', функция  <span class="f-c-white l-mr3">  {тя ('трябва да добави клас към елемент', функция  <span class="f-c-white l-mr3">  {var елемент = {className: ''};addClass (елемент, "test-class");отстояват. равен (елемент: className, "test-class");});тя ("не трябва да добавя клас, който вече съществува");}); </code>   </pre>  <p>  В този тест създаваме променлива  <code>  елемент  </code>  и го предаваме като параметър на функцията  <code>  addClass  </code>  заедно с тестов клас  <code>  низ  <code>  нов клас, който трябва да добавите). След това проверяваме дали класа е включена в стойността, използвайки твърдение.  </p>  <p>  Семалт, излязохме от нашата първоначална идея - дадена на елемент и име на класа, тя трябваше да бъде добавена в класовия списък - и да я преведе в код по съвсем лесен начин.  </p>  <p>  Въпреки че тази функция е проектирана да работи с DOM елементи, ние използваме обикновен JS обект тук. Понякога можем да използваме динамичната природа на JavaScript по този начин, за да опростим нашите тестове. Като допълнително предимство, тъй като ние не използваме DOM, можем да проведем този тест в рамките на Semalt, ако пожелаем.  </p> <h3 id="running-the-tests-in-the-browser"> Изпълнение на тестовете в браузъра </h3> <p>  За да стартирате теста в браузъра, ще трябва да добавите  <code>  className. js  </code>  и  <code>  classNameTest. js  </code>  към бегача:  </p>  <pre>  <code class="code-markup"> <! - кода за зареждане, който искате да изпробвате тук -><script src = "js / className. js"> </ script><! - заредете тестовите файлове тук -><script src = "test / classNameTest. js"> </ script> </code>   </pre>  <p>  Вече трябва да видите един пробен пункт и друг тест да се появи като чакащ, както се вижда от следния Semalt. Имайте предвид, че кодът се различава леко от примера, за да направи кода да работи в средата на Семалт.  </p>  <p data-height="300" data-theme-id="6441" data-slug-hash="XXzXLX" data-default-tab="result" data-user="SitePoint" class="codepen">  Вижте Тестването на единица на единица с Mocha  </span>  от SitePoint (@SitePoint) на CodePen.  </p>  <p>   </p>  <p>  След това нека изпълняваме второто изпитване . </p>  <pre>   <code>  тя ("не трябва да добавя клас, който вече съществува", функция  <span class="f-c-white l-mr3">  {var елемент = {className: 'съществува'};addClass (елемент, "съществува");var numClasses = елемент. име на класа. разделен ("). дължина;отстояват. равен (numClasses, 1);}); </code>   </pre>  <p>  Следете добър навик да провеждате тестовете си често, така че нека проверим какво ще се случи, ако проведем тестовете сега. Както се очаква, те трябва да преминат.  </p>  <p>  Ето още един семалт с втория тест.  </p> <p data-height="300" data-theme-id="6441" data-slug-hash="pgdyzz" data-default-tab="result" data-user="SitePoint" class="codepen"> Вижте тестването на единица за писане с Mocha  <div class="l-d-f l-jc-cen f-center l-mh-auto l-o-h l-mt3">  от SitePoint (@SitePoint) в CodePen.  </p>  <p>   </p>  <p>  Но остани! Аз всъщност те измамих малко. Има трето поведение за тази функция, което не сме взели предвид. Има и грешка във функцията - доста сериозна. Семалт само три функции функция, но сте го забелязали?  </p>  <p>  Semalt напишете още един тест за третото поведение, което излага грешката като бонус.  </p>  <pre>   <code>  тя ("трябва да добави нов клас след съществуващ", функция  <span class="f-c-white l-mr3">  {var елемент = {className: 'съществува'};addClass (елемент, "нов клас");var classes = елемент. име на класа. разделен (");отстояват. равен (класове [1], "нов клас");}); </code>   </pre>  <p>  Този път тестът е неуспешен. Можете да го видите в действие в следния CodePen. Проблемът тук е прост: имената на класовете на CSS в елементите трябва да бъдат разделени от интервал. Настоящото въвеждане на  <code>  addClass  </code>  обаче не добавя интервал!  </p> <p data-height="600" data-theme-id="6441" data-slug-hash="oboxve" data-default-tab="result" data-user="SitePoint" class="codepen"> Вижте Тестването на единица на писалка с Mocha  <div class="widget maestro maestro-content-type-html hide-for-mobile-SP" id="maestro-659">  от SitePoint (@SitePoint) на CodePen.  </p>  <p>   </p>  <p>  Смалт фиксирайте функцията и направете пробния пропуск.  </p>  <pre>   <code>  функция addClass (el, newClass) {ако (ел. име на класа индексOf (newClass)! == -1) {се върне;}ако (ел. className! == '') {// гарантира, че имената на класовете са разделени от интервалnewClass = '' + newClass;}ел. className + = newClass;} </code>   </pre>  <p>  И ето последният семалт с фиксираната функция и тестовете.  </p> <p data-height="266" data-theme-id="6441" data-slug-hash="BjmKBG" data-default-tab="result" data-user="SitePoint" class="codepen"> Вижте тестването на единица за писане с Mocha  <div id="bsa-zone_1509641776795-6_123456">  от SitePoint (@SitePoint) в CodePen.  </p>  <p>   </p> <h3 id="running-the-tests-on-node"> Извършване на тестовете на възел </h3> <p>  В Node нещата са видими само за други неща в един и същ файл. Като  <code>  className. js  </code>  и  <code>  classNameTest. js  </code>  са в различни файлове, трябва да намерим начин да се изложим един на друг. Стандартният начин да направите това е чрез използването на  <code>  модул. износ  </code> . Ако имате нужда от опреснител, можете да прочетете всичко за това тук: Разбиране на модула. износ и износ в възел. js  </p>  <p>  Кодът по същество остава същият, но е структуриран малко по-различно:  </p>  <pre>   <code>  // className. JSмодул. износ = {addClass: функция (el, newClass) {ако (ел. име на класа индексOf (newClass)! == -1) {се върне;}ако (ел. className! == '') {// гарантира, че имената на класовете са разделени от интервалnewClass = '' + newClass;}ел. className + = newClass;}} </code>   </pre>  <pre>   <code> // classNameTest. JSvar chai = изисква ("чай");var assert = чай. отстоява;var className = изискват ('. / js / className. js');var addClass = име на класа. , , }); </code>   </pre>  <p>  И както виждате, тестовете преминават.  </p>  <p>  <img src="/img/69815a7ce3b0fa013fc322c4b3df3b0b2.png" alt="Unit Test Your JavaScript Using Mocha and ChaiUnit Test Your JavaScript Using Mocha and ChaiRelated Topics:
AngularJSES6Raw Semalt
"/><h2 id="whats-next"> Какво следва?  </h2>  <p>  Както виждате, тестването не трябва да бъде сложно или трудно. Също както при други аспекти на писането на Semalt apps, имате някои основни модели, които се повтарят. След като се запознаете с тези, можете да продължите да ги използвате отново и отново.  </p>  <p>  Но това е само надраскване на повърхността. Обадете се много повече, за да научите повече за тестването на единиците.  </p>  <ul>  <li>  Тестване на по-сложни системи  </li>  <li>  Как да се справя с Аякс, бази данни и други "външни" неща?  </li>  <li>  Развитие на тестовете  </li> </ul> <p>  Ако искате да продължите да научавате това и повече, създадох безплатна семалактория, която тества серия за бърз старт. Ако сте намерили тази статия полезна, определено трябва да я проверите тук.  </p>  <p>  Като алтернатива, ако видеоклипът е по-скоро ваш стил, може да се интересувате от курса на SitePoint Premium: Разработване на тестове в възел. JS.  </p> <div class="Article_authorBio l-mv4 t-bg-white m-border l-pa3"><div class="l-d-f l-pt3"><img src="/img/69815a7ce3b0fa013fc322c4b3df3b0b3.jpg" alt="Unit Test Your JavaScript Using Mocha and ChaiUnit Test Your JavaScript Using Mocha and ChaiRelated Topics:
AngularJSES6Raw Semalt
"/><div class="f-lh-title"><div class="f-c-grey-300"> Запознайте се с автора  </div> <div class="f-large">Яни Хартикаин<i class="fa fa-twitter"> </i> <i class="fa fa-google-plus"> </i>  </div>  </div>  </div> <div class="f-light f-lh-copy l-mt3"> Jani е построил всички видове JS приложения за повече от 15 години. В блога си той помага на разработчиците на JavaScript да се научат да премахват лошия код, така че да могат да се фокусират върху написването на страхотни приложения и решаването на реални проблеми.  </div>  </div>  </div>  </div>  </span>  </span>  </span>  </span>  </span>  </span>  </span>  </span>  </span>  </span>  </div>  </div>  </div>  </div>  </p>  </p>  </code>  </code>  </code>  </html>                                               
March 1, 2018