You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

749 lines
69 KiB

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
  7. <meta name="apple-mobile-web-app-capable" content="yes">
  8. <meta name="apple-mobile-web-app-status-bar-style" content="black">
  9. <meta name="mobile-web-app-capable" content="yes">
  10. <title>
  11. Lab 9: System time and Package managers - HackMD
  12. </title>
  13. <link rel="icon" type="image/png" href="https://hackmd.io/favicon.png">
  14. <link rel="apple-touch-icon" href="https://hackmd.io/apple-touch-icon.png">
  15. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha256-916EbMg70RQy9LHiGkXzG8hSg9EdNy97GazNG/aiY1w=" crossorigin="anonymous" />
  16. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha256-eZrrJcwDc/3uDhsdt61sL2oOBY362qM3lon1gyExkL0=" crossorigin="anonymous" />
  17. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ionicons/2.0.1/css/ionicons.min.css" integrity="sha256-3iu9jgsy9TpTwXKb7bNQzqWekRX7pPK+2OLj3R922fo=" crossorigin="anonymous" />
  18. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/octicons/3.5.0/octicons.min.css" integrity="sha256-QiWfLIsCT02Sdwkogf6YMiQlj4NE84MKkzEMkZnMGdg=" crossorigin="anonymous" />
  19. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/themes/prism.min.css" integrity="sha256-vtR0hSWRc3Tb26iuN2oZHt3KRUomwTufNIf5/4oeCyg=" crossorigin="anonymous" />
  20. <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@hackmd/emojify.js@2.1.0/dist/css/basic/emojify.min.css" integrity="sha256-UOrvMOsSDSrW6szVLe8ZDZezBxh5IoIfgTwdNDgTjiU=" crossorigin="anonymous" />
  21. <style>
  22. @import url(https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,500,500i|Source+Code+Pro:300,400,500|Source+Sans+Pro:300,300i,400,400i,600,600i|Source+Serif+Pro&subset=latin-ext);.hljs{background:#fff;color:#333;display:block;overflow-x:auto;padding:.5em}.hljs-comment,.hljs-meta{color:#969896}.hljs-emphasis,.hljs-quote,.hljs-string,.hljs-strong,.hljs-template-variable,.hljs-variable{color:#df5000}.hljs-keyword,.hljs-selector-tag,.hljs-type{color:#a71d5d}.hljs-attribute,.hljs-bullet,.hljs-literal,.hljs-number,.hljs-symbol{color:#0086b3}.hljs-built_in,.hljs-builtin-name{color:#005cc5}.hljs-name,.hljs-section{color:#63a35c}.hljs-tag{color:#333}.hljs-attr,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo,.hljs-title{color:#795da3}.hljs-addition{background-color:#eaffea;color:#55a532}.hljs-deletion{background-color:#ffecec;color:#bd2c00}.hljs-link{text-decoration:underline}.markdown-body{word-wrap:break-word;font-size:16px;line-height:1.5}.markdown-body:after,.markdown-body:before{content:"";display:table}.markdown-body:after{clear:both}.markdown-body>:first-child{margin-top:0!important}.markdown-body>:last-child{margin-bottom:0!important}.markdown-body a:not([href]){color:inherit;text-decoration:none}.markdown-body .absent{color:#c00}.markdown-body .anchor{float:left;line-height:1;margin-left:-20px;padding-right:4px}.markdown-body .anchor:focus{outline:none}.markdown-body blockquote,.markdown-body dl,.markdown-body ol,.markdown-body p,.markdown-body pre,.markdown-body table,.markdown-body ul{margin-bottom:16px;margin-top:0}.markdown-body hr{background-color:#e7e7e7;border:0;height:.25em;margin:24px 0;padding:0}.markdown-body blockquote{border-left:.25em solid #ddd;color:#777;font-size:16px;padding:0 1em}.markdown-body blockquote>:first-child{margin-top:0}.markdown-body blockquote>:last-child{margin-bottom:0}.markdown-body kbd,.popover kbd{background-color:#fcfcfc;border:1px solid;border-color:#ccc #ccc #bbb;border-radius:3px;box-shadow:inset 0 -1px 0 #bbb;color:#555;display:inline-block;font-size:11px;line-height:10px;padding:3px 5px;vertical-align:middle}.markdown-body .loweralpha{list-style-type:lower-alpha}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{font-weight:600;line-height:1.25;margin-bottom:16px;margin-top:24px}.markdown-body h1 .octicon-link,.markdown-body h2 .octicon-link,.markdown-body h3 .octicon-link,.markdown-body h4 .octicon-link,.markdown-body h5 .octicon-link,.markdown-body h6 .octicon-link{color:#000;vertical-align:middle;visibility:hidden}.markdown-body h1:hover .anchor,.markdown-body h2:hover .anchor,.markdown-body h3:hover .anchor,.markdown-body h4:hover .anchor,.markdown-body h5:hover .anchor,.markdown-body h6:hover .anchor{text-decoration:none}.markdown-body h1:hover .anchor .octicon-link,.markdown-body h2:hover .anchor .octicon-link,.markdown-body h3:hover .anchor .octicon-link,.markdown-body h4:hover .anchor .octicon-link,.markdown-body h5:hover .anchor .octicon-link,.markdown-body h6:hover .anchor .octicon-link{visibility:visible}.markdown-body h1 code,.markdown-body h1 tt,.markdown-body h2 code,.markdown-body h2 tt,.markdown-body h3 code,.markdown-body h3 tt,.markdown-body h4 code,.markdown-body h4 tt,.markdown-body h5 code,.markdown-body h5 tt,.markdown-body h6 code,.markdown-body h6 tt{font-size:inherit}.markdown-body h1{font-size:2em}.markdown-body h1,.markdown-body h2{border-bottom:1px solid #eee;padding-bottom:.3em}.markdown-body h2{font-size:1.5em}.markdown-body h3{font-size:1.25em}.markdown-body h4{font-size:1em}.markdown-body h5{font-size:.875em}.markdown-body h6{color:#777;font-size:.85em}.markdown-body ol,.markdown-body ul{padding-left:2em}.markdown-body ol.no-list,.markdown-body ul.no-list{list-style-type:none;padding:0}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-bottom:0;margin-top:0}.markdown-body li>p{margin-top:16px}.markdown-body li+li{padding-top:.25em}.markdown-body dl{padding:0}.markdown-body dl dt{font-size:1em;font-style:italic;font-weight:700;margin-top:16px;padding:0}.markdown-body dl dd{margin-bottom:16px;padding:0 16px}.markdown-body table{display:block;overflow:auto;width:100%;word-break:normal;word-break:keep-all}.markdown-body table th{font-weight:700}.markdown-body table td,.markdown-body table th{border:1px solid #ddd;padding:6px 13px}.markdown-body table tr{background-color:#fff;border-top:1px solid #ccc}.markdown-body table tr:nth-child(2n){background-color:#f8f8f8}.markdown-body img{background-color:#fff;box-sizing:initial;max-width:100%}.markdown-body img[align=right]{padding-left:20px}.markdown-body img[align=left]{padding-right:20px}.markdown-body .emoji{background-color:initial;max-width:none;vertical-align:text-top}.markdown-body span.frame{display:block;overflow:hidden}.markdown-body span.frame>span{border:1px solid #ddd;display:block;float:left;margin:13px 0 0;overflow:hidden;padding:7px;width:auto}.markdown-body span.frame span img{display:block;float:left}.markdown-body span.frame span span{clear:both;color:#333;display:block;padding:5px 0 0}.markdown-body span.align-center{clear:both;display:block;overflow:hidden}.markdown-body span.align-center>span{display:block;margin:13px auto 0;overflow:hidden;text-align:center}.markdown-body span.align-center span img{margin:0 auto;text-align:center}.markdown-body span.align-right{clear:both;display:block;overflow:hidden}.markdown-body span.align-right>span{display:block;margin:13px 0 0;overflow:hidden;text-align:right}.markdown-body span.align-right span img{margin:0;text-align:right}.markdown-body span.float-left{display:block;float:left;margin-right:13px;overflow:hidden}.markdown-body span.float-left span{margin:13px 0 0}.markdown-body span.float-right{display:block;float:right;margin-left:13px;overflow:hidden}.markdown-body span.float-right>span{display:block;margin:13px auto 0;overflow:hidden;text-align:right}.markdown-body code,.markdown-body tt{background-color:#0000000a;border-radius:3px;font-size:85%;margin:0;padding:.2em 0}.markdown-body code:after,.markdown-body code:before,.markdown-body tt:after,.markdown-body tt:before{content:"\00a0";letter-spacing:-.2em}.markdown-body code br,.markdown-body tt br{display:none}.markdown-body del code{text-decoration:inherit}.markdown-body pre{word-wrap:normal}.markdown-body pre>code{background:#0000;border:0;font-size:100%;margin:0;padding:0;white-space:pre;word-break:normal}.markdown-body .highlight{margin-bottom:16px}.markdown-body .highlight pre{margin-bottom:0;word-break:normal}.markdown-body .highlight pre,.markdown-body pre{background-color:#f7f7f7;border-radius:3px;font-size:85%;line-height:1.45;overflow:auto;padding:16px}.markdown-body pre code,.markdown-body pre tt{word-wrap:normal;background-color:initial;border:0;display:inline;line-height:inherit;margin:0;max-width:auto;overflow:visible;padding:0}.markdown-body pre code:after,.markdown-body pre code:before,.markdown-body pre tt:after,.markdown-body pre tt:before{content:normal}.markdown-body .csv-data td,.markdown-body .csv-data th{font-size:12px;line-height:1;overflow:hidden;padding:5px;text-align:left;white-space:nowrap}.markdown-body .csv-data .blob-line-num{background:#fff;border:0;padding:10px 8px 9px;text-align:right}.markdown-body .csv-data tr{border-top:0}.markdown-body .csv-data th{background:#f8f8f8;border-top:0;font-weight:700}.news .alert .markdown-body blockquote{border:0;padding:0 0 0 40px}.activity-tab .news .alert .commits,.activity-tab .news .markdown-body blockquote{padding-left:0}.task-list-item{list-style-type:none}.task-list-item label{font-weight:400}.task-list-item.enabled label{cursor:pointer}.task-list-item+.task-list-item{margin-top:3px}.task-list-item-checkbox{cursor:default!important;float:left;margin:.31em 0 .2em -1.3em!important;vertical-align:middle}.markdown-body{max-width:758px;overflow:visible!important;padding-bottom:40px;padding-top:40px;position:relative}.markdown-body .emoji{vertical-align:top}.markdown-body pre{border:inherit!important}.markdown-body code{color:inherit!important}.markdown-body pre code .wrapper{display:-moz-inline-flex;display:-ms-inline-flex;display:-o-inline-flex;display:inline-flex}.markdown-body pre code .gutter{float:left;overflow:hidden;-webkit-user-select:none;user-select:none}.markdown-body pre code .gutter.linenumber{border-right:3px solid #6ce26c!important;box-sizing:initial;color:#afafaf!important;cursor:default;display:inline-block;min-width:20px;padding:0 8px 0 0;position:relative;text-align:right;z-index:4}.markdown-body pre code .gutter.linenumber>span:before{content:attr(data-linenumber)}.markdown-body pre code .code{float:left;margin:0 0 0 16px}.markdown-body .gist .line-numbers{border-bottom:none;border-left:none;border-top:none}.markdown-body .gist .line-data{border:none}.markdown-body .gist table{border-collapse:inherit!important;border-spacing:0}.markdown-body code[data-gist-id]{background:none;padding:0}.markdown-body code[data-gist-id]:after,.markdown-body code[data-gist-id]:before{content:""}.markdown-body code[data-gist-id] .blob-num{border:unset}.markdown-body code[data-gist-id] table{margin-bottom:unset;overflow:unset}.markdown-body code[data-gist-id] table tr{background:unset}.markdown-body[dir=rtl] pre{direction:ltr}.markdown-body[dir=rtl] code{direction:ltr;unicode-bidi:embed}.markdown-body .alert>p:last-child{margin-bottom:0}.markdown-body pre.abc,.markdown-body pre.flow-chart,.markdown-body pre.graphviz,.markdown-body pre.mermaid,.markdown-body pre.sequence-diagram,.markdown-body pre.vega{background-color:inherit;border-radius:0;overflow:visible;text-align:center;white-space:inherit}.markdown-body pre.abc>code,.markdown-body pre.flow-chart>code,.markdown-body pre.graphviz>code,.markdown-body pre.mermaid>code,.markdown-body pre.sequence-diagram>code,.markdown-body pre.vega>code{text-align:left}.markdown-body pre.abc>svg,.markdown-body pre.flow-chart>svg,.markdown-body pre.graphviz>svg,.markdown-body pre.mermaid>svg,.markdown-body pre.sequence-diagram>svg,.markdown-body pre.vega>svg{height:100%;max-width:100%}.markdown-body pre>code.wrap{word-wrap:break-word;white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap}.markdown-body .alert>p:last-child,.markdown-body .alert>ul:last-child{margin-bottom:0}.markdown-body summary{display:list-item}.markdown-body summary:focus{outline:none}.markdown-body details summary{cursor:pointer}.markdown-body details:not([open])>:not(summary){display:none}.markdown-body figure{margin:1em 40px}.markdown-body .mark,.markdown-body mark{background-color:#fff1a7}.vimeo,.youtube{background-color:#000;background-position:50%;background-repeat:no-repeat;background-size:contain;cursor:pointer;display:table;overflow:hidden;text-align:center}.vimeo,.youtube{position:relative;width:100%}.youtube{padding-bottom:56.25%}.vimeo img{object-fit:contain;width:100%;z-index:0}.youtube img{object-fit:cover;z-index:0}.vimeo iframe,.youtube iframe,.youtube img{height:100%;left:0;position:absolute;top:0;width:100%}.vimeo iframe,.youtube iframe{vertical-align:middle;z-index:1}.vimeo .icon,.youtube .icon{color:#fff;height:auto;left:50%;opacity:.3;position:absolute;top:50%;transform:translate(-50%,-50%);transition:opacity .2s;width:auto;z-index:0}.vimeo:hover .icon,.youtube:hover .icon{opacity:.6;transition:opacity .2s}.slideshare .inner,.speakerdeck .inner{position:relative;width:100%}.slideshare .inner iframe,.speakerdeck .inner iframe{bottom:0;height:100%;left:0;position:absolute;right:0;top:0;width:100%}.figma{display:table;padding-bottom:56.25%;position:relative;width:100%}.figma iframe{border:1px solid #eee;bottom:0;height:100%;left:0;position:absolute;right:0;top:0;width:100%}.markmap-container{height:300px}.markmap-container>svg{height:100%;width:100%}.MJX_Assistive_MathML{display:none}#MathJax_Message{z-index:1000!important}.ui-infobar{color:#777;margin:25px auto -25px;max-width:760px;position:relative;z-index:2}.toc .invisable-node{list-style-type:none}.ui-toc{bottom:20px;position:fixed;z-index:998}.ui-toc.both-mode{margin-left:8px}.ui-toc.both-mode .ui-toc-label{border-bottom-left-radius:0;border-top-left-radius:0;height:40px;padding:10px 4px}.ui-toc-label{background-color:#e6e6e6;border:none;color:#868686;transition:opacity .2s}.ui-toc .open .ui-toc-label{color:#fff;opacity:1;transition:opacity .2s}.ui-toc-label:focus{background-color:#ccc;color:#000;opacity:.3}.ui-toc-label:hover{background-color:#ccc;opacity:1;transition:opacity .2s}.ui-toc-dropdown{margin-bottom:20px;margin-top:20px;max-height:70vh;max-width:45vw;overflow:auto;padding-left:10px;padding-right:10px;text-align:inherit;width:25vw}.ui-toc-dropdown>.toc{max-height:calc(70vh - 100px);overflow:auto}.ui-toc-dropdown[dir=rtl] .nav{letter-spacing:.0029em;padding-right:0}.ui-toc-dropdown a{overflow:hidden;text-overflow:ellipsis;white-space:pre}.ui-toc-dropdown .nav>li>a{color:#767676;display:block;font-size:13px;font-weight:500;padding:4px 20px}.ui-toc-dropdown .nav>li:first-child:last-child>ul,.ui-toc-dropdown .toc.expand ul{display:block}.ui-toc-dropdown .nav>li>a:focus,.ui-toc-dropdown .nav>li>a:hover{background-color:initial;border-left:1px solid #000;color:#000;padding-left:19px;text-decoration:none}.ui-toc-dropdown[dir=rtl] .nav>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav>li>a:hover{border-left:none;border-right:1px solid #000;padding-right:19px}.ui-toc-dropdown .nav>.active:focus>a,.ui-toc-dropdown .nav>.active:hover>a,.ui-toc-dropdown .nav>.active>a{background-color:initial;border-left:2px solid #000;color:#000;font-weight:700;padding-left:18px}.ui-toc-dropdown[dir=rtl] .nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav>.active>a{border-left:none;border-right:2px solid #000;padding-right:18px}.ui-toc-dropdown .nav .nav{display:none;padding-bottom:10px}.ui-toc-dropdown .nav>.active>ul{display:block}.ui-toc-dropdown .nav .nav>li>a{font-size:12px;font-weight:400;padding-bottom:1px;padding-left:30px;padding-top:1px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>a{padding-right:30px}.ui-toc-dropdown .nav .nav>li>ul>li>a{font-size:12px;font-weight:400;padding-bottom:1px;padding-left:40px;padding-top:1px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a{padding-right:40px}.ui-toc-dropdown .nav .nav>li>a:focus,.ui-toc-dropdown .nav .nav>li>a:hover{padding-left:29px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav .nav>li>a:hover{padding-right:29px}.ui-toc-dropdown .nav .nav>li>ul>li>a:focus,.ui-toc-dropdown .nav .nav>li>ul>li>a:hover{padding-left:39px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a:hover{padding-right:39px}.ui-toc-dropdown .nav .nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>a{font-weight:500;padding-left:28px}.ui-toc-dropdown[dir=rtl] .nav .nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>a{padding-right:28px}.ui-toc-dropdown .nav .nav>.active>.nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active>a{font-weight:500;padding-left:38px}.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active>a{padding-right:38px}.markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html[lang^=ja] .markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,MS ゴシック,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html[lang=zh-tw] .markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html[lang=zh-cn] .markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html .markdown-body[lang^=ja]{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,MS ゴシック,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html .markdown-body[lang=zh-tw]{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html .markdown-body[lang=zh-cn]{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html[lang^=ja] .ui-toc-dropdown{font-family:Source Sans Pro,Helvetica,Arial,Meiryo UI,MS PGothic,MS Pゴシック,sans-serif}html[lang=zh-tw] .ui-toc-dropdown{font-family:Source Sans Pro,Helvetica,Arial,Microsoft JhengHei UI,微軟正黑UI,sans-serif}html[lang=zh-cn] .ui-toc-dropdown{font-family:Source Sans Pro,Helvetica,Arial,Microsoft YaHei UI,微软雅黑UI,sans-serif}html .ui-toc-dropdown[lang^=ja]{font-family:Source Sans Pro,Helvetica,Arial,Meiryo UI,MS PGothic,MS Pゴシック,sans-serif}html .ui-toc-dropdown[lang=zh-tw]{font-family:Source Sans Pro,Helvetica,Arial,Microsoft JhengHei UI,微軟正黑UI,sans-serif}html .ui-toc-dropdown[lang=zh-cn]{font-family:Source Sans Pro,Helvetica,Arial,Microsoft YaHei UI,微软雅黑UI,sans-serif}.ui-affix-toc{max-height:70vh;max-width:15vw;overflow:auto;position:fixed;top:0}.back-to-top,.expand-toggle,.go-to-bottom{color:#999;display:block;font-size:12px;font-weight:500;margin-left:10px;margin-top:10px;padding:4px 10px}.back-to-top:focus,.back-to-top:hover,.expand-toggle:focus,.expand-toggle:hover,.go-to-bottom:focus,.go-to-bottom:hover{color:#563d7c;text-decoration:none}.back-to-top,.go-to-bottom{margin-top:0}.ui-user-icon{background-position:50%;background-repeat:no-repeat;background-size:cover;border-radius:50%;display:block;height:20px;margin-bottom:2px;margin-right:5px;margin-top:2px;width:20px}.ui-user-icon.small{display:inline-block;height:18px;margin:0 0 .2em;vertical-align:middle;width:18px}.ui-infobar>small>span{line-height:22px}.ui-infobar>small .dropdown{display:inline-block}.ui-infobar>small .dropdown a:focus,.ui-infobar>small .dropdown a:hover{text-decoration:none}.ui-more-info{color:#888;cursor:pointer;vertical-align:middle}.ui-more-info .fa{font-size:16px}.ui-connectedGithub,.ui-published-note{color:#888}.ui-connectedGithub{line-height:23px;white-space:nowrap}.ui-connectedGithub a.file-path{color:#888;padding-left:22px;text-decoration:none}.ui-connectedGithub a.file-path:active,.ui-connectedGithub a.file-path:hover{color:#888;text-decoration:underline}.ui-connectedGithub .fa{font-size:20px}.ui-published-note .fa{font-size:20px;vertical-align:top}.unselectable{-webkit-user-select:none;-o-user-select:none;user-select:none}.selectable{-webkit-user-select:text;-o-user-select:text;user-select:text}.inline-spoiler-section{cursor:pointer}.inline-spoiler-section .spoiler-text{background-color:#333;border-radius:2px}.inline-spoiler-section .spoiler-text>*{opacity:0}.inline-spoiler-section .spoiler-img{filter:blur(10px)}.inline-spoiler-section.raw{background-color:#333;border-radius:2px}.inline-spoiler-section.raw>*{opacity:0}.inline-spoiler-section.unveil{cursor:auto}.inline-spoiler-section.unveil .spoiler-text{background-color:#3333331a}.inline-spoiler-section.unveil .spoiler-text>*{opacity:1}.inline-spoiler-section.unveil .spoiler-img{filter:none}@media print{blockquote,div,img,pre,table{page-break-inside:avoid!important}a[href]:after{font-size:12px!important}}.markdown-body.slides{color:#222;position:relative;z-index:1}.markdown-body.slides:before{background-color:currentColor;bottom:0;box-shadow:0 0 0 50vw;content:"";display:block;left:0;position:absolute;right:0;top:0;z-index:-1}.markdown-body.slides section[data-markdown]{background-color:#fff;margin-bottom:1.5em;position:relative;text-align:center}.markdown-body.slides section[data-markdown] code{text-align:left}.markdown-body.slides section[data-markdown]:before{content:"";display:block;padding-bottom:56.23%}.markdown-body.slides section[data-markdown]>div:first-child{left:1em;max-height:100%;overflow:hidden;position:absolute;right:1em;top:50%;transform:translateY(-50%)}.markdown-body.slides section[data-markdown]>ul{display:inline-block}.markdown-body.slides>section>section+section:after{border:3px solid #777;content:"";height:1.5em;position:absolute;right:1em;top:-1.5em}.site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,sans-serif}html[lang^=ja] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,MS ゴシック,sans-serif}html[lang=zh-tw] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif}html[lang=zh-cn] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif}body{font-smoothing:subpixel-antialiased!important;-webkit-font-smoothing:subpixel-antialiased!important;-moz-osx-font-smoothing:auto!important;-webkit-overflow-scrolling:touch;font-family:Source Sans Pro,Helvetica,Arial,sans-serif;letter-spacing:.025em}html[lang^=ja] body{font-family:Source Sans Pro,Helvetica,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,MS ゴシック,sans-serif}html[lang=zh-tw] body{font-family:Source Sans Pro,Helvetica,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif}html[lang=zh-cn] body{font-family:Source Sans Pro,Helvetica,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}abbr[data-original-title],abbr[title]{cursor:help}body.modal-open{overflow-y:auto;padding-right:0!important}svg{text-shadow:none}
  23. </style>
  24. <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
  25. <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
  26. <!--[if lt IE 9]>
  27. <script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js" integrity="sha256-3Jy/GbSLrg0o9y5Z5n1uw0qxZECH7C6OQpVBgNFYa0g=" crossorigin="anonymous"></script>
  28. <script src="https://cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.min.js" integrity="sha256-g6iAfvZp+nDQ2TdTR/VVKJf3bGro4ub5fvWSWVRi2NE=" crossorigin="anonymous"></script>
  29. <script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.9/es5-shim.min.js" integrity="sha256-8E4Is26QH0bD52WoQpcB+R/tcWQtpzlCojrybUd7Mxo=" crossorigin="anonymous"></script>
  30. <![endif]-->
  31. </head>
  32. <body>
  33. <div id="doc" class="markdown-body container-fluid comment-enabled" data-hard-breaks="true"><h1 id="Lab-9-System-time-and-Package-managers" data-id="Lab-9-System-time-and-Package-managers"><a class="anchor hidden-xs" href="#Lab-9-System-time-and-Package-managers" title="Lab-9-System-time-and-Package-managers"><span class="octicon octicon-link"></span></a><span>Lab 9: System time and Package managers</span></h1><h2 id="Exercise-1-System-time" data-id="Exercise-1-System-time"><a class="anchor hidden-xs" href="#Exercise-1-System-time" title="Exercise-1-System-time"><span class="octicon octicon-link"></span></a><span>Exercise 1: System time</span></h2><h3 id="Task-1-Time-zone" data-id="Task-1-Time-zone"><a class="anchor hidden-xs" href="#Task-1-Time-zone" title="Task-1-Time-zone"><span class="octicon octicon-link"></span></a><span>Task 1: Time zone</span></h3><ul>
  34. <li><span>Check the current time zone</span><pre><code>$ timedatectl
  35. </code></pre>
  36. <span>You should get output similar to the following:</span><pre><code> Local time: Вс 2022-11-06 12:40:33 +04
  37. Universal time: Вс 2022-11-06 08:40:33 UTC
  38. RTC time: Вс 2022-11-06 08:40:33
  39. Time zone: Europe/Samara (+04, +0400)
  40. System clock synchronized: yes
  41. NTP service: active
  42. RTC in local TZ: no
  43. </code></pre>
  44. </li>
  45. <li><span>Assume that we are in Vladivostok and we want to set the timezone to Vladivostok Standard Time (GMT +10). To do this, first get a list of all available time zones.</span><pre><code>$ timedatectl list-timezones
  46. </code></pre>
  47. <span>You will find the full name for the time zone in Vladivostok from the long list of output:</span><pre><code>Asia/Vladivostok
  48. </code></pre>
  49. </li>
  50. <li><span>Now that we have identified the name of the time zone on our system, switch to that with the following command:</span><pre><code>$ sudo timedatectl set-timezone Asia/Vladivostok
  51. </code></pre>
  52. </li>
  53. <li><span>Run </span><code>timedatectl</code><span> and you should get output different from what we had initially.</span><pre><code>$ timedatectl
  54. Local time: Вс 2022-11-06 18:55:05 +10
  55. Universal time: Вс 2022-11-06 08:55:05 UTC
  56. RTC time: Вс 2022-11-06 08:55:05
  57. Time zone: Asia/Vladivostok (+10, +1000)
  58. System clock synchronized: yes
  59. NTP service: active
  60. RTC in local TZ: no
  61. </code></pre>
  62. </li>
  63. <li><span>To see how this affects system logging, restart rsyslog to trigger some system log events.</span><pre><code>$ systemctl restart rsyslog
  64. </code></pre>
  65. </li>
  66. <li><span>View the log file </span><code>/var/log/syslog</code><span>.</span><pre><code>$ tail -n 15 /var/log/syslog
  67. </code></pre>
  68. <span>You should see output similar to the following with noticeable change in the timestamp.</span><pre><code>Nov 6 12:55:35 sna-vm systemd[1]: systemd-timedated.service: Deactivated successfully.
  69. Nov 6 12:57:44 sna-vm systemd[1606]: Started VTE child process 4376 launched by gnome-terminal-server process 2335.
  70. Nov 6 18:57:54 sna-vm systemd[1]: Stopping System Logging Service...
  71. Nov 6 18:57:54 sna-vm rsyslogd: [origin software="rsyslogd" swVersion="8.2112.0" x-pid="889" x-info="https://www.rsyslog.com"] exiting on signal 15.
  72. Nov 6 18:57:54 sna-vm systemd[1]: rsyslog.service: Deactivated successfully.
  73. Nov 6 18:57:54 sna-vm systemd[1]: Stopped System Logging Service.
  74. Nov 6 18:57:54 sna-vm systemd[1]: Starting System Logging Service...
  75. </code></pre>
  76. </li>
  77. </ul><h4 id="Change-time-zone-with-symlink" data-id="Change-time-zone-with-symlink"><a class="anchor hidden-xs" href="#Change-time-zone-with-symlink" title="Change-time-zone-with-symlink"><span class="octicon octicon-link"></span></a><span>Change time zone with symlink</span></h4><ul>
  78. <li><span>You can manually change the time zone with a symlink. The symlink at </span><code>/etc/localtime</code><span> points to the time zone that is currently configured.</span><pre><code>$ ls -l /etc/localtime
  79. lrwxrwxrwx 1 root root 36 ноя 6 18:54 /etc/localtime -&gt; /usr/share/zoneinfo/Asia/Vladivostok
  80. </code></pre>
  81. </li>
  82. <li><span>Remove the symlink</span><pre><code>$ sudo rm -rf /etc/localtime
  83. </code></pre>
  84. </li>
  85. <li><span>Let’s change time zone to Moscow time. To do this, create a new symlink to the Moscow time </span><code>Europe/Moscow</code><span> in </span><code>/usr/share/zoneinfo/</code><span>.</span><pre><code>$ sudo ln -s /usr/share/zoneinfo/Europe/Moscow /etc/localtime
  86. </code></pre>
  87. </li>
  88. <li><span>Check the time zone again.</span><pre><code>$ timedatectl
  89. </code></pre>
  90. </li>
  91. </ul><h3 id="Task-2-NTP" data-id="Task-2-NTP"><a class="anchor hidden-xs" href="#Task-2-NTP" title="Task-2-NTP"><span class="octicon octicon-link"></span></a><span>Task 2: NTP</span></h3><p><span>We are going to set up an NTP server and then configure a client to use this NTP server. You need two VMs to test this. You can work in pairs to set up the client-sever infrastructure.</span></p><h4 id="Installing-and-configuring-an-NTP-server" data-id="Installing-and-configuring-an-NTP-server"><a class="anchor hidden-xs" href="#Installing-and-configuring-an-NTP-server" title="Installing-and-configuring-an-NTP-server"><span class="octicon octicon-link"></span></a><span>Installing and configuring an NTP server</span></h4><ul>
  92. <li>
  93. <p><span>First install NTP and it’s dependencies.</span></p>
  94. <pre><code>$ apt install -y ntp
  95. $ apt install -y ntpstat
  96. </code></pre>
  97. </li>
  98. <li>
  99. <p><span>Open the NTP configuration file </span><code>/etc/ntp.conf</code><span> and configure the remote NTP server.</span></p>
  100. <pre><code>$ vi /etc/ntp.conf
  101. </code></pre>
  102. <p><span>Locate the following lines in the configuration file</span><br>
  103. <img src="https://i.imgur.com/7LLFXIN.png" alt="" loading="lazy"></p>
  104. <p><span>Replace those lines with the following</span></p>
  105. <pre><code class="hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
  106. <span></span>
  107. <span></span>
  108. <span></span></div><div class="code">pool time1.google.com iburst
  109. pool time2.google.com iburst
  110. pool time3.google.com iburst
  111. pool time4.google.com iburst
  112. </div></div></code></pre>
  113. <p><span>Also place a comment on </span><code>pool ntp.ubuntu.com</code><span>.</span><br>
  114. <span>You should have something similar to the following after this modification:</span><br>
  115. <img src="https://i.imgur.com/fsGWV7w.png" alt="" loading="lazy"></p>
  116. </li>
  117. <li>
  118. <p><span>Restart and enable the NTP service to apply the change.</span></p>
  119. <pre><code>$ systemctl restart ntp
  120. $ systemctl enable ntp
  121. </code></pre>
  122. </li>
  123. <li>
  124. <p><span>Allow NTP port on the firewall.</span></p>
  125. <pre><code>$ sudo ufw allow ntp
  126. </code></pre>
  127. </li>
  128. <li>
  129. <p><span>It will take some time for your NTP server to synchronize with the google NTP servers. Wait for about a minute and run the following command to check the sync status:</span></p>
  130. <pre><code>$ ntpstat
  131. </code></pre>
  132. <p><span>You should get output similar to the following:</span></p>
  133. <pre><code>synchronised to NTP server (185.125.190.56) at stratum 3
  134. time correct to within 977 ms
  135. polling server every 64 s
  136. </code></pre>
  137. <p><span>The local NTP server is ready.</span></p>
  138. </li>
  139. <li>
  140. <p><span>View all NTP peers.</span></p>
  141. <pre><code>$ ntpq -p
  142. remote refid st t when poll reach delay offset jitter
  143. ==============================================================================
  144. time1.google.co .POOL. 16 p - 64 0 0.000 +0.000 0.004
  145. time2.google.co .POOL. 16 p - 64 0 0.000 +0.000 0.004
  146. time3.google.co .POOL. 16 p - 64 0 0.000 +0.000 0.004
  147. time4.google.co .POOL. 16 p - 64 0 0.000 +0.000 0.004
  148. +time1.google.co .GOOG. 1 u 15 64 1 70.098 +3.123 8.037
  149. *time2.google.co .GOOG. 1 u 17 64 1 38.087 +6.703 6.897
  150. +time3.google.co .GOOG. 1 u 15 64 1 39.216 +4.192 7.641
  151. +time4.google.co .GOOG. 1 u 18 64 1 62.781 +8.027 13.030
  152. </code></pre>
  153. </li>
  154. </ul><h4 id="Configuring-the-client" data-id="Configuring-the-client"><a class="anchor hidden-xs" href="#Configuring-the-client" title="Configuring-the-client"><span class="octicon octicon-link"></span></a><span>Configuring the client</span></h4><p><span>We show two approaches for configuring the client. You can use either the systemd service </span><code>systemd-timesyncd</code><span> that comes with systemd-based systems by default, or use </span><code>chronyd</code><span>.</span></p><h5 id="1-Using-systemd-timesyncd" data-id="1-Using-systemd-timesyncd"><a class="anchor hidden-xs" href="#1-Using-systemd-timesyncd" title="1-Using-systemd-timesyncd"><span class="octicon octicon-link"></span></a><span>1. Using </span><code>systemd-timesyncd</code></h5><ul>
  155. <li><span>Edit the service configuration file:</span><pre><code>$ vi /etc/systemd/timesyncd.conf
  156. </code></pre>
  157. <span>Add the following line to the file</span><pre><code>NTP=&lt;ntp-server-address&gt;
  158. </code></pre>
  159. <span>You should have something like this:</span><br>
  160. <img src="https://i.imgur.com/hfME91i.png" alt="" loading="lazy"><br>
  161. <span>Save and exit the file.</span></li>
  162. <li><span>Restart the time sync service</span><pre><code>$ systemctl restart systemd-timesyncd
  163. </code></pre>
  164. </li>
  165. <li><span>Check the status of the time synchronisation:</span><pre><code>$ timedatectl timesync-status
  166. Server: 192.168.132.136 (192.168.132.136)
  167. Poll interval: 1min 4s (min: 32s; max 34min 8s)
  168. Leap: normal
  169. Version: 4
  170. Stratum: 2
  171. Reference: D8EF2308
  172. Precision: 4us (-18)
  173. Root distance: 33.583ms (max: 5s)
  174. Offset: -9.704ms
  175. Delay: 675us
  176. Jitter: 0
  177. Packet count: 1
  178. Frequency: -81,109ppm
  179. </code></pre>
  180. </li>
  181. </ul><h5 id="2-Using-chrony" data-id="2-Using-chrony"><a class="anchor hidden-xs" href="#2-Using-chrony" title="2-Using-chrony"><span class="octicon octicon-link"></span></a><span>2. Using </span><code>chrony</code></h5><ul>
  182. <li><span>Install </span><code>chrony</code><pre><code>$ apt -y install chrony
  183. </code></pre>
  184. </li>
  185. <li><span>Edit the </span><code>chrony</code><span> configuration file:</span><pre><code>$ vi /etc/chrony/chrony.conf
  186. </code></pre>
  187. <span>Locate the following lines and remove them</span><br>
  188. <img src="https://i.imgur.com/HBAdgZW.png" alt="" loading="lazy"><br>
  189. <span>Then add the address of the local NTP server we have configured in the form:</span><pre><code>server &lt;ntp-server-address&gt; iburst prefer
  190. </code></pre>
  191. <img src="https://i.imgur.com/W5mlt6Z.png" alt="" loading="lazy"><br>
  192. <span>Save the configuration and exit.</span></li>
  193. <li><span>Restart and enable the </span><code>chronyd</code><span> service.</span><pre><code>$ systemctl restart chrony
  194. $ systemctl enable chrony
  195. </code></pre>
  196. </li>
  197. <li><span>View all sources</span><pre><code>$ chronyc sources -v
  198. </code></pre>
  199. <blockquote>
  200. <p><span>Remember that chrony is a client/server utility. Therefore, other devices can be configured to use this “client” as their NTP “server”.</span></p>
  201. </blockquote>
  202. </li>
  203. </ul><h4 id="Test-the-setup" data-id="Test-the-setup"><a class="anchor hidden-xs" href="#Test-the-setup" title="Test-the-setup"><span class="octicon octicon-link"></span></a><span>Test the setup</span></h4><ul>
  204. <li><span>First check the current time on the client system.</span><pre><code>$ timedatectl
  205. Local time: Вс 2022-11-06 18:35:16 MSK
  206. Universal time: Вс 2022-11-06 15:35:16 UTC
  207. RTC time: Пн 2022-11-07 11:49:46
  208. Time zone: Europe/Moscow (MSK, +0300)
  209. System clock synchronized: yes
  210. NTP service: active
  211. RTC in local TZ: no
  212. </code></pre>
  213. </li>
  214. <li><span>Go to the NTP server and change the date to something completely wrong.</span><pre><code>$ timedatectl set-time 2030-06-10
  215. </code></pre>
  216. </li>
  217. <li><span>Go to the client system and restart the timesync service to force an immediate sync with the local NTP server.</span><pre><code>$ systemctl restart systemd-timesyncd
  218. OR
  219. $ systemctl restart chrony
  220. </code></pre>
  221. </li>
  222. <li><span>Check the time on the client machine, and you should see that the client has been configured with the new date we added to the server.</span><pre><code>$ timedatectl
  223. Local time: Пн 2030-06-10 00:01:19 MSK
  224. Universal time: Вс 2030-06-09 21:01:19 UTC
  225. RTC time: Вс 2030-06-09 21:01:19
  226. Time zone: Europe/Moscow (MSK, +0300)
  227. System clock synchronized: yes
  228. NTP service: active
  229. RTC in local TZ: no
  230. </code></pre>
  231. </li>
  232. <li><span>The local NTP server will later sync with the Google NTP servers we configured earlier and correct its time. The client machine will then sync with the local NTP server and correct its time too.</span></li>
  233. <li><span>Wait for about a minute or two and check the time on the NTP server to see the change.</span><pre><code>$ timedatectl
  234. Local time: Вс 2022-11-06 18:42:19 MSK
  235. Universal time: Вс 2022-11-06 15:42:19 UTC
  236. RTC time: Вс 2022-11-06 15:42:19
  237. Time zone: Europe/Moscow (MSK, +0300)
  238. System clock synchronized: yes
  239. NTP service: n/a
  240. RTC in local TZ: no
  241. </code></pre>
  242. <span>The time on the client machine will also be corrected after a while.</span></li>
  243. </ul><h2 id="Exercise-2-Package-managers" data-id="Exercise-2-Package-managers"><a class="anchor hidden-xs" href="#Exercise-2-Package-managers" title="Exercise-2-Package-managers"><span class="octicon octicon-link"></span></a><span>Exercise 2: Package managers</span></h2><p><span>A package manager automates the process of installing, configuring, upgrading, and removing packages.</span><br>
  244. <span>There are several package managers depending on the OS. This lab focuses on Ubuntu package managers.</span><br>
  245. <span>Note that Ubuntu is based on the Debian distro and it uses the same APT packaging system as Debian and shares a huge number of packages and libraries from Debian repositories.</span></p><h3 id="Task-3-dpkg" data-id="Task-3-dpkg"><a class="anchor hidden-xs" href="#Task-3-dpkg" title="Task-3-dpkg"><span class="octicon octicon-link"></span></a><span>Task 3: dpkg</span></h3><p><code>dpkg</code><span> is a tool that allows the installation and analysis of </span><code>.deb</code><span> packages. It can also be used to package software.</span></p><ul>
  246. <li>
  247. <p><span>View a list of all installed packages</span></p>
  248. <pre><code>$ dpkg -l
  249. </code></pre>
  250. <p><span>You should get an output similar to the following:</span><br>
  251. <img src="https://i.imgur.com/Te0ZnIm.png" alt="" loading="lazy"></p>
  252. </li>
  253. <li>
  254. <p><span>Install a local </span><code>.deb</code><span> file using the command </span><code>dpkg -i &lt;deb-package&gt;</code><span>.</span><br>
  255. <span>Let’s download and install Google Chrome browser</span></p>
  256. <pre><code>$ wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
  257. $ dpkg -i google-chrome-stable_current_amd64.deb
  258. </code></pre>
  259. </li>
  260. <li>
  261. <p><span>Verify the package installation using </span><code>dpkg -s &lt;deb-package&gt;</code></p>
  262. <pre><code>$ dpkg -s google-chrome-stable
  263. </code></pre>
  264. <p><span>You get an output similar to the following</span></p>
  265. <pre><code>Package: google-chrome-stable
  266. Status: install ok installed
  267. Priority: optional
  268. Section: web
  269. Installed-Size: 299404
  270. Maintainer: Chrome Linux Team &lt;chromium-dev@chromium.org&gt;
  271. Architecture: amd64
  272. Version: 107.0.5304.87-1
  273. Provides: www-browser
  274. Depends: ca-certificates, fonts-liberation, libasound2 (&gt;= 1.0.17), libatk-bridge2.0-0 (&gt;= 2.5.3), libatk1.0-0 (&gt;= 2.2.0), libatspi2.0-0 (&gt;= 2.9.90), libc6 (&gt;= 2.17), libcairo2 (&gt;= 1.6.0), libcups2 (&gt;= 1.6.0), libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3, libdbus-1-3 (&gt;= 1.5.12), libdrm2 (&gt;= 2.4.60), libexpat1 (&gt;= 2.0.1), libgbm1 (&gt;= 8.1~0), libglib2.0-0 (&gt;= 2.39.4), libgtk-3-0 (&gt;= 3.9.10) | libgtk-4-1, libnspr4 (&gt;= 2:4.9-2~), libnss3 (&gt;= 2:3.26), libpango-1.0-0 (&gt;= 1.14.0), libwayland-client0 (&gt;= 1.0.2), libx11-6 (&gt;= 2:1.4.99.1), libxcb1 (&gt;= 1.9.2), libxcomposite1 (&gt;= 1:0.4.4-1), libxdamage1 (&gt;= 1:1.1), libxext6, libxfixes3, libxkbcommon0 (&gt;= 0.4.1), libxrandr2, wget, xdg-utils (&gt;= 1.0.2)
  275. Pre-Depends: dpkg (&gt;= 1.14.0)
  276. Recommends: libu2f-udev, libvulkan1
  277. Description: The web browser from Google
  278. Google Chrome is a browser that combines a minimal design with sophisticated technology to make the web faster, safer, and easier.
  279. </code></pre>
  280. </li>
  281. <li>
  282. <p><span>List all files installed by a package with the command </span><code>dpkg -L &lt;package-name&gt;</code></p>
  283. <pre><code>$ dpkg -L google-chrome-stable
  284. </code></pre>
  285. </li>
  286. <li>
  287. <p><span>Remove a package using </span><code>dpkg -r &lt;package-name&gt;</code></p>
  288. <pre><code>$ dpkg -r google-chrome-stable
  289. </code></pre>
  290. </li>
  291. <li>
  292. <p><span>Check the status of the package again and you should see that it is in the </span><code>deinstall</code><span> state, but the configuration files are still present.</span></p>
  293. <pre><code>$ dpkg -s google-chrome-stable
  294. Package: google-chrome-stable
  295. Status: deinstall ok config-files
  296. </code></pre>
  297. <p><span>The </span><code>-r</code><span> option simply removes the package but all the configuration files are preserved.</span></p>
  298. </li>
  299. <li>
  300. <p><span>To remove a package along with its configuration files, specify the </span><code>--purge</code><span> option.</span></p>
  301. <pre><code>$ dpkg --purge google-chrome-stable
  302. </code></pre>
  303. </li>
  304. <li>
  305. <p><span>Check the status of the package to verify that the package and all its configuration files have been removed.</span></p>
  306. <pre><code>$ dpkg -s google-chrome-stable
  307. dpkg-query: package 'google-chrome-stable' is not installed and no information is available
  308. Use dpkg --info (= dpkg-deb --info) to examine archive files.
  309. </code></pre>
  310. </li>
  311. </ul><h3 id="Task-4-APT" data-id="Task-4-APT"><a class="anchor hidden-xs" href="#Task-4-APT" title="Task-4-APT"><span class="octicon octicon-link"></span></a><span>Task 4: APT</span></h3><p><span>The Advanced Packaging Tools (APT) is a package manager on Ubuntu systems. </span><code>apt</code><span> acts as a user friendly tool that interacts with </span><code>dpkg</code><span>. Unlike </span><code>dpkg</code><span>, </span><code>apt</code><span> allows download and installation of packages from online repositories.</span></p><ul>
  312. <li><span>View all available packages in your repository</span><pre><code>$ apt list
  313. </code></pre>
  314. </li>
  315. <li><span>List only installed packages</span><pre><code>$ apt list --installed
  316. </code></pre>
  317. </li>
  318. <li><span>Search for a package using </span><code>apt search &lt;package-name&gt;</code><span>. Let’s search for “chromium”.</span><pre><code>$ apt search chromium
  319. </code></pre>
  320. <img src="https://i.imgur.com/EnpSwBv.png" alt="" loading="lazy"></li>
  321. <li><span>After knowing the correct package name, you can find out more details about the package using </span><code>apt show &lt;package-name&gt;</code><pre><code>$ apt show chromium-browser
  322. </code></pre>
  323. </li>
  324. <li><span>Proceed to install the package using </span><code>apt install &lt;package-name&gt;</code><pre><code>$ apt install chromium-browser
  325. </code></pre>
  326. </li>
  327. <li><span>Remove a package using </span><code>apt remove &lt;package-name&gt;</code><pre><code>$ apt remove chromium-browser
  328. </code></pre>
  329. </li>
  330. </ul><blockquote>
  331. <p><span>You can install or remove multiple packages in one command by separating them by spaces. e.g </span><code>apt install package1 package2 package3</code><span>.</span><br>
  332. <span>To remove multiple packages is similar e.g </span><code>apt remove package1 package2 package3</code><span>.</span></p>
  333. </blockquote><ul>
  334. <li><span>Specify the </span><code>remove</code><span> option in combination with the </span><code>--purge</code><span> option to remove a package along with its configuration.</span><pre><code>$ apt remove --purge chromium-browser
  335. </code></pre>
  336. </li>
  337. <li><span>Specify </span><code>autoremove</code><span> to remove the package and its dependencies, if not used by any other application. The format is shown below:</span><pre><code>$ apt autoremove &lt;package-name&gt;
  338. </code></pre>
  339. </li>
  340. <li><span>You can update the APT package index to get a list of the available packages. This list can indicate installed packages that need upgrading, as well as new packages that have been added to the repositories.</span><br>
  341. <span>The reposiroties are defined in the </span><code>/etc/apt/sources.list</code><span> file and in the </span><code>/etc/apt/sources.list.d</code><span> directory.</span></li>
  342. <li><span>View the </span><code>sources.list</code><span> file to see all the defined repositories.</span><pre><code>$ cat /etc/apt/sources.list
  343. </code></pre>
  344. </li>
  345. <li><span>To update the local package index with latest updates to repositories, use the following command:</span><pre><code>$ apt update
  346. </code></pre>
  347. </li>
  348. <li><span>APT maintains a list of packages (package index) in </span><code>/var/lib/apt/lists/</code><span>.</span><pre><code>$ ls -lah /var/lib/apt/lists/
  349. </code></pre>
  350. </li>
  351. <li><span>To upgrade a single package that has been previously installed, run the </span><code>apt install &lt;package-name&gt;</code><span> command.</span></li>
  352. <li><span>To upgrade all installed packages, run the following command:</span><pre><code>$ apt upgrade
  353. </code></pre>
  354. <span>This command will upgrade all packages that can be upgraded without installing additional packages or removing conflicting installed packages.</span></li>
  355. <li><span>Run </span><code>apt full-upgrade</code><span> to upgrade the packages, the kernel, and remove conflicting packages or install new ones. The </span><code>full-upgrade</code><span> option is “smart” and can remove unnecessary dependency packages, or install new ones (if required).</span></li>
  356. </ul><h3 id="Task-5-sourceslist" data-id="Task-5-sourceslist"><a class="anchor hidden-xs" href="#Task-5-sourceslist" title="Task-5-sourceslist"><span class="octicon octicon-link"></span></a><span>Task 5: sources.list</span></h3><ul>
  357. <li><span>View the </span><code>sources.list</code><span> file without the comments</span><pre><code>$ grep -o '^[^#]*' /etc/apt/sources.list
  358. deb http://ru.archive.ubuntu.com/ubuntu/ jammy main restricted
  359. deb http://ru.archive.ubuntu.com/ubuntu/ jammy-updates main restricted
  360. deb http://ru.archive.ubuntu.com/ubuntu/ jammy universe
  361. deb http://ru.archive.ubuntu.com/ubuntu/ jammy-updates universe
  362. deb http://ru.archive.ubuntu.com/ubuntu/ jammy multiverse
  363. deb http://ru.archive.ubuntu.com/ubuntu/ jammy-updates multiverse
  364. deb http://ru.archive.ubuntu.com/ubuntu/ jammy-backports main restricted universe multiverse
  365. deb http://security.ubuntu.com/ubuntu jammy-security main restricted
  366. deb http://security.ubuntu.com/ubuntu jammy-security universe
  367. deb http://security.ubuntu.com/ubuntu jammy-security multiverse
  368. </code></pre>
  369. </li>
  370. <li><span>Each line in the </span><code>sources.list</code><span> has a structure in the following order: </span><strong><span>Type</span></strong><span>, </span><strong><span>URL</span></strong><span>, </span><strong><span>Distribution</span></strong><span>, and </span><strong><span>Component</span></strong><span>. Let’s analyse the first line in the </span><code>sources.list</code><span> above.</span>
  371. <ul>
  372. <li><span>The </span><strong><span>Type</span></strong><span> is </span><code>deb</code><span>. The term </span><code>deb</code><span> indicates that it is a repository of binaries.</span></li>
  373. <li><span>The repository </span><strong><span>URL</span></strong><span> is </span><code>http://ru.archive.ubuntu.com/ubuntu/</code><span>. This is the location of the repository where the packages will be downloaded.</span></li>
  374. <li><span>The </span><strong><span>Distribution</span></strong><span> is </span><code>jammy</code><span>. This is the short code name of the release. Run </span><code>$ cat /etc/os-release</code><span> to view the </span><code>VERSION_CODENAME</code><span> of your system.</span></li>
  375. <li><span>The </span><strong><span>Components</span></strong><span> are </span><code>main</code><span> and </span><code>restricted</code><span>. These are information about the licensing of the packages in the repository.</span>
  376. <ul>
  377. <li><code>main</code><span> contains Canonical supported free and open source software.</span></li>
  378. <li><code>restricted</code><span> contains proprietary drivers for devices.</span></li>
  379. <li><code>universe</code><span> contains community supported free and open source software.</span></li>
  380. <li><code>multiverse</code><span> contains software restricted by copyright or legal issues.</span></li>
  381. </ul>
  382. </li>
  383. </ul>
  384. </li>
  385. </ul><h4 id="Adding-repositories" data-id="Adding-repositories"><a class="anchor hidden-xs" href="#Adding-repositories" title="Adding-repositories"><span class="octicon octicon-link"></span></a><span>Adding repositories</span></h4><ul>
  386. <li><span>Let’s try to install a package that is not in Ubuntu repository by default. Install MongoDB</span><pre><code>$ apt install mongo-db
  387. </code></pre>
  388. <span>You should get an output similar to the following</span><pre><code>Reading package lists... Done
  389. Building dependency tree... Done
  390. Reading state information... Done
  391. E: Unable to locate package mongodb-org
  392. </code></pre>
  393. <span>We need to add the MongoDB repository to our repository sources.</span></li>
  394. <li><span>The basic syntax of the add-apt-repository command is as follows:</span><pre><code>$ add-apt-repository [options] repository
  395. </code></pre>
  396. <span>The </span><code>repository</code><span> can be a regular repository entry that can be added to </span><code>sources.list</code><span> in the format </span><code>deb http://ru.archive.ubuntu.com/ubuntu/ distro component</code><span> or a PPA repository in the </span><code>ppa:&lt;user&gt;/&lt;ppa-name&gt;</code><span> format.</span></li>
  397. <li><span>First import MongoDB PGP key. The key is used to verify the integrity of packages that are downloaded from this repository.</span><pre><code>$ curl -fsSL https://www.mongodb.org/static/pgp/server-6.0.asc | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/mongodb-6.gpg
  398. </code></pre>
  399. </li>
  400. <li><span>Create a list for MongoDB</span><pre><code>$ add-apt-repository 'deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/6.0 multiverse'
  401. </code></pre>
  402. <blockquote>
  403. <p><span>Alternatively, you can manually create the list file and add the repository to it.</span></p>
  404. <pre><code>echo "echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/6.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list
  405. </code></pre>
  406. </blockquote>
  407. </li>
  408. <li><span>View the new list file that has been created</span><pre><code>$ cat /etc/apt/sources.list.d/*mongodb*.list
  409. </code></pre>
  410. </li>
  411. <li><span>The </span><code>add-apt-repository</code><span> command automatically updates the local package database for you. If you added the repository via an alternative means, you need to run </span><code>$ apt update</code><span> to update the local package database.</span></li>
  412. <li><span>View the package index directory to see the MongoDB related files created.</span><pre><code>$ ls -lah /var/lib/apt/lists/ | grep mongodb
  413. </code></pre>
  414. <blockquote>
  415. <p><span>MongoDB requires </span><code>libssl1.1 (&gt;= 1.1.1)</code><span>. So let’s download and install this package before proceeding</span></p>
  416. <pre><code>$ wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2.16_amd64.deb
  417. $ dpkg -i ./libssl1.1_1.1.1f-1ubuntu2.16_amd64.deb
  418. </code></pre>
  419. </blockquote>
  420. </li>
  421. <li><span>You can now proced to install MongoDB from the newly enabled repository.</span><pre><code>$ apt install mongodb-org
  422. </code></pre>
  423. <blockquote>
  424. <p><span>You can answer the prompt that asks you to type </span><code>Y</code><span> to verify your choice by adding the option </span><code>-y</code><span> to your install command in the format </span><code>apt install mongodb-org -y</code><span>. This is very useful when writing scripts that install packages.</span></p>
  425. </blockquote>
  426. </li>
  427. <li><span>Verify that MongoDB has been installed</span><pre><code>$ mongod --version
  428. </code></pre>
  429. </li>
  430. <li><span>You can remove a previously enabled repository using the format </span><code>add-apt-repository --remove repository</code><span>. Let’s remove the MongoDB repository</span><pre><code>$ add-apt-repository --remove 'deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/6.0 multiverse'
  431. </code></pre>
  432. </li>
  433. <li><span>Run the following commands to verify that the repository has been removed.</span><pre><code>$ ls -lah /var/lib/apt/lists/ | grep mongodb
  434. $ cat /etc/apt/sources.list.d/*mongodb*.list
  435. </code></pre>
  436. </li>
  437. </ul><h3 id="Task-6-Creating-a-custom-Ubuntu-package" data-id="Task-6-Creating-a-custom-Ubuntu-package"><a class="anchor hidden-xs" href="#Task-6-Creating-a-custom-Ubuntu-package" title="Task-6-Creating-a-custom-Ubuntu-package"><span class="octicon octicon-link"></span></a><span>Task 6: Creating a custom Ubuntu package</span></h3><ul data-original-title="" title="">
  438. <li><span>Create a directory for the package. We will name the package </span><code>snalab</code><span>.</span><pre><code>$ mkdir snalab
  439. </code></pre>
  440. </li>
  441. <li><span>Create the internal structure by placing your program files where they should be installed to on the target system. In this case, we want to place the program file in </span><code>/usr/local/bin</code><span> on the target system, therefore we create the directory </span><code>snalab11/usr/local/bin</code><span>.</span><pre><code>$ mkdir -p snalab/usr/local/bin
  442. </code></pre>
  443. </li>
  444. <li><span>Create the program file (script) </span><code>snalab/usr/local/bin/snalab</code><span> and add the following to it.</span><pre><code class="=bash hljs"><span class="hljs-meta">#!/bin/bash</span>
  445. <span class="hljs-built_in">echo</span> <span class="hljs-string">"Hello World. This is SNA Lab"</span>
  446. </code></pre>
  447. </li>
  448. <li><span>Give the program file execute permission</span><pre><code>chmod +x snalab/usr/local/bin/snalab
  449. </code></pre>
  450. </li>
  451. <li><span>Create a directory </span><code>DEBIAN</code><span> in </span><code>snalab</code><pre><code>$ mkdir snalab/DEBIAN
  452. </code></pre>
  453. </li>
  454. <li><span>Create the control file in the </span><code>DEBIAN</code><span> directory. The control file contains package description and information about the maintainer. Create the file </span><code>snalab/DEBIAN/control</code><span> and add the following content.</span><pre><code class="hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
  455. <span></span>
  456. <span></span>
  457. <span></span>
  458. <span></span></div><div class="code">Package: snalab
  459. Version: 1.0
  460. Maintainer: Awwal
  461. Architecture: all
  462. Description: Hello SNA
  463. </div></div></code></pre>
  464. <blockquote>
  465. <p><span>These are mandatory fields in the control file. There are several other fields that can be defined.</span></p>
  466. </blockquote>
  467. </li>
  468. <li><span>Build the package with </span><code>dpkg</code><pre><code>$ dpkg-deb --build --root-owner-group snalab
  469. </code></pre>
  470. <blockquote>
  471. <p><span>The </span><code>--root-owner-group</code><span> flag makes all deb package content owned by the root user. Without this flag, all files and folders would be owned by your user, which might not exist in the target system the deb package would be installed to.</span></p>
  472. </blockquote>
  473. </li>
  474. <li><span>You should have a debian package in your CWD named </span><code>snalab.deb</code><span>. Proceed to install this package.</span><pre><code>$ dpkg -i snalab.deb
  475. </code></pre>
  476. <span>You should get an output similar to the following</span><pre><code>Selecting previously unselected package snalab11.
  477. (Reading database ... 195723 files and directories currently installed.)
  478. Preparing to unpack snalab11.deb ...
  479. Unpacking snalab11 (1.0) ...
  480. Setting up snalab11 (1.0) ...
  481. </code></pre>
  482. </li>
  483. <li><span>Run the newly installed package.</span><pre><code>$ snalab
  484. Hello World. This is SNA Lab
  485. </code></pre>
  486. </li>
  487. </ul><blockquote>
  488. <p><span>You can have a compiled application in place of the script we have used.</span></p>
  489. </blockquote><h2 id="Questions-to-answer" data-id="Questions-to-answer"><a class="anchor hidden-xs" href="#Questions-to-answer" title="Questions-to-answer"><span class="octicon octicon-link"></span></a><span>Questions to answer</span></h2><blockquote>
  490. <p><strong><span>Instruction:</span></strong><span> Show all steps taken including screenshots of commands executed, files created, and configuration added.</span></p>
  491. </blockquote><ol>
  492. <li><span>What alternative do you have for configuring your NTP server pool if you don’t want to be dependent on NTP servers on the internet. The time must be accurate and appear to be in sync with other devices globally. Describe how you will perform this setup.</span>
  493. <blockquote>
  494. <p><span>The accuracy of the time should be strongly considered.</span></p>
  495. </blockquote>
  496. </li>
  497. <li><span>You have two Linux servers whose time won’t stay in sync for various reasons. They tend to drift so much that they have a 30 second difference after 7 days of operation. What can you do to ensure that they stay in sync with each other without relying on external devices or servers?</span>
  498. <blockquote>
  499. <p><span>Hint: Inaccurate time is not a problem in this case. The goal is to ensure that both servers are in sync.</span></p>
  500. </blockquote>
  501. </li>
  502. <li><span>What are the differences between </span><code>apt</code><span> and </span><code>apt-get</code><span>?</span></li>
  503. <li><span>Why should System Administrators prefer </span><code>apt upgrade</code><span> over </span><code>apt full-upgrade</code><span>?</span></li>
  504. <li><span>Show how you will install </span><strong><span>Atom</span></strong><span> text editor from the apt repository. Provide explanation for every step you take.</span>
  505. <ul>
  506. <li><span>After adding the repository, show the output when you run </span><code>$ apt search atom</code></li>
  507. </ul>
  508. <blockquote>
  509. <p><span>You are not allowed to manually download the debian package and install it.</span></p>
  510. </blockquote>
  511. </li>
  512. <li><span>Create an Ubuntu package that meets the following requirements:</span>
  513. <ul>
  514. <li><span>The package creates the directory </span><code>/var/helloworld/</code><span> on the target system.</span></li>
  515. <li><span>The package contains the python script </span><code>/var/helloworld/helloworld.py</code><span>. The python script is simple:</span><pre><code class="=python hljs"><span class="hljs-meta">#!/usr/bin/env python3</span>
  516. print(<span class="hljs-string">"Hello, World!"</span>)
  517. </code></pre>
  518. </li>
  519. <li><span>The package should deploy a bash script </span><code>helloworld</code><span> that executes </span><code>/var/helloworld/hello.py</code><span> on the target system.</span></li>
  520. </ul>
  521. </li>
  522. </ol><p><span>Take the following steps after building the package</span></p><ul>
  523. <li><span>List the content of the package with the command </span><code>$ dpkg -c &lt;package-name&gt;.deb</code><span>.</span></li>
  524. <li><span>Install the package and show all artifacts added to your system by the package.</span></li>
  525. </ul><blockquote>
  526. <p><span>After a user installs your package, he should be able to run </span><code>$ helloworld</code><span> from the terminal without additinonal steps.</span><br>
  527. <span>The expected flow of execution is </span><code>helloworld (bash script) -&gt; helloworld.py -&gt; Output (Hello, World!)</code></p>
  528. </blockquote><h3 id="Bonus" data-id="Bonus"><a class="anchor hidden-xs" href="#Bonus" title="Bonus"><span class="octicon octicon-link"></span></a><span>Bonus</span></h3><blockquote>
  529. <p><span>The bonus tasks encourage you to failiarize yourself with CentOS and RPM packages. Linux distributions such as Red Hat and CentOS are very common and they utilize RPM packages.</span></p>
  530. </blockquote><ol start="7">
  531. <li><span>Find and add new source repository to be used for yum.</span>
  532. <ul>
  533. <li><span>Install a package from it (for example MongoDB).</span></li>
  534. <li><span>Check with the RPM package manager to verify that the package was installed, and provide details such as dependencies needed.</span></li>
  535. <li><span>Find logs related to all actions from the previous steps.</span></li>
  536. </ul>
  537. </li>
  538. <li><span>Sometimes you might have access to an open-source application source code but might not have the RPM file to install it on your system. In that situation, you can either compile the source code and install the application from source code or build an RPM file from source code by yourself and use the RPM file to install the application. There might also be a situation where you want to build a custom RPM package for the application that you developed.</span><br>
  539. <span>Create an RPM package to deploy any application of your choice.</span></li>
  540. </ol></div>
  541. <div class="ui-toc dropup unselectable hidden-print" style="display:none;">
  542. <div class="pull-right dropdown">
  543. <a id="tocLabel" class="ui-toc-label btn btn-default" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false" title="Table of content">
  544. <i class="fa fa-bars"></i>
  545. </a>
  546. <ul id="ui-toc" class="ui-toc-dropdown dropdown-menu" aria-labelledby="tocLabel">
  547. <div class="toc"><ul class="nav">
  548. <li><a href="#Lab-9-System-time-and-Package-managers" title="Lab 9: System time and Package managers">Lab 9: System time and Package managers</a><ul class="nav">
  549. <li><a href="#Exercise-1-System-time" title="Exercise 1: System time">Exercise 1: System time</a><ul class="nav">
  550. <li><a href="#Task-1-Time-zone" title="Task 1: Time zone">Task 1: Time zone</a></li>
  551. <li><a href="#Task-2-NTP" title="Task 2: NTP">Task 2: NTP</a></li>
  552. </ul>
  553. </li>
  554. <li><a href="#Exercise-2-Package-managers" title="Exercise 2: Package managers">Exercise 2: Package managers</a><ul class="nav">
  555. <li><a href="#Task-3-dpkg" title="Task 3: dpkg">Task 3: dpkg</a></li>
  556. <li><a href="#Task-4-APT" title="Task 4: APT">Task 4: APT</a></li>
  557. <li><a href="#Task-5-sourceslist" title="Task 5: sources.list">Task 5: sources.list</a></li>
  558. <li><a href="#Task-6-Creating-a-custom-Ubuntu-package" title="Task 6: Creating a custom Ubuntu package">Task 6: Creating a custom Ubuntu package</a></li>
  559. </ul>
  560. </li>
  561. <li><a href="#Questions-to-answer" title="Questions to answer">Questions to answer</a><ul class="nav">
  562. <li><a href="#Bonus" title="Bonus">Bonus</a></li>
  563. </ul>
  564. </li>
  565. </ul>
  566. </li>
  567. </ul>
  568. </div><div class="toc-menu"><a class="expand-toggle" href="#">Expand all</a><a class="back-to-top" href="#">Back to top</a><a class="go-to-bottom" href="#">Go to bottom</a></div>
  569. </ul>
  570. </div>
  571. </div>
  572. <div id="ui-toc-affix" class="ui-affix-toc ui-toc-dropdown unselectable hidden-print" data-spy="affix" style="top:17px;display:none;" null null>
  573. <div class="toc"><ul class="nav">
  574. <li><a href="#Lab-9-System-time-and-Package-managers" title="Lab 9: System time and Package managers">Lab 9: System time and Package managers</a><ul class="nav">
  575. <li><a href="#Exercise-1-System-time" title="Exercise 1: System time">Exercise 1: System time</a><ul class="nav">
  576. <li><a href="#Task-1-Time-zone" title="Task 1: Time zone">Task 1: Time zone</a></li>
  577. <li><a href="#Task-2-NTP" title="Task 2: NTP">Task 2: NTP</a></li>
  578. </ul>
  579. </li>
  580. <li><a href="#Exercise-2-Package-managers" title="Exercise 2: Package managers">Exercise 2: Package managers</a><ul class="nav">
  581. <li><a href="#Task-3-dpkg" title="Task 3: dpkg">Task 3: dpkg</a></li>
  582. <li><a href="#Task-4-APT" title="Task 4: APT">Task 4: APT</a></li>
  583. <li><a href="#Task-5-sourceslist" title="Task 5: sources.list">Task 5: sources.list</a></li>
  584. <li><a href="#Task-6-Creating-a-custom-Ubuntu-package" title="Task 6: Creating a custom Ubuntu package">Task 6: Creating a custom Ubuntu package</a></li>
  585. </ul>
  586. </li>
  587. <li><a href="#Questions-to-answer" title="Questions to answer">Questions to answer</a><ul class="nav">
  588. <li><a href="#Bonus" title="Bonus">Bonus</a></li>
  589. </ul>
  590. </li>
  591. </ul>
  592. </li>
  593. </ul>
  594. </div><div class="toc-menu"><a class="expand-toggle" href="#">Expand all</a><a class="back-to-top" href="#">Back to top</a><a class="go-to-bottom" href="#">Go to bottom</a></div>
  595. </div>
  596. <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
  597. <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha256-U5ZEeKfGNOja007MMD3YBI0A3OSZOQbeG6z2f2Y0hu8=" crossorigin="anonymous" defer></script>
  598. <script src="https://cdnjs.cloudflare.com/ajax/libs/gist-embed/2.6.0/gist-embed.min.js" integrity="sha256-KyF2D6xPIJUW5sUDSs93vWyZm+1RzIpKCexxElmxl8g=" crossorigin="anonymous" defer></script>
  599. <script>
  600. var markdown = $(".markdown-body");
  601. //smooth all hash trigger scrolling
  602. function smoothHashScroll() {
  603. var hashElements = $("a[href^='#']").toArray();
  604. for (var i = 0; i < hashElements.length; i++) {
  605. var element = hashElements[i];
  606. var $element = $(element);
  607. var hash = element.hash;
  608. if (hash) {
  609. $element.on('click', function (e) {
  610. // store hash
  611. var hash = this.hash;
  612. if ($(hash).length <= 0) return;
  613. // prevent default anchor click behavior
  614. e.preventDefault();
  615. // animate
  616. $('body, html').stop(true, true).animate({
  617. scrollTop: $(hash).offset().top
  618. }, 100, "linear", function () {
  619. // when done, add hash to url
  620. // (default click behaviour)
  621. window.location.hash = hash;
  622. });
  623. });
  624. }
  625. }
  626. }
  627. smoothHashScroll();
  628. var toc = $('.ui-toc');
  629. var tocAffix = $('.ui-affix-toc');
  630. var tocDropdown = $('.ui-toc-dropdown');
  631. //toc
  632. tocDropdown.click(function (e) {
  633. e.stopPropagation();
  634. });
  635. var enoughForAffixToc = true;
  636. function generateScrollspy() {
  637. $(document.body).scrollspy({
  638. target: ''
  639. });
  640. $(document.body).scrollspy('refresh');
  641. if (enoughForAffixToc) {
  642. toc.hide();
  643. tocAffix.show();
  644. } else {
  645. tocAffix.hide();
  646. toc.show();
  647. }
  648. $(document.body).scroll();
  649. }
  650. function windowResize() {
  651. //toc right
  652. var paddingRight = parseFloat(markdown.css('padding-right'));
  653. var right = ($(window).width() - (markdown.offset().left + markdown.outerWidth() - paddingRight));
  654. toc.css('right', right + 'px');
  655. //affix toc left
  656. var newbool;
  657. var rightMargin = (markdown.parent().outerWidth() - markdown.outerWidth()) / 2;
  658. //for ipad or wider device
  659. if (rightMargin >= 133) {
  660. newbool = true;
  661. var affixLeftMargin = (tocAffix.outerWidth() - tocAffix.width()) / 2;
  662. var left = markdown.offset().left + markdown.outerWidth() - affixLeftMargin;
  663. tocAffix.css('left', left + 'px');
  664. } else {
  665. newbool = false;
  666. }
  667. if (newbool != enoughForAffixToc) {
  668. enoughForAffixToc = newbool;
  669. generateScrollspy();
  670. }
  671. }
  672. $(window).resize(function () {
  673. windowResize();
  674. });
  675. $(document).ready(function () {
  676. windowResize();
  677. generateScrollspy();
  678. });
  679. //remove hash
  680. function removeHash() {
  681. window.location.hash = '';
  682. }
  683. var backtotop = $('.back-to-top');
  684. var gotobottom = $('.go-to-bottom');
  685. backtotop.click(function (e) {
  686. e.preventDefault();
  687. e.stopPropagation();
  688. if (scrollToTop)
  689. scrollToTop();
  690. removeHash();
  691. });
  692. gotobottom.click(function (e) {
  693. e.preventDefault();
  694. e.stopPropagation();
  695. if (scrollToBottom)
  696. scrollToBottom();
  697. removeHash();
  698. });
  699. var toggle = $('.expand-toggle');
  700. var tocExpand = false;
  701. checkExpandToggle();
  702. toggle.click(function (e) {
  703. e.preventDefault();
  704. e.stopPropagation();
  705. tocExpand = !tocExpand;
  706. checkExpandToggle();
  707. })
  708. function checkExpandToggle () {
  709. var toc = $('.ui-toc-dropdown .toc');
  710. var toggle = $('.expand-toggle');
  711. if (!tocExpand) {
  712. toc.removeClass('expand');
  713. toggle.text('Expand all');
  714. } else {
  715. toc.addClass('expand');
  716. toggle.text('Collapse all');
  717. }
  718. }
  719. function scrollToTop() {
  720. $('body, html').stop(true, true).animate({
  721. scrollTop: 0
  722. }, 100, "linear");
  723. }
  724. function scrollToBottom() {
  725. $('body, html').stop(true, true).animate({
  726. scrollTop: $(document.body)[0].scrollHeight
  727. }, 100, "linear");
  728. }
  729. </script>
  730. </body>
  731. </html>