diff --git a/namsefni/35.errors-regex/1.errors.regex.md b/namsefni/35.errors-regex/1.errors.regex.md new file mode 100644 index 0000000..19d978c --- /dev/null +++ b/namsefni/35.errors-regex/1.errors.regex.md @@ -0,0 +1,269 @@ +--- +title: Fyrirlestur 1 – JavaScript villur og regex +--- + +# Fyrirlestur 1 – JavaScript villur og regex + +## Vefforritun 1 — TÖL107G + +### Ólafur Sverrir Kjartansson, [osk@hi.is](mailto:osk@hi.is) + +--- + +## Villumeðhöndlun + +* JavaScript hefur stuðning við [`try catch`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch) eða `exceptions` +* Kóði getur _kastað_ villum: innbyggðum og okkar eigin +* _Grípum_ villur og gerum eitthvað í þeim + +*** + +## Kasta villu + +* Köstum villu með `throw` + * Notum `Error`, innbyggðan hlut sem heldur utan um villur + * `throw Error('villa');` +* Fáum _stacktrace_ með villum, hvaðan þær koma upp + +*** + +## Grípa villu + +* Ef við grípum ekki villu _flýtur_ hún upp þar til hún veldur usla á efsta lagi + * Í versta falli stoppar keyrslu +* Getum _gripið_ villur og gert eitthvað við þær með `try catch` + +*** + +```javascript +try { + // e-ð sem kastar villu +} catch (e) { + // gera e-ð í villu +} +``` + +*** + +## finally + +* Með `finally` getum við keyrt kóða hvort sem við grípum villu eða ekki +* T.d. til að hreinsa upp, loka tengingum, logga + +*** + +```javascript +try { + // e-ð sem kastar villu +} catch (e) { + // gera e-ð í villu +} finally { + // taka til +} +``` + +*** + +## Algengar villur + +Getum fengið upp villur þegar við köllum í innbyggð föll eða gerum eitthvað vitlaust + +* `TypeError` – villa þegar gildi er ekki af þeirri tegund sem við gerum ráð fyrir +* `ReferenceError` – villa þegar reynt að eiga við óskilgreinda breytu +* o.fl. + +*** + +## Hvaða villa? + +* Getum notað `instanceof` virkja sem athuga hvernig _hlutur_ gildi er til að vita hvernig villa kom upp +* Almennt ekki mikið notað + +*** + +```javascript +try { + /* ... */ +} catch (e) { + if (e instanceof TypeError) { + console.log('TypeError', e); + } else if (e instanceof ReferenceError) { + console.log('ReferenceError', e); + } +} +``` + +*** + +## Notkun + +* Þegar við notum kóða frá öðrum +* Köllum í vefþjónustur +* Verjast villum sem geta stoppað keyrslu +* Pössum okkur samt, getur falið villur og búið til erfiða bögga + * Setjum utan um eins fáar línur í einu og við getum—felum ekki mögulega aðrar villur! + +*** + + +Ekki: + +```javascript +try { + const setup = {}; + const result = willThrow(setup); + const calc = result + 1; +} catch (e) { + // gera e-ð í villu +} +``` + +*** + +frekar: + + +```javascript +let result = 0; // ef það er í lagi +try { + result = willThrow(setup); +} catch (e) { + // gera e-ð í villu +} +const calc = result + 1; +``` + +*** + +## Debugger + +* Með debugger getum við stoppað á „unhandled exceptions“ +* `debugger` er lykilorð sem við getum sett í kóðann okkar +* Ef inspector er opinn, mun stöðva keyrslu þegar keyra á þá línu og kveikir á debugger +* Sjáum stöðu forrits, oft betra en að nota `console.log` + +*** + +* [throw](daemi/01.throw.js) +* [catch](daemi/02.catch.js) +* [finally](daemi/03.finally.js) +* [errors](daemi/04.errors.js) +* [fetch try catch](daemi/05.fetch.js) + +--- + +## Regular expressions + +* Höfum stuðning við _reglulegar segðir_ ([regular expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)) í JavaScript +* Skilgreinum _mynstur_ sem er borið saman við texta til að vinna með hann + * Kraftmikið, flókið og oft óskiljanlegt + +*** + +## Reglulegar segðir + +* Að skrifa og skilja reglulegar segðir er sér verkefni sem við ætlum ekki að fara djúpt í +* Skoðum aðeins nokkur dæmi sem geta verið handhæg +* Reglulegar segðir ber að varast, það eru yfirleitt betri leiðir í boði + +*** + +> Some people, when confronted with a problem, think “I know, I'll use regular expressions.” Now they have two problems. +> +> —[Jamie Zawinski](http://regex.info/blog/2006-09-15/247) + +*** + +* Skilgreindar með + * `let r = new RegExp('segð', flags);` + * `let r = /segð/flags;` +* `segð` er regluleg segð og `flags` er strengur sem stillir til hegðun + +*** + +## Segð + +* Strengur skrifaður samkvæmt reglum + * Myndar _stöðuvél_ sem finnur og framkvæmir það sem segð biður um +* `^[0-9]{1,2}.*AB?C$` + * Strengur sem byrjar á einni eða tveim tölum, eftir fylgir einhver strengur og endar síðan á nákvæmlega "AC" eða "ABC" + +*** + +## Hagnýtir hlutir í segðum + +* `[]` skilgreinir bil + * `[abcd]`, `a`, `b`, `c` eða `d` + * `[0-9]`, allar tölur + * `[a-z]`, ASCII lágstafir (unicode er vesen!) + +*** + +* `^` – byrjun strengs +* `$` – endi strengs +* `[^]` skilgreinir bil sem við viljum _ekki_ + * `[^a-c]` ekki `a`–`c` + +*** + +* `\s` – _whitespace_, bil, tab, nýlína +* `.+` – einu sinni eða oftar +* `.*` – núll sinnum eða oftar +* `.{n,m}` – n til m sinnum +* `?` – Gæti verið eða ekki + +*** + +## Flags + +* `g` - global, ekki stoppa eftir fyrstu niðurstöðu +* `i` - ignore case, ekki vera hástafanæm +* `m` - multiline, `^` og `$` virka milli lína + +*** + +## Grúppur + +* Þegar við keyrum regex fáum við niðurstöður til baka +* Hvaða strengur fannst +* Ef við notum sviga til að skilgreina _subexpressions_, fáum við í niðurstöðum hver þeirra fundust + +*** + +## Föll í JavaScript + +* [`r.test(string)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test)- athugar hvort ef `r` passi við `string` +* [`r.exec(string)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec) - keyrir `r` og skilar niðurstöðum í fylki fyrir hvern hóp innan sviga +* [`string.match(r)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match) - svipað `exec` en ef `g` er sett fáum við alla strengi sem finnast +* [`string.replace(r, newString)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace) - skipta út öllum tilvikum þar sem `r` passar fyrir `newString` + +*** + +```javascript +/halló/.test('halló heimur'); +/hæ/.test('halló heimur'); +``` + +```javascript +const re = /quick\s(brown).+?(jumps)/ig; +re.exec('The Quick Brown Fox Jumps Over The Lazy Dog'); +``` + +```javascript +'The Quick Brown Fox Jumps Over The Lazy Dog' + .match(/quick\s(brown).+?(jumps)/ig); +``` + +```javascript +'hæ hæ, hvað segiru? bæ!' + .replace(/(h|b)æ/g, 'lol'); +``` + +*** + +Getur verið mjög hentugt að nota tól til að smíða reglulegar segðir, t.d. [regex101.com](https://regex101.com/r/rsmcG0/1) + +*** + +* [examples](daemi/06.examples.js) +* [replace](daemi/07.replace.js) diff --git a/namsefni/35.errors-regex/daemi/.eslintrc.js b/namsefni/35.errors-regex/daemi/.eslintrc.js new file mode 100644 index 0000000..021918d --- /dev/null +++ b/namsefni/35.errors-regex/daemi/.eslintrc.js @@ -0,0 +1,13 @@ +module.exports = { + rules: { + // leyfum for of + 'no-restricted-syntax': 0, + + // helper.html dæmi + 'function-paren-newline': 0, + + 'import/extensions': 0, + + 'max-len': [true, 100], + }, +}; diff --git a/namsefni/35.errors-regex/daemi/01.throw.js b/namsefni/35.errors-regex/daemi/01.throw.js new file mode 100644 index 0000000..b220a9e --- /dev/null +++ b/namsefni/35.errors-regex/daemi/01.throw.js @@ -0,0 +1,6 @@ +function throws() { + throw Error('Villa!'); +} + +throws(); +console.log('Ég keyri aldrei :('); diff --git a/namsefni/35.errors-regex/daemi/02.catch.js b/namsefni/35.errors-regex/daemi/02.catch.js new file mode 100644 index 0000000..dac6806 --- /dev/null +++ b/namsefni/35.errors-regex/daemi/02.catch.js @@ -0,0 +1,10 @@ +function throws() { + throw Error('Villa!'); +} + +try { + throws(); +} catch (e) { + console.log('Greip villu!', e); +} +console.log('Ég keyri!'); diff --git a/namsefni/35.errors-regex/daemi/03.finally.js b/namsefni/35.errors-regex/daemi/03.finally.js new file mode 100644 index 0000000..d56ad70 --- /dev/null +++ b/namsefni/35.errors-regex/daemi/03.finally.js @@ -0,0 +1,13 @@ +function iThrowErrorsSometimes() { + if (Math.random() > 0.5) { + throw new Error('Villa!'); + } +} + +try { + iThrowErrorsSometimes(); +} catch (e) { + console.log('Greip villu!', e); +} finally { + console.log('Ég keyri alltaf'); +} diff --git a/namsefni/35.errors-regex/daemi/04.errors.js b/namsefni/35.errors-regex/daemi/04.errors.js new file mode 100644 index 0000000..72cf21a --- /dev/null +++ b/namsefni/35.errors-regex/daemi/04.errors.js @@ -0,0 +1,21 @@ +function getResult() { + if (Math.random() > 0.5) { + return null; + } + + return { s: 'hello' }; +} + +const result = getResult(); +try { + const { s } = result; + console.log(s.substr(1)); +} catch (e) { + console.log('Greip villu'); + + if (e instanceof TypeError) { + console.log('Villa er TypeError', e); + } else if (e instanceof ReferenceError) { + console.log('Villa er ReferenceError', e); + } +} diff --git a/namsefni/35.errors-regex/daemi/05.fetch.js b/namsefni/35.errors-regex/daemi/05.fetch.js new file mode 100644 index 0000000..3df06ba --- /dev/null +++ b/namsefni/35.errors-regex/daemi/05.fetch.js @@ -0,0 +1,69 @@ +/* eslint-disable no-unused-vars */ +/* eslint-disable consistent-return */ + +// Hversu nákvæmlega viljum við logga, eða halda utanum stöðu? + +// 1. Ekki mikið, hópum öllum mögulegum villum saman +async function fetchWithSomeErrorHandling(url) { + try { + const response = await fetch(url); + + if (!response.ok) { + // Eiginlegt svindl, vitum að við erum innan try + throw new Error('response not ok'); + } + + // Blöndum villumeðhöndlun við meðhöndlun á exception frá fetch + return await response.json(); + } catch (e) { + // Öll villumeðhöndlun á einum stað, getur orðið erfitt að finna/vinna + // úr villuskilaboðum + console.error('error!', e); + return null; + } +} + +// 2. Mikið, grípum alla mögulega punkta sem geta klikkað og athugum stöðu +async function fetchWithDetailedErrorHandling(url) { + let response; + try { + response = fetch(url); + } catch (e) { + console.error(`error fetching from ${url}`, e); + return null; + } + + if (!response.ok) { + // Hugsanleg gæti response innihaldið upplýsingar um hvað klikkaði + let errorText; + + try { + errorText = await response.text(); + } catch (e) { + // Óþarfi að logga nokkuð hér + } finally { + // Oft viljum við logga að við höfum klárað kall í vefþjónustu + // t.d. til að mæla hversu langan tíma kallið tók, óháð því hvort + // villa komi upp eða ekki + console.info(`called ${url}`); + } + + console.error( + response, + `non 200 status fetching from ${url}`, + response.status, + errorText, + ); + return null; + } + + let json; + try { + json = await response.json(); + } catch (e) { + console.error(`error parsing json from ${url}`, e); + return null; + } + + return json; +} diff --git a/namsefni/35.errors-regex/daemi/06.examples.js b/namsefni/35.errors-regex/daemi/06.examples.js new file mode 100644 index 0000000..bbf47c8 --- /dev/null +++ b/namsefni/35.errors-regex/daemi/06.examples.js @@ -0,0 +1,17 @@ +/halló/.test('halló heimur'); +/hæ/.test('halló heimur'); + +const str = 'The Quick Brown Fox Jumps Over The Lazy Dog'; + +const re = /quick\s(brown).+?(jumps)/ig; +const result = re.exec(str); + +console.log(result); + +const match = str.match(/quick\s(brown).+?(jumps)/ig); + +console.log(match); + +const replace = 'hæ hæ, hvað segiru? bæ!'.replace(/(h|b)æ/g, 'lol'); + +console.log(replace); diff --git a/namsefni/35.errors-regex/daemi/07.replace.js b/namsefni/35.errors-regex/daemi/07.replace.js new file mode 100644 index 0000000..ac7fac9 --- /dev/null +++ b/namsefni/35.errors-regex/daemi/07.replace.js @@ -0,0 +1,8 @@ +const dirty = 'strengur með bilum og \t tab af\nhandahófi og\t rugl'; + +console.log(dirty); + +// finna einn eða fleiri whitespace staf saman og skipta út fyrir eitt bil +const clean = dirty.replace(/\s+/g, ' '); + +console.log(clean); diff --git a/namsefni/35.errors-regex/readme.md b/namsefni/35.errors-regex/readme.md new file mode 100644 index 0000000..207a644 --- /dev/null +++ b/namsefni/35.errors-regex/readme.md @@ -0,0 +1,25 @@ +# Villur og regex + +[Fyrirlestur: Villur og regex](1.errors.regex.md), [vídeó](https://youtu.be/vl_G2uDAORI) + +## Lesefni + +* [Eloquent JavaScript, kafli 8: Bugs and Errors](https://eloquentjavascript.net/08_error.html) +* [Eloquent JavaScript, kafli 9: Regular Expressions](https://eloquentjavascript.net/09_regexp.html) +* [Resilient Web Design, chapter 7: Challenges](https://resilientwebdesign.com/chapter7/) + +## Dæmi + +* [throw](daemi/01.throw.js) +* [catch](daemi/02.catch.js) +* [finally](daemi/03.finally.js) +* [errors](daemi/04.errors.js) +* [fetch try catch](daemi/05.fetch.js) +* [examples](daemi/06.examples.js) +* [replace](daemi/07.replace.js) + +## Ítarefni + +* [`try catch`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch) +* [Exception handling](https://en.wikipedia.org/wiki/Exception_handling) +* [Regular expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) diff --git a/namsefni/36.functional/1.functional.md b/namsefni/36.functional/1.functional.md new file mode 100644 index 0000000..b7fbd80 --- /dev/null +++ b/namsefni/36.functional/1.functional.md @@ -0,0 +1,225 @@ +--- +title: Fyrirlestur – Fallaforritun +--- + +# Fyrirlestur – Fallaforritun + +## Vefforritun 1 — TÖL107G + +### Ólafur Sverrir Kjartansson, [osk@hi.is](mailto:osk@hi.is) + +--- + +## Fallaforritun + +* Ein leið til að vinna með flækjustig +* Blöndum saman einföldum föllum til að gera flókna hluti +* Búum til _abstraction_ + +*** + +```javascript +for (let i = 0; i < 10; i++) { + console.log(i); +} +``` + +*** + + + +```javascript +function repeatLog(n) { + for (let i = 0; i < n; i++) { + console.log(i); + } +} +``` + +*** + + + +```javascript +function repeat(n, action) { + for (let i = 0; i < n; i++) { + action(i); + } +} + +repeat(3, console.log); +// → 0 +// → 1 +// → 2 +``` + +*** + + + +```javascript +const labels = []; +repeat(5, (i) => { + labels.push(`Unit ${i + 1}`); +}); +console.log(labels); +// → ["Unit 1", "Unit 2", "Unit 3", +// "Unit 4", "Unit 5"] +``` + +*** + +## Æðri föll – Higher-order functions + +* Gera a.m.k. annað af: + * Taka inn eitt eða fleiri fall sem argument + * Skila falli +* Önnur föll eru „á fyrstu stétt“ + +*** + +```javascript +function greaterThan(n) { + return m => m > n; +} +const greaterThan10 = greaterThan(10); +console.log(greaterThan10(11)); +// → true +``` + +*** + +```javascript +function repeat(n, action) { + for (let i = 0; i < n; i++) { + action(i); + } +} +function unless(test, then) { + if (!test) then(); +} +repeat(3, (n) => { + unless(n % 2 === 1, () => { + console.log(n, 'is even'); + }); +}); +// → 0 is even +// → 2 is even +``` + +*** + +## forEach + +* [`forEach`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) er aðgerð á fylkjum +* Higher-order fall sem leyfir okkur að ítra yfir fylki +* Eins og `for` lykkja en læsilegra í sumum tilvikum + +*** + + + +```javascript +function el(name, ...children) { + const e = document.createElement(name); + if (Array.isArray(children)) { + children.forEach((child) => { + if (typeof child === 'string') { + e.appendChild(document.createTextNode(child)); + } else if (child) { + e.appendChild(child); + } + }); + } + + return e; +} +``` + +*** + +## Hrein föll – Pure Functions + +* Skila alltaf sama úttaki fyrir sama inntak +* Úttak veltur ekki á stöðu eða upplýsingum fyrir utan fall—óháð umhverfi sínu +* Fall veldur ekki breytingum á umhverfi—engar aukaverkanir + +*** + +## Kostir fallaforritunnar + +* Hugsum meira abstrakt; á hærra stigi +* Minni hávaði og meiri upplýsingar +* Getum gert fyrir helling af „venjulegum“ aðgerðum +* Höfum grunn föll til staðar í málinu + +*** + +## Dæmi um abstract aðgerðir + +* [`every`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every) - á gefið fall við öll stök í fylki? +* [`some`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/some) - á gefið fall við eitthvert stak í fylki? +* [`map`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/map) – útbúa nýtt fylki þar sem búið er að beita aðgerð á hvert stak +* [`reduce`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) – vinna fylki niður í eitt stak eftir falli (og reduceRight) +* [`filter`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) – skila fylki þar sem stök standast próf + +*** + +## `some`, `every` dæmi + +```javascript +const nums = [1, 7, 8, 11]; + +function belowTen(n) { + return n < 10; +} + +nums.every(belowTen); // false +nums.some(belowTen); // true +``` + +*** + +## `reduce` dæmi + +```javascript +function sum(nums) { + return nums.reduce((a, b) => a + b, 0); +} + +sum([1, 2, 3, 4, 5, 6, 7, 8, 9]); // 45 +``` + +*** + +## `map` dæmi + +```javascript +// sum eins og í fyrra dæmi +[1, 2, 3, 4, 5, 6, 7, 8, 9] + .map(i => i * 2) + .reduce((a, b) => a + b, 0); + +// 90 +``` + +*** + +## `filter` dæmi + +```javascript +const colors = [ + 'blue', + 'red', + 'darkblue', + 'lightred', +]; + +colors + .filter(c => c.indexOf('blue') >= 0); +``` + +*** + +* [sorting & filtering](daemi/01.sorting-filtering.html) +* [alphabet dæmi](daemi/02.alphabet.js) diff --git a/namsefni/36.functional/daemi/.eslintrc.js b/namsefni/36.functional/daemi/.eslintrc.js new file mode 100644 index 0000000..021918d --- /dev/null +++ b/namsefni/36.functional/daemi/.eslintrc.js @@ -0,0 +1,13 @@ +module.exports = { + rules: { + // leyfum for of + 'no-restricted-syntax': 0, + + // helper.html dæmi + 'function-paren-newline': 0, + + 'import/extensions': 0, + + 'max-len': [true, 100], + }, +}; diff --git a/namsefni/36.functional/daemi/01.sorting-filtering/index.html b/namsefni/36.functional/daemi/01.sorting-filtering/index.html new file mode 100644 index 0000000..ca487bc --- /dev/null +++ b/namsefni/36.functional/daemi/01.sorting-filtering/index.html @@ -0,0 +1,44 @@ + + + + + sort & filter + + + + +
+
+ + +
+
+ +
+
+ +
+
+ + + + + + + diff --git a/namsefni/36.functional/daemi/01.sorting-filtering/lib/helpers.js b/namsefni/36.functional/daemi/01.sorting-filtering/lib/helpers.js new file mode 100644 index 0000000..0792b5b --- /dev/null +++ b/namsefni/36.functional/daemi/01.sorting-filtering/lib/helpers.js @@ -0,0 +1,34 @@ +/** + * Býr til element með nafni og bætir við öðrum elementum eða texta nóðum. + * @param {string} name Nafn á elementi + * @param {...string | HTMLElement} children Önnur element eða strengir + * @returns {HTMLElement} Elementi með gefnum börnum + */ +export function el(name, ...children) { + const e = document.createElement(name); + + for (const child of children) { + if (typeof child === 'string') { + e.appendChild(document.createTextNode(child)); + } else if (child) { + e.appendChild(child); + } + } + + return e; +} + +/** + * Fjarlægir öll börn `element`. + * @param {HTMLElement} element Element sem á að tæma + * @returns {undefined} Skilar engu + */ +export function empty(element) { + if (!element || !element.firstChild) { + return; + } + + while (element.firstChild) { + element.removeChild(element.firstChild); + } +} diff --git a/namsefni/36.functional/daemi/01.sorting-filtering/lib/ui.js b/namsefni/36.functional/daemi/01.sorting-filtering/lib/ui.js new file mode 100644 index 0000000..aec3cac --- /dev/null +++ b/namsefni/36.functional/daemi/01.sorting-filtering/lib/ui.js @@ -0,0 +1,18 @@ +import { el, empty } from './helpers.js'; + +// Tekur inn lista af nemendum og birtir í HTML +// Hreinsum og birtum allan lista aftur, virkar vel fyrir minni lista +// fer að verða hægt við hundruði staka +export function render(students, studentContainer) { + empty(studentContainer); + students.forEach((student) => { + const studentName = el('strong', student.name); + let studentGraduation = null; + + if (student.graduation) { + studentGraduation = el('em', ` útskrifaðist ${student.graduation}`); + } + const studentElement = el('li', studentName, studentGraduation); + studentContainer.appendChild(studentElement); + }); +} diff --git a/namsefni/36.functional/daemi/01.sorting-filtering/main.js b/namsefni/36.functional/daemi/01.sorting-filtering/main.js new file mode 100644 index 0000000..4d80a3a --- /dev/null +++ b/namsefni/36.functional/daemi/01.sorting-filtering/main.js @@ -0,0 +1,132 @@ +import { render } from './lib/ui.js'; + +// Listi af nemendum +// nöfn frá https://www.behindthename.com/ +const students = [ + { name: 'Skadi Ferran Wang', graduation: 2020 }, + { name: 'Tacita Ranjit McGill', graduation: 2019 }, + { name: 'Heino Pavle Hornick' }, + { name: 'Sima Gunda Babcock' }, + { name: 'Shprintza Draco Hollands', graduation: 2000 }, + { name: 'Melanie Gautstafr Obama', graduation: 2020 }, + { name: 'Jirou Māui Dávid' }, + { name: 'Heard Raginald McQueen', graduation: 2019 }, + { name: 'Mani Altantsetseg Proudfoot', graduation: 2018 }, + { name: 'Rubye Lea Schumacher' }, + { name: 'Nicu Guilherme Yamashita', graduation: 2016 }, + { name: 'Vilhelmo Kaapo Zahariev', graduation: 2005 }, + { name: 'Junichi Klara Nakai' }, + { name: 'Ulf Edward Mac Uileagóid', graduation: 2009 }, + { name: 'Mirela Eadmund Cardoso ', graduation: 2010 }, + { name: 'Lidziya Thorben Noyer', graduation: 2020 }, + { name: 'Åse Abdelaziz Narváez', graduation: 2017 }, + { name: 'Ramon Violeta Van Houten', graduation: 2015 }, + { name: 'Jehovah Domitianus Janz' }, + { name: 'Umukoro Karesinda Dallas ', graduation: 2018 }, + { name: 'Kobe Mikaela Stankiewicz' }, + { name: 'Jeong-Ho Ema Ó Donndubháin', graduation: 2019 }, + { name: 'Meir Calixtus Sampson', graduation: 2000 }, + { name: 'Beate Dušan Bauers' }, + { name: 'Mikael Saam Donne ', graduation: 2020 }, +]; + +// Þar sem við „geymum nemendur“ +const studentContainer = document.querySelector('ul'); + +/** + * Tvær leiðir til að nálgast: + * 1. Gera allt strax, um leið og smellt í checkbox eða skrifaður texti þá + * breytum við viðmóti með nýjum gögnum + * 2. Bregðast við þegar form er „submittað“ + * Í þessu dæmi gerum við ráð fyrir báðu, getum slökkt á því að fáum strax + * uppfærslu með `immediateFeedback`. + */ +const immediateFeedback = true; + +const formEl = document.querySelector('form'); +const searchEl = document.querySelector('input[name=search]'); +const hideGraduatedEl = document.querySelector('input[name=hideGraduated]'); +const hideNotGraduatedEl = document.querySelector('input[name=hideNotGraduated]'); +const sortEl = document.querySelector('select'); + +// Finnur út hver staða á formi sé og skilar á formi sem `filterStudents` og +// `sortStudents` kann á +function formState() { + const search = searchEl.value; + const hideGraduated = hideGraduatedEl.checked; + const hideNotGraduated = hideNotGraduatedEl.checked; + const sort = sortEl.value; + + return { + search, hideGraduated, hideNotGraduated, sort, + }; +} + +function filterStudents( + students, + { search, hideGraduated, hideNotGraduated } = {} +) { + // Nokkrar leiðir að þessu, við förum ekki þá „bestu“ + return students + // Burt með útskrifaða ef svo ber við + .filter((student) => hideGraduated ? !student.graduation : true) + + // Burt með óútskrifaða ef svo ber við + .filter((student) => hideNotGraduated ? student.graduation : true) + + // Finnum alla sem leit á við + .reduce((previous, current) => { + // Viljum leita eftir litlum stöfum sérstaklega + const matchesSearch = search.length > 0 ? + current.name.toLocaleLowerCase().indexOf(search.toLocaleLowerCase()) >= 0 : true; + return previous.concat(matchesSearch ? current : null); + }, []) + // Burt með öll null gildi + .filter(Boolean); +} + +function sortStudents(students, sort) { + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#sorting_non-ascii_characters + let sortFunc = (a, b) => a.name.localeCompare(b.name); + + switch (sort) { + case 'graduation': + // Túlkum óútskrifaða með hæsta mögulega svo þau komi seinast + sortFunc = (a, b) => (a.graduation || 9999) - (b.graduation || 9999); + break; + case 'graduation-reverse': + // Túlkum óútskrifaða með lægsta mögulega svo þau komi seinast + sortFunc = (a, b) => (b.graduation || 0) - (a.graduation || 0); + break; + case 'name-reverse': + sortFunc = (a, b) => b.name.localeCompare(a.name); + break; + case 'name': + default: + } + + return students.sort(sortFunc); +} + +function renderBasedOnFormState() { + const state = formState(); + const filteredStudents = filterStudents(students, state); + const filteredSortedStudents = sortStudents(filteredStudents, state.sort); + render(filteredSortedStudents, studentContainer); +} + +formEl.addEventListener('submit', (e) => { + e.preventDefault(); + renderBasedOnFormState() +}); + +if (immediateFeedback) { + // Ef við viljum leita strax, tengjum við öll input! + searchEl.addEventListener('input', renderBasedOnFormState) + hideGraduatedEl.addEventListener('input', renderBasedOnFormState) + hideNotGraduatedEl.addEventListener('input', renderBasedOnFormState) + sortEl.addEventListener('input', renderBasedOnFormState) +} + +// Í byrjun renderum við allt, í default röðun +render(sortStudents(students, 'name'), studentContainer); diff --git a/namsefni/36.functional/daemi/01.sorting-filtering/package.json b/namsefni/36.functional/daemi/01.sorting-filtering/package.json new file mode 100644 index 0000000..9f3466f --- /dev/null +++ b/namsefni/36.functional/daemi/01.sorting-filtering/package.json @@ -0,0 +1,15 @@ +{ + "name": "01.sorting-filtering", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "dev": "browser-sync start --server --files main.js **/*.js styles.css index.html" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "browser-sync": "^2.27.7" + } +} diff --git a/namsefni/36.functional/daemi/02.alphabet.js b/namsefni/36.functional/daemi/02.alphabet.js new file mode 100644 index 0000000..6cb138a --- /dev/null +++ b/namsefni/36.functional/daemi/02.alphabet.js @@ -0,0 +1,1220 @@ +/* eslint-disable no-unused-vars */ +/* eslint-disable max-len */ +/* eslint-disable no-restricted-syntax */ +/* eslint-disable no-mixed-operators */ + +// Úr https://eloquentjavascript.net/05_higher_order.html + +// Generated from the Unicode 10 database and https://en.wikipedia.org/wiki/Script_(Unicode) +const SCRIPTS = [ + { + name: 'Adlam', + ranges: [[125184, 125259], [125264, 125274], [125278, 125280]], + direction: 'rtl', + year: 1987, + living: true, + link: 'https://en.wikipedia.org/wiki/Fula_alphabets#Adlam_alphabet', + }, + { + name: 'Caucasian Albanian', + ranges: [[66864, 66916], [66927, 66928]], + direction: 'ltr', + year: 420, + living: false, + link: 'https://en.wikipedia.org/wiki/Caucasian_Albanian_alphabet', + }, + { + name: 'Ahom', + ranges: [[71424, 71450], [71453, 71468], [71472, 71488]], + direction: 'ltr', + year: 1250, + living: false, + link: 'https://en.wikipedia.org/wiki/Ahom_alphabet', + }, + { + name: 'Arabic', + ranges: [[1536, 1541], [1542, 1548], [1549, 1563], [1564, 1565], [1566, 1567], [1568, 1600], [1601, 1611], [1622, 1648], [1649, 1757], [1758, 1792], [1872, 1920], [2208, 2229], [2230, 2238], [2260, 2274], [2275, 2304], [64336, 64450], [64467, 64830], [64848, 64912], [64914, 64968], [65008, 65022], [65136, 65141], [65142, 65277], [69216, 69247], [126464, 126468], [126469, 126496], [126497, 126499], [126500, 126501], [126503, 126504], [126505, 126515], [126516, 126520], [126521, 126522], [126523, 126524], [126530, 126531], [126535, 126536], [126537, 126538], [126539, 126540], [126541, 126544], [126545, 126547], [126548, 126549], [126551, 126552], [126553, 126554], [126555, 126556], [126557, 126558], [126559, 126560], [126561, 126563], [126564, 126565], [126567, 126571], [126572, 126579], [126580, 126584], [126585, 126589], [126590, 126591], [126592, 126602], [126603, 126620], [126625, 126628], [126629, 126634], [126635, 126652], [126704, 126706]], + direction: 'rtl', + year: 400, + living: true, + link: 'https://en.wikipedia.org/wiki/Arabic_script', + }, + { + name: 'Imperial Aramaic', + ranges: [[67648, 67670], [67671, 67680]], + direction: 'rtl', + year: 800, + living: false, + link: 'https://en.wikipedia.org/wiki/Aramaic_alphabet', + }, + { + name: 'Armenian', + ranges: [[1329, 1367], [1369, 1376], [1377, 1416], [1418, 1419], [1421, 1424], [64275, 64280]], + direction: 'ltr', + year: 405, + living: true, + link: 'https://en.wikipedia.org/wiki/Armenian_alphabet', + }, + { + name: 'Avestan', + ranges: [[68352, 68406], [68409, 68416]], + direction: 'rtl', + year: 400, + living: false, + link: 'https://en.wikipedia.org/wiki/Avestan_alphabet', + }, + { + name: 'Balinese', + ranges: [[6912, 6988], [6992, 7037]], + direction: 'ltr', + year: 1000, + living: true, + link: 'https://en.wikipedia.org/wiki/Balinese_script', + }, + { + name: 'Bamum', + ranges: [[42656, 42744], [92160, 92729]], + direction: 'ltr', + year: 1896, + living: true, + link: 'https://en.wikipedia.org/wiki/Bamum_script', + }, + { + name: 'Bassa Vah', + ranges: [[92880, 92910], [92912, 92918]], + direction: 'ltr', + year: 1950, + living: false, + link: 'https://en.wikipedia.org/wiki/Bassa_alphabet', + }, + { + name: 'Batak', + ranges: [[7104, 7156], [7164, 7168]], + direction: 'ltr', + year: 1300, + living: true, + link: 'https://en.wikipedia.org/wiki/Batak_alphabet', + }, + { + name: 'Bengali', + ranges: [[2432, 2436], [2437, 2445], [2447, 2449], [2451, 2473], [2474, 2481], [2482, 2483], [2486, 2490], [2492, 2501], [2503, 2505], [2507, 2511], [2519, 2520], [2524, 2526], [2527, 2532], [2534, 2558]], + direction: 'ltr', + year: 1050, + living: true, + link: 'https://en.wikipedia.org/wiki/Bengali_alphabet', + }, + { + name: 'Bhaiksuki', + ranges: [[72704, 72713], [72714, 72759], [72760, 72774], [72784, 72813]], + direction: 'ltr', + year: 1050, + living: false, + link: 'https://en.wikipedia.org/wiki/Bhaiksuki_alphabet', + }, + { + name: 'Bopomofo', + ranges: [[746, 748], [12549, 12591], [12704, 12731]], + direction: 'ltr', + year: 1918, + living: true, + link: 'https://en.wikipedia.org/wiki/Bopomofo', + }, + { + name: 'Brahmi', + ranges: [[69632, 69710], [69714, 69744], [69759, 69760]], + direction: 'ltr', + year: -250, + living: false, + link: 'https://en.wikipedia.org/wiki/Brahmi_script', + }, + { + name: 'Braille', + ranges: [[10240, 10496]], + direction: 'ltr', + year: 1824, + living: true, + link: 'https://en.wikipedia.org/wiki/Braille', + }, + { + name: 'Buginese', + ranges: [[6656, 6684], [6686, 6688]], + direction: 'ltr', + year: 1650, + living: true, + link: 'https://en.wikipedia.org/wiki/Lontara_script', + }, + { + name: 'Buhid', + ranges: [[5952, 5972]], + direction: 'ltr', + year: 1300, + living: true, + link: 'https://en.wikipedia.org/wiki/Buhid_alphabet', + }, + { + name: 'Chakma', + ranges: [[69888, 69941], [69942, 69956]], + direction: 'ltr', + year: 1050, + living: true, + link: 'https://en.wikipedia.org/wiki/Chakma_alphabet', + }, + { + name: 'Canadian Aboriginal', + ranges: [[5120, 5760], [6320, 6390]], + direction: 'ltr', + year: 1840, + living: true, + link: 'https://en.wikipedia.org/wiki/Canadian_Aboriginal_syllabics', + }, + { + name: 'Carian', + ranges: [[66208, 66257]], + direction: 'ltr', + year: -650, + living: false, + link: 'https://en.wikipedia.org/wiki/Carian_alphabets', + }, + { + name: 'Cham', + ranges: [[43520, 43575], [43584, 43598], [43600, 43610], [43612, 43616]], + direction: 'ltr', + year: 750, + living: true, + link: 'https://en.wikipedia.org/wiki/Cham_alphabet', + }, + { + name: 'Cherokee', + ranges: [[5024, 5110], [5112, 5118], [43888, 43968]], + direction: 'ltr', + year: 1820, + living: true, + link: 'https://en.wikipedia.org/wiki/Cherokee_syllabary', + }, + { + name: 'Coptic', + ranges: [[994, 1008], [11392, 11508], [11513, 11520]], + direction: 'ltr', + year: -200, + living: false, + link: 'https://en.wikipedia.org/wiki/Coptic_alphabet', + }, + { + name: 'Cypriot', + ranges: [[67584, 67590], [67592, 67593], [67594, 67638], [67639, 67641], [67644, 67645], [67647, 67648]], + direction: 'rtl', + year: -1100, + living: false, + link: 'https://en.wikipedia.org/wiki/Cypriot_syllabary', + }, + { + name: 'Cyrillic', + ranges: [[1024, 1157], [1159, 1328], [7296, 7305], [7467, 7468], [7544, 7545], [11744, 11776], [42560, 42656], [65070, 65072]], + direction: 'ltr', + year: 950, + living: true, + link: 'https://en.wikipedia.org/wiki/Cyrillic_script', + }, + { + name: 'Devanagari', + ranges: [[2304, 2385], [2387, 2404], [2406, 2432], [43232, 43262]], + direction: 'ltr', + year: 100, + living: true, + link: 'https://en.wikipedia.org/wiki/Devanagari', + }, + { + name: 'Deseret', + ranges: [[66560, 66640]], + direction: 'ltr', + year: 1854, + living: true, + link: 'https://en.wikipedia.org/wiki/Deseret_alphabet', + }, + { + name: 'Duployan', + ranges: [[113664, 113771], [113776, 113789], [113792, 113801], [113808, 113818], [113820, 113824]], + direction: 'ltr', + year: 1860, + living: true, + link: 'https://en.wikipedia.org/wiki/Duployan_shorthand', + }, + { + name: 'Egyptian Hieroglyphs', + ranges: [[77824, 78895]], + direction: 'ltr', + year: -3200, + living: false, + link: 'https://en.wikipedia.org/wiki/Egyptian_hieroglyphs', + }, + { + name: 'Elbasan', + ranges: [[66816, 66856]], + direction: 'ltr', + year: 1750, + living: false, + link: 'https://en.wikipedia.org/wiki/Elbasan_alphabet', + }, + { + name: 'Ethiopic', + ranges: [[4608, 4681], [4682, 4686], [4688, 4695], [4696, 4697], [4698, 4702], [4704, 4745], [4746, 4750], [4752, 4785], [4786, 4790], [4792, 4799], [4800, 4801], [4802, 4806], [4808, 4823], [4824, 4881], [4882, 4886], [4888, 4955], [4957, 4989], [4992, 5018], [11648, 11671], [11680, 11687], [11688, 11695], [11696, 11703], [11704, 11711], [11712, 11719], [11720, 11727], [11728, 11735], [11736, 11743], [43777, 43783], [43785, 43791], [43793, 43799], [43808, 43815], [43816, 43823]], + direction: 'ltr', + year: -900, + living: true, + link: 'https://en.wikipedia.org/wiki/Ge%27ez_script', + }, + { + name: 'Georgian', + ranges: [[4256, 4294], [4295, 4296], [4301, 4302], [4304, 4347], [4348, 4352], [11520, 11558], [11559, 11560], [11565, 11566]], + direction: 'ltr', + year: 430, + living: true, + link: 'https://en.wikipedia.org/wiki/Georgian_scripts', + }, + { + name: 'Glagolitic', + ranges: [[11264, 11311], [11312, 11359], [122880, 122887], [122888, 122905], [122907, 122914], [122915, 122917], [122918, 122923]], + direction: 'ltr', + year: 862, + living: false, + link: 'https://en.wikipedia.org/wiki/Glagolitic_script', + }, + { + name: 'Masaram Gondi', + ranges: [[72960, 72967], [72968, 72970], [72971, 73015], [73018, 73019], [73020, 73022], [73023, 73032], [73040, 73050]], + direction: 'ltr', + year: 1918, + living: true, + link: 'https://en.wikipedia.org/wiki/Gondi_writing#Masaram', + }, + { + name: 'Gothic', + ranges: [[66352, 66379]], + direction: 'ltr', + year: 350, + living: false, + link: 'https://en.wikipedia.org/wiki/Gothic_alphabet', + }, + { + name: 'Grantha', + ranges: [[70400, 70404], [70405, 70413], [70415, 70417], [70419, 70441], [70442, 70449], [70450, 70452], [70453, 70458], [70460, 70469], [70471, 70473], [70475, 70478], [70480, 70481], [70487, 70488], [70493, 70500], [70502, 70509], [70512, 70517]], + direction: 'ltr', + year: 550, + living: false, + link: 'https://en.wikipedia.org/wiki/Grantha_alphabet', + }, + { + name: 'Greek', + ranges: [[880, 884], [885, 888], [890, 894], [895, 896], [900, 901], [902, 903], [904, 907], [908, 909], [910, 930], [931, 994], [1008, 1024], [7462, 7467], [7517, 7522], [7526, 7531], [7615, 7616], [7936, 7958], [7960, 7966], [7968, 8006], [8008, 8014], [8016, 8024], [8025, 8026], [8027, 8028], [8029, 8030], [8031, 8062], [8064, 8117], [8118, 8133], [8134, 8148], [8150, 8156], [8157, 8176], [8178, 8181], [8182, 8191], [8486, 8487], [43877, 43878], [65856, 65935], [65952, 65953], [119296, 119366]], + direction: 'ltr', + year: -800, + living: true, + link: 'https://en.wikipedia.org/wiki/Greek_alphabet', + }, + { + name: 'Gujarati', + ranges: [[2689, 2692], [2693, 2702], [2703, 2706], [2707, 2729], [2730, 2737], [2738, 2740], [2741, 2746], [2748, 2758], [2759, 2762], [2763, 2766], [2768, 2769], [2784, 2788], [2790, 2802], [2809, 2816]], + direction: 'ltr', + year: 1592, + living: true, + link: 'https://en.wikipedia.org/wiki/Gujarati_alphabet', + }, + { + name: 'Gurmukhi', + ranges: [[2561, 2564], [2565, 2571], [2575, 2577], [2579, 2601], [2602, 2609], [2610, 2612], [2613, 2615], [2616, 2618], [2620, 2621], [2622, 2627], [2631, 2633], [2635, 2638], [2641, 2642], [2649, 2653], [2654, 2655], [2662, 2678]], + direction: 'ltr', + year: 1550, + living: true, + link: 'https://en.wikipedia.org/wiki/Gurmukh%C4%AB_alphabet', + }, + { + name: 'Hangul', + ranges: [[4352, 4608], [12334, 12336], [12593, 12687], [12800, 12831], [12896, 12927], [43360, 43389], [44032, 55204], [55216, 55239], [55243, 55292], [65440, 65471], [65474, 65480], [65482, 65488], [65490, 65496], [65498, 65501]], + direction: 'ltr', + year: 1443, + living: true, + link: 'https://en.wikipedia.org/wiki/Hangul', + }, + { + name: 'Han', + ranges: [[11904, 11930], [11931, 12020], [12032, 12246], [12293, 12294], [12295, 12296], [12321, 12330], [12344, 12348], [13312, 19894], [19968, 40939], [63744, 64110], [64112, 64218], [131072, 173783], [173824, 177973], [177984, 178206], [178208, 183970], [183984, 191457], [194560, 195102]], + direction: 'ltr', + year: -1100, + living: true, + link: 'https://en.wikipedia.org/wiki/Chinese_characters', + }, + { + name: 'Hanunoo', + ranges: [[5920, 5941]], + direction: 'ltr', + year: 1300, + living: true, + link: 'https://en.wikipedia.org/wiki/Hanun%C3%B3%27o_alphabet', + }, + { + name: 'Hatran', + ranges: [[67808, 67827], [67828, 67830], [67835, 67840]], + direction: 'rtl', + year: -40, + living: false, + link: 'https://en.wikipedia.org/wiki/Hatran_alphabet', + }, + { + name: 'Hebrew', + ranges: [[1425, 1480], [1488, 1515], [1520, 1525], [64285, 64311], [64312, 64317], [64318, 64319], [64320, 64322], [64323, 64325], [64326, 64336]], + direction: 'rtl', + year: -100, + living: true, + link: 'https://en.wikipedia.org/wiki/Hebrew_alphabet', + }, + { + name: 'Hiragana', + ranges: [[12353, 12439], [12445, 12448], [110593, 110879], [127488, 127489]], + direction: 'ltr', + year: 800, + living: true, + link: 'https://en.wikipedia.org/wiki/Hiragana', + }, + { + name: 'Anatolian Hieroglyphs', + ranges: [[82944, 83527]], + direction: 'ltr', + year: -1400, + living: false, + link: 'https://en.wikipedia.org/wiki/Anatolian_hieroglyphs', + }, + { + name: 'Pahawh Hmong', + ranges: [[92928, 92998], [93008, 93018], [93019, 93026], [93027, 93048], [93053, 93072]], + direction: 'ltr', + year: 1959, + living: true, + link: 'https://en.wikipedia.org/wiki/Pahawh_Hmong', + }, + { + name: 'Old Hungarian', + ranges: [[68736, 68787], [68800, 68851], [68858, 68864]], + direction: 'rtl', + year: 1150, + living: false, + link: 'https://en.wikipedia.org/wiki/Old_Hungarian_alphabet', + }, + { + name: 'Old Italic', + ranges: [[66304, 66340], [66349, 66352]], + direction: 'ltr', + year: -750, + living: false, + link: 'https://en.wikipedia.org/wiki/Old_Italic_script', + }, + { + name: 'Javanese', + ranges: [[43392, 43470], [43472, 43482], [43486, 43488]], + direction: 'ltr', + year: 1250, + living: true, + link: 'https://en.wikipedia.org/wiki/Javanese_script', + }, + { + name: 'Kayah Li', + ranges: [[43264, 43310], [43311, 43312]], + direction: 'ltr', + year: 1962, + living: true, + link: 'https://en.wikipedia.org/wiki/Kayah_Li_alphabet', + }, + { + name: 'Katakana', + ranges: [[12449, 12539], [12541, 12544], [12784, 12800], [13008, 13055], [13056, 13144], [65382, 65392], [65393, 65438], [110592, 110593]], + direction: 'ltr', + year: 800, + living: true, + link: 'https://en.wikipedia.org/wiki/Katakana', + }, + { + name: 'Kharoshthi', + ranges: [[68096, 68100], [68101, 68103], [68108, 68116], [68117, 68120], [68121, 68148], [68152, 68155], [68159, 68168], [68176, 68185]], + direction: 'rtl', + year: -400, + living: false, + link: 'https://en.wikipedia.org/wiki/Kharosthi', + }, + { + name: 'Khmer', + ranges: [[6016, 6110], [6112, 6122], [6128, 6138], [6624, 6656]], + direction: 'ltr', + year: 611, + living: true, + link: 'https://en.wikipedia.org/wiki/Khmer_alphabet', + }, + { + name: 'Khojki', + ranges: [[70144, 70162], [70163, 70207]], + direction: 'ltr', + year: 1520, + living: false, + link: 'https://en.wikipedia.org/wiki/Khojki_script', + }, + { + name: 'Kannada', + ranges: [[3200, 3204], [3205, 3213], [3214, 3217], [3218, 3241], [3242, 3252], [3253, 3258], [3260, 3269], [3270, 3273], [3274, 3278], [3285, 3287], [3294, 3295], [3296, 3300], [3302, 3312], [3313, 3315]], + direction: 'ltr', + year: 450, + living: true, + link: 'https://en.wikipedia.org/wiki/Kannada_alphabet', + }, + { + name: 'Kaithi', + ranges: [[69760, 69826]], + direction: 'ltr', + year: 1550, + living: false, + link: 'https://en.wikipedia.org/wiki/Kaithi', + }, + { + name: 'Tai Tham', + ranges: [[6688, 6751], [6752, 6781], [6783, 6794], [6800, 6810], [6816, 6830]], + direction: 'ltr', + year: 1300, + living: true, + link: 'https://en.wikipedia.org/wiki/Tai_Tham_alphabet', + }, + { + name: 'Lao', + ranges: [[3713, 3715], [3716, 3717], [3719, 3721], [3722, 3723], [3725, 3726], [3732, 3736], [3737, 3744], [3745, 3748], [3749, 3750], [3751, 3752], [3754, 3756], [3757, 3770], [3771, 3774], [3776, 3781], [3782, 3783], [3784, 3790], [3792, 3802], [3804, 3808]], + direction: 'ltr', + year: 1350, + living: true, + link: 'https://en.wikipedia.org/wiki/Lao_alphabet', + }, + { + name: 'Latin', + ranges: [[65, 91], [97, 123], [170, 171], [186, 187], [192, 215], [216, 247], [248, 697], [736, 741], [7424, 7462], [7468, 7517], [7522, 7526], [7531, 7544], [7545, 7615], [7680, 7936], [8305, 8306], [8319, 8320], [8336, 8349], [8490, 8492], [8498, 8499], [8526, 8527], [8544, 8585], [11360, 11392], [42786, 42888], [42891, 42927], [42928, 42936], [42999, 43008], [43824, 43867], [43868, 43877], [64256, 64263], [65313, 65339], [65345, 65371]], + direction: 'ltr', + year: -700, + living: true, + link: 'https://en.wikipedia.org/wiki/Latin_script', + }, + { + name: 'Lepcha', + ranges: [[7168, 7224], [7227, 7242], [7245, 7248]], + direction: 'ltr', + year: 1700, + living: true, + link: 'https://en.wikipedia.org/wiki/Lepcha_alphabet', + }, + { + name: 'Limbu', + ranges: [[6400, 6431], [6432, 6444], [6448, 6460], [6464, 6465], [6468, 6480]], + direction: 'ltr', + year: 1740, + living: true, + link: 'https://en.wikipedia.org/wiki/Limbu_alphabet', + }, + { + name: 'Linear A', + ranges: [[67072, 67383], [67392, 67414], [67424, 67432]], + direction: 'ltr', + year: -2500, + living: false, + link: 'https://en.wikipedia.org/wiki/Linear_A', + }, + { + name: 'Linear B', + ranges: [[65536, 65548], [65549, 65575], [65576, 65595], [65596, 65598], [65599, 65614], [65616, 65630], [65664, 65787]], + direction: 'ltr', + year: -1450, + living: false, + link: 'https://en.wikipedia.org/wiki/Linear_B', + }, + { + name: 'Lisu', + ranges: [[42192, 42240]], + direction: 'ltr', + year: 1915, + living: true, + link: 'https://en.wikipedia.org/wiki/Fraser_alphabet', + }, + { + name: 'Lycian', + ranges: [[66176, 66205]], + direction: 'ltr', + year: -500, + living: false, + link: 'https://en.wikipedia.org/wiki/Lycian_alphabet', + }, + { + name: 'Lydian', + ranges: [[67872, 67898], [67903, 67904]], + direction: 'rtl', + year: -700, + living: false, + link: 'https://en.wikipedia.org/wiki/Lydian_alphabet', + }, + { + name: 'Mahajani', + ranges: [[69968, 70007]], + direction: 'ltr', + year: 1150, + living: false, + link: 'https://en.wikipedia.org/wiki/Mahajani', + }, + { + name: 'Mandaic', + ranges: [[2112, 2140], [2142, 2143]], + direction: 'rtl', + year: 200, + living: true, + link: 'https://en.wikipedia.org/wiki/Mandaic_alphabet', + }, + { + name: 'Manichaean', + ranges: [[68288, 68327], [68331, 68343]], + direction: 'rtl', + year: 250, + living: false, + link: 'https://en.wikipedia.org/wiki/Manichaean_alphabet', + }, + { + name: 'Marchen', + ranges: [[72816, 72848], [72850, 72872], [72873, 72887]], + direction: 'ltr', + year: 650, + living: false, + link: 'https://en.wikipedia.org/wiki/Zhang-Zhung_language#Scripts', + }, + { + name: 'Mende Kikakui', + ranges: [[124928, 125125], [125127, 125143]], + direction: 'rtl', + year: 1880, + living: true, + link: 'https://en.wikipedia.org/wiki/Mende_Kikakui_script', + }, + { + name: 'Meroitic Cursive', + ranges: [[68000, 68024], [68028, 68048], [68050, 68096]], + direction: 'rtl', + year: -300, + living: false, + link: 'https://en.wikipedia.org/wiki/Meroitic_alphabet', + }, + { + name: 'Meroitic Hieroglyphs', + ranges: [[67968, 68000]], + direction: 'rtl', + year: -300, + living: false, + link: 'https://en.wikipedia.org/wiki/Meroitic_alphabet', + }, + { + name: 'Malayalam', + ranges: [[3328, 3332], [3333, 3341], [3342, 3345], [3346, 3397], [3398, 3401], [3402, 3408], [3412, 3428], [3430, 3456]], + direction: 'ltr', + year: 830, + living: true, + link: 'https://en.wikipedia.org/wiki/Malayalam_script', + }, + { + name: 'Modi', + ranges: [[71168, 71237], [71248, 71258]], + direction: 'ltr', + year: 1200, + living: false, + link: 'https://en.wikipedia.org/wiki/Modi_alphabet', + }, + { + name: 'Mongolian', + ranges: [[6144, 6146], [6148, 6149], [6150, 6159], [6160, 6170], [6176, 6264], [6272, 6315], [71264, 71277]], + direction: 'ttb', + year: 1204, + living: false, + link: 'https://en.wikipedia.org/wiki/Mongolian_script', + }, + { + name: 'Mro', + ranges: [[92736, 92767], [92768, 92778], [92782, 92784]], + direction: 'ltr', + year: 1985, + living: true, + link: 'https://en.wikipedia.org/wiki/Mru_language#Alphabet', + }, + { + name: 'Meetei Mayek', + ranges: [[43744, 43767], [43968, 44014], [44016, 44026]], + direction: 'ltr', + year: 200, + living: true, + link: 'https://en.wikipedia.org/wiki/Meitei_script', + }, + { + name: 'Multani', + ranges: [[70272, 70279], [70280, 70281], [70282, 70286], [70287, 70302], [70303, 70314]], + direction: 'ltr', + year: 1750, + living: false, + link: 'https://en.wikipedia.org/wiki/Multani_alphabet', + }, + { + name: 'Myanmar', + ranges: [[4096, 4256], [43488, 43519], [43616, 43648]], + direction: 'ltr', + year: 984, + living: true, + link: 'https://en.wikipedia.org/wiki/Burmese_alphabet', + }, + { + name: 'Old North Arabian', + ranges: [[68224, 68256]], + direction: 'rtl', + year: 750, + living: false, + link: 'https://en.wikipedia.org/wiki/Ancient_North_Arabian', + }, + { + name: 'Nabataean', + ranges: [[67712, 67743], [67751, 67760]], + direction: 'rtl', + year: 150, + living: false, + link: 'https://en.wikipedia.org/wiki/Nabataean_alphabet', + }, + { + name: 'Newa', + ranges: [[70656, 70746], [70747, 70748], [70749, 70750]], + direction: 'ltr', + year: 1000, + living: true, + link: 'https://en.wikipedia.org/wiki/Prachalit_Nepal_alphabet', + }, + { + name: 'Nko', + ranges: [[1984, 2043]], + direction: 'rtl', + year: 1949, + living: false, + link: 'https://en.wikipedia.org/wiki/N%27Ko_alphabet', + }, + { + name: 'Nushu', + ranges: [[94177, 94178], [110960, 111356]], + direction: 'ltr', + year: 1500, + living: true, + link: 'https://en.wikipedia.org/wiki/N%C3%BCshu_script', + }, + { + name: 'Ogham', + ranges: [[5760, 5789]], + direction: 'ltr', + year: 350, + living: false, + link: 'https://en.wikipedia.org/wiki/Ogham', + }, + { + name: 'Ol Chiki', + ranges: [[7248, 7296]], + direction: 'ltr', + year: 1925, + living: true, + link: 'https://en.wikipedia.org/wiki/Ol_Chiki_script', + }, + { + name: 'Old Turkic', + ranges: [[68608, 68681]], + direction: 'rtl', + year: 750, + living: false, + link: 'https://en.wikipedia.org/wiki/Old_Turkic_alphabet', + }, + { + name: 'Oriya', + ranges: [[2817, 2820], [2821, 2829], [2831, 2833], [2835, 2857], [2858, 2865], [2866, 2868], [2869, 2874], [2876, 2885], [2887, 2889], [2891, 2894], [2902, 2904], [2908, 2910], [2911, 2916], [2918, 2936]], + direction: 'ltr', + year: 1060, + living: true, + link: 'https://en.wikipedia.org/wiki/Odia_alphabet', + }, + { + name: 'Osage', + ranges: [[66736, 66772], [66776, 66812]], + direction: 'ltr', + year: 2006, + living: true, + link: 'https://en.wikipedia.org/wiki/Osage_alphabet', + }, + { + name: 'Osmanya', + ranges: [[66688, 66718], [66720, 66730]], + direction: 'ltr', + year: 1920, + living: true, + link: 'https://en.wikipedia.org/wiki/Osmanya_alphabet', + }, + { + name: 'Palmyrene', + ranges: [[67680, 67712]], + direction: 'rtl', + year: -100, + living: false, + link: 'https://en.wikipedia.org/wiki/Palmyrene_alphabet', + }, + { + name: 'Pau Cin Hau', + ranges: [[72384, 72441]], + direction: 'ltr', + year: 1900, + living: true, + link: 'https://en.wikipedia.org/wiki/Pau_Cin_Hau', + }, + { + name: 'Old Permic', + ranges: [[66384, 66427]], + direction: 'ltr', + year: 1372, + living: false, + link: 'https://en.wikipedia.org/wiki/Old_Permic_alphabet', + }, + { + name: 'Phags-pa', + ranges: [[43072, 43123], [43124, 43127]], + direction: 'ttb', + year: 1269, + living: false, + link: 'https://en.wikipedia.org/wiki/%27Phags-pa_script', + }, + { + name: 'Inscriptional Pahlavi', + ranges: [[68448, 68467], [68472, 68480]], + direction: 'rtl', + year: -171, + living: false, + link: 'https://en.wikipedia.org/wiki/Inscriptional_Pahlavi', + }, + { + name: 'Psalter Pahlavi', + ranges: [[68480, 68498], [68505, 68509], [68521, 68528]], + direction: 'rtl', + year: 550, + living: false, + link: 'https://en.wikipedia.org/wiki/Psalter_Pahlavi', + }, + { + name: 'Phoenician', + ranges: [[67840, 67868], [67871, 67872]], + direction: 'rtl', + year: -1200, + living: false, + link: 'https://en.wikipedia.org/wiki/Phoenician_alphabet', + }, + { + name: 'Miao', + ranges: [[93952, 94021], [94032, 94079], [94095, 94112]], + direction: 'ltr', + year: 1936, + living: true, + link: 'https://en.wikipedia.org/wiki/Pollard_script', + }, + { + name: 'Inscriptional Parthian', + ranges: [[68416, 68438], [68440, 68448]], + direction: 'rtl', + year: -250, + living: false, + link: 'https://en.wikipedia.org/wiki/Inscriptional_Parthian', + }, + { + name: 'Rejang', + ranges: [[43312, 43348], [43359, 43360]], + direction: 'ltr', + year: 1750, + living: true, + link: 'https://en.wikipedia.org/wiki/Rejang_script', + }, + { + name: 'Runic', + ranges: [[5792, 5867], [5870, 5881]], + direction: 'ltr', + year: 150, + living: false, + link: 'https://en.wikipedia.org/wiki/Runes', + }, + { + name: 'Samaritan', + ranges: [[2048, 2094], [2096, 2111]], + direction: 'rtl', + year: -600, + living: true, + link: 'https://en.wikipedia.org/wiki/Samaritan_alphabet', + }, + { + name: 'Old South Arabian', + ranges: [[68192, 68224]], + direction: 'rtl', + year: -850, + living: false, + link: 'https://en.wikipedia.org/wiki/Ancient_South_Arabian_script', + }, + { + name: 'Saurashtra', + ranges: [[43136, 43206], [43214, 43226]], + direction: 'ltr', + year: 1920, + living: true, + link: 'https://en.wikipedia.org/wiki/Saurashtra_alphabet', + }, + { + name: 'SignWriting', + ranges: [[120832, 121484], [121499, 121504], [121505, 121520]], + direction: 'ttb', + year: 1974, + living: true, + link: 'https://en.wikipedia.org/wiki/SignWriting', + }, + { + name: 'Shavian', + ranges: [[66640, 66688]], + direction: 'ltr', + year: 1960, + living: true, + link: 'https://en.wikipedia.org/wiki/Shavian_alphabet', + }, + { + name: 'Sharada', + ranges: [[70016, 70094], [70096, 70112]], + direction: 'ltr', + year: 800, + living: true, + link: 'https://en.wikipedia.org/wiki/%C5%9A%C4%81rad%C4%81_script', + }, + { + name: 'Siddham', + ranges: [[71040, 71094], [71096, 71134]], + direction: 'ltr', + year: 550, + living: false, + link: 'https://en.wikipedia.org/wiki/Siddha%E1%B9%83_script', + }, + { + name: 'Khudawadi', + ranges: [[70320, 70379], [70384, 70394]], + direction: 'ltr', + year: 1550, + living: true, + link: 'https://en.wikipedia.org/wiki/Khudabadi_script', + }, + { + name: 'Sinhala', + ranges: [[3458, 3460], [3461, 3479], [3482, 3506], [3507, 3516], [3517, 3518], [3520, 3527], [3530, 3531], [3535, 3541], [3542, 3543], [3544, 3552], [3558, 3568], [3570, 3573], [70113, 70133]], + direction: 'ltr', + year: 700, + living: true, + link: 'https://en.wikipedia.org/wiki/Sinhalese_alphabet', + }, + { + name: 'Sora Sompeng', + ranges: [[69840, 69865], [69872, 69882]], + direction: 'ltr', + year: 1936, + living: true, + link: 'https://en.wikipedia.org/wiki/Sorang_Sompeng_alphabet', + }, + { + name: 'Soyombo', + ranges: [[72272, 72324], [72326, 72349], [72350, 72355]], + direction: 'ltr', + year: 1650, + living: false, + link: 'https://en.wikipedia.org/wiki/Soyombo_alphabet', + }, + { + name: 'Sundanese', + ranges: [[7040, 7104], [7360, 7368]], + direction: 'ltr', + year: 1350, + living: true, + link: 'https://en.wikipedia.org/wiki/Sundanese_script', + }, + { + name: 'Syloti Nagri', + ranges: [[43008, 43052]], + direction: 'ltr', + year: 1303, + living: true, + link: 'https://en.wikipedia.org/wiki/Sylheti_Nagari', + }, + { + name: 'Syriac', + ranges: [[1792, 1806], [1807, 1867], [1869, 1872], [2144, 2155]], + direction: 'rtl', + year: -200, + living: true, + link: 'https://en.wikipedia.org/wiki/Syriac_alphabet', + }, + { + name: 'Tagbanwa', + ranges: [[5984, 5997], [5998, 6001], [6002, 6004]], + direction: 'ltr', + year: 1300, + living: true, + link: 'https://en.wikipedia.org/wiki/Tagbanwa_script', + }, + { + name: 'Takri', + ranges: [[71296, 71352], [71360, 71370]], + direction: 'ltr', + year: 1550, + living: true, + link: 'https://en.wikipedia.org/wiki/Takri_alphabet', + }, + { + name: 'Tai Le', + ranges: [[6480, 6510], [6512, 6517]], + direction: 'ltr', + year: 1200, + living: true, + link: 'https://en.wikipedia.org/wiki/Tai_Le_alphabet', + }, + { + name: 'New Tai Lue', + ranges: [[6528, 6572], [6576, 6602], [6608, 6619], [6622, 6624]], + direction: 'ltr', + year: 1950, + living: true, + link: 'https://en.wikipedia.org/wiki/New_Tai_Lue_alphabet', + }, + { + name: 'Tamil', + ranges: [[2946, 2948], [2949, 2955], [2958, 2961], [2962, 2966], [2969, 2971], [2972, 2973], [2974, 2976], [2979, 2981], [2984, 2987], [2990, 3002], [3006, 3011], [3014, 3017], [3018, 3022], [3024, 3025], [3031, 3032], [3046, 3067]], + direction: 'ltr', + year: 700, + living: true, + link: 'https://en.wikipedia.org/wiki/Tamil_script', + }, + { + name: 'Tangut', + ranges: [[94176, 94177], [94208, 100333], [100352, 101107]], + direction: 'ltr', + year: 1036, + living: false, + link: 'https://en.wikipedia.org/wiki/Tangut_script', + }, + { + name: 'Tai Viet', + ranges: [[43648, 43715], [43739, 43744]], + direction: 'ltr', + year: 1200, + living: true, + link: 'https://en.wikipedia.org/wiki/Tai_Dam_language#Writing_system', + }, + { + name: 'Telugu', + ranges: [[3072, 3076], [3077, 3085], [3086, 3089], [3090, 3113], [3114, 3130], [3133, 3141], [3142, 3145], [3146, 3150], [3157, 3159], [3160, 3163], [3168, 3172], [3174, 3184], [3192, 3200]], + direction: 'ltr', + year: -900, + living: true, + link: 'https://en.wikipedia.org/wiki/Telugu_script', + }, + { + name: 'Tifinagh', + ranges: [[11568, 11624], [11631, 11633], [11647, 11648]], + direction: 'ltr', + year: -300, + living: true, + link: 'https://en.wikipedia.org/wiki/Tifinagh', + }, + { + name: 'Tagalog', + ranges: [[5888, 5901], [5902, 5909]], + direction: 'ltr', + year: 1250, + living: true, + link: 'https://en.wikipedia.org/wiki/Baybayin', + }, + { + name: 'Thaana', + ranges: [[1920, 1970]], + direction: 'rtl', + year: 1599, + living: true, + link: 'https://en.wikipedia.org/wiki/Thaana', + }, + { + name: 'Thai', + ranges: [[3585, 3643], [3648, 3676]], + direction: 'ltr', + year: 1283, + living: true, + link: 'https://en.wikipedia.org/wiki/Thai_alphabet', + }, + { + name: 'Tibetan', + ranges: [[3840, 3912], [3913, 3949], [3953, 3992], [3993, 4029], [4030, 4045], [4046, 4053], [4057, 4059]], + direction: 'ltr', + year: 650, + living: false, + link: 'https://en.wikipedia.org/wiki/Tibetan_alphabet', + }, + { + name: 'Tirhuta', + ranges: [[70784, 70856], [70864, 70874]], + direction: 'ltr', + year: 1450, + living: true, + link: 'https://en.wikipedia.org/wiki/Tirhuta', + }, + { + name: 'Ugaritic', + ranges: [[66432, 66462], [66463, 66464]], + direction: 'ltr', + year: -1400, + living: false, + link: 'https://en.wikipedia.org/wiki/Ugaritic_alphabet', + }, + { + name: 'Vai', + ranges: [[42240, 42540]], + direction: 'ltr', + year: 1830, + living: true, + link: 'https://en.wikipedia.org/wiki/Vai_syllabary', + }, + { + name: 'Warang Citi', + ranges: [[71840, 71923], [71935, 71936]], + direction: 'ltr', + year: 1946, + living: true, + link: 'https://en.wikipedia.org/wiki/Warang_Citi', + }, + { + name: 'Old Persian', + ranges: [[66464, 66500], [66504, 66518]], + direction: 'ltr', + year: -525, + living: false, + link: 'https://en.wikipedia.org/wiki/Old_Persian_cuneiform', + }, + { + name: 'Cuneiform', + ranges: [[73728, 74650], [74752, 74863], [74864, 74869], [74880, 75076]], + direction: 'ltr', + year: -3050, + living: false, + link: 'https://en.wikipedia.org/wiki/Cuneiform_script', + }, + { + name: 'Yi', + ranges: [[40960, 42125], [42128, 42183]], + direction: 'ltr', + year: 1450, + living: true, + link: 'https://en.wikipedia.org/wiki/Yi_script', + }, + { + name: 'Zanabazar Square', + ranges: [[72192, 72264]], + direction: 'ltr', + year: 1700, + living: false, + link: 'https://en.wikipedia.org/wiki/Mongolian_writing_systems#Horizontal_square_script', + }, +]; + +// Dæmi um útfærslu á filter, alltaf nota stöðluðu útgáfu á Array +// t.d. [1, 2, 3].filter(i => i > 1) +function filter(array, test) { + const passed = []; + for (const element of array) { + if (test(element)) { + passed.push(element); + } + } + return passed; +} + +// console.log(filter(SCRIPTS, script => script.living)); + +// --- // + +// Dæmi um útfærslu á map, alltaf nota stöðluðu útgáfu á Array +// t.d. [1, 2, 3].map(i => i * 2) +function map(array, transform) { + const mapped = []; + for (const element of array) { + mapped.push(transform(element)); + } + return mapped; +} + +const rtlScripts = SCRIPTS.filter((s) => s.direction === 'rtl'); +// console.log(map(rtlScripts, s => s.name)); + +// --- // + +// Dæmi um útfærslu á reduce, alltaf nota stöðluðu útgáfu á Array +// t.d. [1, 2, 3].reduce((i, v) => i + v)) +function reduce(array, combine, start) { + let current = start; + for (const element of array) { + current = combine(current, element); + } + return current; +} + +// --- // + +// Skilar hversu margir stafir eru í stafrófi fyrir script +function characterCount(script) { + return script.ranges.reduce((count, [from, to]) => count + (to - from), 0); +} + +/* console.log( + SCRIPTS.reduce((a, b) => (characterCount(a) < characterCount(b) ? b : a)), +); */ + +// console.log(reduce([1, 2, 3, 4], (a, b) => a + b, 0)); + +// --- // + +function characterScript(code) { + for (const script of SCRIPTS) { + // er stafakóðinn á a.m.k. einu bili? + if (script.ranges.some(([from, to]) => code >= from && code < to)) { + return script; + } + } + return null; +} + +// console.log(characterScript(121)); + +function countBy(items, groupName) { + const counts = []; + for (const item of items) { + const name = groupName(item); + const known = counts.findIndex((c) => c.name === name); + if (known === -1) { + counts.push({ name, count: 1 }); + } else { + counts[known].count += 1; + } + } + return counts; +} + +function textScripts(text) { + const scripts = countBy(text, (char) => { + const script = characterScript(char.codePointAt(0)); + return script ? script.name : 'none'; + }).filter(({ name }) => name !== 'none'); + + const total = scripts.reduce((n, { count }) => n + count, 0); + if (total === 0) return 'No scripts found'; + + return scripts + .map(({ name, count }) => `${Math.round(count * 100 / total)}% ${name}`) + .join(', '); +} + +// console.log(textScripts('英国的狗说"woof", 俄罗斯的狗说"тяв"')); diff --git a/namsefni/36.functional/readme.md b/namsefni/36.functional/readme.md new file mode 100644 index 0000000..7603d11 --- /dev/null +++ b/namsefni/36.functional/readme.md @@ -0,0 +1,24 @@ +# Fallaforritun + +[Fyrirlestur: Fallaforritun](1.functional.md), [vídeó](https://youtu.be/baNMhgcqD04) + +## Lesefni + +* [Eloquent JavaScript, kafli 5: Higher-order Functions](https://eloquentjavascript.net/05_higher_order.html) + +## Dæmi + +* [sorting & filtering](daemi/01.sorting-filtering.html) +* [alphabet dæmi](daemi/02.alphabet.js) + +## Ítarefni + +* [Functional Programming](https://en.wikipedia.org/wiki/Functional_programming) +* [Higher-order function](https://en.wikipedia.org/wiki/Higher-order_function) +* [`forEach`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) +* [Pure function](https://en.wikipedia.org/wiki/Pure_function) +* [`every`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every) +* [`some`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/some) +* [`map`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/map) +* [`reduce`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) +* [`filter`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) diff --git a/namsefni/37.tools/1.tools.md b/namsefni/37.tools/1.tools.md new file mode 100644 index 0000000..c18d15e --- /dev/null +++ b/namsefni/37.tools/1.tools.md @@ -0,0 +1,215 @@ +--- +title: Fyrirlestur – Tæki og tól +--- + +# Fyrirlestur – Tæki og tól + +## Vefforritun 1 — TÖL107G + +### Ólafur Sverrir Kjartansson, [osk@hi.is](mailto:osk@hi.is) + +--- + +> Choose your tools wisely. It would be a terrible shame if you abandoned the resilient approach to web design because of a difference of opinion with a piece of software. +> +> –[Resilient Web Design, chapter 7: Challenges](https://resilientwebdesign.com/chapter7/) + +*** + +## Stuðningur við ECMAScript 6/2015 + +* Vafrar almennt með um 95+% stuðning við ECMAScript 6/2015 +* Nýrri virkni (ECMAScript 7+) með góðan stuðning en ekki nóg til að geta notað almennt +* [ECMAScript comptaibility table: ES6](https://kangax.github.io/compat-table/es6/) + +*** + +* Ekki sjálfbært að fletta upp og vita hvað er stutt hvar og hvar ekki +* Notum _transpiler_ til að þýða úr ES6+ í ES5/6 kóða sem allir (valdir) vafrar styðja +* Þurfum að setja upp tól og build ferli til að geta notað +* Polyfill fyrir hluti sem vantar í eldri vafra + +*** + +## Polyfill + +Polyfill er kóði eða plugin sem veitir þér aðgang að virkni sem þú gerir ráð fyrir að vafrinn bjóði upp á. + +*** + +## Transpiler + +* Þýðandi sem þýðir úr forritunarmáli í forritunarmál +* Leyfir okkur að nota _í dag_ virkni sem kemur ekki fyrr en í framtíðinni + * Svipað og polyfill +* [Babel](https://babeljs.io/) sá vinsælasti fyrir JavaScript + * Kemur líka með polyfills! + +*** + +## babel + +* Sækjum með npm +* Setjum upp config sem segir til um virkni, `babel.config.js` +* Keyrum með scriptu + +*** + +```bash +npm install --save-dev @babel/core @babel/cli @babel/preset-env +npm install --save @babel/polyfill +``` + +*** + +```javascript +const presets = [ + ['@babel/preset-env', { + useBuiltIns: 'usage', + corejs: 2, + targets: '> 0.25%, not dead', + }], +]; +module.exports = { presets }; +``` + +*** + +* `@babel/preset-env` leyfir okkur að skilgreina lista út frá notkun + * Vafra með yfir `0,25%` notkun og ekki „dauða“ +* Hægt og rólega detta hlutir út + +*** + +* `useBuiltIns` skilgreinir hvaða og hvernig polyfill eru notuð + * Verðum að hafa svo t.d. `async await` virki +* [`corejs`](https://github.com/zloirock/core-js) er library fyrir almenn polyfill + +*** + +Setjum upp script til að keyra: + +```json +{ + "scripts": { + "babel": "babel src --out-dir dist", + "babel-watch": "babel src --out-dir dist --watch" + } +} +``` + +*** + +## src og dist + +* `src` er oft notað sem heiti á möppu með grunnkóðanum okkar + * _source_ +* `dist` fyrir kóða sem búið er að eiga við, transpileaður grunnkóði + * _distribution_ + +--- + +## Pökkun á kóða + +* Þegar við erum komin með transpiler er næsta skref oft að setja upp tól sem _pakkar kóða_, _bundler_ +* Tekur margar JavaScript skrár og setur þær saman í eina + * Eins og við höfum verið að gera með Sass +* Oft líka kóði frá öðrum, library sem við höfum sótt með npm + +*** + +* Webpack e.t.v. þekktasta tólið sem gerir þetta +* En mörg önnur + * [Rollup](https://rollupjs.org/) + * [Parcel](https://parceljs.org/) + * [Vite](https://vitejs.dev/) + * og „eldri“, [grunt](https://gruntjs.com/), [gulp](https://gulpjs.com/) + +*** + +## Rollup + +* [Rollup](https://rollupjs.org/guide/en) er bundler sem er tilltölulega auðvelt að setja upp +* Hefur stuðning við ES6 modules! + +*** + +* Sækjum með npm + * `npm install --save-dev rollup` +* Skilgreinum config í `rollup.config.js` +* Skilgreinum scriptur til að keyra + * `"rollup": "rollup -c"` + * `"rollup-watch": "rollup -c -w"` + +*** + +```javascript +module.exports = { + input: './src/index.js', + output: { + file: './dist/bundle.js', + format: 'iife', + sourcemap: true, + }, +}; +``` + +--- + +## Rollup plugins + +* Rollup styður plugins +* Getum látið rollup keyra babel +* Tækjakeðjan okkar farin að flækjast... + +*** + +* Sækjum babel og rollup eins og áður + * Sækjum aukalega `rollup-plugin-babel` sem tengir tólin saman +* Skilgreinum config fyrir bæði tól, eða innifelum stillingar fyrir babel í plugin config +* Skilgreinum scriptur sem keyra rollup, þurfum _ekki_ fyrir babel + * Rollup keyrir babel! + +*** + +```bash +npm install --save-dev rollup +npm install --save-dev @babel/core @babel/cli @babel/preset-env +npm install --save-dev rollup-plugin-babel +``` + +*** + + + +```javascript +import babel from 'rollup-plugin-babel'; +module.exports = { + input: './src/index.js', + output: { + file: './dist/bundle.js', + format: 'iife', + sourcemap: true, + }, + plugins: [ + babel({ + sourceMaps: true, + presets: [['@babel/preset-env', + { targets: '> 0.25%, not dead' }]], + }), + ]}; +``` + +*** + +## Plugins + +* Hellingur af öðrum plugins sem geta allskonar, jafnvel sótt og keyrt kóða af NPM + * [`@rollup/plugin-node-resolve`](https://github.com/rollup/plugins/tree/master/packages/node-resolve) finnur og pakkar kóða úr node_modules + * [`rollup-plugin-terser`](https://github.com/TrySound/rollup-plugin-terser) „uglifyar“ kóðann okkar, þjappar honum saman + +*** + +> Choose your tools wisely. It would be a terrible shame if you abandoned the resilient approach to web design because of a difference of opinion with a piece of software. +> +> —[Resilient Web Design, chapter 7: Challenges](https://resilientwebdesign.com/chapter7/) diff --git a/namsefni/37.tools/daemi/.eslintrc.js b/namsefni/37.tools/daemi/.eslintrc.js new file mode 100644 index 0000000..021918d --- /dev/null +++ b/namsefni/37.tools/daemi/.eslintrc.js @@ -0,0 +1,13 @@ +module.exports = { + rules: { + // leyfum for of + 'no-restricted-syntax': 0, + + // helper.html dæmi + 'function-paren-newline': 0, + + 'import/extensions': 0, + + 'max-len': [true, 100], + }, +}; diff --git a/namsefni/37.tools/daemi/dist/bundle.js b/namsefni/37.tools/daemi/dist/bundle.js new file mode 100644 index 0000000..54a84af --- /dev/null +++ b/namsefni/37.tools/daemi/dist/bundle.js @@ -0,0 +1,888 @@ +(function () { + 'use strict'; + + function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error) { + reject(error); + return; + } + + if (info.done) { + resolve(value); + } else { + Promise.resolve(value).then(_next, _throw); + } + } + + function _asyncToGenerator(fn) { + return function () { + var self = this, + args = arguments; + return new Promise(function (resolve, reject) { + var gen = fn.apply(self, args); + + function _next(value) { + asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); + } + + function _throw(err) { + asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); + } + + _next(undefined); + }); + }; + } + + var runtime = {exports: {}}; + + /** + * Copyright (c) 2014-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + + (function (module) { + var runtime = (function (exports) { + + var Op = Object.prototype; + var hasOwn = Op.hasOwnProperty; + var undefined$1; // More compressible than void 0. + var $Symbol = typeof Symbol === "function" ? Symbol : {}; + var iteratorSymbol = $Symbol.iterator || "@@iterator"; + var asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator"; + var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag"; + + function define(obj, key, value) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + return obj[key]; + } + try { + // IE 8 has a broken Object.defineProperty that only works on DOM objects. + define({}, ""); + } catch (err) { + define = function(obj, key, value) { + return obj[key] = value; + }; + } + + function wrap(innerFn, outerFn, self, tryLocsList) { + // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator. + var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator; + var generator = Object.create(protoGenerator.prototype); + var context = new Context(tryLocsList || []); + + // The ._invoke method unifies the implementations of the .next, + // .throw, and .return methods. + generator._invoke = makeInvokeMethod(innerFn, self, context); + + return generator; + } + exports.wrap = wrap; + + // Try/catch helper to minimize deoptimizations. Returns a completion + // record like context.tryEntries[i].completion. This interface could + // have been (and was previously) designed to take a closure to be + // invoked without arguments, but in all the cases we care about we + // already have an existing method we want to call, so there's no need + // to create a new function object. We can even get away with assuming + // the method takes exactly one argument, since that happens to be true + // in every case, so we don't have to touch the arguments object. The + // only additional allocation required is the completion record, which + // has a stable shape and so hopefully should be cheap to allocate. + function tryCatch(fn, obj, arg) { + try { + return { type: "normal", arg: fn.call(obj, arg) }; + } catch (err) { + return { type: "throw", arg: err }; + } + } + + var GenStateSuspendedStart = "suspendedStart"; + var GenStateSuspendedYield = "suspendedYield"; + var GenStateExecuting = "executing"; + var GenStateCompleted = "completed"; + + // Returning this object from the innerFn has the same effect as + // breaking out of the dispatch switch statement. + var ContinueSentinel = {}; + + // Dummy constructor functions that we use as the .constructor and + // .constructor.prototype properties for functions that return Generator + // objects. For full spec compliance, you may wish to configure your + // minifier not to mangle the names of these two functions. + function Generator() {} + function GeneratorFunction() {} + function GeneratorFunctionPrototype() {} + + // This is a polyfill for %IteratorPrototype% for environments that + // don't natively support it. + var IteratorPrototype = {}; + define(IteratorPrototype, iteratorSymbol, function () { + return this; + }); + + var getProto = Object.getPrototypeOf; + var NativeIteratorPrototype = getProto && getProto(getProto(values([]))); + if (NativeIteratorPrototype && + NativeIteratorPrototype !== Op && + hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) { + // This environment has a native %IteratorPrototype%; use it instead + // of the polyfill. + IteratorPrototype = NativeIteratorPrototype; + } + + var Gp = GeneratorFunctionPrototype.prototype = + Generator.prototype = Object.create(IteratorPrototype); + GeneratorFunction.prototype = GeneratorFunctionPrototype; + define(Gp, "constructor", GeneratorFunctionPrototype); + define(GeneratorFunctionPrototype, "constructor", GeneratorFunction); + GeneratorFunction.displayName = define( + GeneratorFunctionPrototype, + toStringTagSymbol, + "GeneratorFunction" + ); + + // Helper for defining the .next, .throw, and .return methods of the + // Iterator interface in terms of a single ._invoke method. + function defineIteratorMethods(prototype) { + ["next", "throw", "return"].forEach(function(method) { + define(prototype, method, function(arg) { + return this._invoke(method, arg); + }); + }); + } + + exports.isGeneratorFunction = function(genFun) { + var ctor = typeof genFun === "function" && genFun.constructor; + return ctor + ? ctor === GeneratorFunction || + // For the native GeneratorFunction constructor, the best we can + // do is to check its .name property. + (ctor.displayName || ctor.name) === "GeneratorFunction" + : false; + }; + + exports.mark = function(genFun) { + if (Object.setPrototypeOf) { + Object.setPrototypeOf(genFun, GeneratorFunctionPrototype); + } else { + genFun.__proto__ = GeneratorFunctionPrototype; + define(genFun, toStringTagSymbol, "GeneratorFunction"); + } + genFun.prototype = Object.create(Gp); + return genFun; + }; + + // Within the body of any async function, `await x` is transformed to + // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test + // `hasOwn.call(value, "__await")` to determine if the yielded value is + // meant to be awaited. + exports.awrap = function(arg) { + return { __await: arg }; + }; + + function AsyncIterator(generator, PromiseImpl) { + function invoke(method, arg, resolve, reject) { + var record = tryCatch(generator[method], generator, arg); + if (record.type === "throw") { + reject(record.arg); + } else { + var result = record.arg; + var value = result.value; + if (value && + typeof value === "object" && + hasOwn.call(value, "__await")) { + return PromiseImpl.resolve(value.__await).then(function(value) { + invoke("next", value, resolve, reject); + }, function(err) { + invoke("throw", err, resolve, reject); + }); + } + + return PromiseImpl.resolve(value).then(function(unwrapped) { + // When a yielded Promise is resolved, its final value becomes + // the .value of the Promise<{value,done}> result for the + // current iteration. + result.value = unwrapped; + resolve(result); + }, function(error) { + // If a rejected Promise was yielded, throw the rejection back + // into the async generator function so it can be handled there. + return invoke("throw", error, resolve, reject); + }); + } + } + + var previousPromise; + + function enqueue(method, arg) { + function callInvokeWithMethodAndArg() { + return new PromiseImpl(function(resolve, reject) { + invoke(method, arg, resolve, reject); + }); + } + + return previousPromise = + // If enqueue has been called before, then we want to wait until + // all previous Promises have been resolved before calling invoke, + // so that results are always delivered in the correct order. If + // enqueue has not been called before, then it is important to + // call invoke immediately, without waiting on a callback to fire, + // so that the async generator function has the opportunity to do + // any necessary setup in a predictable way. This predictability + // is why the Promise constructor synchronously invokes its + // executor callback, and why async functions synchronously + // execute code before the first await. Since we implement simple + // async functions in terms of async generators, it is especially + // important to get this right, even though it requires care. + previousPromise ? previousPromise.then( + callInvokeWithMethodAndArg, + // Avoid propagating failures to Promises returned by later + // invocations of the iterator. + callInvokeWithMethodAndArg + ) : callInvokeWithMethodAndArg(); + } + + // Define the unified helper method that is used to implement .next, + // .throw, and .return (see defineIteratorMethods). + this._invoke = enqueue; + } + + defineIteratorMethods(AsyncIterator.prototype); + define(AsyncIterator.prototype, asyncIteratorSymbol, function () { + return this; + }); + exports.AsyncIterator = AsyncIterator; + + // Note that simple async functions are implemented on top of + // AsyncIterator objects; they just return a Promise for the value of + // the final result produced by the iterator. + exports.async = function(innerFn, outerFn, self, tryLocsList, PromiseImpl) { + if (PromiseImpl === void 0) PromiseImpl = Promise; + + var iter = new AsyncIterator( + wrap(innerFn, outerFn, self, tryLocsList), + PromiseImpl + ); + + return exports.isGeneratorFunction(outerFn) + ? iter // If outerFn is a generator, return the full iterator. + : iter.next().then(function(result) { + return result.done ? result.value : iter.next(); + }); + }; + + function makeInvokeMethod(innerFn, self, context) { + var state = GenStateSuspendedStart; + + return function invoke(method, arg) { + if (state === GenStateExecuting) { + throw new Error("Generator is already running"); + } + + if (state === GenStateCompleted) { + if (method === "throw") { + throw arg; + } + + // Be forgiving, per 25.3.3.3.3 of the spec: + // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume + return doneResult(); + } + + context.method = method; + context.arg = arg; + + while (true) { + var delegate = context.delegate; + if (delegate) { + var delegateResult = maybeInvokeDelegate(delegate, context); + if (delegateResult) { + if (delegateResult === ContinueSentinel) continue; + return delegateResult; + } + } + + if (context.method === "next") { + // Setting context._sent for legacy support of Babel's + // function.sent implementation. + context.sent = context._sent = context.arg; + + } else if (context.method === "throw") { + if (state === GenStateSuspendedStart) { + state = GenStateCompleted; + throw context.arg; + } + + context.dispatchException(context.arg); + + } else if (context.method === "return") { + context.abrupt("return", context.arg); + } + + state = GenStateExecuting; + + var record = tryCatch(innerFn, self, context); + if (record.type === "normal") { + // If an exception is thrown from innerFn, we leave state === + // GenStateExecuting and loop back for another invocation. + state = context.done + ? GenStateCompleted + : GenStateSuspendedYield; + + if (record.arg === ContinueSentinel) { + continue; + } + + return { + value: record.arg, + done: context.done + }; + + } else if (record.type === "throw") { + state = GenStateCompleted; + // Dispatch the exception by looping back around to the + // context.dispatchException(context.arg) call above. + context.method = "throw"; + context.arg = record.arg; + } + } + }; + } + + // Call delegate.iterator[context.method](context.arg) and handle the + // result, either by returning a { value, done } result from the + // delegate iterator, or by modifying context.method and context.arg, + // setting context.delegate to null, and returning the ContinueSentinel. + function maybeInvokeDelegate(delegate, context) { + var method = delegate.iterator[context.method]; + if (method === undefined$1) { + // A .throw or .return when the delegate iterator has no .throw + // method always terminates the yield* loop. + context.delegate = null; + + if (context.method === "throw") { + // Note: ["return"] must be used for ES3 parsing compatibility. + if (delegate.iterator["return"]) { + // If the delegate iterator has a return method, give it a + // chance to clean up. + context.method = "return"; + context.arg = undefined$1; + maybeInvokeDelegate(delegate, context); + + if (context.method === "throw") { + // If maybeInvokeDelegate(context) changed context.method from + // "return" to "throw", let that override the TypeError below. + return ContinueSentinel; + } + } + + context.method = "throw"; + context.arg = new TypeError( + "The iterator does not provide a 'throw' method"); + } + + return ContinueSentinel; + } + + var record = tryCatch(method, delegate.iterator, context.arg); + + if (record.type === "throw") { + context.method = "throw"; + context.arg = record.arg; + context.delegate = null; + return ContinueSentinel; + } + + var info = record.arg; + + if (! info) { + context.method = "throw"; + context.arg = new TypeError("iterator result is not an object"); + context.delegate = null; + return ContinueSentinel; + } + + if (info.done) { + // Assign the result of the finished delegate to the temporary + // variable specified by delegate.resultName (see delegateYield). + context[delegate.resultName] = info.value; + + // Resume execution at the desired location (see delegateYield). + context.next = delegate.nextLoc; + + // If context.method was "throw" but the delegate handled the + // exception, let the outer generator proceed normally. If + // context.method was "next", forget context.arg since it has been + // "consumed" by the delegate iterator. If context.method was + // "return", allow the original .return call to continue in the + // outer generator. + if (context.method !== "return") { + context.method = "next"; + context.arg = undefined$1; + } + + } else { + // Re-yield the result returned by the delegate method. + return info; + } + + // The delegate iterator is finished, so forget it and continue with + // the outer generator. + context.delegate = null; + return ContinueSentinel; + } + + // Define Generator.prototype.{next,throw,return} in terms of the + // unified ._invoke helper method. + defineIteratorMethods(Gp); + + define(Gp, toStringTagSymbol, "Generator"); + + // A Generator should always return itself as the iterator object when the + // @@iterator function is called on it. Some browsers' implementations of the + // iterator prototype chain incorrectly implement this, causing the Generator + // object to not be returned from this call. This ensures that doesn't happen. + // See https://github.com/facebook/regenerator/issues/274 for more details. + define(Gp, iteratorSymbol, function() { + return this; + }); + + define(Gp, "toString", function() { + return "[object Generator]"; + }); + + function pushTryEntry(locs) { + var entry = { tryLoc: locs[0] }; + + if (1 in locs) { + entry.catchLoc = locs[1]; + } + + if (2 in locs) { + entry.finallyLoc = locs[2]; + entry.afterLoc = locs[3]; + } + + this.tryEntries.push(entry); + } + + function resetTryEntry(entry) { + var record = entry.completion || {}; + record.type = "normal"; + delete record.arg; + entry.completion = record; + } + + function Context(tryLocsList) { + // The root entry object (effectively a try statement without a catch + // or a finally block) gives us a place to store values thrown from + // locations where there is no enclosing try statement. + this.tryEntries = [{ tryLoc: "root" }]; + tryLocsList.forEach(pushTryEntry, this); + this.reset(true); + } + + exports.keys = function(object) { + var keys = []; + for (var key in object) { + keys.push(key); + } + keys.reverse(); + + // Rather than returning an object with a next method, we keep + // things simple and return the next function itself. + return function next() { + while (keys.length) { + var key = keys.pop(); + if (key in object) { + next.value = key; + next.done = false; + return next; + } + } + + // To avoid creating an additional object, we just hang the .value + // and .done properties off the next function object itself. This + // also ensures that the minifier will not anonymize the function. + next.done = true; + return next; + }; + }; + + function values(iterable) { + if (iterable) { + var iteratorMethod = iterable[iteratorSymbol]; + if (iteratorMethod) { + return iteratorMethod.call(iterable); + } + + if (typeof iterable.next === "function") { + return iterable; + } + + if (!isNaN(iterable.length)) { + var i = -1, next = function next() { + while (++i < iterable.length) { + if (hasOwn.call(iterable, i)) { + next.value = iterable[i]; + next.done = false; + return next; + } + } + + next.value = undefined$1; + next.done = true; + + return next; + }; + + return next.next = next; + } + } + + // Return an iterator with no values. + return { next: doneResult }; + } + exports.values = values; + + function doneResult() { + return { value: undefined$1, done: true }; + } + + Context.prototype = { + constructor: Context, + + reset: function(skipTempReset) { + this.prev = 0; + this.next = 0; + // Resetting context._sent for legacy support of Babel's + // function.sent implementation. + this.sent = this._sent = undefined$1; + this.done = false; + this.delegate = null; + + this.method = "next"; + this.arg = undefined$1; + + this.tryEntries.forEach(resetTryEntry); + + if (!skipTempReset) { + for (var name in this) { + // Not sure about the optimal order of these conditions: + if (name.charAt(0) === "t" && + hasOwn.call(this, name) && + !isNaN(+name.slice(1))) { + this[name] = undefined$1; + } + } + } + }, + + stop: function() { + this.done = true; + + var rootEntry = this.tryEntries[0]; + var rootRecord = rootEntry.completion; + if (rootRecord.type === "throw") { + throw rootRecord.arg; + } + + return this.rval; + }, + + dispatchException: function(exception) { + if (this.done) { + throw exception; + } + + var context = this; + function handle(loc, caught) { + record.type = "throw"; + record.arg = exception; + context.next = loc; + + if (caught) { + // If the dispatched exception was caught by a catch block, + // then let that catch block handle the exception normally. + context.method = "next"; + context.arg = undefined$1; + } + + return !! caught; + } + + for (var i = this.tryEntries.length - 1; i >= 0; --i) { + var entry = this.tryEntries[i]; + var record = entry.completion; + + if (entry.tryLoc === "root") { + // Exception thrown outside of any try block that could handle + // it, so set the completion value of the entire function to + // throw the exception. + return handle("end"); + } + + if (entry.tryLoc <= this.prev) { + var hasCatch = hasOwn.call(entry, "catchLoc"); + var hasFinally = hasOwn.call(entry, "finallyLoc"); + + if (hasCatch && hasFinally) { + if (this.prev < entry.catchLoc) { + return handle(entry.catchLoc, true); + } else if (this.prev < entry.finallyLoc) { + return handle(entry.finallyLoc); + } + + } else if (hasCatch) { + if (this.prev < entry.catchLoc) { + return handle(entry.catchLoc, true); + } + + } else if (hasFinally) { + if (this.prev < entry.finallyLoc) { + return handle(entry.finallyLoc); + } + + } else { + throw new Error("try statement without catch or finally"); + } + } + } + }, + + abrupt: function(type, arg) { + for (var i = this.tryEntries.length - 1; i >= 0; --i) { + var entry = this.tryEntries[i]; + if (entry.tryLoc <= this.prev && + hasOwn.call(entry, "finallyLoc") && + this.prev < entry.finallyLoc) { + var finallyEntry = entry; + break; + } + } + + if (finallyEntry && + (type === "break" || + type === "continue") && + finallyEntry.tryLoc <= arg && + arg <= finallyEntry.finallyLoc) { + // Ignore the finally entry if control is not jumping to a + // location outside the try/catch block. + finallyEntry = null; + } + + var record = finallyEntry ? finallyEntry.completion : {}; + record.type = type; + record.arg = arg; + + if (finallyEntry) { + this.method = "next"; + this.next = finallyEntry.finallyLoc; + return ContinueSentinel; + } + + return this.complete(record); + }, + + complete: function(record, afterLoc) { + if (record.type === "throw") { + throw record.arg; + } + + if (record.type === "break" || + record.type === "continue") { + this.next = record.arg; + } else if (record.type === "return") { + this.rval = this.arg = record.arg; + this.method = "return"; + this.next = "end"; + } else if (record.type === "normal" && afterLoc) { + this.next = afterLoc; + } + + return ContinueSentinel; + }, + + finish: function(finallyLoc) { + for (var i = this.tryEntries.length - 1; i >= 0; --i) { + var entry = this.tryEntries[i]; + if (entry.finallyLoc === finallyLoc) { + this.complete(entry.completion, entry.afterLoc); + resetTryEntry(entry); + return ContinueSentinel; + } + } + }, + + "catch": function(tryLoc) { + for (var i = this.tryEntries.length - 1; i >= 0; --i) { + var entry = this.tryEntries[i]; + if (entry.tryLoc === tryLoc) { + var record = entry.completion; + if (record.type === "throw") { + var thrown = record.arg; + resetTryEntry(entry); + } + return thrown; + } + } + + // The context.catch method must only be called with a location + // argument that corresponds to a known catch block. + throw new Error("illegal catch attempt"); + }, + + delegateYield: function(iterable, resultName, nextLoc) { + this.delegate = { + iterator: values(iterable), + resultName: resultName, + nextLoc: nextLoc + }; + + if (this.method === "next") { + // Deliberately forget the last sent value so that we don't + // accidentally pass it on to the delegate. + this.arg = undefined$1; + } + + return ContinueSentinel; + } + }; + + // Regardless of whether this script is executing as a CommonJS module + // or not, return the runtime object so that we can declare the variable + // regeneratorRuntime in the outer scope, which allows this module to be + // injected easily by `bin/regenerator --include-runtime script.js`. + return exports; + + }( + // If this script is executing as a CommonJS module, use module.exports + // as the regeneratorRuntime namespace. Otherwise create a new empty + // object. Either way, the resulting object will be used to initialize + // the regeneratorRuntime variable at the top of this file. + module.exports + )); + + try { + regeneratorRuntime = runtime; + } catch (accidentalStrictMode) { + // This module should not be running in strict mode, so the above + // assignment should always work unless something is misconfigured. Just + // in case runtime.js accidentally runs in strict mode, in modern engines + // we can explicitly access globalThis. In older engines we can escape + // strict mode using a global Function call. This could conceivably fail + // if a Content Security Policy forbids using Function, but in that case + // the proper solution is to fix the accidental strict mode problem. If + // you've misconfigured your bundler to force strict mode and applied a + // CSP to forbid Function, and you're not willing to fix either of those + // problems, please detail your unique predicament in a GitHub issue. + if (typeof globalThis === "object") { + globalThis.regeneratorRuntime = runtime; + } else { + Function("r", "regeneratorRuntime = r")(runtime); + } + } + }(runtime)); + + class ShiftCipher{constructor(){this.makeCipherMap({chars:"abcdefghijklmnopqrstuvqxyz",shift:13});}encode(str){return this.rotateChars(str,this.cipherMap)}decode(str){return this.rotateChars(str,this.reversedCipherMap)}makeCipherMap({chars:chars,shift:shift}){shift%=chars.length;let shiftedChars=chars.slice(shift)+chars.slice(0,shift);shiftedChars+=shiftedChars.toUpperCase(),chars+=chars.toUpperCase(),this.cipherMap=new Map(chars.split("").map((i,j)=>[i,shiftedChars[j]]));}get reversedCipherMap(){const reversedChars=[...this.cipherMap.entries()].map(i=>i.reverse());return new Map(reversedChars)}rotateChars(str,cipherMap){return str.split("").map(i=>cipherMap.get(i)||i).join("")}} + + function decode(str, n, alphabet) { + var cipher = new ShiftCipher(); + cipher.makeCipherMap({ + chars: alphabet, + shift: n + }); + return cipher.decode(str.toLocaleUpperCase()); + } + function encode(str, n, alphabet) { + var cipher = new ShiftCipher(); + cipher.makeCipherMap({ + chars: alphabet, + shift: n + }); + return cipher.encode(str.toLocaleUpperCase()); + } + + function start(letters) { + do { + var type = prompt('Hvort viltu kóða eða afkóða streng?') || ''; + var typeLowered = type.toLocaleLowerCase(); + + if (typeLowered !== 'kóða' && typeLowered !== 'afkóða') { + alert("Veit ekki hva\xF0a a\xF0ger\xF0 \u201E".concat(type, "\u201C er. Reyndu aftur.")); + continue; + } + + var nInput = prompt('Hversu mikið á að hliðra streng?'); + var n = Number.parseInt(nInput, 10); + + if (!Number.isInteger(n) || n < 1 || n > letters.length - 1) { + alert("".concat(nInput, " er ekki r\xE9tt. Reyndu aftur.")); + continue; + } + + var str = prompt('Gefðu upp strenginn sem á að hliðra:'); + + if (!str || str.length === 0) { + alert('Þú gafst ekki upp streng. Reyndu aftur.'); + continue; + } + + var invalid = []; + + for (var i = 0; i < str.length; i++) { + var letter = (str[i] || '').toLocaleUpperCase(); + + if (letters.indexOf(letter) < 0) { + invalid.push(letter); + } + } + + if (invalid.length > 0) { + alert("\xDE\xFA gafst upp \xF3l\xF6glega stafi: ".concat(invalid.join(', '), ".")); + continue; + } + + var result = ''; + + if (typeLowered === 'kóða') { + result = encode(str, n, letters); + } else { + result = decode(str, n, letters); + } + + alert("Ni\xF0ursta\xF0a:\n".concat(result)); // eslint-disable-next-line no-restricted-globals + } while (confirm('Aftur?')); + } + + var LETTERS = 'AÁBDÐEÉFGHIÍJKLMNOÓPRSTUÚVXYÝÞÆÖ'; // erum ekki að nota async await, en með því að merkja fallið sem async + // mun babel innifela kóða til að láta virka og stækka bundle helling + + document.addEventListener('DOMContentLoaded', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() { + return regeneratorRuntime.wrap(function _callee$(_context) { + while (1) { + switch (_context.prev = _context.next) { + case 0: + console.log(encode('HALLÓ', 3, LETTERS)); + start(LETTERS); + + case 2: + case "end": + return _context.stop(); + } + } + }, _callee); + }))); + +})(); diff --git a/namsefni/37.tools/daemi/index.html b/namsefni/37.tools/daemi/index.html new file mode 100644 index 0000000..e113876 --- /dev/null +++ b/namsefni/37.tools/daemi/index.html @@ -0,0 +1,12 @@ + + + + + + Fyrirlestur 12 tækja dæmi + + +

shift-cipher

+ + + diff --git a/namsefni/37.tools/daemi/package.json b/namsefni/37.tools/daemi/package.json new file mode 100644 index 0000000..eed2825 --- /dev/null +++ b/namsefni/37.tools/daemi/package.json @@ -0,0 +1,26 @@ +{ + "name": "tools", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "build": "rollup -c", + "rollup-watch": "rollup -c -w" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@babel/cli": "^7.16.0", + "@babel/core": "^7.16.0", + "@babel/preset-env": "^7.16.0", + "@rollup/plugin-babel": "^5.3.0", + "@rollup/plugin-commonjs": "^21.0.1", + "@rollup/plugin-node-resolve": "^13.0.6", + "rollup": "^2.59.0", + "rollup-plugin-terser": "^7.0.2" + }, + "dependencies": { + "shift-cipher": "^1.0.0" + } +} diff --git a/namsefni/37.tools/daemi/readme.md b/namsefni/37.tools/daemi/readme.md new file mode 100644 index 0000000..3a6648d --- /dev/null +++ b/namsefni/37.tools/daemi/readme.md @@ -0,0 +1,11 @@ +# Rollup + babel + npm dæmi + +Notar Rollup með babel, commonjs og resolve-node plugin til að nýta [`shift-cipher`](https://github.com/Bwca/shift-cipher) til að útfæra Ceasar cipher. + +Keyrt með + +```bash +npm run build +``` + +opna síðan `index.html` í vafra, _buildaður_ kóði verður í `dist/`. diff --git a/namsefni/37.tools/daemi/rollup.config.js b/namsefni/37.tools/daemi/rollup.config.js new file mode 100644 index 0000000..bf577b4 --- /dev/null +++ b/namsefni/37.tools/daemi/rollup.config.js @@ -0,0 +1,32 @@ +import { babel } from '@rollup/plugin-babel'; +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import { terser } from 'rollup-plugin-terser'; +import commonjs from '@rollup/plugin-commonjs'; + +const config = { + input: 'src/index.js', + output: { + file: 'dist/bundle.js', + format: 'iife' + }, + plugins: [ + nodeResolve({ preferBuiltins: false }), + commonjs(), + babel({ + babelHelpers: 'bundled', + exclude: 'node_modules/**', + presets: [ + [ + '@babel/preset-env', { + useBuiltIns: 'usage', + corejs: 2, + targets: '> 0.25%, not dead', + }, + ], + ], + }), + // terser() + ] +}; + +export default config; diff --git a/namsefni/37.tools/daemi/src/cipher.js b/namsefni/37.tools/daemi/src/cipher.js new file mode 100644 index 0000000..f52150c --- /dev/null +++ b/namsefni/37.tools/daemi/src/cipher.js @@ -0,0 +1,23 @@ +import { ShiftCipher } from 'shift-cipher'; + +export function decode(str, n, alphabet) { + const cipher = new ShiftCipher(); + + cipher.makeCipherMap({ + chars: alphabet, + shift: n, + }); + + return cipher.decode(str.toLocaleUpperCase()); +} + +export function encode(str, n, alphabet) { + const cipher = new ShiftCipher(); + + cipher.makeCipherMap({ + chars: alphabet, + shift: n, + }); + + return cipher.encode(str.toLocaleUpperCase()); +} diff --git a/namsefni/37.tools/daemi/src/index.js b/namsefni/37.tools/daemi/src/index.js new file mode 100644 index 0000000..ad94c0a --- /dev/null +++ b/namsefni/37.tools/daemi/src/index.js @@ -0,0 +1,13 @@ +// Grunnskrá sem vírar saman virkni + +import { encode } from './cipher'; +import ui from './ui'; + +const LETTERS = 'AÁBDÐEÉFGHIÍJKLMNOÓPRSTUÚVXYÝÞÆÖ'; + +// erum ekki að nota async await, en með því að merkja fallið sem async +// mun babel innifela kóða til að láta virka og stækka bundle helling +document.addEventListener('DOMContentLoaded', async () => { + console.log(encode('HALLÓ', 3, LETTERS)); + ui(LETTERS); +}); diff --git a/namsefni/37.tools/daemi/src/ui.js b/namsefni/37.tools/daemi/src/ui.js new file mode 100644 index 0000000..ac11c90 --- /dev/null +++ b/namsefni/37.tools/daemi/src/ui.js @@ -0,0 +1,53 @@ +/* eslint-disable no-alert */ + +import { decode, encode } from './cipher'; + +export default function start(letters) { + do { + const type = prompt('Hvort viltu kóða eða afkóða streng?') || ''; + const typeLowered = type.toLocaleLowerCase(); + + if (typeLowered !== 'kóða' && typeLowered !== 'afkóða') { + alert(`Veit ekki hvaða aðgerð „${type}“ er. Reyndu aftur.`); + continue; + } + + const nInput = prompt('Hversu mikið á að hliðra streng?'); + const n = Number.parseInt(nInput, 10); + if (!Number.isInteger(n) || n < 1 || n > letters.length - 1) { + alert(`${nInput} er ekki rétt. Reyndu aftur.`); + continue; + } + + const str = prompt('Gefðu upp strenginn sem á að hliðra:'); + + if (!str || str.length === 0) { + alert('Þú gafst ekki upp streng. Reyndu aftur.'); + continue; + } + + const invalid = []; + for (let i = 0; i < str.length; i++) { + const letter = (str[i] || '').toLocaleUpperCase(); + if (letters.indexOf(letter) < 0) { + invalid.push(letter); + } + } + + if (invalid.length > 0) { + alert(`Þú gafst upp ólöglega stafi: ${invalid.join(', ')}.`); + continue; + } + + let result = ''; + if (typeLowered === 'kóða') { + result = encode(str, n, letters); + } else { + result = decode(str, n, letters); + } + + alert(`Niðurstaða:\n${result}`); + + // eslint-disable-next-line no-restricted-globals + } while (confirm('Aftur?')); +} diff --git a/namsefni/37.tools/readme.md b/namsefni/37.tools/readme.md new file mode 100644 index 0000000..39a3a7a --- /dev/null +++ b/namsefni/37.tools/readme.md @@ -0,0 +1,13 @@ +# Tæki og tól + +[Fyrirlestur](1.tools.md), [vídeó](https://youtu.be/ALaPtDXEdgY) + +## Dæmi + +* [Dæmi](daemi/) + +## Ítarefni + +* [Babel](https://babeljs.io/) +* [`corejs`](https://github.com/zloirock/core-js) +* [Rollup](https://rollupjs.org/) diff --git a/namsefni/38.objects/1.objects.md b/namsefni/38.objects/1.objects.md new file mode 100644 index 0000000..b60309e --- /dev/null +++ b/namsefni/38.objects/1.objects.md @@ -0,0 +1,561 @@ +--- +title: Fyrirlestur – Hlutir +--- + +# Fyrirlestur – Hlutir + +## Vefforritun 1 — TÖL107G + +### Ólafur Sverrir Kjartansson, [osk@hi.is](mailto:osk@hi.is) + +--- + +## Hlutir og hjúpun + +* Objects & [encapsulation](https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)) +* Ein af aðal hugmyndum hlutbundinnar forritunar er að skipta forritum upp og láta hvern hluta bera ábyrgð á eigin stöðu +* Hjúpum virkni og flækjustig, vinnum með í gegnum _interface_ + +*** + +## Methods + +* Method er fall á hlut +* Hvað ef við viljum nálgast gögn á hlutnum úr falli? +* Notum `this` + +*** + +## `this` + +* [`this`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) hagar sér öðruvísi í JavaScript en í öðrum málum +* Skilgreinist af því hvernig kallað er í fallið +* Utan hluta er `this` global hluturinn, þ.e. þar sem allt er geymt (í browser `window`) + +*** + +```javascript +function logThis() { console.log(this); } +const Obj = { + logThis() { console.log(this); }, +}; +const btn = document.querySelector('button'); +btn.addEventListener('click', logThis); + +console.log(this); // window +logThis(); // window +Obj.logThis(); // {logThis: f} +btn.click(); // + + + diff --git a/namsefni/38.objects/img/rabbits.svg b/namsefni/38.objects/img/rabbits.svg new file mode 100644 index 0000000..5ee2dac --- /dev/null +++ b/namsefni/38.objects/img/rabbits.svg @@ -0,0 +1,13 @@ + + +toString: <function>...teeth: "small"speak: <function>killerRabbitteeth: "long, sharp, ..."type: "killer"RabbitprototypeObjectcreate: <function>prototype... diff --git a/namsefni/38.objects/readme.md b/namsefni/38.objects/readme.md new file mode 100644 index 0000000..76f1463 --- /dev/null +++ b/namsefni/38.objects/readme.md @@ -0,0 +1,19 @@ +# Hlutir + +[Fyrirlestur: Hlutir](1.objects.md), [vídeó (28:35)](https://youtu.be/wqQz9ETMEdg) + +## Lesefni + +* [Eloquent JavaScript, kafli 6: The Secret Life of Objects](https://eloquentjavascript.net/06_object.html) + +## Dæmi + +* [`this` dæmi](./daemi/01.this.html) + +## Ítarefni + +* [Encapsulation á Wikipedia](https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)) +* [`this`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) +* [Object prototypes](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes) +* [Inheritance and the prototype chain](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain) +* [Classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) diff --git a/namsefni/39.testing/1.testing.md b/namsefni/39.testing/1.testing.md new file mode 100644 index 0000000..85b9c58 --- /dev/null +++ b/namsefni/39.testing/1.testing.md @@ -0,0 +1,245 @@ +--- +title: Fyrirlestur – Prófanir +--- + +# Fyrirlestur – Prófanir + +## Vefforritun 1 — TÖL107G + +### Ólafur Sverrir Kjartansson, [osk@hi.is](mailto:osk@hi.is) + +--- + +## Sjálfvirkar prófanir + +* Þegar við skrifum kóða erum við alltaf að athuga hvernig hann virkar +* Gerum það yfirleitt handvirkt +* Getum eytt tíma og skrifað próf fyrir þessa handvirku athugun +* Höfum séð aðeins með `console.assert()` + +*** + +## Kostir prófa + +* Getum keyrt mörg próf hratt, aftur og aftur +* „Notum“ kóðann okkar á meðan við skrifum hann, getum endað með betra API +* Gefur okkur ákveðið traust á virkni og að við munum ekki brjóta hana seinna meir + +*** + +## Ókostir prófa + +* Það tekur töluvert lengri tíma að skrifa próf en að athuga eitthvað handvirkt _í fyrstu_ +* Geta gefið okkur _falskt_ öryggi um að það séu ekki villur í kóðanum okkar því við skrifuðum próf +* Við breytingar á kóða þarf að uppfæra próf + * ef það er erfitt er mun auðveldara að slökkva bara á þeim + +*** + +## Unit test + +* [Unit test](https://en.wikipedia.org/wiki/Unit_testing) er ekki vel skilgreint hugtak en.. +* Próf á einni einingu í einu án þess að horfa á alla heildina + * Eining gæti verið fall, klasi, módull +* Sumir segja að unit test eigi _ekki_ að snerta á I/O (fara yfir net, lesa af disk) eða einhverju fyrir utan einingu + +*** + +* Hjálpa okkur við að komast að því hvernig við viljum smíða forritið okkar +* Fáum endurgjöf hratt og örugglega meðan við erum að skrifa +* Leyfa okkur að breyta kóða með vissu öryggi — erum með próf til staðar sem grípa villur + +*** + +* Prófin geta komið í stað eða aukið við skjölun, sýna bókstaflega hvernig kerfið virkar +* Fyrir villur sem finnast getum við skrifað próf áður en við lögum + * Minnkum líkur á að villa komi upp aftur + +*** + +## Skilvirk test + +* Einföld & DRY (Don't Repeat Yourself) + * Einn hlutur í einu +* Óhað röð sem þau eru keyrð í +* Endurtakanleg (repeatable) með sömu niðurstöðum +* _Hröð_, viljum ekki vera að bíða eftir keyrslu, eiga helst að keyra undir 1 sek + +*** + +## Assertions — staðhæfingar + +* Við skrifum prófin okkar þ.a. þau staðhæfi eitthvað í lokin + * Við gefum rétt gildi og athugum hvort það sé eins + * `assert(result === 'foo');` +* Ættum að hafa færri en fleiri staðhæfingar í hverju prófi +* Ein leið til að skipuleggja próf er að fylgja [_arrange, act, assert_](http://wiki.c2.com/?ArrangeActAssert) + +*** + +## Arrange, Act, Assert + +```javascript +const input = 'bar'; // Arrange + +const result = reverse(input); // Act + +assert(result === 'rab'); // Assert +``` + +*** + +## Test-driven development (TDD) + +Í [Test-driven development (TDD)](https://en.wikipedia.org/wiki/Test-driven_development) ítrum við: + +1. Skrifum próf sem bregst +2. Skrifum kóða sem lætur öll prófi heppnast +3. Hreinsum/refactorum kóða og keyrum próf + +*** + +![TDD flæði](img/tdd.png "Mynd: https://en.wikipedia.org/wiki/File:Test-driven_development.PNG") + +*** + +## Jest + +* [Jest](https://jestjs.io/) er JavaScript testing framework +* Virkar með allskonar, t.d.: JavaScript, React, TypeScript, Node +* Sækjum með + * `npm install --save-dev jest` + +*** + +```javascript +import { describe, expect, it } from '@jest/globals'; +import { reverse } from '../src/lib/reverse.js'; + +describe('main.js', () => { + it('should reverse a string', () => { + const input = 'bar'; + + const result = reverse(input); + + expect(result).toBe('rab'); + }); +}); +``` + +*** + +Til að geta prófað kóða skrifaðann fyrir JavaScript modules, þurfum við að: + +* Setja `"type": "module"` í `package.json` +* Keyra með Node með flagginu `--experimental-vm-modules` sem kveikir á stuðning + * `"test": "NODE_OPTIONS='--experimental-vm-modules' jest ./test/*.js"` + +--- + +## Continuous integration + +* [Continuous integration (CI)](https://en.wikipedia.org/wiki/Continuous_integration) er þegar við keyrum öll test við hvert commit í source control +* „Integration“ kemur frá því að við erum að _integratea_ við `main` branch + * Ef það er gert sjaldan getur komið upp staða þar sem gefa á út og það þarf að mergea mörgu í einu + * _Integration hell_ +* Ákveðið traust á því að `main` sé alltaf tilbúið til útgáfu + +*** + +## Continuous deployment + +* [Continuous deployment (CD)](https://en.wikipedia.org/wiki/Continuous_deployment) er þegar við gefum `main` út á raunkerfi fyrir hverja breytingu sem stenst próf +* Höldum `main` alltaf í _deployable_ ástandi +* Hægt að gefa út oft á dag +* Netlify uppsetningar, eins og við höfum verið að nota þær, nýta continuous deployment + +*** + +## Netlify + +* Getum stillt þannig að Netlify keyri prófin okkar _áður_ en gefið út +* Svo lengi sem testin okkar grípa ákveðnar villur, munu þær ekki komast út á raunkerfi +* Fáum aukið öryggi í continuous deployment ferlið okkar + +*** + +[Netlify CI dæmi](https://github.com/vefforritun/vef1-2021-netlify-ci) + +--- + +## Önnur tól + +* Að nota sjálfvirk próf er gott, en oft þurfum við líka að nota „handvirk“ próf +* Höfum notað í haust: HTML validator, Jigsaw CSS validator, aXe + +*** + +## Performance atriði + +Hversu „performant“ vefirnir okkar er margþætt verkefni sem snertir á öllu sem viðkemur vefforritun, t.d. + +* Hvaða forritunarumhverfi við notum í bakenda +* Hvernig við útfærum bakenda, t.d. tengingar við gagnagrunn og vefþjónustur +* Hversu hratt við skilum efni á framenda + +*** + +* Hvaða forritunarumhverfi við notum á framenda +* Hve mikið af JavaScript við hlöðum inn +* Hve mikið af efni (myndum, myndböndum) við vísum í +* Hvort við séum að nota CDN +* o.fl. + +--- + +## Core Web Vitals + +* [Core Web Vitals](https://web.dev/vitals/) eru mælistikur frá Google sem eiga að mæla hluti sem hafa raunveruleg áhrif á notendur +* Í dag eru þrír hlutir mældir + +*** + +## Largest Contentful Paint (LCP) + +* [Largest Contentful Paint (LCP)](https://web.dev/lcp/) mælir hversu langan tíma það tekur að birta „mikilvægasta“ efni síðu + * Túlka mikilvægast sem stærsta +* Áður var oft mælt [First Meaningful Paint (FMP)](https://web.dev/first-meaningful-paint/) sem tímann sem það tók fyrsta efni vefs að birtast + +*** + +![LCP skjáskot](./img/lcp1.png) + +*** + +![LCP skjáskot](./img/lcp2.png) + +*** + +## First Input Delay (FID) + +* [First Input Delay (FID)](https://web.dev/fid/) mælir hversu langan tíma það tekur frá fyrstu gagnvirkni (interaction) þar til henni er svarað +* Þetta getur verið hægt í byrjun því verið er að sækja gögn, vinna úr þeim eða eiga við DOM + +*** + +## Cumulative Layout Shift (CLS) + +* [Cumulative Layout Shift (CLS)](https://web.dev/cls/) mælir hversu mikið efni á síðu færist til meðan verið er að klára að sækja öll gögn og teikna +* Efni sem færist mikið til getur verið afsakplega hvimleitt og valdið því að maður ýti vitlaust eða missi af efni + +--- + +## Performance debug + +* Ef við erum með hlut sem veldur hægagangi eða lækkar skor hjá okkur getur verið misauðvelt að laga þau +* [Performance debug](https://developer.chrome.com/docs/devtools/evaluate-performance/) tólið í Chrome er kraftmikið og getur hjálpað við að debugga þetta + * Mjög mikið af upplýsingum og getur verið erfitt að átta sig á til að byrja með + +*** + +## Tól + +* [Lighthouse](https://developers.google.com/web/tools/lighthouse/) í Chrome keyrir allskonar próf, t.d. fyrir Core Web Vitals og „Best Practices“ +* [PageSpeed Insights](https://developers.google.com/speed/pagespeed/insights/) bíður upp á að keyra svipuð próf á miðlægum þjón +* [WebPageTest](https://www.webpagetest.org/) keyrir hraðamælingar, hversu vel svör frá bakenda eru, CDN notkun o.fl. diff --git a/namsefni/39.testing/img/lcp1.png b/namsefni/39.testing/img/lcp1.png new file mode 100644 index 0000000..ac995f4 Binary files /dev/null and b/namsefni/39.testing/img/lcp1.png differ diff --git a/namsefni/39.testing/img/lcp2.png b/namsefni/39.testing/img/lcp2.png new file mode 100644 index 0000000..b48ca49 Binary files /dev/null and b/namsefni/39.testing/img/lcp2.png differ diff --git a/namsefni/39.testing/img/tdd.png b/namsefni/39.testing/img/tdd.png new file mode 100644 index 0000000..64491d4 Binary files /dev/null and b/namsefni/39.testing/img/tdd.png differ diff --git a/namsefni/39.testing/readme.md b/namsefni/39.testing/readme.md new file mode 100644 index 0000000..574967e --- /dev/null +++ b/namsefni/39.testing/readme.md @@ -0,0 +1,21 @@ +# Prófanir + +[Fyrirlestur: Prófanir](1.testing.md), [vídeó (44:56)](https://youtu.be/ukPMToSzFRc) + +## Ítarefni + +* [Encapsulation á Wikipedia](https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)) +* [`this`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) +* [Object prototypes](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes) +* [Inheritance and the prototype chain](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain) +* [Classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) +* [Unit test](https://en.wikipedia.org/wiki/Unit_testing) +* [Arrange Act Assert](http://wiki.c2.com/?ArrangeActAssert) +* [Test-driven development (TDD)](https://en.wikipedia.org/wiki/Test-driven_development) +* [Continuous integration (CI)](https://en.wikipedia.org/wiki/Continuous_integration) +* [Continuous deployment (CD)](https://en.wikipedia.org/wiki/Continuous_deployment) +* [Core Web Vitals](https://web.dev/vitals/) +* [Performance debug](https://developer.chrome.com/docs/devtools/evaluate-performance/) +* [Lighthouse](https://developers.google.com/web/tools/lighthouse/) +* [PageSpeed Insights](https://developers.google.com/speed/pagespeed/insights/) +* [WebPageTest](https://www.webpagetest.org/) diff --git a/namsefni/40.html5/1.html5.md b/namsefni/40.html5/1.html5.md new file mode 100644 index 0000000..3466b4b --- /dev/null +++ b/namsefni/40.html5/1.html5.md @@ -0,0 +1,125 @@ +--- +title: Fyrirlestur – JavaScript API í vafra +--- + +# Fyrirlestur – JavaScript API í vafra + +## Vefforritun 1 — TÖL107G + +### Ólafur Sverrir Kjartansson, [osk@hi.is](mailto:osk@hi.is) + +--- + +## Vafra API + +* Vafrar hafa mörg JavaScript API +* Leyfa okkur að gera áhugaverða hluti +* Höfum séð nokkur, lítum á nokkur í viðbót, [enn fleiri til](https://developer.mozilla.org/en-US/docs/Web/API) + +*** + +## localStorage & sessionStorage + +* Vistum strengi í vafra með `window.localStorage` + * `setItem(key, value)` vistar `value` undir `key` + * `removeItem(key)` fjarlægir gögn undir `key` + * `getItem(key)` sækir gögn undir `key` + +*** + +* Notum JSON ef við þurfum að vista flóknari gagnategundir, þurfum að sjá um að þýða á milli +* `sessionStorage` virkar aðeins í þessu „session“, gögn þurrkast út þegar glugga/tab er lokað + +[`localStorage` Dæmi](daemi/01.localstorage.html) + +*** + +## Multimedia + +* Getum unnið með vídeó og hljóð í gegnum `