added cactus theme files

This commit is contained in:
2022-07-31 17:32:45 -07:00
parent 1c054014c6
commit b32268d438
142 changed files with 17322 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 ZERAN WU
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,299 @@
## Cactus
A hugo theme for personal blog. Fork from hexo theme [cactus](https://github.com/probberechts/hexo-theme-cactus) created by @probberechts.
[Live demo on github pages](https://www.takuzen.me/hugo-theme-cactus/).
Some works are still in progress. See [TODOS](#todos) below.
## Install
1. clone cactus to your hugo site's `themes` folder.
```
git clone https://github.com/monkeyWzr/hugo-theme-cactus.git themes/cactus
```
2. change your theme to cactus in your site config
```toml
# config.toml
theme = "cactus"
```
3. config your site. See [Config] or a [complete config sample](exampleSite/config.toml)
4. test your site
```
hugo server
```
5. publish your site in your prefered way. See hugo's doc: [Hosting & Deployment](https://gohugo.io/hosting-and-deployment/)
## Config
### Color themes
```toml
[params]
colortheme = "white" # dark, light, white, or classic
```
### Custom CSS
```toml
[params]
css = ["css/custom.css"]
```
You can add multiple custom stylesheets which will be loaded after the main theme css.
For example, the above line will load the CSS-file placed at `/static/css/custom.css`.
### Navigation
```toml
# Main menu which appears below site header.
[[menu.main]]
name = "Home"
url = "/"
weight = 1
[[menu.main]]
name = "All posts"
url = "/posts"
weight = 2
[[menu.main]]
name = "Tags"
url = "/tags"
weight = 3
[[menu.main]]
name = "About"
url = "/about"
weight = 4
```
### Homepage settings
* description: description will be displayed in the homepage. Markdown syntax is supported in the description string.
```toml
[params]
description = "Hugo is a general-purpose website framework. Technically speaking, Hugo is a static site generator. Unlike systems that dynamically build a page with each visitor request, Hugo builds pages when you create or update your content. Since websites are viewed far more often than they are edited, Hugo is designed to provide an optimal viewing experience for your websites end users and an ideal writing experience for website authors."
```
* set your main section (used as the link for the "writings" title on the homepage)
```toml
[params]
mainSection = "posts"
```
* change the default main section title from Writings, to something else:
```toml
[params]
mainSectionTitle = "Blog"
```
* Show only the 5 most recent posts (default)
```toml
[params]
showAllPostsOnHomePage = false
postsOnHomePage = 5
```
* show all posts
```toml
[params]
showAllPostsOnHomePage = true
postsOnHomePage = 5 # this option will be ignored
```
* show tagsoverview (default) or not
*
```toml
[params]
tagsOverview = true
```
* display the table of contents inline on blog posts, rather than as part of the navigation menu:
```toml
[params]
tocInline = true
```
* show projects list (default) or not.
```toml
[params]
showProjectsList = true
projectsUrl = "https://github.com/monkeyWzr"
```
Projects section will not be shown if no data file is detected. See [Projects list](#projects-list) below.
### Projects list
Create your projects data file `data/projects.yaml|toml|json`. Hugo support yaml, toml and json formats.
for former hexo cactus users: please assign your json array to a `list` key.
for example, `data/projects.json`:
```json
{
"list": [
{
"name":"Hexo",
"url":"https://hexo.io/",
"desc":"A fast, simple & powerful blog framework"
},
{
"name":"Font Awesome",
"url":"http://fontawesome.io/",
"desc":"The iconic font and CSS toolkit"
}
]
}
```
### Social media links
```toml
[[params.social]]
name = "github"
link = "https://github.com/monkeyWzr"
[[params.social]]
name = "email"
link = "monkeywzr@gmail.com" # no need for "mailto:" at the start
[[params.social]]
name = "linkedin"
link = "https://www.linkedin.com/in/monkeywzr/"
```
The `name` key expects the name of a [Font Awesome icon](https://fontawesome.com/icons?d=gallery&s=brands).
### Copyright
Assign your copy right to `.Site.Copyright`. Cactus will append current year to the head.
TODO: Customizable copyright year
```toml
copyright = "Zeran Wu" # cactus theme will use site title if copyright is not set
```
### Comments
Comments is disabled by default. Enable comments in your `.Site.Params`.
```toml
[params]
[params.comments]
enabled = true
# engine = "disqus" # in progress
```
You can also enable/disable comments per post. in your posts' front matter, add:
```yaml
comments: true
```
The site config is ignored when `comments` option exists in front matter.
The default engine is disqus. **By now only disqus is supported in cactus.** I will add more options sooner or later. See [Comments Alternatives](https://gohugo.io/content-management/comments/#comments-alternatives)
Before using disqus, you need to register and get your [disqus shortname](https://help.disqus.com/en/articles/1717111-what-s-a-shortname). Assign your shortname in `.Site.disqusShortname`, or cactus will use `.Site.Title` by default.
```
disqusShortname = "wzr" # cactus will use site title if not set
```
### highlight
Use hugo's built-in [syntax highlighting](https://gohugo.io/getting-started/configuration-markup#highlight).
default config:
```toml
[markup]
[markup.highlight]
codeFences = true
guessSyntax = false
hl_Lines = ""
lineNoStart = 1
lineNos = false
lineNumbersInTable = true
noClasses = true
style = "monokai"
tabWidth = 4
```
### Analytics
Cactus uses hugo's bulit in analytics templates. Check [hugo's documents](https://gohugo.io/templates/internal#google-analytics) for details.
Set you tracking id in your site config.
```toml
googleAnalytics = "UA-XXXXXXXX-XX" # or G-XXXXXXXX if you are using Google Analytics v4 (gtag.js)
```
If you are using Google Analytics v3 (analytics.js), you can switch to asynchronous tracking by set `params.googleAnalyticsAsync` to `true`.
```toml
[params]
googleAnalyticsAsync = true # not required
```
### RSS
The rss feed is not generated by default. you can enable it in your site config:
```toml
[params]
rss = true
```
The rss link will be `https://example.com/index.xml` assuming your `baseURL` is set to `https://example.com/`
Please also check [Configure RSS](https://gohugo.io/templates/rss/#configure-rss)
### Mathjax
Cactus supports mathjax. Just add `mathjax` option in your site config:
```toml
[params]
mathjax = true # not required
```
You can also enable/disable mathjax per post. In your posts' front matter, add:
```yaml
mathjax: true # or false
```
The site config will be ignored when `mathjax` option exists in front matter.
### Archive
Pagination on posts archive can be disabled to show all posts in chronological order
```toml
[params]
showAllPostsArchive = true # or false (default)
```
## TODOS
- [ ] More comments engines
- [x] RSS
- [ ] I18n
- [x] Analytics
- [ ] Local Search
- [ ] toc template
- [ ] Customizable copyright year
- [ ] gallery
- [ ] expose [mathjax configuration](https://docs.mathjax.org/en/latest/web/configuration.html#web-configuration)
## License
MIT

View File

@@ -0,0 +1,119 @@
// $base-style
h1,
.h1 {
display: block;
margin-top: 3rem;
margin-bottom: 1rem;
color: $color-accent-1;
letter-spacing: .01em;
font-weight: 700;
font-style: normal;
font-size: 1.5em;
@include antialias();
}
h2,
.h2 {
position: relative;
display: block;
margin-top: 2rem;
margin-bottom: .5rem;
color: $color-accent-2;
text-transform: none;
letter-spacing: normal;
font-weight: bold;
font-size: 1rem;
}
h3 {
color: $color-accent-2;
text-decoration: underline;
font-weight: bold;
font-size: .9rem;
}
h4
h5
h6 {
display: inline;
text-decoration: none;
color: $color-accent-3;
font-weight: bold;
font-size: .9rem;
}
h3
h4
h5
h6 {
margin-top: .9rem;
margin-bottom: .5rem;
}
hr {
border: .5px dashed $color-accent-3;
opacity: .5;
margin: 0;
margin-top: 20px;
margin-bottom: 20px;
}
strong {
font-weight: bold;
}
em
cite {
font-style: italic;
}
sup
sub {
position: relative;
vertical-align: baseline;
font-size: .75em;
line-height: 0;
}
sup {
top: -.5em;
}
sub {
bottom: -.2em;
}
small {
font-size: .85em;
}
acronym
abbr {
border-bottom: 1px dotted;
}
ul
ol
dl {
line-height: $line-height;
}
ul ul,
ol ul,
ul ol,
ol ol {
margin-top: 0;
margin-bottom: 0;
}
ol {
list-style: decimal;
}
dt {
font-weight: bold;
}
table {
width: 100%;
border-collapse: collapse;
text-align: left;
font-size: $font-size - 2px;
overflow: auto;
display: block;
}
th {
padding: 8px;
border-bottom: 1px dashed $color-border;
color: $color-accent-2;
font-weight: bold;
font-size: $font-size - 1px;
}
td {
padding: 0 8px;
border-bottom: none;
}

View File

@@ -0,0 +1,6 @@
@font-face {
font-style: normal;
font-family: "JetBrains Mono";
font-display: swap;
src: local("JetBrains Mono"), local("JetBrains-Mono"), url("../lib/JetBrainsMono/web/woff2/JetBrainsMono-Regular.woff2") format("woff2"), url("../lib/JetBrainsMono/web/woff/JetBrainsMono-Regular.woff") format("woff"), url("../lib/JetBrainsMono/web/eot/JetBrainsMono-Regular.eot") format("embedded-opentype"), url("../lib/JetBrainsMono/ttf/JetBrainsMono-Regular.ttf") format("truetype");
};

View File

@@ -0,0 +1,20 @@
@mixin antialias() {
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
}
@mixin hyphens($value) {
hyphens: $value;
-moz-hyphens: $value;
-ms-hyphens: $value;
-webkit-hyphens: $value;
}
@mixin underline($size, $color) {
background-image: linear-gradient(transparent, transparent $size, $color $size, $color);
background-position: bottom;
background-size: 100% 6px;
background-repeat: repeat-x;
}
@mixin no-select() {
user-select: none;
-khtml-user-select: none;
}

View File

@@ -0,0 +1,319 @@
/* Basscss */
.inline {
display: inline;
}
.block {
display: block;
}
.inline-block {
display: inline-block;
}
.table {
display: table;
}
.table-cell {
display: table-cell;
}
.overflow-hidden {
overflow: hidden;
}
.overflow-scroll {
overflow: scroll;
}
.overflow-auto {
overflow: auto;
}
.clearfix:before,
.clearfix:after {
display: table;
content: " ";
}
.clearfix:after {
clear: both;
}
.left {
float: left;
}
.right {
float: right;
}
.fit {
max-width: 100%;
}
.truncate {
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.max-width-1 {
max-width: 24rem;
}
.max-width-2 {
max-width: 32rem;
}
.max-width-3 {
max-width: 48rem;
}
.max-width-4 {
max-width: 64rem;
}
.border-box {
box-sizing: border-box;
}
.m0 {
margin: 0;
}
.mt0 {
margin-top: 0;
}
.mr0 {
margin-right: 0;
}
.mb0 {
margin-bottom: 0;
}
.ml0 {
margin-left: 0;
}
.mx0 {
margin-right: 0;
margin-left: 0;
}
.my0 {
margin-top: 0;
margin-bottom: 0;
}
.m1 {
margin: .5rem;
}
.mt1 {
margin-top: .5rem;
}
.mr1 {
margin-right: .5rem;
}
.mb1 {
margin-bottom: .5rem;
}
.ml1 {
margin-left: .5rem;
}
.mx1 {
margin-right: .5rem;
margin-left: .5rem;
}
.my1 {
margin-top: .5rem;
margin-bottom: .5rem;
}
.m2 {
margin: 1rem;
}
.mt2 {
margin-top: 1rem;
}
.mr2 {
margin-right: 1rem;
}
.mb2 {
margin-bottom: 1rem;
}
.ml2 {
margin-left: 1rem;
}
.mx2 {
margin-right: 1rem;
margin-left: 1rem;
}
.my2 {
margin-top: 1rem;
margin-bottom: 1rem;
}
.m3 {
margin: 2rem;
}
.mt3 {
margin-top: 2rem;
}
.mr3 {
margin-right: 2rem;
}
.mb3 {
margin-bottom: 2rem;
}
.ml3 {
margin-left: 2rem;
}
.mx3 {
margin-right: 2rem;
margin-left: 2rem;
}
.my3 {
margin-top: 2rem;
margin-bottom: 2rem;
}
.m4 {
margin: 4rem;
}
.mt4 {
margin-top: 4rem;
}
.mr4 {
margin-right: 4rem;
}
.mb4 {
margin-bottom: 4rem;
}
.ml4 {
margin-left: 4rem;
}
.mx4 {
margin-right: 4rem;
margin-left: 4rem;
}
.my4 {
margin-top: 4rem;
margin-bottom: 4rem;
}
.mxn1 {
margin-right: -.5rem;
margin-left: -.5rem;
}
.mxn2 {
margin-right: -1rem;
margin-left: -1rem;
}
.mxn3 {
margin-right: -2rem;
margin-left: -2rem;
}
.mxn4 {
margin-right: -4rem;
margin-left: -4rem;
}
.ml-auto {
margin-left: auto;
}
.mr-auto {
margin-right: auto;
}
.mx-auto {
margin-right: auto;
margin-left: auto;
}
.p0 {
padding: 0;
}
.pt0 {
padding-top: 0;
}
.pr0 {
padding-right: 0;
}
.pb0 {
padding-bottom: 0;
}
.pl0 {
padding-left: 0;
}
.px0 {
padding-right: 0;
padding-left: 0;
}
.py0 {
padding-top: 0;
padding-bottom: 0;
}
.p1 {
padding: .5rem;
}
.pt1 {
padding-top: .5rem;
}
.pr1 {
padding-right: .5rem;
}
.pb1 {
padding-bottom: .5rem;
}
.pl1 {
padding-left: .5rem;
}
.py1 {
padding-top: .5rem;
padding-bottom: .5rem;
}
.px1 {
padding-right: .5rem;
padding-left: .5rem;
}
.p2 {
padding: 1rem;
}
.pt2 {
padding-top: 1rem;
}
.pr2 {
padding-right: 1rem;
}
.pb2 {
padding-bottom: 1rem;
}
.pl2 {
padding-left: 1rem;
}
.py2 {
padding-top: 1rem;
padding-bottom: 1rem;
}
.px2 {
padding-right: 1rem;
padding-left: 1rem;
}
.p3 {
padding: 2rem;
}
.pt3 {
padding-top: 2rem;
}
.pr3 {
padding-right: 2rem;
}
.pb3 {
padding-bottom: 2rem;
}
.pl3 {
padding-left: 2rem;
}
.py3 {
padding-top: 2rem;
padding-bottom: 2rem;
}
.px3 {
padding-right: 2rem;
padding-left: 2rem;
}
.p4 {
padding: 4rem;
}
.pt4 {
padding-top: 4rem;
}
.pr4 {
padding-right: 4rem;
}
.pb4 {
padding-bottom: 4rem;
}
.pl4 {
padding-left: 4rem;
}
.py4 {
padding-top: 4rem;
padding-bottom: 4rem;
}
.px4 {
padding-right: 4rem;
padding-left: 4rem;
}

View File

@@ -0,0 +1,13 @@
// Fonts
$font-family-body: "JetBrains Mono", monospace;
$font-family-mono: "JetBrains Mono", monospace;
$font-family-tt: "Inconsolata", monospace;
$font-size: 14px;
$line-height: 1.725;
$page-width: 48rem;
// Logo
$logo-width: 50px;
$logo-height: 50px;
$logo-grayout: true;
// Colors
$colors: "dark" // white dark light classic

View File

@@ -0,0 +1,13 @@
$color-background: #fafafa;
$color-footer-mobile-1: darken($color-background, 2%);
$color-footer-mobile-2: darken($color-background, 10%);
$color-background-code: darken($color-background, 2%);
$color-border: #666;
$color-meta: #666;
$color-meta-code: lighten($color-meta, 10%);
$color-link: rgba(86, 124, 119, .4);
$color-text: #22272a;
$color-accent-1: #cc2a41;
$color-accent-2: rgba(86, 124, 119, .8);
$color-accent-3: #666;
$color-quote: #cc2a41;

View File

@@ -0,0 +1,13 @@
$color-background: #1d1f21;
$color-footer-mobile-1: lighten($color-background, 2%);
$color-footer-mobile-2: lighten($color-background, 10%);
$color-background-code: lighten($color-background, 2%);
$color-border: #666;
$color-meta: #666;
$color-meta-code: #666;
$color-link: rgba(212, 128, 170, 1);
$color-text: #c9cacc;
$color-accent-3: #cccccc;
$color-accent-2: #eeeeee;
$color-accent-1: #2bbc8a;
$color-quote: #ccffb6;

View File

@@ -0,0 +1,14 @@
// by @GabiThume (https://github.com/gabithume)
$color-background: #e2e0de;
$color-footer-mobile-1: darken($color-background, 2%);
$color-footer-mobile-2: darken($color-background, 10%);
$color-background-code: darken($color-background, 2%);
$color-border: #666;
$color-meta: #666;
$color-meta-code: lighten($color-meta, 10%);
$color-link: rgba(43, 188, 138, 1);
$color-text: #363533;
$color-accent-3: #666666;
$color-accent-2: #111111;
$color-accent-1: #d44375;
$color-quote: #ab2251;

View File

@@ -0,0 +1,14 @@
// by @sergodeeva (https://github.com/sergodeeva)
$color-background: #FFFFFF;
$color-footer-mobile-1: darken($color-background, 2%);
$color-footer-mobile-2: darken($color-background, 10%);
$color-background-code: darken($color-background, 2%);
$color-border: #666;
$color-meta: #666;
$color-meta-code: lighten($color-meta, 10%);
$color-link: rgba(212, 128, 170, 1);
$color-text: #383838;
$color-accent-3: #8c8c8c;
$color-accent-2: #383838;
$color-accent-1: #2bbc8a;
$color-quote: #2bbc8a;

View File

@@ -0,0 +1,32 @@
#archive {
.post-list {
padding: 0;
.post-item {
margin-bottom: 1rem;
margin-left: 0;
list-style-type: none;
.meta {
display: block;
margin-right: 16px;
min-width: 100px;
color: $color-meta;
font-size: 14px;
}
}
}
@media (min-width: 480px) {
.post-list {
.post-item {
display: flex;
margin-bottom: 5px;
margin-left: 1rem;
.meta {
text-align: left;
}
}
}
}
}

View File

@@ -0,0 +1,158 @@
article {
header {
.posttitle {
margin-top: 0;
margin-bottom: 0;
text-transform: none;
font-size: 1.5em;
line-height: 1.25;
}
.meta {
margin-top: 0;
margin-bottom: 1rem;
}
.meta * {
color: $color-accent-3;
font-size: .85rem;
}
.author {
text-transform: uppercase;
letter-spacing: .01em;
font-weight: 700;
}
.postdate {
display: inline;
}
}
.content {
h2 {
&:before {
position: absolute;
top: -4px;
left: -1rem;
color: $color-accent-1;
content: "#";
font-weight: bold;
font-size: 1.2rem;
}
}
}
.content img,
.content video {
display: block;
margin: auto;
max-width: 100%;
height: auto;
/* http://webdesignerwall.com/tutorials/css-elastic-videos */
.video-container {
position: relative;
overflow: hidden;
padding-top: 56.25% e;
// (9/16 * 100)% // 16:9 ratio
height: 0;
iframe,
object,
embed {
position: absolute;
top: 0;
left: 0;
margin-top: 0;
width: 100%;
height: 100%;
}
}
blockquote {
margin: 1rem 10px;
padding: .5em 10px;
background: inherit;
color: $color-quote;
quotes: "\201C" "\201D" "\2018" "\2019";
font-weight: bold;
p {
margin: 0;
}
&:before {
margin-right: .25em;
color: $color-quote;
content: "\201C";
vertical-align: -.4em;
font-size: 2em;
line-height: .1em;
}
footer {
margin: line-height 0;
color: $color-meta;
font-size: 11px;
a {
background-image: linear-gradient(transparent, transparent 5px, $color-meta 5px, $color-meta);
color: $color-meta;
}
a:hover {
background-image: linear-gradient(transparent, transparent 4px, lighten($color-meta, 20%) 4px, lighten($color-meta, 20%));
color: lighten($color-meta, 20%);
}
cite {
&:before {
padding: 0 .5em;
content: "";
}
}
}
}
.pullquote {
margin: 0;
width: 45%;
text-align: left;
&.left {
margin-right: 1em;
margin-left: .5em;
}
&.right {
margin-right: .5em;
margin-left: 1em;
}
}
.caption {
position: relative;
display: block;
margin-top: .5em;
color: $color-meta;
text-align: center;
font-size: .9em;
}
}
}
.posttitle {
text-transform: none;
font-size: 1.5em;
line-height: 1.25;
}
.article-tag {
.tag-link {
&:before {
content: "#";
@include underline(10px, $color-link);
}
}
}
.article-category {
.category-link {
@include underline(10px, $color-link);
}
}
@media (min-width: 480px) {
.article-read-time,
.article-tag,
.article-category {
display: inline;
&:before {
content: "|";
}
}
};

View File

@@ -0,0 +1,18 @@
#categories {
.category-list-title {
color: $color-meta;
}
.category-list {
.category-list-item {
.category-list-count {
color: $color-meta;
}
.category-list-count:before {
content: " (";
}
.category-list-count:after {
content: ")";
}
}
}
}

View File

@@ -0,0 +1,3 @@
.blog-post-comments {
margin-top: 4rem;
}

View File

@@ -0,0 +1,66 @@
#footer {
position: absolute;
bottom: 0;
margin-bottom: 10px;
width: 100%;
color: $color-meta;
vertical-align: top;
text-align: center;
font-size: 11px;
ul {
margin: 0;
padding: 0;
list-style: none;
}
li {
display: inline-block;
margin-right: 15px;
border-right: 1px solid;
border-color: $color-border;
vertical-align: middle;
a {
margin-right: 15px;
}
}
li:last-child {
margin-right: 0;
border-right: 0;
a {
margin-right: 0;
}
}
a {
color: $color-meta;
text-decoration: underline;
background-image: none;
}
a:hover {
color: lighten($color-meta, 20%);
}
.footer-left {
height: 20px;
vertical-align: middle;
line-height: 20px;
}
}
@media (min-width: 39rem) {
#footer {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
align-items: center;
align-content: center;
margin-bottom: 20px;
.footer-left {
align-self: flex-start;
margin-right: 20px;
}
.footer-right {
align-self: flex-end;
}
}
};

View File

@@ -0,0 +1,123 @@
#header {
margin: 0 auto 2rem;
width: 100%;
h1,
.h1 {
margin-top: 0;
margin-bottom: 0;
color: $color-text;
letter-spacing: .01em;
font-weight: 700;
font-style: normal;
font-size: 1.5rem;
line-height: 2rem;
@include antialias();
}
a {
background: none;
color: inherit;
text-decoration: none;
}
#logo {
display: inline-block;
float: left;
margin-right: 20px;
width: $logo-width;
height: $logo-height;
border-radius: 5px;
background-size: $logo-width $logo-height;
background-repeat: no-repeat;
@if $logo-grayout {
filter: grayscale(100%);
-webkit-filter: grayscale(100%);
}
}
#nav {
color: $color-accent-1;
letter-spacing: .01em;
font-weight: 200;
font-style: normal;
font-size: .8rem;
ul {
margin: 0;
padding: 0;
list-style-type: none;
line-height: 15px;
a {
margin-right: 15px;
color: $color-accent-1;
}
a:hover {
@include underline(5px, $color-accent-1);
}
li {
display: inline-block;
margin-right: 15px;
border-right: 1px dotted;
border-color: $color-accent-1;
vertical-align: middle;
}
.icon {
display: none;
}
li:last-child {
margin-right: 0;
border-right: 0;
a {
margin-right: 0;
}
}
}
}
}
@if $logo-grayout {
#header:hover {
#logo {
filter: none;
-webkit-filter: none;
}
}
}
@media screen and (max-width: 480px) {
#header #title {
display: table;
margin-right: 5rem;
min-height: $logo-height;
h1 {
display: table-cell;
vertical-align: middle;
}
}
#header #nav {
ul {
a:hover {
background: none;
}
li {
display: none;
border-right: 0;
}
li.icon {
position: absolute;
top: 77px;
right: 1rem;
display: inline-block;
}
}
ul.responsive {
li {
display: block;
}
}
li:not(:first-child) {
padding-top: 1rem;
padding-left: $logo-width + 20px;
font-size: 1rem;
}
}
};

View File

@@ -0,0 +1,40 @@
.post-list {
padding: 0;
.post-item {
margin-bottom: 1rem;
margin-left: 0;
list-style-type: none;
.meta {
display: block;
margin-right: 16px;
min-width: 100px;
color: $color-meta;
font-size: 14px;
}
}
}
@media (min-width: 480px) {
.post-list {
.post-item {
display: flex;
margin-bottom: 5px;
.meta {
text-align: left;
}
}
}
}
.project-list {
padding: 0;
list-style: none;
.project-item {
margin-bottom: 5px;
p {
display: inline;
}
}
}

View File

@@ -0,0 +1,25 @@
.pagination {
display: inline-block;
margin-top: 2rem;
width: 100%;
text-align: center;
.page-number {
color: $color-text;
font-size: .8rem;
}
a {
padding: 4px 6px;
border-radius: 5px;
// background-color: $color-accent-1
background-image: none;
color: $color-text;
text-decoration: none;
}
a:hover {
background-image: none;
}
a:hover:not(.active) {
color: $color-accent-2;
}
}

View File

@@ -0,0 +1,256 @@
#header-post {
position: fixed;
top: 2rem;
right: 0;
display: inline-block;
float: right;
z-index: 100;
a {
background: none;
color: inherit;
text-decoration: none;
}
a.icon {
background: none;
&:hover {
color: $color-link;
}
}
nav {
ul {
display: block;
list-style-image: none;
list-style-position: outside;
list-style-type: none;
padding-inline-start: 40px;
li {
display: list-item;
margin-right: 0px;
}
}
}
nav > ul {
margin-block-end: 1em;
margin-block-start: 1em;
}
ul {
display: inline-block;
margin: 0;
padding: 0;
list-style-type: none;
li {
display: inline-block;
margin-right: 15px;
vertical-align: middle;
}
li:last-child {
margin-right: 0;
}
}
#menu-icon {
float: right;
margin-right: 2rem;
margin-left: 15px;
&:hover {
color: $color-accent-1;
}
}
#menu-icon-tablet {
float: right;
margin-right: 2rem;
margin-left: 15px;
&:hover {
color: $color-accent-1;
}
}
#top-icon-tablet {
position: fixed;
right: 2rem;
bottom: 2rem;
margin-right: 2rem;
margin-left: 15px;
&:hover {
color: $color-accent-1;
}
}
.active {
color: $color-accent-1;
}
#menu {
visibility: hidden;
margin-right: 2rem;
}
#nav {
color: $color-accent-1;
letter-spacing: .01em;
font-weight: 200;
font-style: normal;
font-size: .8rem;
ul {
line-height: 15px;
a {
margin-right: 15px;
color: $color-accent-1;
}
a:hover {
@include underline(5px, $color-accent-1);
}
li {
border-right: 1px dotted $color-accent-1;
}
li:last-child {
margin-right: 0;
border-right: 0;
a {
margin-right: 0;
}
}
}
}
#actions {
float: right;
margin-top: 2rem;
margin-right: 2rem;
width: 100%;
text-align: right;
ul {
display: block;
}
.info {
display: block;
font-style: italic;
}
}
#share {
clear: both;
padding-top: 1rem;
padding-right: 2rem;
text-align: right;
li {
display: block;
margin: 0;
}
}
#toc {
float: right;
clear: both;
overflow: auto;
margin-top: 1rem;
padding-right: 2rem;
max-width: 20em;
max-height: calc(95vh - 7rem);
text-align: right;
a:hover {
color: $color-link;
}
// .toc-level-1 > .toc-link
// display: none
nav > ul > li {
color: $color-text;
font-size: .8rem;
&:before {
color: $color-accent-1;
content: "#";
margin-right: 8px;
}
}
nav > ul > li > ul > li {
color: $color-meta;
font-size: .7rem;
&:before {
color: $color-accent-1;
content: "·";
font-weight: bold;
margin-right: 3px;
}
}
nav > ul > li > ul > li > ul > li {
color: darken($color-meta, 20%);
font-size: .4rem;
}
.toc-level-5 {
display: none;
}
.toc-level-6 {
display: none;
}
.toc-number {
display: none;
}
// smartphone + phapblet
}
}
@media screen and (max-width: 500px) {
#header-post {
display: none;
}
}
@media screen and (max-width: 900px) {
#header-post {
#menu-icon {
display: none;
}
#actions {
display: none;
}
}
}
@media screen and (max-width: 1199px) {
#header-post {
#toc {
display: none;
}
}
}
@media screen and (min-width: 900px) {
#header-post {
#menu-icon-tablet {
display: none !important;
}
#top-icon-tablet {
display: none !important;
}
}
}
@media screen and (min-width: 1199px) {
#header-post {
#actions {
width: auto;
ul {
display: inline-block;
float: right;
}
.info {
display: inline;
float: left;
margin-right: 2rem;
font-style: italic;
}
}
}
};

View File

@@ -0,0 +1,154 @@
#footer-post {
position: fixed;
right: 0;
bottom: 0;
left: 0;
z-index: 5000000;
width: 100%;
border-top: 1px solid $color-border;
background: $color-footer-mobile-1;
transition: opacity .2s;
a {
background: none;
color: inherit;
text-decoration: none;
}
a.icon {
background: none;
&:hover {
color: $color-link;
}
}
#nav-footer {
padding-right: 1rem;
padding-left: 1rem;
background: $color-footer-mobile-2;
text-align: center;
a {
color: $color-accent-1;
font-size: 1em;
}
a:hover {
@include underline(5px, $color-accent-1);
}
ul {
display: table;
margin: 0;
padding: 0;
width: 100%;
list-style-type: none;
li {
display: inline-table;
padding: 10px;
width: 20%;
vertical-align: middle;
}
}
}
#actions-footer {
overflow: auto;
margin-top: 1rem;
margin-bottom: 1rem;
padding-right: 1rem;
padding-left: 1rem;
width: 100%;
text-align: center;
white-space: nowrap;
a {
display: inline-block;
padding-left: 1rem;
color: $color-accent-1;
}
}
#share-footer {
padding-right: 1rem;
padding-left: 1rem;
background: $color-footer-mobile-2;
text-align: center;
ul {
display: table;
margin: 0;
padding: 0;
width: 100%;
list-style-type: none;
li {
display: inline-table;
padding: 10px;
width: 20%;
vertical-align: middle;
}
}
}
#toc-footer {
clear: both;
padding-top: 1rem;
padding-bottom: 1rem;
background: $color-footer-mobile-2;
text-align: left;
#TableOfContents {
ul {
margin: 0;
padding-left: 20px;
list-style-type: none;
li {
line-height: 30px;
}
}
}
a:hover {
color: $color-link;
}
// .toc-level-1 > .toc-link
// display: none
#TableOfContents > ul > li {
color: $color-text;
font-size: .8rem;
&:before {
color: $color-accent-1;
content: "#";
margin-right: 8px;
}
}
#TableOfContents > ul > li > ul > li {
color: $color-meta;
font-size: .7rem;
line-height: 15px;
&:before {
color: $color-accent-1;
content: "·";
font-weight: bold;
margin-right: 3px;
}
}
#TableOfContents > ul > li > ul > li > ul > li {
display: none;
}
// .toc-level-5
// display: none
// .toc-level-6
// display: none
// .toc-number
// display: none
}
}
@media screen and (min-width: 500px) {
#footer-post-container {
display: none;
}
};

View File

@@ -0,0 +1,49 @@
.search-input {
padding: 4px 7px;
width: 100%;
outline: none;
border: solid 1px $color-accent-3;
border-radius: 5px;
background-color: $color-background;
color: $color-text;
font-size: 1.2rem;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
&:focus {
border: solid 1px $color-accent-1;
}
}
#search-result {
ul.search-result-list {
padding: 0;
list-style-type: none;
}
li {
margin: 2em auto;
}
a.search-result-title {
background-image: none;
color: $color-text;
text-transform: capitalize;
font-weight: bold;
line-height: 1.2;
}
p.search-result {
overflow: hidden;
margin: .4em auto;
max-height: 13em;
text-align: justify;
font-size: .8em;
}
em.search-keyword {
border-bottom: 1px dashed $color-link;
color: $color-link;
font-weight: bold;
}
}
.search-no-result {
display: none;
padding-bottom: .5em;
color: $color-text;
}

View File

@@ -0,0 +1,13 @@
#tag-cloud {
.tag-cloud-title {
color: $color-meta;
}
.tag-cloud-tags {
clear: both;
text-align: center;
a {
display: inline-block;
margin: 10px;
}
}
}

View File

@@ -0,0 +1,86 @@
// ref: https://github.com/primer/primer/blob/master/modules/primer-tooltips/lib/tooltips.scss
.tooltipped {
position: relative;
}
// This is the tooltip bubble
.tooltipped::after {
position: absolute;
z-index: 1000000;
display: none;
padding: .2em .5em;
-webkit-font-smoothing: subpixel-antialiased;
color: $color-background;
font-display: swap;
font-weight: 400;
font-size: $font-size * 0.8;
font-family: $font-family-body;
line-height: $line-height;
text-rendering: geometricPrecision;
text-align: center;
word-wrap: break-word;
white-space: pre;
content: attr(aria-label);
background: $color-text;
border-radius: 3px;
opacity: 0;
}
// This is the tooltip arrow
.tooltipped::before {
position: absolute;
z-index: 1000001;
display: none;
width: 0;
height: 0;
color: $color-text;
pointer-events: none;
content: '';
border: 6px solid transparent;
opacity: 0;
}
// delay animation for tooltip
@keyframes tooltip-appear {
from {
opacity: 0;
}
to {
opacity: 1;
}
};
// This will indicate when we'll activate the tooltip
.tooltipped:hover,
.tooltipped:active,
.tooltipped:focus {
&::before,
&::after {
display: inline-block;
text-decoration: none;
animation-name: tooltip-appear;
animation-duration: 0.1s;
animation-fill-mode: forwards;
animation-timing-function: ease-in;
}
// Tooltipped south
}
.tooltipped-s,
.tooltipped-sw {
&::after {
top: 100%;
right: 50%;
margin-top: 6px;
}
&::before {
top: auto;
right: 50%;
bottom: -7px;
margin-right: -6px;
border-bottom-color: $color-text;
}
}
.tooltipped-sw::after {
margin-right: -16px;
}
// Move the tooltip body to the center of the object.
.tooltipped-s::after {
transform: translateX(50%);
}

View File

@@ -0,0 +1,105 @@
@font-face {
font-family: Vazir;
src: url('../lib/vazir-font/Vazir.eot');
src: url("../lib/vazir-font/Vazir.eot?#iefix") format('embedded-opentype'), url("../lib/vazir-font/Vazir.woff2") format('woff2'), url("../lib/vazir-font/Vazir.woff") format('woff'), url("../lib/vazir-font/Vazir.ttf") format('truetype');
font-weight: normal;
}
@font-face {
font-family: Vazir;
src: url('../lib/vazir-font/Vazir-Bold.eot');
src: url("../lib/vazir-font/Vazir-Bold.eot?#iefix") format('embedded-opentype'), url("../lib/vazir-font/Vazir-Bold.woff2") format('woff2'), url("../lib/vazir-font/Vazir-Bold.woff") format('woff'), url("../lib/vazir-font/Vazir-Bold.ttf") format('truetype');
font-weight: bold;
}
@font-face {
font-family: Vazir;
src: url('../lib/vazir-font/Vazir-Light.eot');
src: url("../lib/vazir-font/Vazir-Light.eot?#iefix") format('embedded-opentype'), url("../lib/vazir-font/Vazir-Light.woff2") format('woff2'), url("../lib/vazir-font/Vazir-Light.woff") format('woff'), url("../lib/vazir-font/Vazir-Light.ttf") format('truetype');
font-weight: 300;
}
.rtl {
font-family: Vazir, sans-serif;
direction: rtl;
#nav {
li {
margin-right: 0px !important;
padding-left: 15px;
border-right: 0px !important;
border-left: 1px dotted;
}
li:last-child {
margin-right: 15px !important;
border-left: 0 !important;
}
}
#header {
#logo {
float: right;
margin-right: 0;
margin-left: 20px;
}
}
#footer {
li {
margin-right: 0px;
padding-left: 15px;
border-right: 0px;
border-left: 1px dotted;
}
li:last-child {
margin-right: 15px !important;
border-left: 0 !important;
}
#logo {
float: right;
}
}
article {
.content {
h2:before {
right: -1rem;
}
}
}
.post-list {
.post-item {
.meta {
margin-left: 16px;
margin-right: inherit;
}
}
}
}
@media screen and (min-width: 480px) {
.rtl {
.post-list {
.post-item {
.meta {
text-align: left;
}
}
}
}
}
@media screen and (max-width: 480px) {
.rtl {
#header {
#title {
margin-left: 5rem;
margin-right: 0;
}
#nav {
ul {
li {
left: 1rem;
right: auto;
border: 0;
}
}
}
}
}
};

View File

@@ -0,0 +1,231 @@
@import "variables";
@import "colors/{{ site.Params.colortheme | default "white" }}";
@import "util";
@import "mixins";
@import "extend";
@import "fonts";
// global-reset()
*,
*:before,
*:after {
box-sizing: border-box;
}
html {
margin: 0;
padding: 0;
height: 100%;
border-top: 2px solid $color-text;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
body {
margin: 0;
height: 100%;
background-color: $color-background;
color: $color-text;
font-display: swap;
font-weight: 400;
font-size: $font-size;
font-family: $font-family-body;
line-height: $line-height;
text-rendering: geometricPrecision;
flex: 1;
@include antialias();
@extend $base-style !optional;
}
.content {
position: relative;
display: flex;
flex-direction: column;
min-height: 100%;
overflow-wrap: break-word;
p {
@include hyphens(auto);
}
code {
@include hyphens(manual);
}
a {
color: $color-text;
text-decoration: none;
@include underline(5px, $color-text);
&:hover {
background-image: linear-gradient(transparent, transparent 4px, $color-link 4px, $color-link);
}
}
a.icon {
background: none;
&:hover {
color: $color-link;
}
}
h1 a,
.h1 a,
h2 a,
h3 a,
h4 a,
h5 a,
h6 a {
background: none;
color: inherit;
text-decoration: none;
}
h1 a:hover,
.h1 a:hover,
h2 a:hover,
h3 a:hover,
h4 a:hover,
h5 a:hover,
h6 a:hover {
@include underline(6px, $color-link);
}
h6 {
a {
background: none;
color: inherit;
text-decoration: none;
}
}
h6 {
a:hover {
@include underline(6px, $color-link);
}
}
}
@media (min-width: 540px) {
.image-wrap {
flex-direction: row;
margin-bottom: 2rem;
.image-block {
flex: 1 0 35%;
margin-right: 2rem;
}
p {
flex: 1 0 65%;
}
}
}
.max-width {
max-width: $page-width;
}
@media (max-width: 480px) { // smaller margins at smaller screen widths
.px3 {
padding-right: 1rem;
padding-left: 1rem;
}
.my4 {
margin-top: 2rem;
margin-bottom: 2rem;
}
}
@media (min-width: 480px) {
p {
text-align: justify;
}
}
@import "partial/header";
@import "partial/post/actions_desktop";
@import "partial/post/actions_mobile";
@import "partial/index";
@import "partial/article";
@import "partial/archive";
@import "partial/comments";
@import "partial/footer";
@import "partial/pagination";
@import "partial/search";
@import "partial/tags";
@import "partial/tooltip";
@import "partial/categories";
pre {
overflow-x: auto;
padding: 15px 15px 10px 15px;
border: 1px dotted $color-border;
border-radius: 2px;
-webkit-border-radius: 2px;
font-size: 13px;
font-family: $font-family-mono;
line-height: 22px;
position: relative;
.code-copy-btn {
position: absolute;
top: 0;
right: 0;
border: 0;
border-radius: 0 2px;
padding: 0;
font-family: "JetBrains Mono", monospace;
font-weight: 800;
font-size: 0.9em;
line-height: 1.7;
color: #fff;
background-color: #8c8c8c;
min-width: 60px;
text-align: center;
cursor: pointer;
letter-spacing: 0em;
}
.code-copy-btn:hover {
background-color: #666;
color: #2bbc8a;
}
code {
display: block;
padding: 0;
border: none;
}
}
code {
font-family: $font-family-mono;
padding: 0 5px;
border: 1px dotted $color-border;
border-radius: 2px;
-webkit-border-radius: 2px;
}
.highlight {
& > div {
border-radius: 2px;
-webkit-border-radius: 2px;
}
pre {
border: none;
background: none;
}
table {
pre {
margin-top: 0;
}
td:first-child {
pre {
padding-right: 0;
}
}
td:last-child {
pre {
padding-left: 0;
}
}
}
}

View File

@@ -0,0 +1,13 @@
language: minimal
dist: trusty
env:
- HUGO_VERSION=0.74.2
install:
- curl -LO https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_Linux-64bit.deb
- sudo dpkg -i hugo_${HUGO_VERSION}_Linux-64bit.deb
script:
- chmod +x ./deploy.sh
- ./deploy.sh
branches:
only:
- src

View File

@@ -0,0 +1,6 @@
---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
---

View File

@@ -0,0 +1,94 @@
baseURL = "https://example.com"
languageCode = "en-us"
title = "Cactus theme example"
theme = "cactus"
copyright = "You" # cactus will use title if copyright is not set
disqusShortname = "example" # Used when comments is enabled. Cactus will use site title if not set
# googleAnalytics = "UA-1234-5"
# summaryLength = 2
# Main menu which appears below site header.
[[menu.main]]
name = "Home"
url = "/"
weight = 1
[[menu.main]]
name = "Writings"
url = "/posts"
weight = 2
[[menu.main]]
name = "Tags"
url = "/tags"
weight = 3
[[menu.main]]
name = "About"
url = "/about"
weight = 4
[markup]
[markup.tableOfContents]
endLevel = 4
ordered = false
startLevel = 2
[markup.highlight]
codeFences = true
guessSyntax = false
hl_Lines = ""
lineNoStart = 1
lineNos = true
lineNumbersInTable = false
noClasses = true
style = "dracula"
tabWidth = 4
[params]
colortheme = "white" # dark, light, white, or classic
rss = true # generate rss feed. default value is false
googleAnalyticsAsync = true # use asynchronous tracking. Synchronous tracking by default
showAllPostsArchive = false # default
# Home page settings
description = "Hugo is a general-purpose website framework. Technically speaking, Hugo is a static site generator. Unlike systems that dynamically build a page with each visitor request, Hugo builds pages when you create or update your content. Since websites are viewed far more often than they are edited, Hugo is designed to provide an optimal viewing experience for your websites end users and an ideal writing experience for website authors."
mainSection = "posts" # your main section
showAllPostsOnHomePage = false # default
postsOnHomePage = 5 # this option will be ignored if showAllPostsOnHomePage is set to true
tagsOverview = true # show tags overview by default.
showProjectsList = true # show projects list by default (if projects data file exists).
projectsUrl = "https://github.com/gohugoio" # title link for projects list
# https://gohugo.io/functions/format/#hugo-date-and-time-templating-reference
dateFormat = "2006-01-02" # default
# Post page settings
show_updated = true # default
showReadTime = true # default
[params.comments]
enabled = true # default
engine = "cactus_comments" # only disqus, utterances, and cactus_comments is supported
[params.comments.utterances]
repo = "<github_username>/<github_reponame>"
label = "hugo-site-name" # you can use however you want to label your name in your repo's issues
theme = "github-light"
[params.comments.cactuscomments]
siteName = "your_cactus_comments_sitename" # see https://cactus.chat/ on how to register your site name
#serverUrl = "" # Defaults to https://matrix.cactus.chat:8448 (Cactus Chat public server)
#serverName = "" # Defaults to cactus.chat
# the value of name should be an valid font awesome icon name (brands type)
# https://fontawesome.com/icons?d=gallery&s=brands
[[params.social]]
name = "github"
link = "https://github.com/gohugoio"
[[params.social]]
name = "linkedin"
link = "https://www.linkedin.com/company/github/"
[[params.social]]
name = "email"
link = "example@example.com" # no need for "mailto:" in the head

View File

@@ -0,0 +1,7 @@
---
title: About me
date: 2016-08-24 17:51:42
---
Github: [monkeyWzr](https://github.com/monkeyWzr)

View File

@@ -0,0 +1,168 @@
---
title: 幸せ
date: 2016-10-22 16:56:54
categories: life
keywords:
---
:-)
Look at the stars
抬头仰望满天繁星
Look how they shine for you
看它们为你绽放着 闪烁不息
And everything you do
而你的一颦一举
Yeah' they were all Yellow
却满含胆怯和羞意
I came along
我追随着你的气息
I wrote a song for you
为你写下一首歌曲
And all the things you do
回想着你的所有举动和笑意
it was called Yellow
并用Yellow为这首歌命名
So then I took my turn
我耗尽心力
Oh what a thing to have done
用行动表达我的爱意
And it was all Yellow
噢这过程充满不安羞怯和点滴暖意
Your skin
你的每寸肌肤
Oh yeah' your skin and bones
你的冰肌玉骨
Turn into something beautiful
是那般美好 在我心永驻
Do you know? you know I love you so
你可知道 我已深深爱上了你
You know I love you so
你知道我已深深为你着迷
I swam across
我曾为你横越海洋
I jumped across for you
也曾为你翻越高山
Oh what a thing to do
而这一切行动的意义
Cos you were all Yellow
只为你满含羞怯的笑意
I drew a line
我拿起笔 小心翼翼
I drew a line for you
画着我脑海中美好的你
Oh what a thing to do
为你做这样一件事情
And it was all Yellow
心中却也充满暖意
Your skin
你的每寸肌肤
Oh yeah your skin and bones
你的冰肌玉骨
Turn into something beautiful
是那般美好 在我心永驻
Do you know?
你可知道
For you I'd bleed myself dry
为你我愿意付出一切
For you I'd bleed myself dry
直到生命燃尽 也甘心如饴
It's true
这就是我的真心
Look how they shine for you
看那漫天繁星正为你闪耀不已
Look how they shine for you
仿佛亦惊叹于你的美丽
Look how they shine for
看那漫天繁星正为你闪耀不已
Look how they shine for you
仿佛亦能读懂我此刻心情
Look how they shine for you
看那漫天繁星正为你闪耀不已
Look how they shine
那漫天的璀璨 皆是为你
Look at the stars
抬头仰望那满天繁星
Look how they shine for you
看它们正为你绽放着 闪烁不息
And all the things that you do
皆是因为你的一颦一举

View File

@@ -0,0 +1,78 @@
---
title: composer中的autoload
date: 2016-11-05 02:42:06
category: tech
tags:
- php
keywords:
- composer
- autoload
- psr-4
---
composer的autoload可以轻松的实现php的自动加载。在`composer.json`中添加`autoload`字段即可。当前支持 `PSR-0` `PSR-4` `classmap`解析和`files`包含。官方推荐PSR-4标准添加类时不需要重新生成加载器
### PSR-4
Under the `psr-4` key you define a mapping from namespaces to paths, relative to the package root. When autoloading a class like `Foo\\Bar\\Baz` a namespace prefix `Foo\\` pointing to a directory `src/` means that the autoloader will look for a file named `src/Bar/Baz.php` and include it if present. Note that as opposed to the older PSR-0 style, the prefix (`Foo\\`) is not present in the file path.
<!-- more -->
Namespace prefixes must end in `\\` to avoid conflicts between similar prefixes. For example Foo would match classes in the FooBar namespace so the trailing backslashes solve the problem: `Foo\\` and `FooBar\\` are distinct.
The PSR-4 references are all combined, during install/update, into a single key => value array which may be found in the generated file `vendor/composer/autoload_psr4.php`.
实例:
```
{
"autoload": {
"psr-4": {
"Monolog\\": "src/",
"Vendor\\Namespace\\": ""
}
}
}
```
如果需要在多个目录下搜索相同前缀,可以以数组的形式指定。
```
{
"autoload": {
"psr-4": { "Monolog\\": ["src/", "lib/"] }
}
}
```
也可为所有命名空间指定默认文件夹:
```
{
"autoload": {
"psr-4": { "": "src/" }
}
}
```
### classmap
`classmap` 引用的所有组合,都会在 `install/update` 过程中生成,并存储到 `vendor/composer/autoload_classmap.php` 文件中。这个 `map` 是经过扫描指定目录(同样支持直接精确到文件)中所有的 `.php``.inc` 文件里内置的类而得到的。
你可以用 `classmap` 生成支持支持自定义加载的不遵循 `PSR-0/4` 规范的类库。要配置它指向需要的目录,以便能够准确搜索到类文件。
实例:
```
{
"autoload": {
"classmap": ["src/", "lib/", "Something.php"]
}
}
```
__相关链接__
[Example Implementations of PSR-4](http://www.php-fig.org/psr/psr-4/examples/)
[The composer.json Schema](https://getcomposer.org/doc/04-schema.md#autoload)
[如何使用composer的autoload来自动加载自己编写的函数库与类库](http://drops.leavesongs.com/php/composer-autoload-class-and-function-written-myself.html)
[使用composer中的autoload](http://gywbd.github.io/posts/2014/12/composer-autoload.html)

View File

@@ -0,0 +1,138 @@
---
title: netfilter/iptables 笔记
date: 2016-11-29 21:08:52
category: notes
tags:
- Linux
keywords:
- iptables
- netfilter
- linux网络安全
- 运维
---
## netfilter 与 iptables
`netfilter`是linux默认的防火墙在2.4之后的版本正式进入内核。`netfilter` 使用四个表(Table)来存放控制信息包过滤处理的规则集。每张表由链(Chain)组成,每条链又包含了多条规则(rule)。
`iptables`是用来编辑操作这些表的一个工具。`iptables`包中也包含了针对IPv6的工具`ip6tables`
四个表及其包含的链:
<!-- more -->
* filter
- INPUT
- FORWARD
- OUTPUT
* nat
- PREROUTING
- POSTROUTING
- OUTPUT
* mangle
- PREROUTING
- INPUT
- FORWARD
- OUTPUT
- POSTROUTING
* raw
- PREROUTING
- OUTPUT
![img](/img/2016-11-29-iptables-usage_1.png)
### filter机制
`filter``netfilter`中最重要的机制,其任务是执行数据包的过滤操作。具有三种内建链:
* INPUT - 来自外部的数据包(访问本机)
* OUTPUT - 发往外部的数据包(本机访问外部)
* FORWORD - “路过”本机的数据包,转发到其他设备
链中规则的匹配方式遵循`first match``filter`会根据数据包特征从相应链中的第一条规则开始逐一进行匹配。只要遇到满足特征的规则后便不再继续。
每条链在最底端都定义了默认规则。默认规则只会有一种状态:`ACCEPT`或者`DROP`。默认为`ACCEPT`
## iptables命令参数
格式:
```
iptables -操作方式 [链名] [条件匹配] [选项]
iptables -[ACD] chain rule-specification [options]
iptables -I chain [rulenum] rule-specification [options]
iptables -R chain rulenum rule-specification [options]
iptables -D chain rulenum [options]
iptables -[LS] [chain [rulenum]] [options]
iptables -[FZ] [chain] [options]
iptables -[NX] chain
iptables -E old-chain-name new-chain-name
iptables -P chain target [options]
iptables -h (print this help information)
```
常用操作方式:
* `-L(--list)` *[chain]* 列出所有规则或指定链的规则
* `-A(--append)` *chain* 在指定链中添加新规则
* `-C(--check)` *chain* 检查规则是否存在
* `-D(--delete)` *chain rule_num* 删除链中匹配的规则
* `-F(--flush)` *[chain]* 清除指定链或者全部链中的规则
* `-P(--policy)` *chain* 设置指定链的默认策略
* `-R(--replace)` *chain rule_num* 替换指定链中特定行的规则第一行行数为1
常用选项:
* `-p(--protocol)` *proto* 指定协议,如`tcp` `udp` `icmp`
* `-j(--jump)` *target* 规则的目标(??),如`ACCEPT` `DROP` `REJECT`
* `-s(--source)` *address[/mask]* 数据包源IP可为单IP或CIDR网段或域名
* `-d(--destination)` *address[/mask]* 数据包目的IP可为单IP或CIDR网段或域名
* `--dport` *port* 目的端口,必须指明`-p`
* `--sport` *port* 来源端口,必须指明`-p`
* `--line-numbers` 显示行号
>关于`-p`配置的上层协议,可参考`/etc/protocols`
## state模块
`state`模块实现了“连接跟踪”功能,用来解决某些情况下防火墙内主机对外建立链接的问题。
`state`模块定义了四种数据包链接状态,分别为`ESTABLISHED` `NEW` `RELATED` `INVALID` 四种。在TCP/IP标准的定义中UDP和ICMP数据包是没有链接状态的但是在state模块的定义中任何数据包都有连接状态。
### ESTABLISHED状态
只要数据包能够成功穿过防火墙,则之后的所有数据包(包括响应数据包)都会被标记为是`ESTABLISHED`状态。
当我们设置防火墙INPUT链的默认策略为`DROP`防火墙内主机很多服务如ssh客户端基本上就无法与外面的ssh服务端建立连接了。原因很简单ssh客户端使用的端口是随机的防火墙无法预知客户端会使用哪一个端口发起链接。因此即使客户端发出了请求ssh服务端返回的相应数据包也会被防火墙的默认策略拦截。
ESTABLISHED状态可以很轻易的解决此问题见[#解决应用程序无法从防火墙主机上对外建立新连接的问题](#解决应用程序无法从防火墙主机上对外建立新连接的问题)
### NEW状态
每一条链接中的地一个数据包的状态定义为`NEW`
### RELATED状态
`RELATED`状态的数据包其含义是指被动产成的应答数据包且此数据包不属于当前任何链接。换一种说法就是只要应答的数据包是因为本机发起的连接送出vhu一个数据包导致了另一条连接的产生那么这个新连接的所有数据包都属于`RELATED`状态。
以ubuntu上上的tracepath工具为例在检测本机与目的主机间跳数时tracepath是通过发送TTL值从1递增的`tcp`数据包来检测每一跳。路径中的路由器因TTL减为0而回送了一个`ICMP`数据包(ICMP Type 11)该数据包就属于RELATED状态。
### INVALID状态
`INVALID`状态指的是状态不明的数据包,即不属于`ESTABLISHED` `NEW` `RELATED`三种类型的数据包。所有的`INVALID`数据包都应该视为恶意数据包。
## 实例
### 丢弃icmp协议包禁止ping
通过此规则实现禁止ping本机的效果
```
iptables -A INPUT -p icmp -j DROP
```
### 解决应用程序无法从防火墙主机上对外建立新连接的问题
```
iptables -A INPUT -p tcp -m state ESTABLISHED -j ACCEPT
```

View File

@@ -0,0 +1,274 @@
---
title: ruby学习笔记
date: 2016-12-08 22:54:49
category: notes
tags:
- ruby
keywords:
- ruby
---
## regular expressions
`=~`是用于正则表达式的匹配操作符。返回匹配到的字符串位置或nil。
```ruby
"abcdef" =~ /d/ # return 3
"aaaaaa" =~ /d/ # return nil
```
<!-- more -->
## !和?
The exclamation point (!, sometimes pronounced aloud as "bang!") indicates something potentially destructive, that is to say, something that can change the value of what it touches.
```
ruby> s1 = "forth"
"forth"
ruby> s1.chop! # This changes s1.
"fort"
ruby> s2 = s1.chop # This puts a changed copy in s2,
"for"
ruby> s1 # ... without disturbing s1.
"fort"
```
You'll also sometimes see chomp and chomp! used. These are more selective: the end of a string gets bit off only if it happens to be a newline.
The other method naming convention is the question mark (?, sometimes pronounced aloud as "huh?") indicates a "predicate" method, one that can return either true or false.
## 四种内部中断循环的方式
* `break`
* `next` 等同与continue
* `redo` restarts the current iteration
* `return`
## 迭代器 iterator
Ruby's String type has some useful iterators. `each_byte` is an iterator for each character in the string.
```shell
irb(main):001:0> "abc".each_byte{|c| printf "<%c>", c}; print "\n"
<a><b><c>
=> nil
```
Another iterator of String is `each_line`.
```shell
irb(main):002:0> "a\nb\nc\n".each_line{|l| print l}
a
b
c
=> "a\nb\nc\n"
```
ruby的 `for in` 也是一种迭代。We can use a control structure `retry` in conjunction with an iterated loop, and it will retry the loop from the beginning.
### yield
`yield` occurs sometimes in a definition of an iterator. `yield` moves control to the block of code that is passed to the iterator (this will be explored in more detail in the chapter about procedure objects). The following example defines an iterator repeat, which repeats a block of code the number of times specified in an argument.
```ruby
irb(main):003:0> def repeat(num)
irb(main):004:1> while num > 0
irb(main):005:2> yield
irb(main):006:2> num -= 1
irb(main):007:2> end
irb(main):008:1> end
=> :repeat
irb(main):009:0> repeat(3) { puts "foo" }
foo
foo
foo
=> nil
```
## class
### 继承
继承的格式为:
```ruby
class Superclass
def breathe
puts "inhale and exhale"
end
def identify
puts "I'm super"
end
def speak(word)
puts word
end
end
class Subclass<Superclass
# code...
end
```
可在在子类中重新声明基类方法,也可以使用`super`关键字来扩展基类方法。`super`也允许我们传递参数给基类方法。
```ruby
class Subclass<Superclass
def identify
super
puts "I'm sub too"
end
def speak(word)
super("this is from Superclass")
puts "now it's from Subclass: #{word}"
end
end
```
### 初始化(构造函数)
`ruby`使用`initialize`关键字来实现构造函数的功能。
```ruby
class Fruit
def initialize( k="apple")
@kind = k
@condition = "ripe"
end
end
apple = Fruit.new "apple"
```
## variables
* `[a-z] or _` 本地变量
* `$` 全局变量
* `@` 实例变量 instance variable
* `[A-Z]` 常量
### 全局变量
全局变量以 `$` 开头。初始化之前,全局变量的值为`nil`。可定义一段procedure来追踪全局变量。
```ruby
$x #return nil
trace_var :$x, proc{puts "$x is now #{$x}"}
$x = 5 #return $x is now 5
```
一些特殊的变量(不一定是全局作用域):
* `$!` latest error message
* `$@` location of error
* `$_` 上一次由gets读入的字符串
* `$.` line number last read by interpreter
* `$&` string last matched by regexp
* `$~` the last regexp match, as an array of subexpressions
* `$n` the nth subexpression in the last match (same as $~[n])
* `$=` case-insensitivity flag
* `$/` input record separator
* `$\` output record separator
* `$0` the name of the ruby script file
* `$*` 命令行参数
* `$$` 当前解释器的进程id
* `$?` 上一次子进程的退出状态码
### 实例变量
An instance variable has a name beginning with `@`, and its scope is confined to whatever object __self__ refers to. Two different objects, even if they belong to the same class, are allowed to have different values for their instance variables. From outside the object, instance variables __cannot be altered or even observed__ (i.e., ruby's instance variables are never public) except by whatever methods are explicitly provided by the programmer. As with globals, instance variables have the nil value until they are initialized.
Instance variables do not need to be declared. This indicates a flexible object structure; in fact, each instance variable is dynamically appended to an object when it is first assigned.
### 常量
常量名以大写字母开头。给常量重新赋值会得到警告。
```shell
irb(main):009:0> Wzr=1222
=> 1222
irb(main):010:0> Wzr=1223
(irb):10: warning: already initialized constant Wzr
(irb):9: warning: previous definition of Wzr was here
=> 1223
```
常量可以在类和模块中定义,并允许外部访问。
```ruby
class ConstClass
C1=120
end
ConstClass::C1 # return 120
```
## 访问器(accessor)
实例属性需要通过属性访问器访问。常规访问器有简化写法:
```ruby
class Fruit
def kind=(k)
@kind = k
end
def kind
@kind
end
end
```
### inspect方法
当创建一个对象时解释器会返回一些信息:
```ruby
irb(main):009:0> apple = Fruit.new
=> #<Fruit:0x00000000a34f58>
irb(main):010:0>
```
可以通过`inspect`关键字来改变这种默认行为。
```ruby
class Fruit
def inspect
"a fruit is created"
end
end
```
`inspect`方法常用来调试,可通过下面两种方式显示调用:
```ruby
p anObject
puts anObject.inspect
```
### shortcuts
`Ruby`提供了访问器的一些简写形式:
|缩写|效果|
| :------: | :------: |
|attr_reader :v| def v; @v; end|
|attr_writer :v| def v=(value); @v=value; end|
|attr_accessor :v| attr_reader :v; attr_writer :v|
|attr_accessor :v, :w| attr_accessor :v; attr_accessor :w|
## 注释
单行注释以`#`开头。
块注释可使用`=begin` `=end`来标记。
```ruby
=begin
这是一段注释块。This is a comment block.
Egg, I dreamed I was old.
=end
```
## Dynamic Dispatch
## Mixins
Ruby has no multiple inheritance. But it has mixins.
### Lookup rulres
When looking for receiver obj's method m,
* look in obj's class
* look in mixins the class includes(later includes shadow)
* look in obj's superclass
* look in mixins the superclass inculdes
* ...

View File

@@ -0,0 +1,119 @@
---
title: php的闭包特性
date: 2017-01-11 18:39:17
category: notes
tags:
- php
keywords:
- php
- 闭包
- lambada
- 匿名函数
---
闭包和匿名函数在`PHP 5.3.0`引入并且PHP将两者视为相同的概念。闭包其实是伪装成函数的对象它的实质其实是`Closure`实例。
创建闭包非常简单:
```php
$c = function($name) {
return sprintf("Hello World! Hello %s!", $name);
};
echo $c('PHP');
```
使用`use`对闭包附加状态,多个参数使用`,`分隔:
```php
function callPerson($name) {
return function($about) use ($name) {
return sprintf("%s, %s", $name, $about);
}
}
$triver = callPerson('Triver');
echo $triver("slow down, please!!");
```
附加的变量会被封装到闭包内,即使返回的闭包队形已经跳出了`callPerson()`的作用域也仍然会记住`$name`的值。
闭包有一个有趣的`bindTo()`方法,可以将闭包的内部状态绑定到其他对象上,第二个参数指定了绑定闭包的对象所属的类,从而实现在闭包中访问绑定对象的私有方法和属性。
```php
class Bind {
protected $name = 'no name';
public $change;
public function addAction($action) {
$this->change = $action->bindTo($this, __CLASS__);
}
}
$bind = new Bind();
$bind->addAction(function() {
$this->name = "php";
return $this->name;
});
$change = $bind->change;
echo $change();
```
使用这个特性可以方便的为类添加方法并绑定:
```php
trait MetaTrait
{
//定义$methods数组,用于保存方法(函数)的名字和地址。
private $methods = array();
//定义addMethod方法使用闭包类绑定匿名函数。
public function addMethod($methodName, $methodCallable)
{
if (!is_callable($methodCallable)) {
throw new InvalidArgumentException('Second param must be callable');
}
$this->methods[$methodName] = Closure::bind($methodCallable, $this, get_class());
}
//方法重载。为了避免当调用的方法不存在时产生错误,
//可以使用 __call() 方法来避免。
public function __call($methodName, array $args)
{
if (isset($this->methods[$methodName])) {
return call_user_func_array($this->methods[$methodName], $args);
}
throw RunTimeException('There is no method with the given name to call');
}
}
class HackThursday {
use MetaTrait;
private $dayOfWeek = 'Thursday';
}
$test = new HackThursday();
$test->addMethod('when', function () {
return $this->dayOfWeek;
});
echo $test->when();
```
php7 中增加了 `Closure::call()` 方法,可以更高效的绑定对象作用域并调用。
```php
class A {private $x = 1;}
// Pre PHP 7 code
$getXCB = function() {return $this->x;};
$getX = $getXCB->bindTo(new A, 'A'); // intermediate closure
echo $getX();
// PHP 7+ code
$getX = function() {return $this->x;};
echo $getX->call(new A);
```

View File

@@ -0,0 +1,73 @@
---
title: java散列知识点总结
date: 2017-02-18 19:19:01
category: notes
tags:
- Algorithms
keywords:
- hash
- 散列
- 哈希
- java
---
java 的根类 `Object` 具有 `hashcode` 方法。当 `equal` 方法被重写时也应当重写 `hashcode` 方法。
## 基本数据类型的散列码
* `byte` `short` `int` `char` 类型的搜索键将会转换为 `int`
* `float` 类型的搜索键使用 `Float.floatToIntBits(key)` 作为散列码。
* `long` 类型的搜索键会进行折叠操作,如下:
```java
iny hashCode = (int) (key ^ (key >> 32));
```
* `double` 类型的搜索键会使用 `Double.doubleToLongBits(key)` 方法转换为 `long` 类型然后再进行折叠。
## 字符串类型的散列码
对于字符串一般使用多项式散列码进行计算,
~~这里放个公式的图~~
b的较好取值为3133373941。在 java String 类中 `b` 取31。
```java
public static int hash(String key, int tableSize)
{
int hashVal = 0;
for (int i = 0; i < key.length(); i++)
hashVal = 37*hashVal + key.charAt(i);
hashVal %= tableSize;
if (hashVal < 0)
hashVal += tableSize;
return hashVal;
}
```
## 压缩散列码
由于散列码可能是很大的正数,通常应该对其进行压缩以防止超出索引的范围。若索引范围为 `0 ~ n - 1` ,通常的做法是 `h(hashCode) = hashCode % N` 选择N为大于2的素数。
`java.util.HashMap` 的实现中将N设置为2的幂值这样可以使用位运算代替上述的取模`h(hashCode) = hashCode & (N - 1)` ,两者是完全等价的。
## 处理冲突
### 开放地址法
开放地址法是在冲突发生时,在散列表中找到一个开放位置的过程。
* 线性探测,存在成簇问题
* 二次探测,存在二次成簇问题,并且不能保证一个开放的单元总是可以被找到。
* 再哈希法
### 链地址法
链地址法是将具有同样索引的条目放在同一位置,每个位置使用一个桶(ArrayList or LinkedList)来放置多个条目。
## 装填因子
装填因子衡量一个散列表有多满。`lamda = n / N` 。对于开放地址法,装填因子介于 0 ~ 1对于链地址法装填因子可能为任意值。通常开放地址法需要将装填因子维持在0.5以下而链地址法为0.9以下。`java.util.HashMap` 采用了阈值0.75。

View File

@@ -0,0 +1,438 @@
---
title: ES6について
date: 2019-01-18 16:00:00
tags:
- JavaScript
category: tech
keywords:
- Javascript
- ES2015
- ES6
---
## Overview
[https://github.com/lukehoban/es6features#readme](https://github.com/lukehoban/es6features#readme)
[http://help.wtf/es6](http://help.wtf/es6)
[http://es6-features.org](http://es6-features.org)
## String
### String.x is deprecated; use String.prototype.x instead.
非推奨の構文:
```Javascript
var num = 15;
String.replace(num, /5/, '2');
```
標準の構文:
```Javascript
var num = 15;
String(num).replace(/5/, '2');
```
### Template literal
Nesting templates:
```Javascript
const classes = `header ${ isLargeScreen() ? '' : `icon-${item.isCollapsed ? 'expander' : 'collapser'}` }`;
```
<!--more-->
タグ付けされたtemplate
```Javascript
var a = 5;
var b = 10;
function tag(strings, ...values) {
console.log(strings[0]); // "Hello "
console.log(strings[1]); // " world"
console.log(values[0]); // 15
console.log(values[1]); // 50
return "Bazinga!";
}
tag`Hello ${ a + b } world ${ a * b}`;
// "Bazinga!"
```
[http://help.wtf/es6#template_literals](http://help.wtf/es6#template_literals)
```Javascript
// Backticks enclose a template literal; ${} interpolates arbitrary expressions
let num = 99; // see block scope
console.log(`${num} bottles of beer on the wall, ${num} bottles of beer
Take one down and pass it around, ${--num} bottles of beer!`);
// Tagged form: Attach a function that processes string fragments and evaluated
// expressions
function celsius(strings, ...values) {
let rv = '';
strings.forEach((string, index) => { // See arrow functions
rv += string;
if (typeof values[index] !== 'undefined')
rv += Math.round((values[index] - 32) / 1.8);
});
return rv;
}
// Converts all the interpolated numbers to the proper unit
console.log(celsius `Today temperatures ranged from ${60} to ${65} degrees.`);
```
## var and let
[https://eslint.org/docs/rules/no-var](https://eslint.org/docs/rules/no-var)
>ECMAScript 6 allows programmers to create variables with block scope instead of function scope using the let and const keywords. Block scope is common in many other programming languages and helps programmers avoid mistakes.
```Javascript
if (true) {
var i = 1;
let j = 2;
}
console.log(i) // 1
console.log(j) // ReferenceError: not defined
```
## Default function parameters
```Javascript
function multiply(a, b = 1) {
return a * b;
}
```
## Iterators and for...of
```Javascript
let fibonacci = {
[Symbol.iterator]() {
let pre = 0, cur = 1;
return {
next() {
[pre, cur] = [cur, pre + cur];
return { done: false, value: cur }
}
}
}
}
for (var n of fibonacci) {
// truncate the sequence at 1000
if (n > 1000)
break;
console.log(n);
}
```
More: [Duck Typing](https://en.wikipedia.org/wiki/Duck_typing)
## Modules
### import and export
[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import)
[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export)
### Module Loaders
Module loaders support:
* Dynamic loading
* State isolation
* Global namespace isolation
* Compilation hooks
* Nested virtualization
The default module loader can be configured, and new loaders can be constructed to evaluate and load code in isolated or constrained contexts.
```Javascript
// Dynamic loading System is default loader
System.import('lib/math').then(function(m) {
alert("2π = " + m.sum(m.pi, m.pi));
});
// Create execution sandboxes new Loaders
var loader = new Loader({
global: fixup(window) // replace console.log
});
loader.eval("console.log('hello world!');");
// Directly manipulate module cache
System.get('jquery');
System.set('jquery', Module({$: $})); // WARNING: not yet finalized
```
## Promises
[JavaScript Promiseの本](https://github.com/azu/promises-book)
```Javascript
function asyncFunction() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('Async Hello world');
}, 16);
});
}
asyncFunction().then(function (value) {
console.log(value); // => 'Async Hello world'
}).catch(function (error) {
console.error(error);
});
```
## Generators
[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols)
```Javascript
// A generator function will return an object that implements the iteration
// protocol, i.e., it has a next() method that returns
// { value: < some value>, done: <true or false> }
function* incRand(max) { // Asterisk defines this as a generator function
while (true) {
// Pause execution after the yield, resume when next(<something>) is called
// and assign <something> to x
let x = yield Math.floor(Math.random() * max + 1);
max += x;
}
}
var rng = incRand(2); // Now we have a generator object to work with
console.log(rng.next()); // { value: <between 1 and 2>, done: false }
console.log(rng.next(3)); // as above, but between 1 and 5
console.log(rng.next()); // as above, but NaN since 5 + undefined results in NaN
console.log(rng.next(20)); // Oops, looks like we broke it! NaN again.
rng.throw(new Error('Unrecoverable generator state.')); // Will be thrown from yield
```
## shorthand of Object initializer
[https://ariya.io/2013/02/es6-and-object-literal-property-value-shorthand](https://ariya.io/2013/02/es6-and-object-literal-property-value-shorthand)
```Javascript
// Shorthand property names (ES2015)
var a = 'foo', b = 42, c = {};
var o = {a, b, c};
// Shorthand method names (ES2015)
var o = {
property(parameters) {}
};
// Computed property names (ES2015)
var prop = 'foo';
var o = {
[prop]: 'hey',
['b' + 'ar']: 'there'
};
```
[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)
## Destructuring
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables. Destructuring is **fail-soft**, similar to standard object lookup foo["bar"], producing undefined values when not found.
```Javascript
let [n1, n2, n3, n4, ...r] = [100, 'three', 34, {number: 23}, 694, 'eighteen'];
console.log(n1, n2, n3, n4); // "100 'three' 34 { number: 23 }"
console.log(r); // "[ 694, 'eighteen' ]"
```
Two variables values can be swapped in one destructuring expression
```Javascript
var a = 1;
var b = 3;
[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1
```
Object Destructuring
```Javascript
var o = {p: 42, q: true};
var {p, q} = o;
console.log(p); // 42
console.log(q); // true
```
Works for function parameters
```Javascript
var fmt = ({id = 0, name}) => `${id}: ${name}`;
console.log(fmt({ id: 1, name: 'joe'}));
```
## symbol
[https://developer.mozilla.org/en-US/docs/Glossary/Symbol](https://developer.mozilla.org/en-US/docs/Glossary/Symbol)
`sympol` is a primitive data type. The Symbol() function returns a value of type symbol and every returned value is unique. It **does not** support `new Symbol()`
```Javascript
var sym1 = Symbol();
var sym2 = Symbol('foo');
var sym3 = Symbol('foo');
Symbol('foo') === Symbol('foo'); // false
var sym = new Symbol(); // TypeError
```
## Map + Set + WeakMap + WeakSet
Reference: [Why WeakMap?](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap#Why_WeakMap)
>Native WeakMaps hold "weak" references to key objects, which means that they do not prevent garbage collection in case there would be no other reference to the key object. This also avoids preventing garbage collection of values in the map.
```Javascript
/ Sets
var s = new Set();
s.add("hello").add("goodbye").add("hello");
s.size === 2;
s.has("hello") === true;
// Maps
var m = new Map();
m.set("hello", 42);
m.set(s, 34);
m.get(s) == 34;
// Weak Maps
var wm = new WeakMap();
wm.set(s, { extra: 42 });
wm.size === undefined
// Weak Sets
var ws = new WeakSet();
ws.add({ data: 42 });
// Because the added object has no other references, it will not be held in the set
```
## New APIs in core libraries
```Javascript
// Number
Number.EPSILON
Number.isInteger(Infinity) // false
Number.isNaN("NaN") // false
// Math
Math.acosh(3) // 1.762747174039086
Math.hypot(3, 4) // 5
Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2) // 2
// String
"abcde".includes("cd") // true
"abc".repeat(3) // "abcabcabc"
// Array
Array.from(document.querySelectorAll('*')) // Returns a real Array
Array.of(1, 2, 3) // Similar to new Array(...), but without special one-arg behavior
[0, 0, 0].fill(7, 1) // [0,7,7]
[1, 2, 3].find(x => x == 3) // 3
[1, 2, 3].findIndex(x => x == 2) // 1
[1, 2, 3, 4, 5].copyWithin(3, 0) // [1, 2, 3, 1, 2]
["a", "b", "c"].entries() // iterator [0, "a"], [1,"b"], [2,"c"]
["a", "b", "c"].keys() // iterator 0, 1, 2
["a", "b", "c"].values() // iterator "a", "b", "c"
// Object
Object.assign(Point, { origin: new Point(0,0) })
```
## Proxies
The Proxy object is used to define custom behavior for fundamental operations (e.g. property lookup, assignment, enumeration, function invocation, etc).
See more examples at [MDN Proxy doc]([https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy))
**No-op forwarding proxy**
``` Javascript
var target = {};
var p = new Proxy(target, {});
p.a = 37; // operation forwarded to the target
console.log(target.a); // 37. The operation has been properly forwarded
```
**Validation**
```Javascript
let validator = {
set: function(obj, prop, value) {
if (prop === 'age') {
if (!Number.isInteger(value)) {
throw new TypeError('The age is not an integer');
}
if (value > 200) {
throw new RangeError('The age seems invalid');
}
}
// The default behavior to store the value
obj[prop] = value;
// Indicate success
return true;
}
};
let person = new Proxy({}, validator);
person.age = 100;
console.log(person.age); // 100
person.age = 'young'; // Throws an exception
person.age = 300; // Throws an exception
```
## Binary and Octal Literals
```
0b111110111 === 503 // true
0o767 === 503 // true
```
## その他
### Reflect API
[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect)
### Tail calls
```Javascript
function factorial(n, acc = 1) {
'use strict';
if (n <= 1) return acc;
return factorial(n - 1, n * acc);
}
// Stack overflow in most implementations today,
// but safe on arbitrary inputs in ES6
factorial(100000)
```
### Unicode
[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicode)

View File

@@ -0,0 +1,111 @@
---
title: VueのNavigation Guards
date: 2019-01-25 09:00:00
tags:
- JavaScript
- Vue.js
category: tech
keywords:
- Vue.js
- Javascript
- ES2015
- ES6
---
Navigation guards are provided by `vue-router`.
Three ways to hook:
* globally
* per-route
* in-component
__NOTE:__
1. Params or query changes won't trigger enter/leave navigation guards. You can either watch the `$route` object to react to those changes, or use the `beforeRouteUpdate` in-component guard.
2. Make sure to always call the next function, otherwise the hook will never be resolved.
## Global
```Javascript
const router = new VueRouter({ ... })
// Before Guards
router.beforeEach((to, from, next) => {
// ...
})
// Resolve Guards
// beforeResolve guards will be called right before the navigation is confirmed
// after all in-component guards and async route components are resolved
router.beforeResolve((to, from, next) => {
// ...
})
// After Hooks
router.afterEach((to, from) => {
// ...
})
```
## Pre-reoute
```Javascript
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
```
## In-component
```Javascript
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// called before the route that renders this component is confirmed.
// does NOT have access to `this` component instance,
// because it has not been created yet when this guard is called!
// However, you can access the instance by passing a callback to next.
// The callback will be called when the navigation is confirmed
// and the component instance will be passed to the callback as the argument
beforeRouteEnter (to, from, next) {
next(vm => {
// access to component instance via `vm`
})
}
},
beforeRouteUpdate (to, from, next) {
// called when the route that renders this component has changed,
// but this component is reused in the new route.
// For example, for a route with dynamic params `/foo/:id`, when we
// navigate between `/foo/1` and `/foo/2`, the same `Foo` component instance
// will be reused, and this hook will be called when that happens.
// has access to `this` component instance.
},
beforeRouteLeave (to, from, next) {
// called when the route that renders this component is about to
// be navigated away from.
// has access to `this` component instance.
}
}
```
## Resolve flow
+ Navigation triggered.
+ Call leave guards in deactivated components.
+ Call global beforeEach guards.
+ Call beforeRouteUpdate guards in reused components.
+ Call beforeEnter in route configs.
+ Resolve async route components.
+ Call beforeRouteEnter in activated components.
+ Call global beforeResolve guards.
+ Navigation confirmed.
+ Call global afterEach hooks.
+ DOM updates triggered.
+ Call callbacks passed to next in beforeRouteEnter guards with instantiated instances.

View File

@@ -0,0 +1,88 @@
---
title: Object.assign() with accessor descriptor
date: 2019-03-08 09:00:00
tags:
- JavaScript
category: tech
keywords:
- Javascript
- ES2015
- ES6
---
[MDN docs:](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Copying_accessors)
>The Object.assign() method only copies enumerable and own properties from a source object to a target object. It uses [[Get]] on the source and [[Set]] on the target, so it will invoke getters and setters. Therefore it assigns properties versus just copying or defining new properties. This may make it unsuitable for merging new properties into a prototype if the merge sources contain getters.
For example
```js
class Cat {
constructor(name) {
this._name = name;
}
get name() {
return this._name;
}
set name(value) {
this._name = value;
}
}
let nyannko = new Cat("nyannko");
let copy = Object.assign({}, nyannko)
console.log(nyannko.name) // nyannko
console.log(copy.name) // undefined
```
The `name` property is lost.
<!--more-->
To copy accessors, we can use `Object.getOwnPropertyDescriptor()` and `Object.defineProperty()` as the MDN docs recommend:
```js
var obj = {
foo: 1,
get bar() {
return 2;
}
};
var copy = Object.assign({}, obj);
console.log(copy);
// { foo: 1, bar: 2 }, the value of copy.bar is obj.bar's getter's return value.
// This is an assign function that copies full descriptors
function completeAssign(target, ...sources) {
sources.forEach(source => {
let descriptors = Object.keys(source).reduce((descriptors, key) => {
descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
return descriptors;
}, {});
// by default, Object.assign copies enumerable Symbols too
Object.getOwnPropertySymbols(source).forEach(sym => {
let descriptor = Object.getOwnPropertyDescriptor(source, sym);
if (descriptor.enumerable) {
descriptors[sym] = descriptor;
}
});
Object.defineProperties(target, descriptors);
});
return target;
}
var copy = completeAssign({}, obj);
console.log(copy);
// { foo:1, get bar() { return 2 } }
```
The other way is `Object.prototype.__proto__` (but **not recommended**):
```js
let completeCopy = Object.assign({__proto__: nyannko.__proto__}, nyannko);
console.log(completeCopy.name); // nyannko
```
`Object.prototype.__proto__` is deprecated so be aware that this may cease to work at any time.
[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto)

View File

@@ -0,0 +1,50 @@
---
title: Bind specific arguments of a function
date: 2019-03-08 09:00:00
tags:
- JavaScript
category: tech
keywords:
- Javascript
- ES2015
- ES6
---
To bind specific (nth) arguments of a function, we can write a decorator instead of using `Function.bind()`:
```js
function func(p1, p2, p3) {
console.log(p1, p2, p3);
}
// the binding starts after however many are passed in.
function decorator(...bound_args) {
return function(...args) {
return func(...args, ...bound_args);
};
}
// bind the last parameter
let f = decorator("3");
f("a", "b"); // a b 3
// bind the last two parameter
let f2 = decorator("2", "3")
f2("a"); // a 2 3
```
Even if we want to bind just the nth argument, we can do as follows:
```js
// bind a specific (nth) argument
function decoratorN(n, bound_arg) {
return function(...args) {
args[n-1] = bound_arg;
return func(...args);
}
}
let fN = decoratorN(2, "2");
fN("a","b","c"); // a 2 c
```
[https://stackoverflow.com/questions/27699493/javascript-partially-applied-function-how-to-bind-only-the-2nd-parameter](https://stackoverflow.com/questions/27699493/javascript-partially-applied-function-how-to-bind-only-the-2nd-parameter)

View File

@@ -0,0 +1,153 @@
---
title: Js tips I can't remember
date: 2019-03-22 09:00:00
tags:
- JavaScript
category: tech
keywords:
- Javascript
- ES2015
- ES6
---
## `__proto__` VS `prototype`
>`__proto__` is the actual object that is used in the lookup chain to resolve methods and others. `prototype` is the object that is used to build `__proto__` when creating an object with `new`.
>The "cool kids" in JavaScript would generally pronounce `__proto__` as "**dunder proto**".
[https://stackoverflow.com/questions/9959727/proto-vs-prototype-in-javascript](https://stackoverflow.com/questions/9959727/proto-vs-prototype-in-javascript)
```javascript
( new Foo ).__proto__ === Foo.prototype; // true
( new Foo ).prototype === undefined; // true
```
<!--more-->
## `{}` VS `Object.create(null)`
`Object.create(null)` can create a *'pure'* empty object that is without the delegation to `Object.prototype`.
```javascript
let obj1 = {};
let obj2 = Object.create(null);
console.log(obj1.__proto__); // {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
console.log(obj2.__proto__); // undefined
```
## Computed Property Names
ES6 adds computed property names, which is helpful when declaring objects using the object-literal syntax.
```javascript
var prefix = "foo";
var myObject = {
[prefix + "bar"]: "hello",
[prefix + "baz"]: "world"
};
myObject["foobar"]; // hello
myObject["foobaz"]; // world
```
## Dangerous `Function.prototype.name` comparison
Sometimes we may spectify a function by comparing the function name:
```javascript
function Foo() {};
let foo = new Foo();
if (foo.constructor.name === 'Foo') {
console.log("'foo' is an instance of 'Foo'");
} else {
console.log('Oops!');
}
```
It may behave unexpectedly after building because most build tools compress the code to forms like:
```javascript
function a() {};
let b = new a();
if (b.constructor.name === 'Foo') {
console.log("'foo' is an instance of 'Foo'");
} else {
console.log('Oops!');
}
```
## A more robust way of performing object property check
Normally we use `hasOwnProperty()` checks to see if object has the property or not. But consider objects created by:
```javascript
// this will not consult the [[Prototype]] chain
let obj = Object.create(null)
```
Such object does not link to `Object.prototype`, thus `obj.hasOwnProperty(...)` would fail and raise error.
We can use a more robust way to perform property check:
```javascript
Object.prototype.hasOwnProperty.call(obj,"a") //false
```
Or:
```javascript
// this will check the current object or any higher level of the [[Prototype]] chain
"a" in obj
```
## `for...in` vs `for...of`
The `for..in` loop iterates over the list of enumerable properties on an object (including its `[[Prototype]]` chain).The `for...of` iterate over the values directly instead of the array indices (or object properties). It asks built-in or custom `@@iterator` of the thing to be iterated.
```javascript
let arr = ['a', 'b', 'c']
arr.name = 'foo'
arr // ["a", "b", "c", name: "foo"]
for (key in arr)
console.log(key) // 0 1 2 name
for (value of arr)
console.log(value) // a b c
```
## "(Prototypal) Inheritance"
When writing "prototype style" code like implementing Parent-Child class inheritance:
```javascript
function Foo(name) {
this.name = name;
}
Foo.prototype.myName = function() {
return this.name;
};
function Bar(name,label) {
Foo.call( this, name );
this.label = label;
}
// Then trying to build a family with Foo and Bar
// ...
```
A common mis-conception/confusion here is that either of the following approaches would also work, but they do not work as you'd expect:
```javascript
// doesn't work like you want!
Bar.prototype = Foo.prototype;
// works kinda like you want, but with
// side-effects you probably don't want :(
Bar.prototype = new Foo();
```
the right way is:
```javascript
// "make a new 'Bar dot prototype' object that's linked to 'Foo dot prototype'."
// pre-ES6
// throws away default existing `Bar.prototype`
Bar.prototype = Object.create( Foo.prototype );
// ES6+
// modifies existing `Bar.prototype`
Object.setPrototypeOf( Bar.prototype, Foo.prototype );
```
**reference**: [You-Dont-Know-JS: "(Prototypal) Inheritance"](https://github.com/getify/You-Dont-Know-JS/blob/master/this%20%26%20object%20prototypes/ch5.md#prototypal-inheritance)

View File

@@ -0,0 +1,54 @@
---
title: JavaScript Comparison operation at a glance
date: 2019-03-28 09:00:00
tags:
- JavaScript
category: tech
keywords:
- Javascript
- ES2015
- ES6
---
When given a scenario like:
```javascript
console.log(null > -1) //true
```
It produces `true`, which makes me think `null` is treated as `0`. But when I run:
```javascript
console.log(null == 0) // false
console.log(null > 0) // false
console.log(null < 0) // false
```
They all output `false`!
I googled a lot and finally found answers in [Ecma-262 Specification](http://www.ecma-international.org/ecma-262/8.0/#sec-abstract-equality-comparison).
The comparison `x == y`, where x and y are values, produces true or false. Such a comparison is performed as follows:
<!-- more -->
```text
1. If Type(x) is the same as Type(y), then return the result of performing Strict Equality Comparison x === y.
2. If x is null and y is undefined, return true.
3. If x is undefined and y is null, return true.
4. If Type(x) is Number and Type(y) is String, return the result of the comparison x == ToNumber(y).
5. If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
6. If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
7. If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
8. If Type(x) is either String, Number, or Symbol and Type(y) is Object, return the result of the comparison x == ToPrimitive(y).
9. If Type(x) is Object and Type(y) is either String, Number, or Symbol, return the result of the comparison ToPrimitive(x) == y.
10. Return false.
```
Relational comparison is much more complex so I'm not copying that section. Read at the [spec website](http://www.ecma-international.org/ecma-262/8.0/#sec-abstract-relational-comparison).
## TL;DR
Anyway it seems that in `null == 0`, `null` is treated just as is, and **equality** comparison between `null` and `Number` always return **false** (No 10).
But when it comes `null > -1`, `null` is conversed to 0 using [ToNumber()](http://www.ecma-international.org/ecma-262/8.0/#sec-tonumber) algorithm.
Read more:
* [https://github.com/getify/You-Dont-Know-JS/issues/1238](https://github.com/getify/You-Dont-Know-JS/issues/1238)
* [http://www.ecma-international.org/ecma-262/8.0/#sec-abstract-relational-comparison](http://www.ecma-international.org/ecma-262/8.0/#sec-abstract-relational-comparison)
* [http://www.ecma-international.org/ecma-262/8.0/#sec-tonumber](http://www.ecma-international.org/ecma-262/8.0/#sec-tonumber)

View File

@@ -0,0 +1,208 @@
---
title: uipath ノート(一)
date: 2019-10-27 09:00:00
tags:
- RPA
categories:
- notes
keywords:
- RPA
- uipath
---
## 変数
* Int32
* String
* Boolean
* GenericValue [参照](https://docs.uipath.com/studio/lang-ja/docs/genericvalue-variables)
>UiPath Studio には GenericValue 変数の自動変換メカニズムがあり、式を正しく定義することで、目的の結果を得ることができます。式の最初の要素は、Studio から操作するガイドラインとして使用されることを考慮してください。例えば、2 つの GenericValue 変数を追加し、式の最初の変数が String として定義されてた場合、最初に代入された値を元に 2 つの値を結合し、文字列となります。 Integer として定義した場合の結果は、合計の値となります。
* Array
* DataTime
* DataTable
[.Net 変数型を参照して探す方法](https://docs.uipath.com/studio/lang-ja/docs/managing-variables#section-browsing-for-net-variable-types)
## アクティビティ
### レイアウトダイアグラム
* シーエンス: より高度で複雑な自動化に向こう
* フローチャート: シンプルな自動化プロジェクトに適している
* ステートマシン
* Global Exception Handler (グローバル例外ハンドラー)
>参照:[https://docs.uipath.com/studio/lang-ja/docs/workflow-design](https://docs.uipath.com/studio/lang-ja/docs/workflow-design)
### 選択肢
* 条件分岐(If): シーケンス用条件分岐
* フロー条件分岐(flow desicion): フローチャート用条件分岐
* フロースイッチ (Flow Switch)
### 繰り返し
* 繰り返し(前判定)(While)
* 繰り返し(後判定)(Do While)
* 繰り返し(コレクションの各要素)(For Each)
### データ操作
* CSVを読み込み(Read CSV)
- オプションにエンコーディングを指定できる(日本語データがある場合、`"SHIFT-JIS"`を指定する)
- 列名を含める(IncludeColumnNames)を指定できる
- 出力タイプ:`System.Data.DataTable` [Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/api/system.data.datatable?view=netframework-4.8)
- `Select`メソッドで半角スペースを含む列名で指定する場合、半角スペースが特殊文字ではなく文字列として認識されるため、`[]`で列名を囲う
```
Names.Select("[メンバー ステータス] = 'Yes'")
```
### その他
* メッセージボックス
* 代入(assign)
* 待機 (Delay)
* 入力ダイアログinput dialog:
* フォルダーを選択(Select Folder)
* 一行を書き込み(Write Line) Debug用
* アプリケーションを開く(Open Application)
* ブラウザを開く(Open Browser)
* ブラウザーにアタッチ(Attach Browser)
* 文字を入力(Type Into)
* ハイライト(Highlight)
* [アンカーベース(Anchor Base)](#アンカーベース-Anchor-Base)
* スクリーンショットをと撮る(Take Screenshot)
* 要素の有無を検出(Element Exists)
* 要素の消滅を待つ(Wait Element Vanish)
## レコーディング機能
<span style="color: green">\[○\]レコーディング可</span>
* 左クリック
- ボタン
- チェックボックス
- ドロップダウン
- ...
* 文字入力
<span style="color: red">\[×\]レコーディング不可</span>
* ショットカットキー
* 修飾キー(`ctrl + c`など)
* 右クリック
* マウスホバー
**ショットカット**
* F2 - 時間差で選択
* F3 - 領域を選択
### ベーシック
* 適する操作内容:複数ウィンドウ上の単一の操作
* 生成されるワークフローがシンプル
### デスクトップ
* 適する操作内容:同一ウィンドウ上の連続した操作
* 生成されるワークフローが複雑
* セレクターの保守性が良い
### ウェブ
ウェブアプリとブラウザーでレコーディングを行うためのものです。コンテナーを生成し、既定で 入力をシミュレート (Simulate Type)/クリック (Click) の入力メソッドを使用します。
## 入力/出力方法まとめ
### 入力
* デフォルト(Default)
- 互換性が高い
- キーボード対応
* ウィンドウメッセージ(Windows Message)
- バックグラウンド処理
- キーボード対応
* シミュレート(Simulate Type/Click)
- 互換性が低い
- バックグラウンド処理
- フィールド内自動削除
### 出力
* フルテキスト(FullText)
- スピード:★★★★★
- 正確さ100%
- バックグラウンド処理
- 非表示の項目を取得
* ネイティブ(Native)
- スピード:★★★★
- 正確さ100%
- 文字情報を取得
* OCR
- スピード:★★
- 正確さ98%(?)
- 文字情報を取得
- CITRIX対応
## セレクター
* 部分セレクター
* 完全セレクター
* 動的なセレクター:ワイルドカードを使ってる
* アンカーベース(Anchor Base)
* 相対的なアンカー(Select Relative Element)
>セレクターがあまり安定しないと考えられるときには、[Anchor Baseアンカーベース] アクティビティや、UiPath Explorer の [Select Relative Element相対的なアンカーを選択してください] を使用することで、信頼性の高い自動化を構築できる場合があります。
### アンカーベース(Anchor Base)
アンカーとして使用できるアクティビティ:
* 要素を探す(Find Element)
* 画像を探す(Find Image)
## EXCEL操作
* EXCELアプリケーションスコープ(Excel Application Scope)
* 範囲を追加(Append Range)
* データテーブルを並べ替え(Sort Data Table)
* データテーブルをフィルタリング(Filter Data Table)
* Build Data Table
* Generate Data Table
* Output Data Table
## PDF操作
PDF Activities Pack
`UiPath.PDF.Activities`
* PDFのテキストを読み込み(Read PDf Text)
- 範囲(Range):ページ範囲を指定する。ディフォルトは`"ALL"`。例: `1` `3-5`
* OCRでPDFを読み込み(Read PDF With OCR)
* 画面スクレイピング(Screen Scraping)も適用
## MAIL操作
MailMessageの型
```
System.Net.Mail.MailMessage
System.Web.Mail.MailMessage
```
* SMTP
* POP3
* IMAP
* Outlook
* Exchange
* IBM Notes
## Debug
* トライキャッチ(Try Catch)
* メッセージをログ(Log Message)
- Critical
- Error
- Warning
- Information
- Trace
- Verbose: Traceと同じレベルだが、アクティビティ start および end の両方のメッセージと、使用される変数および引数の値を記録する

View File

@@ -0,0 +1,114 @@
---
title: JavaScript URI エンコーディング
date: 2019-11-10 09:00:00
tags:
- JavaScript
categories:
- notes
keywords:
- Javascript
- encodeURIComponent
---
## まとめ
`encodeURI()``encodeURIComponent()`はRFC 2396準拠である。
`encodeURI()` は完全な URI を表すのに必要な文字 (Reserved Characters) はエンコードしません。
また、予約されていないが "そのまま" URI に使用できる(Unreserved Marks) 文字をエンコードしません。
`encodeURIComponent()` は "Unreserved Marks" 文字をエンコードしません。
```JavaScript
var set1 = ";,/?:@&=+$#"; // Reserved Characters
var set2 = "-_.!~*'()"; // Unreserved Marks
console.log(encodeURI(set1)); // ;,/?:@&=+$
console.log(encodeURI(set2)); // -_.!~*'()
console.log(encodeURIComponent(set1)); // %3B%2C%2F%3F%3A%40%26%3D%2B%24
console.log(encodeURIComponent(set2)); // -_.!~*'()
```
## rfc2396 appendix-A
[https://tools.ietf.org/html/rfc2396#appendix-A](https://tools.ietf.org/html/rfc2396#appendix-A)
```
URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
absoluteURI = scheme ":" ( hier_part | opaque_part )
relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
hier_part = ( net_path | abs_path ) [ "?" query ]
opaque_part = uric_no_slash *uric
uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" |
"&" | "=" | "+" | "$" | ","
net_path = "//" authority [ abs_path ]
abs_path = "/" path_segments
rel_path = rel_segment [ abs_path ]
rel_segment = 1*( unreserved | escaped |
";" | "@" | "&" | "=" | "+" | "$" | "," )
scheme = alpha *( alpha | digit | "+" | "-" | "." )
authority = server | reg_name
reg_name = 1*( unreserved | escaped | "$" | "," |
";" | ":" | "@" | "&" | "=" | "+" )
server = [ [ userinfo "@" ] hostport ]
userinfo = *( unreserved | escaped |
";" | ":" | "&" | "=" | "+" | "$" | "," )
hostport = host [ ":" port ]
host = hostname | IPv4address
hostname = *( domainlabel "." ) toplabel [ "." ]
domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
toplabel = alpha | alpha *( alphanum | "-" ) alphanum
IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit
port = *digit
path = [ abs_path | opaque_part ]
path_segments = segment *( "/" segment )
segment = *pchar *( ";" param )
param = *pchar
pchar = unreserved | escaped |
":" | "@" | "&" | "=" | "+" | "$" | ","
query = *uric
fragment = *uric
uric = reserved | unreserved | escaped
reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
"$" | ","
unreserved = alphanum | mark
mark = "-" | "_" | "." | "!" | "~" | "*" | "'" |
"(" | ")"
escaped = "%" hex hex
hex = digit | "A" | "B" | "C" | "D" | "E" | "F" |
"a" | "b" | "c" | "d" | "e" | "f"
alphanum = alpha | digit
alpha = lowalpha | upalpha
lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
"j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
"s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" |
"J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" |
"S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
"8" | "9"
```
## 参考
[https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent)
[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI)
[https://qiita.com/aosho235/items/0581fc82f8ce2c5ac055](https://qiita.com/aosho235/items/0581fc82f8ce2c5ac055)
[https://tools.ietf.org/html/rfc2396](https://tools.ietf.org/html/rfc2396)

View File

@@ -0,0 +1,49 @@
---
title: uipath ノート(二)- Best Practice
date: 2019-11-18 09:00:00
tags:
- RPA
categories:
- notes
keywords:
- RPA
- uipath
---
## 時間をかけて各ワークフローに適したレイアウトを選択しましょう。
* メイン: フローチャートまたはステートマシン
* ビジネスロジック: フローチャート
* UI インタラクション: シーケンス
* フローチャートを使用することで、入れ子状の IF を回避
## プロセスを小さなワークフローに分割しましょう。
* 分割したものを個別に開発、テスト
* ワークフローの再利用
* 分割ファイルで作業することによる、より効率的な共同作業
## 必ず例外を処理しましょう。
* 例外が発生しやすいワークフローを [Try Catch (トライキャッチ)] ブロックに配置
* 外部から呼び出されたワークフローでも同様
* リカバリシーケンスの設定
## ワークフローを読みやすいものにしましょう。
* すべてのコンポーネントにわかりやすい名前を選択
* 注記やコメントの使用
* リアルタイムの実行状況のログ取得
* 環境設定を Config ファイルに格納
## 不要になったアプリケーションを終了させることで、常にクリーンな状態を維持しましょう。

View File

@@ -0,0 +1,80 @@
---
title: uipath ノート(三)- uipath orchestrator
date: 2019-11-23 09:00:00
tags:
- RPA
categories:
- notes
keywords:
- RPA
- uipath
---
## 利用手順
Official doc: [https://docs.uipath.com/robot/docs/from-orchestrator-and-the-orchestrator-settings-window](https://docs.uipath.com/robot/docs/from-orchestrator-and-the-orchestrator-settings-window)
### マシンを追加
マシン側でマシン名とユーザ名を確認
```
C:\Users\user>hostname
DESKTOP-ABCDE5F
C:\Users\user>whoami
desktop-abcde5f\user
C:\Users\user>
```
追加完了後、マシンキーを取得する。
### ロボットを登録
* Type: studio (開発用?)
* Domain/Username: 上記のユーザ名
### ローカルのorchestrator設定
Uipath Robotを開き⇒orchestratorの設定で、上記のマシンキーを入力する。
orchestrator URLに `https://platform.uipath.com/` を入力する.
`Invalid machine key`というエラーが出たら、下記のようなURLを試す
```
https://platform.uipath.com/<account name>/<service name>
```
参照:[Uipath orchestrator error : invalid machine key](https://forum.uipath.com/t/uipath-orchestrator-error-invalid-machine-key/153438/16)
### ロボットグループ(Environment)作成
### プロジェクトをパブリッシュ(Publish)
### プロセスを追加
Automations  Processes
### ジョブ(Jobs)の実行
Monitoring  Jobs
## その他
### 再パブリッシュすると、Processが最新バージョンを使うため、変更作業が必要
Processes  More Options  View Process  最新のバージョンに切り替える
### ジョブの停止
* 停止(Stop):必ずワークフロー内で「停止すべきか確認(Should Stop)」アクティビティを使用する
* 強制終了(Kill):処理中の内容に関わらず、ジョブを停止する
### アクティブなジョブは削除できない
### パラメーター変更の優先順位
ジョブ (Jobs) -> プロセス (Processes) -> パッケージ(UiPath Studio)
### マシンテンプレート
Machine Templates only work for Active Directory users, Attended Floating Robots and Studio Floating Robots.

View File

@@ -0,0 +1,646 @@
---
title: Standard ML notes
date: 2019-12-30 09:00:00
tags:
- SML
categories:
- notes
keywords:
- SML
---
## Basics
### Comments
```ML
(* SML comment *)
```
### Variable bindings and Expressions
```ML
val x = 34;
(* static environment: x : int *)
(* dynamic environment: x --> 34 *)
val y = x + 1;
(* Use tilde character instead of minus to reprsent negation *)
val z = ~1;
(* Integer Division *)
val w = y div x
```
Strings:
```ML
(* `\n`のようなエスケープシーケンスが利用できる *)
val x = "hello\n";
(* 文字列の連結には'^'を使う *)
val y = "hello " ^ "world";
```
An ML program is a sequence of bindings. Each binding gets **type-checked** and then **evaluated**.
What type a binding has depends on a static environment. How a binding is evaluated depends on a dynamic environment.
Sometimes we use just `environment` to mean dynamic environment and use `context` as a synonym for static environment.
* Syntaxs : How to write it.
* Semantics: How it type-checks and evaluates
* Value: an expression that has no more computation to do
### Shadowing
**Bindings are immutable** in SML. Given `val x = 8 + 9;` we produce a dynamic environment where x maps to 17.
In this environment x will always map to 17; there is no "assignment statement" in ML for changing what x maps to.
You can have another binding later, say `val x = 19;`, but that just creates a differnt environment
where the later binding for x **shadows** the earlier one.
### Function Bindings
```ML
fun pow (x:int, y:int) = (* correct only for y >= 0 *)
if y = 0
then 1
else x * pow(x, y-1);
fun cube (x : int) =
pow(x, 3);
val ans = cube(4);
(* The parentheses are not necessary if there is only one argument
val ans = cube 4; *)
```
* Syntax: `fun x0 (x1 : t1, ..., xn : tn) = e`
* Type-checking:
- `t1 * ... * tn -> t`
- The type of a function is "argument types" -> "reslut types"
* Evaluation:
- A function is a value
- The environment we extends arguments with is that “was current” when the function was defined, not the one where it is being called.
### Pairs and other Tuples
```ML
fun swap (pr : int*bool) =
(#2 pr, #1 pr);
fun sum_two_pairs (pr1 : int * int, pr2 : int * int) =
(#1 pr1) + (#2 pr1 ) + (#1 pr2) + (#2 pr2);
fun div_mod (x : int, y: int) =
(x div y, x mod y);
fun sort_pair(pr : int * int) =
if (#1 pr) < (#2 pr) then
pr
else
(#2 pr, #1 pr);
```
ML supportstuplesby allowing any number of parts. Pairs and tuples can be nested however you want. For example, a 3-tuple (i.e., a triple) of integers has type int*int*int. An example is (7,9,11) and you retrieve the parts with #1 e, #2 e, and #3 e where e is an expression that evaluates to a triple.
```ML
val a = (7, 9, 11) (* int * int * int *)
val x = (3, (4, (5,6))); (* int * (int * (int * int)) *)
val y = (#2 x, (#1 x, #2 (#2 x))); (* (int * (int * int)) * (int * (int * int)) *)
val ans = (#2 y, 4); (* (int * (int * int)) * int *)
```
### Lists
```ML
val x = [7,8,9];
5::x; (* 5 consed onto x *)
6::5::x;
[6]::[[1,2],[3,4];
```
To append a list t a list, use list-append operator `@`:
[Reference# The Standard ML Basis Library]([http://sml-family.org/Basis/list.html](http://sml-family.org/Basis/list.html))
>Interface:
> **val** [@](http://sml-family.org/Basis/list.html#SIG:LIST.@:VAL) **:** _'a_ list * _'a_ list **->** _'a_ list
```
val x = [1,2] @ [3,4,5]; (* [1,2,3,4,5] *)
```
Accessing:
```ML
val x = [7,8,9];
null x; (* False *)
null []; (* True *)
hd x; (* 7 *)
tl x; (* [8, 9] *)
```
### List Functions
```ML
fun sum_list(xs : int list) =
if null xs
then 0
else hd xs + sum_list(tl xs);
fun list_product(xs : int list) =
if null xs
then 1
else hd xs * list_product(tl xs);
fun countdown(x : int) =
if x = 0
then []
else x :: countdown(x - 1);
fun append (xs : int lisst, ys : int list) =
if null xs
then ys
else (hd xs) :: append((tl xs), ys);
fun sum_pair_list(xs : (int * int) list) =
if null xs
then 0
else #1 (hd xs) + #2 (hd xs) + sum_pair_list(tl xs);
fun firsts (xs : (int * int) list) =
if null xs
then []
else (#1 (hd xs)) :: firsts(tl xs);
fun seconds (xs : (int * int) list) =
if null xs
then []
else (#2 (hd xs)) :: seconds(tl xs);
fun sum_pair_list2 (xs : (int * int) list) =
(sum_list(firsts xs)) + (sum_list(seconds xs));
```
Functions that make and us lists are almost always recursice becasue a list has an unknown length. To write a recursive function the thought process involves two steps:
* think about the _base case_
* think about the _recursive case_
### Let Expressions
* Syntax: `let b1 b2 ... bn in e end`
- Each `bi` is any binding an `e` is any expression
```ML
let val x = 1
in
(let val x = 2 in x+1 end) + (let val y = x+2 in y+1 end)
end
fun countup_from1 (x:int) =
let fun count (from:int) =
if from=x
then x::[]
else from :: count(from+1)
in
count(1)
end
```
### Options
An option value has either 0 or 1 thing: `None` is an option value carrying nothing whereas `SOME e` evaluates e to a value v and becomes the option carrying the one value v. The type of `NONE` is `'a option` and the type of `SOME e` is `t option` if e has type t.
We have:
* `isSome` which evaluates to false if its argument is NONE
* `valOf` to get the value carried by `SOME`(raising exception for `NONE`)
```ML
fun max1( xs : int list) =
if null xs
then NONE
else
let val tl_ans = max1(tl xs)
in
if isSome tl_ans andalso valOf tl_ans > hd xs
then tl_ans
else SOME (hd xs)
end;
```
## Some More Expressions
Boolean operations:
* `e1 andalso e2`
- if result of e1 is false then false else result of e2
* `e1 orelse e2`
* `not e1`
**※Syntax `&&` and `||` don't exist in ML and `!` means something different.**
**`andalso` and `orelse` are just keywords. `not` is a pre-defined function.**
Comparisons:
* `=` `<>` `>` `<` `>=` `<=`
- `=` and `<>` can be used with any "equality type" but not with real
## Build New Types
To Create a compound type, there are really only three essential building blocks:
* **Each-of** : A compound type t describes values that contain each of values of type `t1` `t2` ... `tn`
* **One-of**: A compound type t describes values that contain a value of one of the types `t1` `t2` ... `tn`
* **Self-refenence**: A compound type t may refer to itself in its definition in order to describe recursive data structures like lists and trees.
### Records
Record types are "each-of" types where each component is a named field. The order of fields never matters.
```ML
val x = {bar = (1+2,true andalso true), foo = 3+4, baz = (false,9) }
#bar x (* (3, true) *)
```
Tupels are actually syntactic sugar for records. `#1 e`, `#2 e`, etc. mean: get the contents of the field named 1, 2, etc.
```ML
- val x = {1="a",2="b"};
val x = ("a","b") : string * string
- val y = {1="a", 3="b"};
val y = {1="a",3="b"} : {1:string, 3:string}
```
### Datatype bindings
```ML
datatype mytype = TwoInts of int*int
| Str of string
| Pizza;
val a = Str "hi"; (* Str "hi" : mytype *)
val b = Str; (* fn : string -> mytype *)
val c = Pizza; (* Pizza : mytype *)
val d = TwoInts(1+2, 3+4); (* TwoInts (3,7) : mytype *)
val e = a; (* Str "hi" : mytype *)
```
The example above adds four things to the environment:
* A new type mytype that we can now use just like any other types
* Three constructors `TwoInts`, `Str`, `Pizza`
We can also create a type synonmy which is entirely interchangeable with the existing type.
```ML
type foo = int
(* we can write foo wherever we write int and vice-versa *)
```
## Case Expressions
To access to datatype values, we can use a case expression:
```ML
fun f (x : mytype) =
case x of
Pizza => 3
| Str s => 8
| TwoInts(i1, i2) => i1 + i2;
f(Str("a")); (* val it = 8 : int *)
```
We separate the branches with the `|` character. Each branch has the form `p => e` where p is a pattern and e is an expression. Patterns are used to match against the result of evaluating the case's first expression. This is why evaluating a case-expression is called pattern-matching.
## Lists and Options are Datatypes too
`SOME` and `NONE` are actually constructors. So you can use them in a case like:
```ML
fun inc_or_zero intoption =
case intoption of
NONE => 0
| SOME i => i+1;
```
As for list, `[]` and `::` are also constructors. `::` is a little unusual because it is an infix operator so when in patterns:
```ML
fun sum_list xs =
case xs of
[] => 0
| x::xs' => x + sum_list xs';
fun append(xs, ys) =
case xs of
[] => ys
| x::xs' => x :: append(xs', ys);
```
## Pattern-matching
Val-bindings are actually using pattern-matching.
```ML
val (x, y, z) = (1,2,3);
(*
val x = 1 : int
val y = 2 : int
val z = 3 : int
*)
```
When defining a function, we can also use pattern-matching
```ML
fun sum_triple (x, y, z) =
x + y + z;
```
Actually, all functions in ML takes one tripple as an argument. There is no such thing as a mutli-argument function or zero-argument function in ML.
The binding `fun () = e` is using the unit-pattern `()` to match against calls that pass the unit value `()`, which is the only value fo a pre-defined datatype `unit`.
The definition of patterns is recursive. We can use nested patterns instead of nested cae expressions.
We can use wildcard pattern `_` in patterns.
```ML
fun len xs =
case xs of
[] => 0
| _::xs' => 1 + len xs';
```
### Function Patterns
In a function binding, we can use a syntactic sugar instead of using case expressions:
```ML
fun f p1 = e1
| f p2 = e2
...
| f pn = en
```
for example
```ML
fun append ([], ys) = ys
| append (x::xs', ys) = x :: append(xs', ys);
```
## Exceptions
To create new kinds of exceptions we can use exception bindings.
```ML
exception MyUndesirableCondition;
exception MyOtherException of int * int;
```
Use `raise` to raise exceptions. Use `handle` to catch exceptions.
```ML
fun hd xs =
case xs of
[] => raise List.Empty
| x::_ => x;
(* The type of maxlist will be int list * exn -> int *)
fun maxlist(xs, ex) =
case xs of
[] => raise ex
| x::[] => x
| x::xs' => Int.max(x, maxlist(xs', ex));
(* e1 handle ex => e2 *)
val y = maxlist([], MyUndesirableCondition)
handle MyUndesirableCondition => 42;
```
## Tail Recursion
There is a situation in a recursive call called **tail call**:
>when f makes a recursive call to f, there is nothing more for the caller to do after the callee returns except return the callee's result.
Consider a sum function:
```ML
fun sum1 xs =
case xs of
[] => 0
| i::xs' => i + sum1 xs'
```
When the function runs, it will keep a call-stack for each recursive call . But if we change a little bit using tail call :
```ML
fun sum2 xs =
let fun f (xs,acc) =
case xs of
[] => acc
| i::xs' => f(xs',i+acc)
in
f(xs,0)
end
```
we use a local helper `f` and a accumulator `acc` so that the return value of `f` is just the return value of `sum2` . As a result, there is no need to keep every call in stack, just the current `f` is enough. And that's ML and most of other functional programming languages do.
Another example: when reversing a list:
```ML
fun rev1 lst =
case lst of
[] => []
| x::xs => (rev1 xs) @ [x]
fun rev2 lst =
let fun aux(lst,acc) =
case lst of
[] => acc
| x::xs => aux(xs, x::acc)
in
aux(lst,[])
end
```
`rev1` is `O(n^2)` but rev2 is almost as simple as `O(n)`.
To make sure which calls are tail calls, we can use a recursive defination of **tail position** like:
* In `fun f(x) = e`, `e` is in tail position.
* If an expression is not in tail position, then none of its subexpressions are
* If `if e1 then e2 else e3` is in tail position, then `e2` and `e3` are in tail position (but not `e1`). (Case-expressions are similar.)
* If `let b1 ... bn in e end` is in tail position, then e is in tail position (but no expressions in the bindings are).
* Function-call arguments are not in tail position.
## First-class Functions
The most common use of first class functions is passing them as arguments to other functions.
```ML
fun n_times (f, n, x) =
if n=0
then x
else f (n_times(f, n-1,x))
```
The function `n_times` is called higher-order funciton. Its type is:
```ML
fn : ('a -> 'a) * int * 'a -> 'a
```
`'a` means they can be any type. This is called _parametric polymorphism_ , or _generic types_ .
Instead, consider a function that is not polymorphic:
```ML
(* (int -> int) * int -> int *)
fun times_until_zero (f, x) =
if x = 0
then 0
else 1 + times_until_zero(f, f x)
```
### Anonymous Functions
```ML
fun triple_n_times (n, x) =
n_times((fn x => 3*x), n, x)
```
Maps:
```ML
(* ('a -> 'b) * 'a list -> 'b list *)
fun map (f, xs) =
case xs of
[] => []
| x::xs' => (f x)::(map(f, xs'));
```
Filters:
```ML
(* ('a -> bool) * 'a list -> 'a list *)
fun filter (f, xs) =
case xs of
[] => []
| x::xs' => if f x
then x::(filter (f, xs'))
else filter (f, xs');
```
### Lexical scope VS dynamic scope
### Combining Functions
```ML
fun sqrt_of_abs i = (Math.sqrt o Real.fromInt o abs) i;
```
Use our own infix operator to define a left-to-right syntax.
```ML
infix |>
fun x |> f = f x;
fun sqrt_of_abs i = i |> abs |> Real.fromInt |> Math.sqrt;
```
### Currying
```ML
(* fun sorted(x, y z) = z >= y andalso y >= x *)
val sorted = fn x => fn y => fn z => z >= y andalso y >= x;
(* just syntactic sugar for code above *)
fun sorted_nicer x y z = z >= y andalso y >= x;
```
when calling curried the function:
```ML
(* ((sorted_nicer x) y) z *)
(* or just: *)
sorted_nicer x y z
```
```ML
```
## Type Inference
Key steps in ML:
* Determine types of bindings in order
* For each val of fun binding:
* Analyze definition for all necessary facts
* Type erro if no way for all facts to hold
* Use type variables like `'a` for any unconstrained type
* Enforce the value restriction
One example:
```ML
(*
compose : T1 * T2 -> T3
f : T1
g : T2
x : T4
body being a function has type T3=T4->T5
from g being passed x, T2=T4->T6 for some T6
from f being passed the result of g, T1=T6->T7
from call to f being body of anonymous function, T7 = T5
all together, (T6->T5) * (T4->T6) -> (T4->T5)
so ('a->'b) * ('c->'a) -> ('c->'b)
*)
fun compose (f, g) = fn x => f (g x)
```
### Value restriction
A variable-binding can have a polymorphic type only if the expression is a variable or value:
```ML
val r = ref NONE
val _ = r := SOME "hi"
val i - 1 + valOf (!r)
```
If there is is no value-restriction, the code above will type check, which shouldn't.
With value restriction, ML will give a warning when type-checking:
```
- val r = ref NONE;
stdIn:2.5-2.17 Warning: type vars not generalized because of
value restriction are instantiated to dummy types (X1,X2,...)
val r = ref NONE : ?.X1 option ref
```
## Mutual Recursion
Mutual recursion allows `f` to call `g` and `g` to call `f`.
In ML, There is an `and` keyword to allow that:
```ML
fun p1 = e1
and p2 = e2
and p3 = p3
```
## Modules
```ML
structure MyMathLib =
struct
fun fact x = x
val half_pi = Math.pi / 2.0
fun doubler x = x * 2
end
```
### Signatures
A signature is a type for a module.
```ML
signature SIGNAME =
sig types-for-bindings
end
```
Ascribing a signature to a module:
```ML
structure myModule :> SIGNAME =
struct bindings end;
```
Anything not in the signature cannot be used outside the module.
```ML
signature MATHLIB =
sig
val fact : int -> int
val half_pi : real
(* make doubler unaccessable outside the MyMathLib *)
(* val doubler : int -> int *)
end
structure MyMathLib :> MATHLIB =
struct
fun fact x = x
val half_pi = Math.pi / 2.0
fun doubler x = x * 2
end
```
### Signature matching
## Equivalence
* PL Equivalence
* Asymptotic equivalence
* System equivalence

View File

@@ -0,0 +1,245 @@
---
title: Racket notes
date: 2020-02-29 09:00:00
tags:
- racket
categories:
- notes
keywords:
- racket
---
## Basic
```racket
#lang racket
(provide (all-defined-out))
;this is a comment
(define s "hello")
(define x 3)
(define y (+ x 2))
(define cube1
(lambda (x)
(* x (* x x))))
(define cube2
(lambda (x)
(* x x x)))
(define (cube3 x)
(* x x x))
(define (pow1 x y)
(if (=y 0)
1
(* x (pow1 x (- y 1)))))
; currying
(define pow2
(lambda (x)
(lambda (y)
(pow1 x y))))
```
### List
* Empty list: `null`
* `()` doesn"t work for `null` but `'()` does
* build a list: `(list e1 ... en)`
* Constructor: `cons`
* Access head of list: `car`
* Access tail of list: `cdr`
* Check for empty: `null?`
### Syntax
A term is either:
* An atom like `#t, #f, 34, "hi", null, 4.0, x,...`
* A special form like `define, lambda, if`
* A sequence of terms in parentheses: `(t1 t2 t3)`
* Can use `[` anything you use `(`
Remember parentheses matters! For example:
`(e)` means call e with 0 argument.
### Dynamic typing
```racket
(define lst (list #t "hi" 1 (list 2 3 4)))
```
### Cond
```racket
(define (sum3 xs)
(cond [(null? xs) 0]
[(number? (car xs)) (+ (car xs) (sum3 (cdr xs)))]
[#t 0]))
```
### What is true?
Anything that is not `#f` is true `#t`.
### Local bindings
#### let/let*/letrec
```racket
(let ([x1 e1]
[x2 e2]
...
[xn en])
e)
```
Racket uses the environment **before** the let-expression to evaluate `e1 e2 ... en`, which means if `en` uses `x1`, `x2`, that would mean some outer variables of the same name. Instead, the expressions in `let*` are evaluated in the environment produced from the previous bindings (later ones shadow) .
The expressions in `letrec` are evaluated in the environment that includes all th bindings. It is needed for mutual recursion.
### set!
Racket has assignment statements:
```racket
(set! x e)
```
Once you have side-effects, sequences are useful:
```racket
(begin e1 e2 e3)
```
### cons/mcons
`cons` produces pairs or lists. (Actually lists are just extented pairs)
```racket
(define pr (cons 1 (cons #t "hi"))) ; is a pair
(define lst (cons 1 (cons #t (cons "hi" null)))) ; is a list
```
`mcons` is another way to make pairs which allows you to change the value inside piars:
```racket
(define mpr (mcons 1 (mcons #t "hi")))
(mcar mpr) ; 1
(mcdr mpr) ; (mcons (#t "hi"))
(set-mcdr! mpr 47) ; mpr becomes (mcons 1 47)
```
Related form:
* `mcons`
* `mcar`
* `mcdr`
* `mpair?`
* `set-mcar!`
* `set-mcdr!`
## Delayed Evaluation and Thunk
In most programming languages, given `e1 e2 ... en`, the function arguments `e2, ..., en` are evaluated once before the function body is executed.
So if we define a function like:
```rkt
(define (my-if-bad x y z) (if x y z))
(define (factorial-wrong x)
(my-if-bad (= x 0)
1
(* x (factorial-wrong (- x 1)))))
```
if we use `if` instead of `my-if-bad`, `factorial-wrong` acts just like we want. But with `my-if-bad`, the function never stops because the two branches evaluate at the same time.
Thanks to lambda, we can delay the evaluation, using the fact that function bodies are not evaluated until the function gets called.
```rkt
(define (my-if x y z) (if x (y) (z)))
(define (factorial x)
(my-if (= x 0)
(lambda () 1)
(lambda () (* x (factorial (- x 1))))))
```
The general idiom of using a zero-argument function to delay evaluation is also called a **thunk** (or, thunk the argument).
By the way,
## Lazy-evaluation/Call-by-need/Promises
## Streams
A stream is an infinite sequence of values.
```racket
#lang racket
; 1 1 1 1 ...
(define ones (lambda () (cons 1 ones)))
; 1 2 3 4 ...
(define nats
(letrec ([f (lambda (x) (cons x (lambda () (f (+ x 1)))))])
(lambda () (f 1))))
; 2 4 6 8 ...
(define power-of-two
(letrec ([f (lambda (x) (cons x (lambda () (f (* x 2)))))])
(lambda () (f 2))))
; higher-order maker
(define (stream-maker fn arg)
(letrec ([f (lambda (x) (cons x (lambda () (f (fn x arg)))))])
(lambda () (f arg))))
```
## Memoization (Not Memorization)
Memoization is another idiom related to lazy evaluation that does not actually use thunks. To implement memoization we do use mutation: Whenever the function is called with an argument we have not seen before, we compute the answer and then add the result to the table.
```racket
(define fibonacci
(letrec([memo null]
[f (lambda (x)
(let ([ans (assoc x memo)])
(if ans
(cdr ans)
(let ([new-ans (if (or (= x 1) (= x 2))
1
(+ (f (- x 1))
(f (- x 2))))])
(begin
(set! memo (cons (cons x new-ans) memo))
new-ans)))))])
f))
```
## Macros
Think about these things about macros and how Racket handles them better than other macro systems(notably C/C++)
* Tokenization
* Parenthesization
* Scope
### Syntax
```racket
(define-syntax myif
(syntax-rules (then else)
[(my-if e1 then e2 else e3)
(if e1 e2 e3)]))
(define-syntax my-delay
(syntax-rules ()
[(my-delay e)
(mcons #f (lambda () e))]))
```
### Hygiene
## Recursive Datatypes Via Rackets's `struct`
[https://docs.racket-lang.org/reference/define-struct.html?q=struct#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._struct%29%29](https://docs.racket-lang.org/reference/define-struct.html?q=struct#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._struct%29%29)
```racket
(struct foo (bar baz quux) #:transparent
```

View File

@@ -0,0 +1,24 @@
---
title: Programming Language - Subtyping
date: 2020-04-29 09:00:00
tags:
- programming language
category: tech
keywords:
- subtyping
---
## Some Good Subtyping Rules
* Width subtyping: A supertype can have a subset of fields with the same types, i.e., a subtype can have extra fields.
* Permutation subtypings: A supertype can have the same set of fields with the same types in a different order.
* Transitivity: if t1 is subtype of t2, and t2 is subtype of t3, then t1 is subtype of t3.
* Reflexivity: Every type is a subtype of itself.
Given the three features of (1) setting a field, (2) letting depth
subtyping change the type of a field, and (3) having a sound type system actually prevent field-missing errors, we can have any two of the three, but not all of them.
## Function Subtyping
Function subtyping **contravariant** in argument(s) and **covariant** in results.
If t3 is subtype of t1, and t2 is a subtype of t4, then `t1 -> t2` is a subtype of `t3 -> t4`.

View File

@@ -0,0 +1,622 @@
---
title: Algorithms - Graphs
date: 2020-05-01 09:00:00
tags:
- Algorithms
category: notes
keywords:
- Algorithms
- Graphs
mathjax: true
---
## Undirected Graphs
### Some problems
* Path
* Shortest path
* Cycle
* Ehler tour: A cycle that uses each edge excatly once.
* Hamilton tour: A cycle that uses each vertex exactly once
- classical NP-complete problem.
* Connectivity
* MST:
* Biconnectivity: A vertex whose removal disconnects the graph
* Planarity
* Graph isomorphism: Are two graphs identical?
- No one knows so far. A lonstanding open problem
### Representations
Real-world graphs tend to be **sparse** (huge number of vertices, small average vertex degree).
* Set-of-edges representation
- unefficient
* Adjacency-matrix representation
- space cost is prohibitive
* Adjacency-list array representation
- GOOD
### Adjacency-list Data structure
* Space usage proportional to V + E
* Constant time to add an edge
* Time proportional to the degree of v to iterate through vertices adjacent to v
### Depth-first Search (DFS)
Typical applications:
* Find all vertices connected to a given source vertex
* Find a path between two vertices
Algorithm:
* Use recursion (a function-call stack) or an explicit stack.
* Mark each visited vertex (and keep track of edge taken to visit it)
* Return (retrace steps) when no unvisited options
```Java
public class DepthFirstPaths{
private blloean[] marked;
private int[] edgeTO;
private int s;
public DepthFirstPaths(Graph G, int s)
{
// ...
dfs(G, s);
}
private void dfs(Graph Gm int v)
{
marked[v] = true;
for (int w : G.adj(v))
if (!marked[v])
{
dfs(G, w)
edgeTo[w] = v;
}
}
}
```
Propositions:
1. DFS marks all vertices connected to s in time proportional to the sum of their degrees.
2. After DFS, can find vertices connected to s in constant time and can find a path to s in time proportional to its length.
### Breadth-first Search (BFS)
Typical applications:
* shortest path
Algorithm:
* Put s onto a queue, and mark s as visited
* Take the next vertex v from the queue and mark it
* Put onto the queue all unmarked vertices that are adjacent to v
```Java
public class BreadthFirstPaths
{
private boolean[] marked;
private int[] edgeTo;
// ...
private void bfs(Graph G, int s)
{
Queue<Integer> q = new Queue<>();
q.enqueue(s);
marked[s] = ture;
while (!q.isEmpty())
{
int v = q.dequeue();
for (int w: G.adj(v))
{
if (!marked[w])
{
q.enqueue(w);
marked[w] = true;
edgeTo[w] = v;
}
}
}
}
}
```
Proposition:
1. BFS computes shortest paths (fewest number of edges) from s to all other vertices in a graph in time proportional to E + V
### Applications of DFS
#### Connected components
The goal is to preprocess graph to answer queries of the form *is v connected to w?* in constant time.
The relation *is connected to* is an equivalence relation:
* Reflexive: v is connected to v
* Symmetric: if v is connected to w, then w is connected to v
* Transitive: if v connected to w and w connected to x, then v connected to x
```Java
public class CC {
private boolean[] marked;
private int[] id;
private int count;
public CC(Graph G) {
marked = new boolean[G.V()];
id = new int[G.V()];
for (int v = 0, v < G.V(); v++) {
if (!marked[v]) {
dfs(G, v);
count++;
}
}
}
// ...
private void dfs(Graph G, int v) {
marked[v] = true;
id[v] = count;
for (int w : G.adj(v)) {
if (!marked[w]) {
dfs(G, w)
}
}
}
}
```
#### Cycle detection
Problem: Is a given graph acylic?
**TODO**
#### Two-colorability
Problem: Is the graph bipartite?
**TODO**
#### Symbol graphs
**TODO**
#### Degrees of separation
**TODO**
## Directed Graphs
>A directed graph (or digraph) is a set of vertices and a collection of directed edges. Each directed edge connects an ordered pair of vertices.
* *outdegree*: the number of edges going **from** it
* *indegree*: the number fo edges going **into** it
* *directed path*: a sequence of vertices in which there is a (directed) edge pointing from each vertex in the sequence to its successor in the sequence
* *directed cycle*
* *simple cycle*: a cycle with no repeated edges or vertices
### Representations
Again, use [adjacency-lists representation](#Adjacency-list-Data-structure)
* Based on iterating over vertices pointing from v
* Real-world digraphs tend to be sparse
```Java
public class Digraph {
private final int V;
private final Bag<Integer>[] adj;
public Digraph(int V) {
this.V = V;
adj = (Bag<Integer>[]) new Bag[V];
for (int v = 0; v < V; v++) {
adj[v] = new Bag<Integer>[];
}
}
public void addEdge(int v, int w) {
adj[v].add(w);
}
public Iterable<Integer> adj(int v) {
return adj[v];
}
}
```
### Digraph search
Reachabiliity problem: Find all vertices reachable from s along a directed path.
We can use [the same dfs method as for undirected graphs](#Depth-first-Search-(DFS)).
* Every undirected graph is a digraph with edges in both directions.
* DFS is a digraph algorithm,
Reachability applications:
* program control-flow analysis
- Dead-code elimination
- infinite-loop detection
* mark-sweep garbage collector
Other DFS problems:
* Path findind
* Topological sort
* Directed cycle detection
* ...
BFS problems:
* shortest path
* multiple-source shortest paths
* web crawler application
### Topological Sort
>Topological sort: Given a digraph, put the vertices in order such that all its directed edges point from a vertix earlier in the order to a vertex later in the order (or report impossible).
A digraph has a topological order **if and only if** it is a *directed acyclic graph* (DAG).
Topological sort redraws DAG so all edges poitn upwards.
use **DFS** again. It can be proved that reverse postorder of a DAG is a topological order.
(check P578 for the definition of Preorder/Postorder)
```Java
public class DepthFirstOrder {
private boolean[] marked;
private Stack<Integer> reversePost;
publiv DepthFirstOrder(Digraph G) {
reversePost = new Stack<Integer>();
marked = new boolean[G.V()];
for (int v = 0; v < G.V(); v++) {
if (!marked[v]) dfs(G, v);
}
}
private void dfs(Digrapg G, int v) {
marked[v] = true;
for (int w : G.adj(v)) {
if (!marked[w]) dfs(G, w)
}
reversePost.push(v);
}
}
```
#### Directed cycle detection
To find out if a given digraph is a DAG, we can try to find a directec cycle in the digraph.
Use DFS and a stack to track the cycle.
```Java
// TODO
```
Some very typical applications of directed cycle detection and topological sort:
(A directed cycle means the problem is infeasible)
* job schedule
* course scuedule
* inheritance
* spreadsheet
- vertex: cell
- edge: formula
* symbolic links
### Strong components
Vertices v and w are **strongly connected** if there is both a directed path from v to w and a directed path from w to v.
Strong connectivity is an equvicalence relation.
#### Kosaraju-Sharir Algorithm
Kosaraju-Sharir is easy to implement but difficutl to understand. It runs DFS twice:
* Given a digraph G, run DFS to compute the topological order of its reverse $G^R$
* Run DFS on G in the order given by first DFS
TODO: ADD Proof
[https://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/KosarajuSharirSCC.java.html](https://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/KosarajuSharirSCC.java.html)
```Java
public class KosarajuSharirSCC {
private boolean[] marked; // marked[v] = has vertex v been visited?
private int[] id; // id[v] = id of strong component containing v
private int count; // number of strongly-connected components
/**
* Computes the strong components of the digraph {@code G}.
* @param G the digraph
*/
public KosarajuSharirSCC(Digraph G) {
// compute reverse postorder of reverse graph
DepthFirstOrder dfs = new DepthFirstOrder(G.reverse());
// run DFS on G, using reverse postorder to guide calculation
marked = new boolean[G.V()];
id = new int[G.V()];
for (int v : dfs.reversePost()) {
if (!marked[v]) {
dfs(G, v);
count++;
}
}
}
// DFS on graph G
private void dfs(Digraph G, int v) {
marked[v] = true;
id[v] = count;
for (int w : G.adj(v)) {
if (!marked[w]) dfs(G, w);
}
}
// ...
}
```
## Minimum Spanning Trees
An edge-weighted-graph is a graph where we associate weight or costs with each edge.
A spanning tree of an undirected edge-weighted graph G is a subgraph T that is both **a tree (conneted and acyclic)** and **spanning (includes all of the vertices)**.
Given an (connected) undirected edge-weighted graph G with V vertices and E edges, the MST of it must have **V - 1** edges.
If the graph is not connceted, we compute minimum spanning forest (MST of each component).
* A *cut* in a graph is a partition of its vertices into two (nonempty) sets
* A *crossing edge* connects a vertex in one set with a vertex in the other.
* Cut property: Given any cut, the crossing edge of min weight is in the MST.
### Edge-weight Graph Data Type
Edge:
[https://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/Edge.java.html](https://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/Edge.java.html)
EdgeWeigthedGraph:
[https://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/EdgeWeightedGraph.java.html](https://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/EdgeWeightedGraph.java.html)
### **Greedy MST Algorithm:**
* Start with all edges colored gray.
* Find cut with no blacked crossing edges; color its min-weight edge black.
* Repeat until V-1 edges are colored black.
### Implementations 1: Kruskal's algorithm
For edges in ascending order of weight:
* Add next edge to Tree unless doing so would create a cycle.
To efficiently solve this problem, use union-find :
1. use a priority queue to maintain all the edges in V
2. union-find data structure:
- maintain a set for each connected component in T.
- if v and w are in saome set, then adding v->w would create a cycle
- to add v>w to T, merge sets containing v and w.
TODO: Add code
### Implementations 2: Prim's algorithm
* Start with vertex 0 and greedily grow tree T.
* Add To T the min weight edge with exactly oue endpoint in T.
* Reapeat unitl V - 1 edges.
The key to solve this problem is how do we find the crossing edge of minimal weight efficiently.
A lazy solution (in time proportional to $ElogE$, fair enough):
1. Maintain a PQ of edges with (at least) one endpoint in T
- Key = edge, priority = weight
2. Delete-min to determine next edge e = v->w to add to T
3. Disregard if both endpoints v and w are marked (both in T)
4. Otherwise, let w be the unmarked vertex (not in T)
- add to PQ and edge incident to w (assuming other endpoint not in T)
- add e to T and mark w
TODO: add code
A eager solution (in time proprotional to $ElogV$, better):
1. Maintain a PQ of vertices connected by an edge to T, where priority of v = weight of shortedt edge connecting v to T
2. Delete min vertex v and add its associated edge e = v->w to T
3. Update PQ by considering all edges e = v->x incident to v
- ignore if x is already in T
- add x to PQ if not alread on it
- decrease priority of x if v->x becomes shortest edge connecting x to T
This solution uses an [indexed priority queue](https://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/IndexMinPQ.java.html) data structure.
TODO: add code
## Shortest Paths
**Some variants:**
* Which vertices?
- Single source
- Source-sink
- All pairs
* Edge weights
- Nonegative weights
- Euclidean weights
- Arbitrary weights
* Cycles?
- No directed cycles
- No negative cycles
### Edge-weighted digraph data strcuture
Weighted directed edge:
[https://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/DirectedEdge.java.html](https://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/DirectedEdge.java.html)
Edge-weighted digraph:
[https://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/EdgeWeightedDigraph.java.html](https://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/EdgeWeightedDigraph.java.html)
Use adjacency-lists implementation same as [EdgeWeightedGraph](https://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/EdgeWeightedGraph.java.html)
### Generic Single-source Shortest paths
Our goal is to find the shortest path from s to every other vertex. As a result, what we find will be the **shortest-paths tree (SPT)** for source s.
#### Relax edge e = v->w
* distTo[v] is length of shortest known path from s to v
* distTo[w] is length of shortest known path from s to w
* esgeTo[w] is last edge on shortest known pathh from s to w
* if e = v->w gives shorter path to w through v, update both distTo[w] and edgeTo[w]
```Java
private void relax(DirectedEdge e) {
int v = e.from(), w = e.to();
if (distTo[w] > distTo[v] + e.weight()) {
distTo[w] = distTo[v] + e.weight();
edgeTo[w] = e;
}
}
```
#### Optimality conditions
Given an edge-weighted digraph G, distTo[] are the shortest path distances from s **iff**:
* distTo[s] = 0
* For each vertex v, distTo[v] is the length of some path from s to v.
* For each edge e = v->w, distTo[w] <= distTo[v] + e.weight()
#### Generic algorithm
```
Generic algorithm (to compute SPT from s) {
Initialize distTo[s] = 0 and distTo[v] = $\infty$
Repeat until optimality conditions are satisfied:
- Relax any edge
}
```
Efficient implementations:
* Nonnegative weights: [Dijkstra's algorithm](#implement-1-dijkstras-algorithm)
* No directed cycles (DAGs): [Topological sort algorithm](#implement-2-topological-sort-algorithm)
* No negative cycles: [Bellman-Ford](#implement-3-bellman-ford-algorithm)
### Implement 1: Dijkstra's algorithm
When there is no nonnegative weight exists, we can use Dijkstra's algorithm.
* Consider vertices in increasing order of distance from s (non-tree vertex with the lowest distTo[] value)
* add vertex to tree and relax all edges pointing from that vertex
```Java
public class DijkstraSP{
// ...
public DijkstraSP(EdgeWeightedDigraph G, int s) {
edgeTo = new DirectedEdge[G.V()];
distTo = new double[G.V()];
pq = new IndexMinPQ<Double>(G.V());
for (int v = 0; v < G.V(); v++) {
distTo[v] = Double.POSITIVE_INFINITY;
}
distTo[s] = 0;
pq.insert(s, 0.0);
while(!pq.isEmpty()) {
int v= pq.delMin();
for (DirectedEdge e : G.adj(v)) {
relax(e);
}
}
}
private void relax(DirectedEdge e) {
int v = e.from(), w = e.to();
if (distTo[w] > distTo[v] + e.weight()) {
distTo[w] = distTo[v] + e.weight();
edgeTo[w] = e;
if (pq.contains(w)) pq.decreaseKey(w, distTo[w]);
else pq.insert(w, distTo[w]);
}
}
}
```
**Compare to Prim's algorithm:**
* Both are computing a graph's spanning tree
* Prim's algorithm choose closest vertex to tree as next vertex, while Dijkstra's algorithm choose closest vertex to the source
### Implement 2: Topological sort algorithm
When the graph is a DAG, we can consider vertices in topological order and do relaxing.
```Java
// ...
Topological topological = new Topological(G);
for (int v : topological.order()) {
for (DirectedEdge e : G.adj(v)) {
relax(e);
}
}
```
**[Seam carving](https://en.wikipedia.org/wiki/Seam_carving)**: Resize an image without distortion.
**Longest paths**:
* Formuate as a shortest paths problem in edge-weighted DAGs
- Negate all weights
- Find shortest paths
- Negate weights in result
* Allpication: Parallel job scheduling ([Critical path method, CPM](https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AA%E3%83%86%E3%82%A3%E3%82%AB%E3%83%AB%E3%83%91%E3%82%B9%E6%B3%95)).
### Implement 3: Bellman-Ford algorithm
>A SPT exists iff no negative cycles (a directed cycle whose sum of edge weights is negative).
When we want to find shortest paths with nagative weights, Dijkstra's algorithms doesn't work.
We can use Bellman-Ford algorithm as long as there is no negative cycle in the graph.
(Bellman-Ford algorithm is a dynamic programming algorithm)
* Initialize distTo[s] = 0 and distTo[v] = $\infty$
* Maintain a queue and repeat until the queue is empty or find a cycle:
- Pop vertex v from q
- Relax each edge pointing from v to any vertex w:
- if distTo[w] can be de decreased, update distTo[w] and add w to the queue
```Java
// ...
public BellmanFordSP(EdgeWeightedDigraph G, int s) {
distTo = new double[G.V()];
edgeTo = new DirectedEdge[G.V()];
onQueue = new boolean[G.V()];
for (int v = 0; v < G.V(); v++)
distTo[v] = Double.POSITIVE_INFINITY;
distTo[s] = 0.0;
// Bellman-Ford algorithm
queue = new Queue<Integer>();
queue.enqueue(s);
onQueue[s] = true;
while (!queue.isEmpty() && !hasNegativeCycle()) {
int v = queue.dequeue();
onQueue[v] = false;
relax(G, v);
}
}
private void relax(EdgeWeightedDigraph G, int v) {
for (DirectedEdge e : G.adj(v)) {
int w = e.to();
if (distTo[w] > distTo[v] + e.weight()) {
distTo[w] = distTo[v] + e.weight();
edgeTo[w] = e;
if (!onQueue[w]) {
queue.enqueue(w);
onQueue[w] = true;
}
}
if (++cost % G.V() == 0) {
findNegativeCycle();
if (hasNegativeCycle()) return; // found a negative cycle
}
}
}
```
Bellman-Ford algorithm can also be used for finding a negative cycle.
Negative cycle application: arbitrage detection.

View File

@@ -0,0 +1,191 @@
---
title: Changes to String in java (from 1.7.0_06)
date: 2020-06-06 09:00:00
tags:
- Algorithms
categories:
- notes
keywords:
- Algorithms
- String
- radix sort
---
Before 1.7.0_06, `String` has 4 non static field:
* char[] value
* int[] offset
* int count
* int hash
`Subing.substring` create a String by sharing the original String's internal `char[] value` and setting offset. This saves memory and makes `String.substring` run in a constant time($O(1)$).
Meanwhile, this feature may cause **memory leak**[^1].
[http://hg.openjdk.java.net/jdk6/jdk6/jdk/file/8deef18bb749/src/share/classes/java/lang/String.java](http://hg.openjdk.java.net/jdk6/jdk6/jdk/file/8deef18bb749/src/share/classes/java/lang/String.java)
```Java
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
{
/** The value is used for character storage. */
private final char value[];
/** The offset is the first index of the storage that is used. */
private final int offset;
/** The count is the number of characters in the String. */
private final int count;
/** Cache the hash code for the string */
private int hash; // Default to 0
// ...
// Package private constructor which shares value array for speed.
String(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
// ...
/**
* Returns a new string that is a substring of this string. The
* substring begins at the specified <code>beginIndex</code> and
* extends to the character at index <code>endIndex - 1</code>.
* Thus the length of the substring is <code>endIndex-beginIndex</code>.
* <p>
* Examples:
* <blockquote><pre>
* "hamburger".substring(4, 8) returns "urge"
* "smiles".substring(1, 5) returns "mile"
* </pre></blockquote>
*
* @param beginIndex the beginning index, inclusive.
* @param endIndex the ending index, exclusive.
* @return the specified substring.
* @exception IndexOutOfBoundsException if the
* <code>beginIndex</code> is negative, or
* <code>endIndex</code> is larger than the length of
* this <code>String</code> object, or
* <code>beginIndex</code> is larger than
* <code>endIndex</code>.
*/
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > count) {
throw new StringIndexOutOfBoundsException(endIndex);
}
if (beginIndex > endIndex) {
throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
}
return ((beginIndex == 0) && (endIndex == count)) ? this :
new String(offset + beginIndex, endIndex - beginIndex, value);
}
// ...
}
```
Since Java 1.7.0_06, `offset` and `count` fields were removed. `String.substring` makes new copies of `value`, which means we can forget about the memory leak but the runtime becomes $O(N)$ at the same time.
[http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/lang/String.java](http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/lang/String.java)
```Java
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
// ...
/**
* Allocates a new {@code String} that contains characters from a subarray
* of the character array argument. The {@code offset} argument is the
* index of the first character of the subarray and the {@code count}
* argument specifies the length of the subarray. The contents of the
* subarray are copied; subsequent modification of the character array does
* not affect the newly created string.
*
* @param value
* Array that is the source of characters
*
* @param offset
* The initial offset
*
* @param count
* The length
*
* @throws IndexOutOfBoundsException
* If the {@code offset} and {@code count} arguments index
* characters outside the bounds of the {@code value} array
*/
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
// ...
/**
* Returns a string that is a substring of this string. The
* substring begins at the specified {@code beginIndex} and
* extends to the character at index {@code endIndex - 1}.
* Thus the length of the substring is {@code endIndex-beginIndex}.
* <p>
* Examples:
* <blockquote><pre>
* "hamburger".substring(4, 8) returns "urge"
* "smiles".substring(1, 5) returns "mile"
* </pre></blockquote>
*
* @param beginIndex the beginning index, inclusive.
* @param endIndex the ending index, exclusive.
* @return the specified substring.
* @exception IndexOutOfBoundsException if the
* {@code beginIndex} is negative, or
* {@code endIndex} is larger than the length of
* this {@code String} object, or
* {@code beginIndex} is larger than
* {@code endIndex}.
*/
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > value.length) {
throw new StringIndexOutOfBoundsException(endIndex);
}
int subLen = endIndex - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return ((beginIndex == 0) && (endIndex == value.length)) ? this
: new String(value, beginIndex, subLen);
}
// ...
}
```
The auther's comment[^2]:
<a class="embedly-card" href="https://www.reddit.com/r/programming/comments/1qw73v/til_oracle_changed_the_internal_string/cdhb77f">Card</a>
<script async src="//embed.redditmedia.com/widgets/platform.js" charset="UTF-8"></script>
[^1]: http://java-performance.info/changes-to-string-java-1-7-0_06/
[^2]: https://www.reddit.com/r/programming/comments/1qw73v/til_oracle_changed_the_internal_string/cdhb77f/

View File

@@ -0,0 +1,160 @@
---
title: Code Block Test
date: 2021-06-27 09:00:00
tags:
- test
categories:
- tech
keywords:
- markdown
- code block
---
`String`
Using indents:
text
text
text
Fenced code block:
```
text
text
<tag>
```
Fenced code block with language (lineNumbersInTable = false):
```Java
// JavaJavaJavaJavaJavaJavaJavaJavaJavaJavaJavaJavaJavaJavaJavaJavaJavaJavaJavaJavaJavaJavaJavaJavaJavaJavaJavaJavaJavaJava
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
{
/** The value is used for character storage. */
private final char value[];
/** The offset is the first index of the storage that is used. */
private final int offset;
/** The count is the number of characters in the String. */
private final int count;
/** Cache the hash code for the string */
private int hash; // Default to 0
// ...
// Package private constructor which shares value array for speed.
String(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
// ...
/**
* Returns a new string that is a substring of this string. The
* substring begins at the specified <code>beginIndex</code> and
* extends to the character at index <code>endIndex - 1</code>.
* Thus the length of the substring is <code>endIndex-beginIndex</code>.
* <p>
* Examples:
* <blockquote><pre>
* "hamburger".substring(4, 8) returns "urge"
* "smiles".substring(1, 5) returns "mile"
* </pre></blockquote>
*
* @param beginIndex the beginning index, inclusive.
* @param endIndex the ending index, exclusive.
* @return the specified substring.
* @exception IndexOutOfBoundsException if the
* <code>beginIndex</code> is negative, or
* <code>endIndex</code> is larger than the length of
* this <code>String</code> object, or
* <code>beginIndex</code> is larger than
* <code>endIndex</code>.
*/
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > count) {
throw new StringIndexOutOfBoundsException(endIndex);
}
if (beginIndex > endIndex) {
throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
}
return ((beginIndex == 0) && (endIndex == count)) ? this :
new String(offset + beginIndex, endIndex - beginIndex, value);
}
// ...
}
```
Using hugo's `highlight` [shortcode]([highlight](https://gohugo.io/content-management/syntax-highlighting/#highlight-shortcode)) (lineNumbersInTable = true):
{{< highlight typescript "linenos=table, hl_lines=8 18-21" >}}
// TypeScript
type OptionalUser = {
[K in keyof User]?: User[K]
}
// ! we can remove optional constraint
type RequiredUser = {
[K in keyof OptionalUser]-?: User[K]
}
type NullableUser = {
[K in keyof User]: User[K] | null
}
type ReadonlyUser = {
readonly [K in keyof User]: User[K]
}
// ! we can remove readonly constraint
type ModifiableUser = {
-readonly [K in keyof User]: User[K]
}
{{< /highlight >}}
Without line number
{{< highlight javascript "linenos=false" >}}
(() => {
function createCopyButton(codeNode) {
const copyBtn = document.createElement('button')
copyBtn.className = 'code-copy-btn'
copyBtn.type = 'button'
copyBtn.innerText = 'copy'
copyBtn.parentElement = codeNode.parentElement
let resetTimer
copyBtn.addEventListener('click', () => {
navigator.clipboard.writeText(codeNode.innerText).then(() => {
copyBtn.innerText = 'copied!'
}).then(() => {
clearTimeout(resetTimer)
resetTimer = setTimeout(() => {
copyBtn.innerText = 'copy'
}, 1000)
})
})
return copyBtn
}
document.querySelectorAll('pre > code').forEach((codeNode) => {
const copyBtn = createCopyButton(codeNode);
codeNode.parentNode.insertBefore(copyBtn, codeNode)
})
})()
{{< / highlight >}}

View File

@@ -0,0 +1,14 @@
{
"list": [
{
"name":"Hugo",
"url":"https://gohugo.io/",
"desc":"The worlds fastest framework for building websites."
},
{
"name":"Hugo Themes",
"url":"https://github.com/gohugoio/hugoThemes",
"desc":"A curated directory of Hugo themes"
}
]
}

View File

@@ -0,0 +1,27 @@
#!/bin/sh
# if [ "`git status -s`" ]
# then
# echo "The working directory is dirty. Please commit any pending changes."
# exit 1;
# fi
echo "Deleting old publication"
rm -rf public
echo "Generating site"
hugo
echo "Updating master branch"
cd public
git init
git config --global push.default matching
git config --global user.email "${GitHubEMail}"
git config --global user.name "${GitHubUser}"
git add --all .
git commit -m "Publishing to master (deploy.sh)"
echo "Pushing to github"
git push --quiet --force https://${GitHubKEY}@github.com/${GitHubUser}/${GitHubRepo}.git master

View File

@@ -0,0 +1 @@
{"Target":"css/styles.94f653e9e151e28067a7c5dbbc4600cbd5a3c721e79faaf971e523c40f3b249b8e4f20bb57810dfffa8d559ca5c140fd56eb4cd9c0853113ad08e66afdb08bdd.css","MediaType":"text/css","Data":{"Integrity":"sha512-lPZT6eFR4oBnp8XbvEYAy9WjxyHnn6r5ceUjxA87JJuOTyC7V4EN//qNVZylwUD9VutM2cCFMROtCOZq/bCL3Q=="}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="{{ .Site.LanguageCode }}">
{{ partial "head.html" . }}
<body class="max-width mx-auto px3 ltr">
<div class="content index py4">
{{ partial "header.html" . }}
{{ block "main" . }}
{{ end }}
{{ partial "footer.html" . }}
</div>
</body>
<link rel="stylesheet" href={{ "lib/font-awesome/css/all.min.css" | relURL }}>
<script src={{ "lib/jquery/jquery.min.js" | relURL }}></script>
<script src={{ "js/main.js" | relURL }}></script>
</html>

View File

@@ -0,0 +1,30 @@
{{ define "main"}}
<div id="archive">
<ul class="post-list">
{{ $pages := .Paginator.Pages }}
{{ if .Site.Params.showAllPostsArchive }}
{{ $pages = .Pages }}
{{ end }}
{{ range (sort $pages "Date" "desc") }}
{{ $pageYear := (.Date.Format "2006") }}
{{ if (ne $pageYear ($.Scratch.Get "year")) }}
{{ $.Scratch.Set "year" $pageYear }}
<h2>{{ $pageYear }}</h2>
{{ end }}
<li class="post-item">
<div class="meta">
<time datetime="{{ time .Date }}" itemprop="datePublished">{{ .Date.Format (.Site.Params.dateFormat | default "2006-01-02") }}</time>
</div>
<span>
<a class="" href="{{ .Permalink }}">{{ if .Title }} {{ .Title }} {{ else }} Untitled {{ end }}</a>
</span>
</li>
{{ end }}
</ul>
{{ if eq .Site.Params.showAllPostsArchive false }}
{{ partial "pagination.html" . }}
{{ end }}
</div>
{{ end }}

View File

@@ -0,0 +1,12 @@
{{ define "main" }}
<article class="post" itemscope itemtype="http://schema.org/BlogPosting">
<!-- TODO: gallery -->
<div class="content" itemprop="articleBody">
{{ if (eq .Type "search") }}
<!-- TODO: search https://gohugo.io/tools/search/ -->
{{ else }}
{{ .Content }}
{{ end }}
</div>
</article>
{{ end }}

View File

@@ -0,0 +1,41 @@
{{ define "main" }}
<article class="post" itemscope itemtype="http://schema.org/BlogPosting">
<div class="content" itemprop="articleBody">
{{ if (eq .Type "tags")}}
<div id="tag-cloud">
{{ if (eq (len .Data.Terms) 0) }}
<div class="tag-cloud-title">
No tags
</div>
{{ end }}
<div class="tag-cloud-tags">
{{ $AllRegularPagesCount := len .Site.RegularPages }}
{{ range $elem := .Data.Terms.Alphabetical }}
<a style="font-size: {{ (add 0.8 (mul 15 (div (float $elem.Count) $AllRegularPagesCount))) }}rem;" href="{{ $elem.Page.Permalink }}">
{{- .Page.Title -}}
</a>
{{ end }}
</div>
</div>
{{ else if (eq .Type "categories")}}
<div id="categories">
{{ if (eq (len .Data.Terms) 0) }}
<div class="category-list-title">
No categories
</div>
{{ end }}
<div class="category-list">
<ul class="category-list">
{{ range .Data.Terms.Alphabetical }}
<li class="category-list-item">
<a class="category-list-link" href="{{ .Page.Permalink }}">{{ .Page.Title }}</a>
<span class="category-list-count">{{ .Count }}</span>
</li>
{{ end }}
</ul>
</div>
</div>
{{ end }}
</div>
</article>
{{ end }}

View File

@@ -0,0 +1,111 @@
{{ define "main" }}
<section id="about">
{{ if isset .Site.Params "description" }}
{{ .Site.Params.description | $.Page.RenderString }}
{{ end }}
{{ if isset .Site.Params "social" }}
<p>Find me on
{{ $length := (len .Site.Params.social) }}
{{ range $index, $elem := .Site.Params.social}}
{{ if eq $elem.name "email" }}
<a class="icon" target="_blank" rel="noopener" href="mailto:{{ $elem.link }}" aria-label="Email">
<i class="fas fa-envelope" aria-hidden="true"></i>
</a>
{{ else if eq $elem.name "rss" }}
<a class="icon" target="_blank" rel="noopener" href="{{ $elem.link }}" aria-label="RSS">
<i class="fas fa-rss" aria-hidden="true"></i>
</a>
{{ else if eq $elem.name "scholar" }}
<a class="icon" target="_blank" rel="noopener" href="{{ $elem.link }}" aria-label="Google Scholar">
<i class="fas fa-graduation-cap" aria-hidden="true"></i>
</a>
{{ else }}
<a class="icon" target="_blank" rel="noopener" href="{{ $elem.link }}" aria-label="{{ $elem.name }}">
<i class="fab fa-{{ lower $elem.name }}" aria-hidden="true"></i>
</a>
{{ end }}
{{ if (lt (add $index 2) $length) }}
{{- print " , " -}}
{{ else if (lt (add $index 1) $length) }}
{{- print " and " -}}
{{ else }}
{{- print "." -}}
{{ end }}
{{ end }}
</p>
{{ end }}
{{ partial "optional-about.html" . }}
</section>
<section id="writing">
<span class="h1"><a href="{{ .Site.Params.mainSection | absURL }}">{{ .Site.Params.mainSectionTitle | default "Writings" }}</a></span>
{{ if (and (and (isset .Site.Params "tagsoverview") (eq .Site.Params.tagsOverview true)) (gt (len .Site.Taxonomies.tags) 0)) }}
<span class="h2">Topics</span>
<span class="widget tagcloud">
{{ $AllRegularPagesCount := len .Site.RegularPages }}
{{ range $elem := .Site.Taxonomies.tags.Alphabetical }}
<a style="font-size: {{ (add 0.5 (mul 5 (div (float $elem.Count) $AllRegularPagesCount))) }}rem;" href="{{ $elem.Page.Permalink }}">
{{- .Page.Title -}}
</a>
{{ end }}
</span>
<span class="h2">Most recent</span>
{{ end }}
{{ $showAllPostsOnHomePage := false }}
{{ if (isset .Site.Params "showallpostsonhomepage") }}
{{ $showAllPostsOnHomePage = .Site.Params.ShowAllPostsOnHomePage }}
{{ end }}
{{ $dataFormat := .Site.Params.dateFormat | default "2006-01-02" }}
{{ $mainPosts := (sort ( where site.RegularPages "Type" "in" site.Params.mainSections ) "Date" "desc") }}
{{ if $showAllPostsOnHomePage }}
<ul class="post-list">
{{ range (.Paginate $mainPosts).Pages }}
<li class="post-item">
<div class="meta"><time datetime="{{ time .Date }}" itemprop="datePublished">{{ .Date.Format $dataFormat }}</time></div>
<span><a href="{{ .Permalink }}">{{ if .Title }} {{- .Title -}} {{ else }} {{- print "Untitled" -}}{{ end }}</a></span>
</li>
{{ end }}
</ul>
{{ partial "pagination.html" . }}
{{ else }}
<ul class="post-list">
{{ .Scratch.Set "count" 5 }}
{{ if isset .Site.Params "postsonhomepage" }}
{{ .Scratch.Set "count" .Site.Params.postsOnHomePage }}
{{ end }}
{{ range (first (.Scratch.Get "count") $mainPosts) }}
<li class="post-item">
<div class="meta"><time datetime="{{ time .Date }}" itemprop="datePublished">{{ .Date.Format $dataFormat }}</time></div>
<span><a href="{{ .Permalink }}">{{ if .Title }} {{- .Title -}} {{ else }} {{- print "Untitled" -}}{{ end }}</a></span>
</li>
{{ end }}
</ul>
{{ end }}
</section>
{{ $showProjectsList := false }}
{{ if (isset .Site.Params "showprojectslist") }}
{{ $showProjectsList = .Site.Params.showProjectsList }}
{{ else if .Site.Data.projects }}
{{ $showProjectsList = true }}
{{ end }}
{{ if $showProjectsList }}
{{ $projectsUrl := "#" }}
{{ if isset .Site.Params "projectsurl" }}
{{ $projectsUrl = .Site.Params.projectsUrl }}
{{ end }}
<section id="projects">
<span class="h1"><a href="{{ $projectsUrl }}">Projects</a></span>
<ul class="project-list">
{{ range .Site.Data.projects.list }}
<li class="project-item">
<a href="{{ .url }}">{{ .name }}</a>: {{ .desc | markdownify }}
</li>
{{ end }}
</ul>
</section>
{{ end }}
{{ end }}

View File

@@ -0,0 +1,22 @@
{{ if (not (isset .Site.Params "comments")) }}
{{ .Scratch.Set "enable_comments" false }}
{{ else if (isset .Params "comments") }}
{{ .Scratch.Set "enable_comments" .Params.comments }}
{{ else if (isset .Site.Params.Comments "enabled") }}
{{ .Scratch.Set "enable_comments" .Site.Params.Comments.Enabled }}
{{ else }}
{{ .Scratch.Set "enable_comments" true }}
{{ end }}
{{ $enable_comments := .Scratch.Get "enable_comments" }}
{{ if $enable_comments }}
<div class="blog-post-comments">
{{ if (or (not (isset .Site.Params.Comments "engine")) (eq .Site.Params.Comments.Engine "disqus")) }}
{{ partial "comments/disqus.html" . }}
{{ else if eq .Site.Params.Comments.Engine "utterances" }}
{{ partial "comments/utterances.html" . }}
{{ else if eq .Site.Params.Comments.Engine "cactus_comments" }}
{{ partial "comments/cactus_comments.html" . }}
{{ end }}
</div>
{{ end }}

View File

@@ -0,0 +1,11 @@
<div id="cactus-comments-thread">
<script>
initComments({
node: document.getElementById("cactus-comments-thread"),
defaultHomeserverUrl: '{{ default "https://matrix.cactus.chat:8448" .Site.Params.Comments.Cactuscomments.ServerUrl }}',
serverName: '{{ default "cactus.chat" .Site.Params.Comments.Cactuscomments.ServerName }}',
siteName: "{{ .Site.Params.Comments.Cactuscomments.SiteName }}",
commentSectionId: "{{ .RelPermalink }}"
})
</script>
</div>

View File

@@ -0,0 +1,17 @@
<div id="disqus_thread">
<script type="text/javascript">
(function() {
// Don't ever inject Disqus on localhost--it creates unwanted
// discussions from 'localhost:1313' on your Disqus account...
// if (window.location.hostname == "localhost")
// return;
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
var disqus_shortname = '{{ if .Site.DisqusShortname }}{{ .Site.DisqusShortname }}{{ else }}{{ .Site.Title }}{{ end }}';
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
<a href="https://disqus.com/" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
</div>

View File

@@ -0,0 +1,10 @@
<div id="disquss_thread">
<script src="https://utteranc.es/client.js"
repo="{{ .Site.Params.Comments.Utterances.Repo }}"
issue-term="pathname"
label="{{ .Site.Params.Comments.Utterances.Label }}"
theme="{{ .Site.Params.Comments.Utterances.Theme }}"
crossorigin="anonymous"
async>
</script>
</div>

View File

@@ -0,0 +1,2 @@
<!-- TODO -->
<link rel="icon" type="image/png" href="{{ "images/favicon.ico" | absURL }}" />

View File

@@ -0,0 +1,14 @@
<footer id="footer">
<div class="footer-left">
Copyright &copy; {{ now.Format "2006" }} {{ if .Site.Copyright }} {{ print .Site.Copyright | markdownify }} {{ else }} {{ print .Site.Title }} {{ end }}
</div>
<div class="footer-right">
<nav>
<ul>
{{ range .Site.Menus.main }}
<li><a href="{{ .URL }}">{{ .Name }}</a></li>
{{ end }}
</ul>
</nav>
</div>
</footer>

View File

@@ -0,0 +1,50 @@
<head>
<link rel="preload" href="{{ "lib/font-awesome/webfonts/fa-brands-400.woff2" | relURL }}" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="{{ "lib/font-awesome/webfonts/fa-regular-400.woff2" | relURL }}" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="{{ "lib/font-awesome/webfonts/fa-solid-900.woff2" | relURL }}" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="{{ "lib/JetBrainsMono/web/woff2/JetBrainsMono-Regular.woff2" | relURL }}" as="font" type="font/woff2" crossorigin="anonymous">
<script type="text/javascript" src="https://latest.cactus.chat/cactus.js"></script>
<link rel="stylesheet" href="https://latest.cactus.chat/style.css" type="text/css">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>{{ if .IsPage }} {{ .Title }} | {{ end }}{{ .Site.Title }}</title>
<link rel = 'canonical' href = '{{ .Permalink }}'>
{{ with .Site.Params.description }}<meta name="description" content="{{ . }}">{{ end }}
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="all,follow">
<meta name="googlebot" content="index,follow,snippet,archive">
{{ template "_internal/opengraph.html" . }}
{{ template "_internal/twitter_cards.html" . }}
{{ .Scratch.Set "colortheme" "white"}}
{{ if .Site.Params.Colortheme }}
{{ .Scratch.Set "colortheme" .Site.Params.Colortheme }}
{{ end }}
{{ $colortheme := .Scratch.Get "colortheme" }}
{{- $options := (dict "targetPath" "css/styles.css" "outputStyle" "compressed" "enableSourceMap" "true") -}}
{{- $styles := resources.Get "scss/style.scss" | resources.ExecuteAsTemplate "scss/style.scss" . | resources.ToCSS $options | resources.Fingerprint "sha512" }}
<link rel="stylesheet" href="{{ $styles.Permalink }}" integrity="{{ $styles.Data.Integrity }}">
<!-- Custom CSS -->
{{ range .Site.Params.css }} <link rel="stylesheet" href="{{ . | absURL }}"> {{ end }}
{{ `
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
` | safeHTML }}
{{ partial "favicon.html" . }}
{{ if .Site.Params.rss }}
{{ with .OutputFormats.Get "RSS" }}
{{ printf `<link href="%s" rel="%s" type="%s" title="%s" />` .Permalink .Rel .MediaType.Type $.Site.Title | safeHTML }}
{{ end }}
{{ end }}
{{ if .Site.GoogleAnalytics }}
{{ if .Site.Params.googleAnalyticsAsync }}
{{ template "_internal/google_analytics_async.html" . }}
{{ else }}
{{ template "_internal/google_analytics.html" . }}
{{ end }}
{{ end }}
</head>

View File

@@ -0,0 +1,25 @@
<header id="header">
<a href="{{ .Site.BaseURL }}">
{{ if (isset .Site.Params "gravatar") }}
<div id="logo" style="background-image: url(https://www.gravatar.com/avatar/{{ md5 .Site.Params.gravatar }}?s=100&d=identicon)"></div>
{{ else if (isset .Site.Params "logo") }}
<div id="logo" style="background-image: url({{ .Site.Params.logo | absURL }})"></div>
{{ else }}
<div id="logo" style="background-image: url({{ "images/logo.png" | absURL }})"></div>
{{ end}}
<div id="title">
<h1>{{ .Site.Title }}</h1>
</div>
</a>
<div id="nav">
<ul>
<li class="icon">
<a href="#" aria-label="Menu"><i class="fas fa-bars fa-2x" aria-hidden="true"></i></a>
</li>
{{ range .Site.Menus.main }}
<li><a href="{{ .URL }}">{{ .Name }}</a></li>
{{ end }}
</ul>
</div>
</header>

View File

@@ -0,0 +1,57 @@
<div id="header-post">
<a id="menu-icon" href="#"><i class="fas fa-bars fa-lg"></i></a>
<a id="menu-icon-tablet" href="#"><i class="fas fa-bars fa-lg"></i></a>
<a id="top-icon-tablet" href="#" onclick="$('html, body').animate({ scrollTop: 0 }, 'fast');" style="display:none;" aria-label="Top of Page"><i class="fas fa-chevron-up fa-lg"></i></a>
<span id="menu">
<span id="nav">
<ul>
{{ range .Site.Menus.main }}
<li><a href="{{ .URL }}">{{ .Name }}</a></li>
{{ end }}
</ul>
</span>
<br/>
<span id="actions">
<ul>
{{ if .Prev }}
<li>
<a class="icon" href=" {{ .Prev.Permalink }}" aria-label="Previous">
<i class="fas fa-chevron-left" aria-hidden="true" onmouseover="$('#i-prev').toggle();" onmouseout="$('#i-prev').toggle();"></i>
</a>
</li>
{{ end }}
{{ if .Next }}
<li>
<a class="icon" href="{{ .Next.Permalink }}" aria-label="Next">
<i class="fas fa-chevron-right" aria-hidden="true" onmouseover="$('#i-next').toggle();" onmouseout="$('#i-next').toggle();"></i>
</a>
</li>
{{ end }}
<li>
<a class="icon" href="#" onclick="$('html, body').animate({ scrollTop: 0 }, 'fast');" aria-label="Top of Page">
<i class="fas fa-chevron-up" aria-hidden="true" onmouseover="$('#i-top').toggle();" onmouseout="$('#i-top').toggle();"></i>
</a>
</li>
<li>
<a class="icon" href="#" aria-label="Share">
<i class="fas fa-share-alt" aria-hidden="true" onmouseover="$('#i-share').toggle();" onmouseout="$('#i-share').toggle();" onclick="$('#share').toggle();return false;"></i>
</a>
</li>
</ul>
<span id="i-prev" class="info" style="display:none;">Previous post</span>
<span id="i-next" class="info" style="display:none;">Next post</span>
<span id="i-top" class="info" style="display:none;">Back to top</span>
<span id="i-share" class="info" style="display:none;">Share post</span>
</span>
<br/>
<div id="share" style="display: none">
{{ .Scratch.Set "icon_class_name" ""}}
{{ partial "share.html" . }}
</div>
{{ if not .Site.Params.tocInline }}
<div id="toc">
{{ .TableOfContents }}
</div>
{{ end }}
</span>
</div>

View File

@@ -0,0 +1,38 @@
<div id="footer-post-container">
<div id="footer-post">
<div id="nav-footer" style="display: none">
<ul>
{{ range .Site.Menus.main }}
<li><a href="{{ .URL }}">{{ .Name }}</a></li>
{{ end }}
</ul>
</div>
{{ if not .Site.Params.tocInline }}
<div id="toc-footer" style="display: none">
{{ .TableOfContents }}
</div>
{{ end }}
<div id="share-footer" style="display: none">
{{ .Scratch.Set "icon_class_name" "fa-lg" }}
{{ partial "share.html" . }}
</div>
<div id="actions-footer">
<!-- TODO: rewrite the toggle function. hide the others when one menu is displayed -->
<a id="menu-toggle" class="icon" href="#" onclick="$('#nav-footer').toggle();return false;" aria-label="Menu">
<i class="fas fa-bars fa-lg" aria-hidden="true"></i> Menu</a>
{{ if not .Site.Params.tocInline }}
<a id="toc-toggle" class="icon" href="#" onclick="$('#toc-footer').toggle();return false;" aria-label="TOC">
<i class="fas fa-list fa-lg" aria-hidden="true"></i> TOC</a>
{{ end }}
<a id="share-toggle" class="icon" href="#" onclick="$('#share-footer').toggle();return false;" aria-label="Share">
<i class="fas fa-share-alt fa-lg" aria-hidden="true"></i> share</a>
<a id="top" style="display:none" class="icon" href="#" onclick="$('html, body').animate({ scrollTop: 0 }, 'fast');" aria-label="Top of Page">
<i class="fas fa-chevron-up fa-lg" aria-hidden="true"></i> Top</a>
</div>
</div>
</div>

View File

@@ -0,0 +1,13 @@
{{ $pag := $.Paginator }}
{{ if gt $pag.TotalPages 1 }}
<div class="pagination">
{{ if $pag.HasPrev }}
<a href="{{ $pag.Prev.URL }}"><i class="fas fa-angle-left"></i></a>
{{ end }}
<span class="page-number">Page {{ $pag.PageNumber }} of {{ $pag.TotalPages }}</span>
{{ if $pag.HasNext }}
<a href="{{ $pag.Next.URL }}"><i class="fas fa-angle-right"></i>
</a>
{{ end }}
</div>
{{ end }}

View File

@@ -0,0 +1,54 @@
<ul>
{{ $icon_class_name := .Scratch.Get "icon_class_name"}}
{{ if .Description }}
{{ .Scratch.Set "description" .Description }}
{{ else }}
{{ .Scratch.Set "description" .Summary }}
{{ end }}
{{ $description := .Scratch.Get "description" }}
<li>
<a class="icon" href="http://www.facebook.com/sharer.php?u={{ .Permalink }}" aria-label="Facebook">
<i class="fab fa-facebook {{ $icon_class_name }}" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="https://twitter.com/share?url={{ .Permalink }}&text={{ .Title }}" aria-label="Twitter">
<i class="fab fa-twitter {{ $icon_class_name }}" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="http://www.linkedin.com/shareArticle?url={{ .Permalink }}&title={{ .Title }}" aria-label="Linkedin">
<i class="fab fa-linkedin {{ $icon_class_name }}" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="https://pinterest.com/pin/create/bookmarklet/?url={{ .Permalink }}&is_video=false&description={{ .Title }}" aria-label="Pinterest">
<i class="fab fa-pinterest {{ $icon_class_name }}" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="mailto:?subject={{ .Title }}&body=Check out this article: {{ .Permalink }}" aria-label="Email">
<i class="fas fa-envelope {{ $icon_class_name }}" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="https://getpocket.com/save?url={{ .Permalink }}&title={{ .Title }}" aria-label="Pocket">
<i class="fab fa-get-pocket {{ $icon_class_name }}" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="http://reddit.com/submit?url={{ .Permalink }}&title={{ .Title }}" aria-label="reddit">
<i class="fab fa-reddit {{ $icon_class_name }}" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="http://www.tumblr.com/share/link?url={{ .Permalink }}&name={{ .Title }}&description={{ $description }}" aria-label="Tumblr">
<i class="fab fa-tumblr {{ $icon_class_name }}" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="https://news.ycombinator.com/submitlink?u={{ .Permalink }}&t={{ .Title }}" aria-label="Hacker News">
<i class="fab fa-hacker-news {{ $icon_class_name }}" aria-hidden="true"></i>
</a>
</li>
</ul>

View File

@@ -0,0 +1,117 @@
<!DOCTYPE html>
<html lang="{{ .Site.LanguageCode }}">
{{ partial "head.html" . }}
<body class="max-width mx-auto px3 ltr">
<div class="content index py4">
{{ partial "page_nav.html" . }}
<article class="post" itemscope itemtype="http://schema.org/BlogPosting">
<header>
<h1 class="posttitle" itemprop="name headline">
{{ .Title }}
</h1>
<div class="meta">
{{ if (or (isset .Site "author") (isset .Site "title"))}}
<span class="author" itemprop="author" itemscope itemtype="http://schema.org/Person">
<span itemprop="name">
{{ if isset .Site "author" }}
{{ .Site.Author }}
{{ else if isset .Site "title" }}
{{ .Site.Title }}
{{ end }}
</span>
</span>
{{ end }}
<div class="postdate">
{{ $dataFormat := .Site.Params.dateFormat | default "2006-01-02" }}
<time datetime="{{ .Date }}" itemprop="datePublished">{{ .Date.Format $dataFormat }}</time>
{{ if (and .Site.Params.show_updated (ne .Lastmod .Date)) }}
(Updated: <time datetime="{{ .Lastmod }}" itemprop="dateModified">{{ .Lastmod.Format $dataFormat }}</time>)
{{ end }}
</div>
{{ $showReadTime := .Site.Params.showReadTime | default false }}
{{if $showReadTime}}
<div class="article-read-time">
<i class="far fa-clock"></i>
{{ $readTime := math.Round (div (countwords .Content) 220.0) }}
{{ $readTime }} minute read
</div>
{{ end }}
{{ if gt .Params.categories 0 }}
<div class="article-category">
<i class="fas fa-archive"></i>
{{ range $index, $value := .Params.categories }}
{{ if gt $index 0 }} {{ print ", " }} {{ end }}
<a class="category-link" href="{{ "/categories/" | relLangURL }}{{ $value | urlize }}">{{ $value }}</a>
{{ end }}
</div>
{{ end }}
{{ if gt .Params.tags 0 }}
<div class="article-tag">
<i class="fas fa-tag"></i>
{{ range $index, $value := .Params.tags }}
{{ if gt $index 0 }} {{ print ", " }} {{ end }}
<a class="tag-link" href="{{ "/tags/" | relLangURL }}{{ $value | urlize }}" rel="tag">{{ $value }}</a>
{{ end }}
</div>
{{ end }}
</div>
</header>
{{ with .Resources.ByType "image" }}
<div class="article-gallery">
{{ range $index, $value := . }}
<a class="gallery-item" href="{{ .RelPermalink }}" rel="gallery_{{ $index }}">
<img src="{{ .RelPermalink }}" itemprop="image" />
</a>
{{ end }}
</div>
{{ end }}
{{ if .Site.Params.tocInline }}
<div id="toc">
{{ .TableOfContents }}
</div>
{{ end }}
<div class="content" itemprop="articleBody">
{{ .Content}}
</div>
</article>
{{ partial "comments.html" . }}
{{ partial "page_nav_mobile.html" . }}
{{ partial "footer.html" . }}
</div>
</body>
<link rel="stylesheet" href={{ "/lib/font-awesome/css/all.min.css" | relURL }}>
<script src={{ "/lib/jquery/jquery.min.js" | relURL }}></script>
<script src={{ "/js/main.js" | relURL }}></script>
{{ if not (isset site.Params "disablecopy") }}
<script src={{ "js/code-copy.js" | relURL }}></script>
{{ end }}
{{ $mathjax := false }}
{{ if isset .Params "mathjax" }}
{{ $mathjax = .Params.mathjax }}
{{ else if isset .Site.Params "mathjax" }}
{{ $mathjax = .Site.Params.mathjax }}
{{ end }}
{{ if $mathjax }}
<script>
MathJax = {
tex: {
inlineMath: [['$', '$'], ['\\(', '\\)']]
},
svg: {
fontCache: 'global'
}
};
</script>
<script type="text/javascript" id="MathJax-script" async
src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js">
</script>
{{ end }}
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

View File

@@ -0,0 +1,36 @@
(() => {
function createCopyButton(codeNode) {
const copyBtn = document.createElement('button')
copyBtn.className = 'code-copy-btn'
copyBtn.type = 'button'
copyBtn.innerText = 'copy'
let resetTimer
copyBtn.addEventListener('click', () => {
navigator.clipboard.writeText(codeNode.innerText).then(() => {
copyBtn.innerText = 'copied!'
}).then(() => {
clearTimeout(resetTimer)
resetTimer = setTimeout(() => {
copyBtn.innerText = 'copy'
}, 1000)
})
})
return copyBtn
}
document.querySelectorAll('pre > code')
.forEach((codeNode) => {
const copyBtn = createCopyButton(codeNode);
const preNode = codeNode.parentNode
codeNode.parentNode.insertBefore(copyBtn, codeNode)
})
document.querySelectorAll('.highlight table > tbody > tr > td:first-child .code-copy-btn')
.forEach((btn) => {
btn.remove()
})
})()

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,113 @@
/**
* Sets up Justified Gallery.
*/
if (!!$.prototype.justifiedGallery) {
var options = {
rowHeight: 140,
margins: 4,
lastRow: "justify"
};
$(".article-gallery").justifiedGallery(options);
}
$(document).ready(function() {
/**
* Shows the responsive navigation menu on mobile.
*/
$("#header > #nav > ul > .icon").click(function() {
$("#header > #nav > ul").toggleClass("responsive");
});
/**
* Controls the different versions of the menu in blog post articles
* for Desktop, tablet and mobile.
*/
if ($(".post").length) {
var menu = $("#menu");
var nav = $("#menu > #nav");
var menuIcon = $("#menu-icon, #menu-icon-tablet");
/**
* Display the menu on hi-res laptops and desktops.
*/
if ($(document).width() >= 1440) {
menu.css("visibility", "visible");
menuIcon.addClass("active");
}
/**
* Display the menu if the menu icon is clicked.
*/
menuIcon.click(function() {
if (menu.css("visibility") === "hidden") {
menu.css("visibility", "visible");
menuIcon.addClass("active");
} else {
menu.css("visibility", "hidden");
menuIcon.removeClass("active");
}
return false;
});
/**
* Add a scroll listener to the menu to hide/show the navigation links.
*/
if (menu.length) {
$(window).on("scroll", function() {
var topDistance = menu.offset().top;
// hide only the navigation links on desktop
if (!nav.is(":visible") && topDistance < 50) {
nav.show();
} else if (nav.is(":visible") && topDistance > 100) {
nav.hide();
}
// on tablet, hide the navigation icon as well and show a "scroll to top
// icon" instead
if ( ! $( "#menu-icon" ).is(":visible") && topDistance < 50 ) {
$("#menu-icon-tablet").show();
$("#top-icon-tablet").hide();
} else if (! $( "#menu-icon" ).is(":visible") && topDistance > 100) {
$("#menu-icon-tablet").hide();
$("#top-icon-tablet").show();
}
});
}
/**
* Show mobile navigation menu after scrolling upwards,
* hide it again after scrolling downwards.
*/
if ($( "#footer-post").length) {
var lastScrollTop = 0;
$(window).on("scroll", function() {
var topDistance = $(window).scrollTop();
if (topDistance > lastScrollTop){
// downscroll -> show menu
$("#footer-post").hide();
} else {
// upscroll -> hide menu
$("#footer-post").show();
}
lastScrollTop = topDistance;
// close all submenu"s on scroll
$("#nav-footer").hide();
$("#toc-footer").hide();
$("#share-footer").hide();
// show a "navigation" icon when close to the top of the page,
// otherwise show a "scroll to the top" icon
if (topDistance < 50) {
$("#actions-footer > #top").hide();
} else if (topDistance > 100) {
$("#actions-footer > #top").show();
}
});
}
}
});

View File

@@ -0,0 +1,154 @@
// A local search script with the help of
// [hexo-generator-search](https://github.com/PaicHyperionDev/hexo-generator-search)
// Copyright (C) 2015
// Joseph Pan <http://github.com/wzpan>
// Shuhao Mao <http://github.com/maoshuhao>
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
// 02110-1301 USA
//
// Modified by:
// Pieter Robberechts <http://github.com/probberechts>
/*exported searchFunc*/
var searchFunc = function(path, searchId, contentId) {
function stripHtml(html) {
html = html.replace(/<style([\s\S]*?)<\/style>/gi, "");
html = html.replace(/<script([\s\S]*?)<\/script>/gi, "");
html = html.replace(/<figure([\s\S]*?)<\/figure>/gi, "");
html = html.replace(/<\/div>/ig, "\n");
html = html.replace(/<\/li>/ig, "\n");
html = html.replace(/<li>/ig, " * ");
html = html.replace(/<\/ul>/ig, "\n");
html = html.replace(/<\/p>/ig, "\n");
html = html.replace(/<br\s*[\/]?>/gi, "\n");
html = html.replace(/<[^>]+>/ig, "");
return html;
}
function getAllCombinations(keywords) {
var i, j, result = [];
for (i = 0; i < keywords.length; i++) {
for (j = i + 1; j < keywords.length + 1; j++) {
result.push(keywords.slice(i, j).join(" "));
}
}
return result;
}
$.ajax({
url: path,
dataType: "xml",
success: function(xmlResponse) {
// get the contents from search data
var datas = $("entry", xmlResponse).map(function() {
return {
title: $("title", this).text(),
content: $("content", this).text(),
url: $("link", this).attr("href")
};
}).get();
var $input = document.getElementById(searchId);
if (!$input) { return; }
var $resultContent = document.getElementById(contentId);
$input.addEventListener("input", function(){
var resultList = [];
var keywords = getAllCombinations(this.value.trim().toLowerCase().split(" "))
.sort(function(a,b) { return b.split(" ").length - a.split(" ").length; });
$resultContent.innerHTML = "";
if (this.value.trim().length <= 0) {
return;
}
// perform local searching
datas.forEach(function(data) {
var matches = 0;
if (!data.title || data.title.trim() === "") {
data.title = "Untitled";
}
var dataTitle = data.title.trim().toLowerCase();
var dataContent = stripHtml(data.content.trim());
var dataUrl = data.url;
var indexTitle = -1;
var indexContent = -1;
var firstOccur = -1;
// only match artiles with not empty contents
if (dataContent !== "") {
keywords.forEach(function(keyword) {
indexTitle = dataTitle.indexOf(keyword);
indexContent = dataContent.indexOf(keyword);
if( indexTitle >= 0 || indexContent >= 0 ){
matches += 1;
if (indexContent < 0) {
indexContent = 0;
}
if (firstOccur < 0) {
firstOccur = indexContent;
}
}
});
}
// show search results
if (matches > 0) {
var searchResult = {};
searchResult.rank = matches;
searchResult.str = "<li><a href='"+ dataUrl +"' class='search-result-title'>"+ dataTitle +"</a>";
if (firstOccur >= 0) {
// cut out 100 characters
var start = firstOccur - 20;
var end = firstOccur + 80;
if(start < 0){
start = 0;
}
if(start == 0){
end = 100;
}
if(end > dataContent.length){
end = dataContent.length;
}
var matchContent = dataContent.substr(start, end);
// highlight all keywords
var regS = new RegExp(keywords.join("|"), "gi");
matchContent = matchContent.replace(regS, function(keyword) {
return "<em class=\"search-keyword\">"+keyword+"</em>";
});
searchResult.str += "<p class=\"search-result\">" + matchContent +"...</p>";
}
searchResult.str += "</li>";
resultList.push(searchResult);
}
});
resultList.sort(function(a, b) {
return b.rank - a.rank;
});
var result ="<ul class=\"search-result-list\">";
for (var i = 0; i < resultList.length; i++) {
result += resultList[i].str;
}
result += "</ul>";
$resultContent.innerHTML = result;
});
}
});
};

View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Some files were not shown because too many files have changed in this diff Show More