├── .github └── workflows │ └── main.yml ├── .gitignore ├── .prettierrc.json ├── LICENSE ├── README-en_US.md ├── README.md ├── bin ├── code996.ps1 ├── code996.sh └── code996_en.sh ├── index.html ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── fonts │ ├── vcr-osd.ttf │ ├── zpix.ttf │ └── zpix.woff2 ├── js │ └── chart.xkcd.min.js └── preview │ ├── 1.png │ ├── 2.png │ └── 3.png ├── src ├── App.vue ├── main.ts ├── public │ ├── components │ │ ├── CommonFooter.vue │ │ └── GithubCorner.vue │ └── styles │ │ ├── common.scss │ │ ├── index.scss │ │ ├── module-intro.scss │ │ ├── module-result.scss │ │ └── reset.scss ├── router │ └── index.ts ├── sfc.d.ts ├── shims-vue.d.ts ├── typings │ └── index.ts ├── utils │ ├── index.ts │ └── time.ts └── view │ ├── intro │ └── index.vue │ └── result │ ├── components │ ├── BarChart.vue │ ├── CompareTable.vue │ └── PieChart.vue │ ├── core │ ├── hour.ts │ ├── index.ts │ ├── table.ts │ ├── url-helper.ts │ ├── utils.ts │ └── week.ts │ └── index.vue ├── tsconfig.json ├── userscript.js └── vite.config.ts /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Deploy GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - pre 8 | 9 | # 任务 10 | jobs: 11 | build-and-deploy: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v2 16 | with: 17 | persist-credentials: false 18 | 19 | - name: Build 20 | run: npm install && npm run build 21 | 22 | - name: Deploy 23 | uses: JamesIves/github-pages-deploy-action@releases/v4 24 | with: 25 | ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }} 26 | REPOSITORY_NAME: hellodigua/code996 27 | BRANCH: gh-pages 28 | FOLDER: dist 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | .DS_Store 3 | 4 | # Node.js 5 | node_modules 6 | 7 | # local env files 8 | .env.local 9 | .env.*.local 10 | 11 | # Log files 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | *.log 16 | 17 | # Editor 18 | .vscode/ 19 | !.vscode/settings.json 20 | 21 | # Project 22 | dist/ 23 | stats.html 24 | .npmignore -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "semi": false, 4 | "singleQuote": true, 5 | "trailingComma": "es5", 6 | "arrowParens": "always", 7 | "htmlWhitespaceSensitivity": "ignore" 8 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README-en_US.md: -------------------------------------------------------------------------------- 1 | # code996 2 | 3 | code996 is an analytics tool that can be used to calculate the commit time distribution of a Git project and derive the coding intensity of that project. 4 | 5 | Preview: https://hellodigua.github.io/code996/ 6 | 7 | English | [简体中文](./README.md) 8 | 9 | ## How to Use 10 | 11 | For Mac or Linux users. 12 | 13 | **In the root directory of your Git project**, run the following command. 14 | 15 | ```sh 16 | curl -fsSL https://fastly.jsdelivr.net/gh/hellodigua/code996/bin/code996_en.sh | bash 17 | ``` 18 | 19 | Windows users. 20 | 21 | Download the script `https://fastly.jsdelivr.net/gh/hellodigua/code996/bin/code996_en.sh` 22 | 23 | Then move the script to the Git project directory you want to analyze, and execute the following command. 24 | 25 | ```sh 26 | sh code996_en.sh 27 | ``` 28 | 29 | ## Preview 30 | 31 | Basic information about the project to analyze. 32 | 33 | ![basic](./public/preview/1.png) 34 | 35 | View commit distribution by graph: ! 36 | 37 | ![chart](./public/preview/2.png) 38 | 39 | Compare project work time types. 40 | 41 | ![reference](./public/preview/3.png) 42 | 43 | ## How it works 44 | 45 | 1. use git-log to query the project **current branches** and get the commit statistics summarized by hour and by day 46 | 2. convert the query results from the local script to URL arguments and open the URL to the browser 47 | 3. get the data from the URL, process it with some rules, and visualize the results 48 | 49 | ## Is it safe? 50 | 51 | 1. neither the script side nor the web side collects any data 52 | 2. the URL itself does not disclose sensitive information such as project name, except for common data such as start time of analysis, commit statistics, etc. 53 | 3. all code has been open source, accepting community supervision 54 | 55 | ## Caution 56 | 57 | - The analysis results are for reference only and do not constitute any recommendation 58 | - The original analysis data is transmitted via URL, please be careful if you want to share it 59 | - Please do not use it for official purposes 60 | 61 | ## Other Questions 62 | 63 | ### Q: What is the 996 Index? 64 | 65 | The 996 Index is a data indicator defined by the project to reflect the overtime situation of the project. 66 | 67 | After standardizing the overtime situation, we can easily compare the work intensity of projects across teams and companies. 68 | 69 | ### Q: Under what circumstances are code996's analysis results inaccurate? 70 | 71 | - The default statistics of the script is the overall project commit time, which represents the work status of all participants in the project during this time, and may deviate from the actual situation of individuals 72 | - In addition to coding, we also need to meet, write documents, study and fish, so it can't cover the actual working time either 73 | - Projects developed across borders and time zones cannot be counted correctly 74 | - Projects with irregular working hours (e.g. personal open source projects) can't be counted either 75 | 76 | ### Q: I have a better idea 77 | 78 | Any ideas and comments are welcome to share, and you are welcome to modify it after Fork. 79 | 80 | ## Disclaimer 81 | 82 | This project is for learning and communication only, code996 does not assume any responsibility for any consequences caused by the use and dissemination of this program and its ancillary products. 83 | 84 | We have listed below some of the possible consequences of using this program, please be aware of them. 85 | 86 | - Computer crash, lag, reboot 87 | - Blue screen, white screen, black screen, splash screen 88 | - Your boss or colleague sees you groping for fish 89 | - You are found by your colleague through code996 that you are fishing in the past 90 | - Leak confidential information and be dealt with by security department 91 | - Late for work 92 | - Being graduated 93 | - Stock market crash 94 | - Earth explodes 95 | 96 | ## License 97 | 98 | This program and its source code and compiled products are subject to the [Unlicense](LICENSE) license, and its dependencies on related libraries and content are not licensed under promise, please refer to their original licenses. 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # code996 2 | 3 | code996 是一个分析工具,它可以统计 Git 项目的 commit 时间分布,进而推导出项目的编码工作强度。 4 | 5 | Preview:https://hellodigua.github.io/code996/ 6 | 7 | 简体中文 | [English](./README-en_US.md) 8 | 9 | ## 预览 10 | 11 | 分析 Git 项目的基本情况: 12 | 13 | ![basic](./public/preview/1.png) 14 | 15 | 通过图表查看 commit 提交分布: 16 | 17 | ![chart](./public/preview/2.png) 18 | 19 | 对比项目工作时间类型: 20 | 21 | ![reference](./public/preview/3.png) 22 | 23 | ## 如何使用 24 | 25 | **本地分析**:在 Git 项目的根目录,执行以下脚本: 26 | 27 | ```sh 28 | curl -fsSL https://fastly.jsdelivr.net/gh/hellodigua/code996/bin/code996.sh | bash 29 | ``` 30 | 31 | **在线分析**:gitlab 项目可以使用浏览器用户脚本 `userscript.js` 进行在线分析 32 | 33 |
34 | 具体使用方法请展开查看 35 | 36 | ### Gitlab 线上版本 37 | 38 | - 安装浏览器插件 tampermonkey https://www.tampermonkey.net/ 39 | - 拷贝 userscript.js 文件到 tampermonkey(或选择[在线安装](https://greasyfork.org/en/scripts/452007-gitlab-996-index-statistic)) 40 | - 打开需要分析的 gitlab 项目页面,点击按钮可得到分析结果 41 | 42 | image 43 | 44 | ### PowerShell 版本 45 | 46 | > 请使用 PowerShell 7 或更高版本 47 | 48 | ```sh 49 | iwr https://fastly.jsdelivr.net/gh/hellodigua/code996/bin/code996.ps1 -OutFile ([System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), 'code996.ps1')); & ([System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), 'code996.ps1')); ri ([System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), 'code996.ps1')) 50 | ``` 51 | 52 |
53 | 54 | ## 它怎样工作 55 | 56 | 1. 使用 git-log 对项目**当前的分支**进行查询,得到以小时汇总和以天汇总的 commit 统计结果 57 | 2. 将本地脚本得到的查询结果转为 URL 参数,并打开 URL 到浏览器 58 | 3. 从 URL 拿到数据,并使用一些规则处理,并将结果可视化展现 59 | 60 | ## 它有什么用 61 | 62 | 它可以帮助你分辨 996 的公司和行为并远离它,具体包括: 63 | 64 | 1. 在入职的当天即可知道新公司的加班情况如何 65 | 2. 揪出公司里的卷王 66 | 3. 对比不同项目的加班强度 67 | 68 | ## 它安全吗 69 | 70 | 1. 脚本端和 Web 端均不会收集任何数据 71 | 2. 除分析的起始时间、commit 统计结果等通用数据外,URL 本身不泄露如项目名等敏感信息 72 | 3. 所有代码均已开源,接受社区监督 73 | 74 | ## 其他 Question 75 | 76 | ### Q:996 指数是什么? 77 | 78 | 996 指数是本项目定义的,用于反映项目加班情况的数据指标。 79 | 80 | 在对加班情况标准化之后,我们可以方便的对跨团队、跨公司项目的工作强度进行对比。 81 | 82 | ### Q:什么情况下它的分析结果不准确? 83 | 84 | - 脚本默认统计的是项目整体的提交时间,代表了项目中的所有参与者在这段时间的工作状态,可能与个人的实际情况有偏差 85 | - 除了 coding,我们还需要开会、写文档、学习、摸鱼等,因此它也无法覆盖实际的工作时间 86 | - 跨国、跨时区开发的项目无法正确统计 87 | - 工作时间不固定的项目(如个人开源项目)也无法统计 88 | 89 | ## 注意事项 90 | 91 | - 分析结果仅供参考,不构成任何建议 92 | - 原始分析数据通过 URL 传输,如需分享,请慎重 93 | - 项目仅供学习与交流,code996 不对使用、传播本程序及附属产物造成的任何后果承担任何责任 94 | 95 | ## 贡献者 96 | 97 | 感谢 [YLinXin](https://github.com/YLinXin) | [Nekotora](https://flag.moe/) | [Xuemuyang](https://github.com/Xuemuyang) 等小伙伴对本项目的贡献,希望这个项目能帮助到不希望加班的开发者们。 98 | 99 | 站点主题及灵感来自 [996.ICU](https://github.com/996icu/996.ICU)。 100 | 101 | 如果有问题欢迎在 issue 提出,或通过邮件联系我。 102 | 103 | ## 使用许可 104 | 105 | 本程序及其源码和编译产物附属 [Unlicense](LICENSE) 许可,其依赖的相关库和内容不做许可承诺,请参考他们的原始许可。 106 | 107 | ![license](https://img.shields.io/github/license/hellodigua/code996) 108 | ![](https://img.shields.io/jsdelivr/gh/hm/hellodigua/code996) 109 | ![views](https://us-central1-trackgit-analytics.cloudfunctions.net/token/ping/l2vhuyzttoxl2nx0wzl2) 110 | -------------------------------------------------------------------------------- /bin/code996.ps1: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env pwsh 2 | 3 | <# 4 | .DESCRIPTION 5 | 用于统计 Git 项目的 commit 时间分布,进而推导出这个项目的编码工作强度的脚本。 6 | 不支持 Windows PowerShell 及 PowerShell 6,仅支持 PowerShell 7 及更高版本! 7 | .EXAMPLE 8 | ./code996.ps1 "2022-1-1" -Author lc6464 9 | .EXAMPLE 10 | ./code996.ps1 "2022-1-1" 11 | .EXAMPLE 12 | ./code996.ps1 -EndTime "2022-7-13" 13 | .EXAMPLE 14 | ./code996.ps1 "2022-1-1" "2022-1-31" 15 | .PARAMETER StartDate 16 | 统计数据的开始日期(默认为今年的第一天)。 17 | .PARAMETER EndDate 18 | 统计数据的结束日期(默认为今天)。 19 | .PARAMETER Author 20 | 统计数据的作者(默认为所有提交者)。 21 | #> 22 | param([DateTime] $StartDate, [DateTime] $EndDate, [string] $Author) 23 | 24 | if ($PSVersionTable.PSVersion.Major -lt 7) { 25 | Write-Host "此脚本不支持 Windows PowerShell 及 PowerShell 6,请使用 PowerShell 7 或更高版本!" 26 | } else { 27 | function GetGitData { 28 | param([string] $Format) 29 | $builder = [Text.StringBuilder]::new() 30 | $output = [System.Collections.Generic.List[string]]::new() 31 | $outputRaw = git log --author=$Author --date=format:$Format --after=$StartDateStr --before=$EndDateStr | Select-String "^Date: (\d\d?)$" 32 | foreach ($one in $outputRaw) { 33 | $output.Add($one.Matches.Groups[1].Value) 34 | } 35 | $groups = $output | group 36 | foreach ($one in $groups) { 37 | $_ = $builder.Append($one.Count.ToString() + "_" + ($Format -eq "%H" ? $one.Name.ToString().PadLeft(2, '0') : $one.Name.ToString()) + ",") 38 | } 39 | if ($builder.Length -eq 0) { 40 | Write-Output $null 41 | } else { 42 | $builder.Length -= 1 43 | Write-Output $builder.ToString() 44 | } 45 | } 46 | 47 | 48 | 49 | $StartDateStr = ($StartDate ?? [DateTime]::new((date).Year - 1, 1, 1)).ToString("yyyy-MM-dd") 50 | $EndDateStr = ($EndDate ?? (date)).ToString("yyyy-MM-dd") 51 | 52 | if ($StartDate -gt $EndDate) { 53 | Write-Host "开始日期须早于结束日期!" 54 | } else { 55 | $outputByDay = GetGitData %u 56 | 57 | $outputByHour = GetGitData %H 58 | 59 | $result = $StartDateStr + "_$EndDateStr&week=$outputByDay&hour=$outputByHour" 60 | 61 | # url 62 | $GithubUrl = "https://hellodigua.github.io/code996/#/result?time=$result" 63 | $VercelUrl = "https://code996.vercel.app/#/result?time=$result" 64 | 65 | 66 | Write-Host "复制以下 URL 以查看可视化分析结果:" 67 | Write-Host $VercelUrl 68 | Write-Host "" 69 | Write-Host "也可以访问以下镜像站点链接:" 70 | Write-Host "GitHub Pages:" 71 | Write-Host "$GitHubUrl" 72 | Write-Host "" 73 | 74 | Start-Process $VercelUrl 75 | } 76 | } -------------------------------------------------------------------------------- /bin/code996.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | Help() 4 | { 5 | echo "你也可以使用自定义参数进行指定查询" 6 | echo 7 | echo "格式: bash $0 [2022-01-01] [2022-04-04] [author]" 8 | echo "示例: bash code996.sh 2022-01-01 2022-12-31 digua" 9 | echo "参数:" 10 | echo "1st 分析的起始时间." 11 | echo "2nd 分析的结束时间." 12 | echo "3rd 指定提交用户,可以是 name 或 email." 13 | echo 14 | } 15 | 16 | OS_DETECT() 17 | { 18 | # Detect OS 19 | case "$(uname -s)" in 20 | 21 | Linux) 22 | # echo 'Linux' 23 | open_url="xdg-open" 24 | ;; 25 | 26 | Darwin) 27 | # echo 'macOS' 28 | open_url="open" 29 | ;; 30 | 31 | CYGWIN*|MINGW32*|MSYS*|MINGW*) 32 | # echo 'Windows' 33 | open_url="start" 34 | ;; 35 | 36 | *) 37 | echo 'Other OS' 38 | echo "trying to use xdg-open to open the url" 39 | open_url="xdg-open" 40 | ;; 41 | esac 42 | 43 | } 44 | OS_DETECT 45 | 46 | 47 | time_start=$1 48 | 49 | 50 | if [ "$1" == "--help" ] 51 | then 52 | Help 53 | exit 0 54 | elif [ "$1" == "-h" ] 55 | then 56 | Help 57 | exit 0 58 | fi 59 | 60 | if [ -z $1 ] 61 | then 62 | time_start="2022-01-01" 63 | fi 64 | 65 | time_end=$2 66 | if [ -z $2 ] 67 | then 68 | time_end=$(date "+%Y-%m-%d") 69 | fi 70 | 71 | author=$3 72 | if [ -z $3 ] 73 | then 74 | author="" 75 | fi 76 | 77 | 78 | by_day_output=`git -C "$PWD" log --author=$author --date=format:%u --after="$time_start" --before="$time_end" |grep "Date:"|awk '{print $2}'|sort|uniq -c` 79 | 80 | by_hour_output=`git -C "$PWD" log --author=$author --date=format:%H --after="$time_start" --before="$time_end" |grep "Date:"|awk '{print $2}'|sort|uniq -c` 81 | 82 | for i in "${by_day_output[@]}" 83 | do 84 | by_day_result=`echo "$i"|sed -E 's/^ +//g'|sed 's/ /_/g'|tr '\n' ','` 85 | 86 | done 87 | 88 | 89 | # should modify by day format %a or %A 90 | # day_sorted=('Monday' 'Tuesday' 'Wednesday' 'Thursday' 'Friday' 'Saturday' 'Sunday') 91 | # day_sorted=('Mon' 'Tue' 'Wed' 'Thu' 'Fri' 'Sat' 'Sun') 92 | 93 | RED='\033[1;91m' 94 | NC='\033[0m' # No Color 95 | 96 | echo -e "${RED}统计时间范围:$time_start 至 $time_end" 97 | 98 | for i in "${by_day_output[@]}" 99 | do 100 | echo 101 | echo -e "${NC}一周七天 commit 分布${RED}" 102 | echo -e " 总提交次数 星期\n$i"|column -t 103 | by_day_result=`echo "$i"|sed -E 's/^ +//g'|sed "s/ /_/g"|tr '\n' ','` 104 | done 105 | 106 | 107 | for i in "${by_hour_output[@]}" 108 | do 109 | echo 110 | echo -e "${NC}24小时 commit 分布${RED}" 111 | echo -e " 总提交次数 小时\n$i"|column -t 112 | by_hour_result=`echo "$i"|sed -E 's/^ +//g'|sed "s/ /_/g"|tr '\n' ','` 113 | done 114 | 115 | 116 | by_day_result=`echo "$by_day_result"|sed -E 's/,$//g'` 117 | 118 | by_hour_result=`echo "$by_hour_result"|sed -E 's/,$//g'` 119 | 120 | 121 | result=$time_start"_"$time_end"&week="$by_day_result"&hour="$by_hour_result 122 | 123 | # url 124 | github_url="https://hellodigua.github.io/code996/#/result?time=$result" 125 | vercel_url="https://code996.vercel.app/#/result?time=$result" 126 | 127 | echo 128 | echo -e "${NC}复制以下url以查看可视化分析结果:" 129 | echo -e "${RED}$github_url" 130 | echo -e "${NC}" 131 | echo -e "${NC}若 GitHub 访问过慢,也可以访问以下镜像链接:" 132 | echo -e "${NC}Vercel节点:" 133 | echo -e "${RED}$vercel_url" 134 | echo -e "${NC}" 135 | 136 | $open_url "$github_url" 137 | -------------------------------------------------------------------------------- /bin/code996_en.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | Help() 4 | { 5 | # Display Help 6 | echo "Hey please give me three param like this!" 7 | echo 8 | echo "Syntax: bash $0 [2022-01-01] [2022-04-04] [author]" 9 | echo "example: bash code996.sh 2022-01-01 2022-12-31 digua" 10 | echo "options:" 11 | echo "1st param Calculate from time." 12 | echo "2nd param Calculate to time." 13 | echo "3rd param Calculate by committer." 14 | echo 15 | echo "You can be inspired by 'git log --help' to get more detail." 16 | } 17 | 18 | OS_DETECT() 19 | { 20 | # Detect OS 21 | case "$(uname -s)" in 22 | 23 | Linux) 24 | # echo 'Linux' 25 | open_url="xdg-open" 26 | ;; 27 | 28 | Darwin) 29 | # echo 'macOS' 30 | open_url="open" 31 | ;; 32 | 33 | CYGWIN*|MINGW32*|MSYS*|MINGW*) 34 | # echo 'Windows' 35 | open_url="start" 36 | ;; 37 | 38 | *) 39 | echo 'Other OS' 40 | echo "trying to use xdg-open to open the url" 41 | open_url="xdg-open" 42 | ;; 43 | esac 44 | 45 | } 46 | OS_DETECT 47 | 48 | 49 | time_start=$1 50 | 51 | 52 | if [ "$1" == "--help" ] 53 | then 54 | Help 55 | exit 0 56 | elif [ "$1" == "-h" ] 57 | then 58 | Help 59 | exit 0 60 | fi 61 | 62 | if [ -z $1 ] 63 | then 64 | time_start="2022-01-01" 65 | fi 66 | 67 | time_end=$2 68 | if [ -z $2 ] 69 | then 70 | time_end=$(date "+%Y-%m-%d") 71 | fi 72 | 73 | author=$3 74 | if [ -z $3 ] 75 | then 76 | author="" 77 | fi 78 | 79 | 80 | by_day_output=`git -C "$PWD" log --author=$author --date=format:%u --after="$time_start" --before="$time_end" |grep "Date:"|awk '{print $2}'|sort|uniq -c` 81 | 82 | by_hour_output=`git -C "$PWD" log --author=$author --date=format:%H --after="$time_start" --before="$time_end" |grep "Date:"|awk '{print $2}'|sort|uniq -c` 83 | 84 | for i in "${by_day_output[@]}" 85 | do 86 | by_day_result=`echo "$i"|sed -E 's/^ +//g'|sed 's/ /_/g'|tr '\n' ','` 87 | 88 | done 89 | 90 | RED='\033[1;91m' 91 | NC='\033[0m' # No Color 92 | 93 | echo -e "${RED}Calculation time range:$time_start to $time_end" 94 | 95 | for i in "${by_day_output[@]}" 96 | do 97 | echo 98 | # echo -e "${RED}By Day:" 99 | echo -e "${NC}Weekly commit distribution${RED}" 100 | echo -e " Statistics Weekly\n$i"|column -t 101 | by_day_result=`echo "$i"|sed -E 's/^ +//g'|sed "s/ /_/g"|tr '\n' ','` 102 | done 103 | 104 | 105 | for i in "${by_hour_output[@]}" 106 | do 107 | echo 108 | echo -e "${NC}24 Hours commit distribution${RED}" 109 | echo -e " Statistics Hours\n$i"|column -t 110 | by_hour_result=`echo "$i"|sed -E 's/^ +//g'|sed "s/ /_/g"|tr '\n' ','` 111 | done 112 | 113 | 114 | by_day_result=`echo "$by_day_result"|sed -E 's/,$//g'` 115 | 116 | by_hour_result=`echo "$by_hour_result"|sed -E 's/,$//g'` 117 | 118 | 119 | result=$time_start"_"$time_end"&week="$by_day_result"&hour="$by_hour_result"&lang=en" 120 | 121 | # default site 122 | github_url="https://hellodigua.github.io/code996/#/result?time=$result" 123 | vercel_url="https://code996.vercel.app/#/result?time=$result" 124 | 125 | echo 126 | echo -e "${NC}You can manually click the url below when you want to see the result if something goes wrong:" 127 | echo -e "${RED}$github_url" 128 | echo -e "${NC}" 129 | echo -e "${NC}vercel server:" 130 | echo -e "${RED}$vercel_url" 131 | echo -e "${NC}" 132 | 133 | $open_url "$github_url" 134 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | code996 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "code996", 3 | "version": "0.1.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/helper-validator-identifier": { 8 | "version": "7.15.7", 9 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", 10 | "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", 11 | "dev": true 12 | }, 13 | "@babel/parser": { 14 | "version": "7.15.8", 15 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz", 16 | "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==", 17 | "dev": true 18 | }, 19 | "@babel/types": { 20 | "version": "7.15.6", 21 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz", 22 | "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", 23 | "dev": true, 24 | "requires": { 25 | "@babel/helper-validator-identifier": "^7.14.9", 26 | "to-fast-properties": "^2.0.0" 27 | } 28 | }, 29 | "@emmetio/abbreviation": { 30 | "version": "2.2.2", 31 | "resolved": "https://registry.npmjs.org/@emmetio/abbreviation/-/abbreviation-2.2.2.tgz", 32 | "integrity": "sha512-TtE/dBnkTCct8+LntkqVrwqQao6EnPAs1YN3cUgxOxTaBlesBCY37ROUAVZrRlG64GNnVShdl/b70RfAI3w5lw==", 33 | "dev": true, 34 | "requires": { 35 | "@emmetio/scanner": "^1.0.0" 36 | } 37 | }, 38 | "@emmetio/css-abbreviation": { 39 | "version": "2.1.4", 40 | "resolved": "https://registry.npmjs.org/@emmetio/css-abbreviation/-/css-abbreviation-2.1.4.tgz", 41 | "integrity": "sha512-qk9L60Y+uRtM5CPbB0y+QNl/1XKE09mSO+AhhSauIfr2YOx/ta3NJw2d8RtCFxgzHeRqFRr8jgyzThbu+MZ4Uw==", 42 | "dev": true, 43 | "requires": { 44 | "@emmetio/scanner": "^1.0.0" 45 | } 46 | }, 47 | "@emmetio/scanner": { 48 | "version": "1.0.0", 49 | "resolved": "https://registry.npmjs.org/@emmetio/scanner/-/scanner-1.0.0.tgz", 50 | "integrity": "sha512-8HqW8EVqjnCmWXVpqAOZf+EGESdkR27odcMMMGefgKXtar00SoYNSryGv//TELI4T3QFsECo78p+0lmalk/CFA==", 51 | "dev": true 52 | }, 53 | "@rollup/pluginutils": { 54 | "version": "4.2.1", 55 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", 56 | "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", 57 | "dev": true, 58 | "requires": { 59 | "estree-walker": "^2.0.1", 60 | "picomatch": "^2.2.2" 61 | } 62 | }, 63 | "@types/estree": { 64 | "version": "0.0.51", 65 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", 66 | "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", 67 | "dev": true 68 | }, 69 | "@types/node": { 70 | "version": "17.0.33", 71 | "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.33.tgz", 72 | "integrity": "sha512-miWq2m2FiQZmaHfdZNcbpp9PuXg34W5JZ5CrJ/BaS70VuhoJENBEQybeiYSaPBRNq6KQGnjfEnc/F3PN++D+XQ==", 73 | "dev": true 74 | }, 75 | "@vitejs/plugin-vue": { 76 | "version": "1.9.3", 77 | "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-1.9.3.tgz", 78 | "integrity": "sha512-yW6H/q+4Mc2PcVjSOelcsMrg/k15DnMUz8jyCFsI04emc3aLwo4AoofUfGnjHUkgirrDxSJLVqQVGhonQ3yykA==", 79 | "dev": true 80 | }, 81 | "@volar/code-gen": { 82 | "version": "0.27.24", 83 | "resolved": "https://registry.npmjs.org/@volar/code-gen/-/code-gen-0.27.24.tgz", 84 | "integrity": "sha512-s4j/QqOZUW03PeD6LmVYI00Q1C3CfJEOePDOQwDvCTUov4lFk0iSBtFyYhjlLyQ1pdtV1+TDTErkj2aMQtc4PA==", 85 | "dev": true, 86 | "requires": { 87 | "@volar/shared": "^0.27.24", 88 | "@volar/source-map": "^0.27.24" 89 | } 90 | }, 91 | "@volar/html2pug": { 92 | "version": "0.27.13", 93 | "resolved": "https://registry.npmjs.org/@volar/html2pug/-/html2pug-0.27.13.tgz", 94 | "integrity": "sha512-3NYgNA5F3PDsKbbpOrVdGy2S7ZYmZIbFmbp1A/27DDzjj/uIC9Pj7HXVvbYOzi8HcOxUPt0BMrh4TVzBUaCFww==", 95 | "dev": true, 96 | "requires": { 97 | "domelementtype": "^2.2.0", 98 | "domhandler": "^4.2.0", 99 | "htmlparser2": "^6.1.0", 100 | "pug": "^3.0.2" 101 | } 102 | }, 103 | "@volar/shared": { 104 | "version": "0.27.24", 105 | "resolved": "https://registry.npmjs.org/@volar/shared/-/shared-0.27.24.tgz", 106 | "integrity": "sha512-Mi8a4GQaiorfb+o4EqOXDZm9E/uBJXgScFgF+NhtcMBOUKHNMKQyLI7YRGumtyJTTdaX7nSDJjGGTkv23tcOtQ==", 107 | "dev": true, 108 | "requires": { 109 | "upath": "^2.0.1", 110 | "vscode-jsonrpc": "^8.0.0-next.2", 111 | "vscode-uri": "^3.0.2" 112 | } 113 | }, 114 | "@volar/source-map": { 115 | "version": "0.27.24", 116 | "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-0.27.24.tgz", 117 | "integrity": "sha512-2I5a7cXqekZ66D6lHep7ttJgvVVtPEBUIe1hnpcGbnXWNA2ya6f6jKNNyTmrXQyfkh32IEuaUd4kocR+3AKMag==", 118 | "dev": true, 119 | "requires": { 120 | "@volar/shared": "^0.27.24" 121 | } 122 | }, 123 | "@volar/transforms": { 124 | "version": "0.27.24", 125 | "resolved": "https://registry.npmjs.org/@volar/transforms/-/transforms-0.27.24.tgz", 126 | "integrity": "sha512-sOHi1ZSapFlxn7yPl4MO5TXd9aWC0BVq2CgXAJ2EESb+ddh2uJbGQgLLNocX+MDh419cUuuFT2QAJpuWHhJcng==", 127 | "dev": true, 128 | "requires": { 129 | "@volar/shared": "^0.27.24", 130 | "vscode-languageserver": "^8.0.0-next.2" 131 | } 132 | }, 133 | "@vscode/emmet-helper": { 134 | "version": "2.8.2", 135 | "resolved": "https://registry.npmjs.org/@vscode/emmet-helper/-/emmet-helper-2.8.2.tgz", 136 | "integrity": "sha512-A/+pkBYQq2JTow1A2flfTmEOmiF780KpdkoX7VBjQ7wujeA+CFUPd17YdeIa9aim20+J5Jp7SFujPDwVFiQucQ==", 137 | "dev": true, 138 | "requires": { 139 | "emmet": "^2.3.0", 140 | "jsonc-parser": "^2.3.0", 141 | "vscode-languageserver-textdocument": "^1.0.1", 142 | "vscode-languageserver-types": "^3.15.1", 143 | "vscode-nls": "^5.0.0", 144 | "vscode-uri": "^2.1.2" 145 | }, 146 | "dependencies": { 147 | "vscode-languageserver-types": { 148 | "version": "3.16.0", 149 | "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz", 150 | "integrity": "sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA==", 151 | "dev": true 152 | }, 153 | "vscode-uri": { 154 | "version": "2.1.2", 155 | "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-2.1.2.tgz", 156 | "integrity": "sha512-8TEXQxlldWAuIODdukIb+TR5s+9Ds40eSJrw+1iDDA9IFORPjMELarNQE3myz5XIkWWpdprmJjm1/SxMlWOC8A==", 157 | "dev": true 158 | } 159 | } 160 | }, 161 | "@vue/compiler-core": { 162 | "version": "3.2.20", 163 | "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.20.tgz", 164 | "integrity": "sha512-vcEXlKXoPwBXFP5aUTHN9GTZaDfwCofa9Yu9bbW2C5O/QSa9Esdt7OG4+0RRd3EHEMxUvEdj4RZrd/KpQeiJbA==", 165 | "dev": true, 166 | "requires": { 167 | "@babel/parser": "^7.15.0", 168 | "@vue/shared": "3.2.20", 169 | "estree-walker": "^2.0.2", 170 | "source-map": "^0.6.1" 171 | } 172 | }, 173 | "@vue/compiler-dom": { 174 | "version": "3.2.20", 175 | "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.20.tgz", 176 | "integrity": "sha512-QnI77ec/JtV7R0YBbcVayYTDCRcI9OCbxiUQK6izVyqQO0658n0zQuoNwe+bYgtqnvGAIqTR3FShTd5y4oOjdg==", 177 | "dev": true, 178 | "requires": { 179 | "@vue/compiler-core": "3.2.20", 180 | "@vue/shared": "3.2.20" 181 | } 182 | }, 183 | "@vue/compiler-sfc": { 184 | "version": "3.2.33", 185 | "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.33.tgz", 186 | "integrity": "sha512-H8D0WqagCr295pQjUYyO8P3IejM3vEzeCO1apzByAEaAR/WimhMYczHfZVvlCE/9yBaEu/eu9RdiWr0kF8b71Q==", 187 | "requires": { 188 | "@babel/parser": "^7.16.4", 189 | "@vue/compiler-core": "3.2.33", 190 | "@vue/compiler-dom": "3.2.33", 191 | "@vue/compiler-ssr": "3.2.33", 192 | "@vue/reactivity-transform": "3.2.33", 193 | "@vue/shared": "3.2.33", 194 | "estree-walker": "^2.0.2", 195 | "magic-string": "^0.25.7", 196 | "postcss": "^8.1.10", 197 | "source-map": "^0.6.1" 198 | }, 199 | "dependencies": { 200 | "@babel/parser": { 201 | "version": "7.17.10", 202 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.10.tgz", 203 | "integrity": "sha512-n2Q6i+fnJqzOaq2VkdXxy2TCPCWQZHiCo0XqmrCvDWcZQKRyZzYi4Z0yxlBuN0w+r2ZHmre+Q087DSrw3pbJDQ==" 204 | }, 205 | "@vue/compiler-core": { 206 | "version": "3.2.33", 207 | "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.33.tgz", 208 | "integrity": "sha512-AAmr52ji3Zhk7IKIuigX2osWWsb2nQE5xsdFYjdnmtQ4gymmqXbjLvkSE174+fF3A3kstYrTgGkqgOEbsdLDpw==", 209 | "requires": { 210 | "@babel/parser": "^7.16.4", 211 | "@vue/shared": "3.2.33", 212 | "estree-walker": "^2.0.2", 213 | "source-map": "^0.6.1" 214 | } 215 | }, 216 | "@vue/compiler-dom": { 217 | "version": "3.2.33", 218 | "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.33.tgz", 219 | "integrity": "sha512-GhiG1C8X98Xz9QUX/RlA6/kgPBWJkjq0Rq6//5XTAGSYrTMBgcLpP9+CnlUg1TFxnnCVughAG+KZl28XJqw8uQ==", 220 | "requires": { 221 | "@vue/compiler-core": "3.2.33", 222 | "@vue/shared": "3.2.33" 223 | } 224 | }, 225 | "@vue/shared": { 226 | "version": "3.2.33", 227 | "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.33.tgz", 228 | "integrity": "sha512-UBc1Pg1T3yZ97vsA2ueER0F6GbJebLHYlEi4ou1H5YL4KWvMOOWwpYo9/QpWq93wxKG6Wo13IY74Hcn/f7c7Bg==" 229 | } 230 | } 231 | }, 232 | "@vue/compiler-ssr": { 233 | "version": "3.2.33", 234 | "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.33.tgz", 235 | "integrity": "sha512-XQh1Xdk3VquDpXsnoCd7JnMoWec9CfAzQDQsaMcSU79OrrO2PNR0ErlIjm/mGq3GmBfkQjzZACV+7GhfRB8xMQ==", 236 | "requires": { 237 | "@vue/compiler-dom": "3.2.33", 238 | "@vue/shared": "3.2.33" 239 | }, 240 | "dependencies": { 241 | "@babel/parser": { 242 | "version": "7.17.10", 243 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.10.tgz", 244 | "integrity": "sha512-n2Q6i+fnJqzOaq2VkdXxy2TCPCWQZHiCo0XqmrCvDWcZQKRyZzYi4Z0yxlBuN0w+r2ZHmre+Q087DSrw3pbJDQ==" 245 | }, 246 | "@vue/compiler-core": { 247 | "version": "3.2.33", 248 | "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.33.tgz", 249 | "integrity": "sha512-AAmr52ji3Zhk7IKIuigX2osWWsb2nQE5xsdFYjdnmtQ4gymmqXbjLvkSE174+fF3A3kstYrTgGkqgOEbsdLDpw==", 250 | "requires": { 251 | "@babel/parser": "^7.16.4", 252 | "@vue/shared": "3.2.33", 253 | "estree-walker": "^2.0.2", 254 | "source-map": "^0.6.1" 255 | } 256 | }, 257 | "@vue/compiler-dom": { 258 | "version": "3.2.33", 259 | "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.33.tgz", 260 | "integrity": "sha512-GhiG1C8X98Xz9QUX/RlA6/kgPBWJkjq0Rq6//5XTAGSYrTMBgcLpP9+CnlUg1TFxnnCVughAG+KZl28XJqw8uQ==", 261 | "requires": { 262 | "@vue/compiler-core": "3.2.33", 263 | "@vue/shared": "3.2.33" 264 | } 265 | }, 266 | "@vue/shared": { 267 | "version": "3.2.33", 268 | "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.33.tgz", 269 | "integrity": "sha512-UBc1Pg1T3yZ97vsA2ueER0F6GbJebLHYlEi4ou1H5YL4KWvMOOWwpYo9/QpWq93wxKG6Wo13IY74Hcn/f7c7Bg==" 270 | } 271 | } 272 | }, 273 | "@vue/devtools-api": { 274 | "version": "6.1.4", 275 | "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.1.4.tgz", 276 | "integrity": "sha512-IiA0SvDrJEgXvVxjNkHPFfDx6SXw0b/TUkqMcDZWNg9fnCAHbTpoo59YfJ9QLFkwa3raau5vSlRVzMSLDnfdtQ==" 277 | }, 278 | "@vue/reactivity": { 279 | "version": "3.2.20", 280 | "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.20.tgz", 281 | "integrity": "sha512-nSmoLojUTk+H8HNTAkrUduB4+yIUBK2HPihJo2uXVSH4Spry6oqN6lFzE5zpLK+F27Sja+UqR9R1+/kIOsHV5w==", 282 | "dev": true, 283 | "requires": { 284 | "@vue/shared": "3.2.20" 285 | } 286 | }, 287 | "@vue/reactivity-transform": { 288 | "version": "3.2.33", 289 | "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.33.tgz", 290 | "integrity": "sha512-4UL5KOIvSQb254aqenW4q34qMXbfZcmEsV/yVidLUgvwYQQ/D21bGX3DlgPUGI3c4C+iOnNmDCkIxkILoX/Pyw==", 291 | "requires": { 292 | "@babel/parser": "^7.16.4", 293 | "@vue/compiler-core": "3.2.33", 294 | "@vue/shared": "3.2.33", 295 | "estree-walker": "^2.0.2", 296 | "magic-string": "^0.25.7" 297 | }, 298 | "dependencies": { 299 | "@babel/parser": { 300 | "version": "7.17.10", 301 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.10.tgz", 302 | "integrity": "sha512-n2Q6i+fnJqzOaq2VkdXxy2TCPCWQZHiCo0XqmrCvDWcZQKRyZzYi4Z0yxlBuN0w+r2ZHmre+Q087DSrw3pbJDQ==" 303 | }, 304 | "@vue/compiler-core": { 305 | "version": "3.2.33", 306 | "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.33.tgz", 307 | "integrity": "sha512-AAmr52ji3Zhk7IKIuigX2osWWsb2nQE5xsdFYjdnmtQ4gymmqXbjLvkSE174+fF3A3kstYrTgGkqgOEbsdLDpw==", 308 | "requires": { 309 | "@babel/parser": "^7.16.4", 310 | "@vue/shared": "3.2.33", 311 | "estree-walker": "^2.0.2", 312 | "source-map": "^0.6.1" 313 | } 314 | }, 315 | "@vue/shared": { 316 | "version": "3.2.33", 317 | "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.33.tgz", 318 | "integrity": "sha512-UBc1Pg1T3yZ97vsA2ueER0F6GbJebLHYlEi4ou1H5YL4KWvMOOWwpYo9/QpWq93wxKG6Wo13IY74Hcn/f7c7Bg==" 319 | } 320 | } 321 | }, 322 | "@vue/runtime-core": { 323 | "version": "3.2.33", 324 | "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.33.tgz", 325 | "integrity": "sha512-N2D2vfaXsBPhzCV3JsXQa2NECjxP3eXgZlFqKh4tgakp3iX6LCGv76DLlc+IfFZq+TW10Y8QUfeihXOupJ1dGw==", 326 | "requires": { 327 | "@vue/reactivity": "3.2.33", 328 | "@vue/shared": "3.2.33" 329 | }, 330 | "dependencies": { 331 | "@vue/reactivity": { 332 | "version": "3.2.33", 333 | "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.33.tgz", 334 | "integrity": "sha512-62Sq0mp9/0bLmDuxuLD5CIaMG2susFAGARLuZ/5jkU1FCf9EDbwUuF+BO8Ub3Rbodx0ziIecM/NsmyjardBxfQ==", 335 | "requires": { 336 | "@vue/shared": "3.2.33" 337 | } 338 | }, 339 | "@vue/shared": { 340 | "version": "3.2.33", 341 | "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.33.tgz", 342 | "integrity": "sha512-UBc1Pg1T3yZ97vsA2ueER0F6GbJebLHYlEi4ou1H5YL4KWvMOOWwpYo9/QpWq93wxKG6Wo13IY74Hcn/f7c7Bg==" 343 | } 344 | } 345 | }, 346 | "@vue/runtime-dom": { 347 | "version": "3.2.33", 348 | "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.33.tgz", 349 | "integrity": "sha512-LSrJ6W7CZTSUygX5s8aFkraDWlO6K4geOwA3quFF2O+hC3QuAMZt/0Xb7JKE3C4JD4pFwCSO7oCrZmZ0BIJUnw==", 350 | "requires": { 351 | "@vue/runtime-core": "3.2.33", 352 | "@vue/shared": "3.2.33", 353 | "csstype": "^2.6.8" 354 | }, 355 | "dependencies": { 356 | "@vue/shared": { 357 | "version": "3.2.33", 358 | "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.33.tgz", 359 | "integrity": "sha512-UBc1Pg1T3yZ97vsA2ueER0F6GbJebLHYlEi4ou1H5YL4KWvMOOWwpYo9/QpWq93wxKG6Wo13IY74Hcn/f7c7Bg==" 360 | } 361 | } 362 | }, 363 | "@vue/server-renderer": { 364 | "version": "3.2.33", 365 | "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.33.tgz", 366 | "integrity": "sha512-4jpJHRD4ORv8PlbYi+/MfP8ec1okz6rybe36MdpkDrGIdEItHEUyaHSKvz+ptNEyQpALmmVfRteHkU9F8vxOew==", 367 | "requires": { 368 | "@vue/compiler-ssr": "3.2.33", 369 | "@vue/shared": "3.2.33" 370 | }, 371 | "dependencies": { 372 | "@vue/shared": { 373 | "version": "3.2.33", 374 | "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.33.tgz", 375 | "integrity": "sha512-UBc1Pg1T3yZ97vsA2ueER0F6GbJebLHYlEi4ou1H5YL4KWvMOOWwpYo9/QpWq93wxKG6Wo13IY74Hcn/f7c7Bg==" 376 | } 377 | } 378 | }, 379 | "@vue/shared": { 380 | "version": "3.2.20", 381 | "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.20.tgz", 382 | "integrity": "sha512-FbpX+hD5BvXCQerEYO7jtAGHlhAkhTQ4KIV73kmLWNlawWhTiVuQxizgVb0BOkX5oG9cIRZ42EG++d/k/Efp0w==", 383 | "dev": true 384 | }, 385 | "acorn": { 386 | "version": "7.4.1", 387 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", 388 | "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", 389 | "dev": true 390 | }, 391 | "ansi-regex": { 392 | "version": "5.0.1", 393 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 394 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 395 | "dev": true 396 | }, 397 | "ansi-styles": { 398 | "version": "4.3.0", 399 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 400 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 401 | "dev": true, 402 | "requires": { 403 | "color-convert": "^2.0.1" 404 | } 405 | }, 406 | "anymatch": { 407 | "version": "3.1.2", 408 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", 409 | "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", 410 | "dev": true, 411 | "requires": { 412 | "normalize-path": "^3.0.0", 413 | "picomatch": "^2.0.4" 414 | } 415 | }, 416 | "asap": { 417 | "version": "2.0.6", 418 | "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", 419 | "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", 420 | "dev": true 421 | }, 422 | "assert-never": { 423 | "version": "1.2.1", 424 | "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.2.1.tgz", 425 | "integrity": "sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==", 426 | "dev": true 427 | }, 428 | "babel-walk": { 429 | "version": "3.0.0-canary-5", 430 | "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", 431 | "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", 432 | "dev": true, 433 | "requires": { 434 | "@babel/types": "^7.9.6" 435 | } 436 | }, 437 | "binary-extensions": { 438 | "version": "2.2.0", 439 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 440 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 441 | "dev": true 442 | }, 443 | "braces": { 444 | "version": "3.0.2", 445 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 446 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 447 | "dev": true, 448 | "requires": { 449 | "fill-range": "^7.0.1" 450 | } 451 | }, 452 | "call-bind": { 453 | "version": "1.0.2", 454 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 455 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 456 | "dev": true, 457 | "requires": { 458 | "function-bind": "^1.1.1", 459 | "get-intrinsic": "^1.0.2" 460 | } 461 | }, 462 | "character-parser": { 463 | "version": "2.2.0", 464 | "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", 465 | "integrity": "sha1-x84o821LzZdE5f/CxfzeHHMmH8A=", 466 | "dev": true, 467 | "requires": { 468 | "is-regex": "^1.0.3" 469 | } 470 | }, 471 | "chart.xkcd": { 472 | "version": "1.1.13", 473 | "resolved": "https://registry.npmjs.org/chart.xkcd/-/chart.xkcd-1.1.13.tgz", 474 | "integrity": "sha512-++JC2J1D13MdB4XZHYfa/gekbJ9DtYMwSFohbtTsryrf1C3ylMy3jcNKgSSo6CA38lS3HDR1Xol+BGWtwZFJTg==", 475 | "requires": { 476 | "d3-axis": "^1.0.12", 477 | "d3-scale": "^3.2.0", 478 | "d3-selection": "^1.4.1", 479 | "d3-shape": "^1.3.7", 480 | "dayjs": "^1.8.17" 481 | }, 482 | "dependencies": { 483 | "d3-array": { 484 | "version": "2.12.1", 485 | "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", 486 | "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", 487 | "requires": { 488 | "internmap": "^1.0.0" 489 | } 490 | }, 491 | "d3-axis": { 492 | "version": "1.0.12", 493 | "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.12.tgz", 494 | "integrity": "sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ==" 495 | }, 496 | "d3-color": { 497 | "version": "2.0.0", 498 | "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz", 499 | "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==" 500 | }, 501 | "d3-format": { 502 | "version": "2.0.0", 503 | "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz", 504 | "integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==" 505 | }, 506 | "d3-interpolate": { 507 | "version": "2.0.1", 508 | "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz", 509 | "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==", 510 | "requires": { 511 | "d3-color": "1 - 2" 512 | } 513 | }, 514 | "d3-path": { 515 | "version": "1.0.9", 516 | "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", 517 | "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" 518 | }, 519 | "d3-scale": { 520 | "version": "3.3.0", 521 | "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.3.0.tgz", 522 | "integrity": "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==", 523 | "requires": { 524 | "d3-array": "^2.3.0", 525 | "d3-format": "1 - 2", 526 | "d3-interpolate": "1.2.0 - 2", 527 | "d3-time": "^2.1.1", 528 | "d3-time-format": "2 - 3" 529 | } 530 | }, 531 | "d3-selection": { 532 | "version": "1.4.2", 533 | "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz", 534 | "integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==" 535 | }, 536 | "d3-shape": { 537 | "version": "1.3.7", 538 | "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", 539 | "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", 540 | "requires": { 541 | "d3-path": "1" 542 | } 543 | }, 544 | "d3-time": { 545 | "version": "2.1.1", 546 | "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz", 547 | "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==", 548 | "requires": { 549 | "d3-array": "2" 550 | } 551 | }, 552 | "d3-time-format": { 553 | "version": "3.0.0", 554 | "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz", 555 | "integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==", 556 | "requires": { 557 | "d3-time": "1 - 2" 558 | } 559 | }, 560 | "internmap": { 561 | "version": "1.0.1", 562 | "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", 563 | "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==" 564 | } 565 | } 566 | }, 567 | "chokidar": { 568 | "version": "3.5.2", 569 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", 570 | "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", 571 | "dev": true, 572 | "requires": { 573 | "anymatch": "~3.1.2", 574 | "braces": "~3.0.2", 575 | "fsevents": "~2.3.2", 576 | "glob-parent": "~5.1.2", 577 | "is-binary-path": "~2.1.0", 578 | "is-glob": "~4.0.1", 579 | "normalize-path": "~3.0.0", 580 | "readdirp": "~3.6.0" 581 | } 582 | }, 583 | "cliui": { 584 | "version": "7.0.4", 585 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", 586 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", 587 | "dev": true, 588 | "requires": { 589 | "string-width": "^4.2.0", 590 | "strip-ansi": "^6.0.0", 591 | "wrap-ansi": "^7.0.0" 592 | } 593 | }, 594 | "color-convert": { 595 | "version": "2.0.1", 596 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 597 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 598 | "dev": true, 599 | "requires": { 600 | "color-name": "~1.1.4" 601 | } 602 | }, 603 | "color-name": { 604 | "version": "1.1.4", 605 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 606 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 607 | "dev": true 608 | }, 609 | "constantinople": { 610 | "version": "4.0.1", 611 | "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", 612 | "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", 613 | "dev": true, 614 | "requires": { 615 | "@babel/parser": "^7.6.0", 616 | "@babel/types": "^7.6.1" 617 | } 618 | }, 619 | "csstype": { 620 | "version": "2.6.20", 621 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", 622 | "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" 623 | }, 624 | "dayjs": { 625 | "version": "1.11.0", 626 | "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.0.tgz", 627 | "integrity": "sha512-JLC809s6Y948/FuCZPm5IX8rRhQwOiyMb2TfVVQEixG7P8Lm/gt5S7yoQZmC8x1UehI9Pb7sksEt4xx14m+7Ug==" 628 | }, 629 | "define-lazy-prop": { 630 | "version": "2.0.0", 631 | "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", 632 | "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", 633 | "dev": true 634 | }, 635 | "doctypes": { 636 | "version": "1.1.0", 637 | "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", 638 | "integrity": "sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk=", 639 | "dev": true 640 | }, 641 | "dom-serializer": { 642 | "version": "1.3.2", 643 | "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", 644 | "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", 645 | "dev": true, 646 | "requires": { 647 | "domelementtype": "^2.0.1", 648 | "domhandler": "^4.2.0", 649 | "entities": "^2.0.0" 650 | } 651 | }, 652 | "domelementtype": { 653 | "version": "2.2.0", 654 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", 655 | "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", 656 | "dev": true 657 | }, 658 | "domhandler": { 659 | "version": "4.2.2", 660 | "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.2.tgz", 661 | "integrity": "sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w==", 662 | "dev": true, 663 | "requires": { 664 | "domelementtype": "^2.2.0" 665 | } 666 | }, 667 | "domutils": { 668 | "version": "2.8.0", 669 | "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", 670 | "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", 671 | "dev": true, 672 | "requires": { 673 | "dom-serializer": "^1.0.1", 674 | "domelementtype": "^2.2.0", 675 | "domhandler": "^4.2.0" 676 | } 677 | }, 678 | "emmet": { 679 | "version": "2.3.4", 680 | "resolved": "https://registry.npmjs.org/emmet/-/emmet-2.3.4.tgz", 681 | "integrity": "sha512-3IqSwmO+N2ZGeuhDyhV/TIOJFUbkChi53bcasSNRE7Yd+4eorbbYz4e53TpMECt38NtYkZNupQCZRlwdAYA42A==", 682 | "dev": true, 683 | "requires": { 684 | "@emmetio/abbreviation": "^2.2.2", 685 | "@emmetio/css-abbreviation": "^2.1.4" 686 | } 687 | }, 688 | "emoji-regex": { 689 | "version": "8.0.0", 690 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 691 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 692 | "dev": true 693 | }, 694 | "entities": { 695 | "version": "2.2.0", 696 | "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", 697 | "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", 698 | "dev": true 699 | }, 700 | "esbuild": { 701 | "version": "0.13.8", 702 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.13.8.tgz", 703 | "integrity": "sha512-A4af7G7YZLfG5OnARJRMtlpEsCkq/zHZQXewgPA864l9D6VjjbH1SuFYK/OSV6BtHwDGkdwyRrX0qQFLnMfUcw==", 704 | "dev": true, 705 | "requires": { 706 | "esbuild-android-arm64": "0.13.8", 707 | "esbuild-darwin-64": "0.13.8", 708 | "esbuild-darwin-arm64": "0.13.8", 709 | "esbuild-freebsd-64": "0.13.8", 710 | "esbuild-freebsd-arm64": "0.13.8", 711 | "esbuild-linux-32": "0.13.8", 712 | "esbuild-linux-64": "0.13.8", 713 | "esbuild-linux-arm": "0.13.8", 714 | "esbuild-linux-arm64": "0.13.8", 715 | "esbuild-linux-mips64le": "0.13.8", 716 | "esbuild-linux-ppc64le": "0.13.8", 717 | "esbuild-netbsd-64": "0.13.8", 718 | "esbuild-openbsd-64": "0.13.8", 719 | "esbuild-sunos-64": "0.13.8", 720 | "esbuild-windows-32": "0.13.8", 721 | "esbuild-windows-64": "0.13.8", 722 | "esbuild-windows-arm64": "0.13.8" 723 | } 724 | }, 725 | "esbuild-android-arm64": { 726 | "version": "0.13.8", 727 | "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.13.8.tgz", 728 | "integrity": "sha512-AilbChndywpk7CdKkNSZ9klxl+9MboLctXd9LwLo3b0dawmOF/i/t2U5d8LM6SbT1Xw36F8yngSUPrd8yPs2RA==", 729 | "dev": true, 730 | "optional": true 731 | }, 732 | "esbuild-darwin-64": { 733 | "version": "0.13.8", 734 | "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.13.8.tgz", 735 | "integrity": "sha512-b6sdiT84zV5LVaoF+UoMVGJzR/iE2vNUfUDfFQGrm4LBwM/PWXweKpuu6RD9mcyCq18cLxkP6w/LD/w9DtX3ng==", 736 | "dev": true, 737 | "optional": true 738 | }, 739 | "esbuild-darwin-arm64": { 740 | "version": "0.13.8", 741 | "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.8.tgz", 742 | "integrity": "sha512-R8YuPiiJayuJJRUBG4H0VwkEKo6AvhJs2m7Tl0JaIer3u1FHHXwGhMxjJDmK+kXwTFPriSysPvcobXC/UrrZCQ==", 743 | "dev": true, 744 | "optional": true 745 | }, 746 | "esbuild-freebsd-64": { 747 | "version": "0.13.8", 748 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.8.tgz", 749 | "integrity": "sha512-zBn6urrn8FnKC+YSgDxdof9jhPCeU8kR/qaamlV4gI8R3KUaUK162WYM7UyFVAlj9N0MyD3AtB+hltzu4cysTw==", 750 | "dev": true, 751 | "optional": true 752 | }, 753 | "esbuild-freebsd-arm64": { 754 | "version": "0.13.8", 755 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.8.tgz", 756 | "integrity": "sha512-pWW2slN7lGlkx0MOEBoUGwRX5UgSCLq3dy2c8RIOpiHtA87xAUpDBvZK10MykbT+aMfXc0NI2lu1X+6kI34xng==", 757 | "dev": true, 758 | "optional": true 759 | }, 760 | "esbuild-linux-32": { 761 | "version": "0.13.8", 762 | "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.13.8.tgz", 763 | "integrity": "sha512-T0I0ueeKVO/Is0CAeSEOG9s2jeNNb8jrrMwG9QBIm3UU18MRB60ERgkS2uV3fZ1vP2F8i3Z2e3Zju4lg9dhVmw==", 764 | "dev": true, 765 | "optional": true 766 | }, 767 | "esbuild-linux-64": { 768 | "version": "0.13.8", 769 | "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.13.8.tgz", 770 | "integrity": "sha512-Bm8SYmFtvfDCIu9sjKppFXzRXn2BVpuCinU1ChTuMtdKI/7aPpXIrkqBNOgPTOQO9AylJJc1Zw6EvtKORhn64w==", 771 | "dev": true, 772 | "optional": true 773 | }, 774 | "esbuild-linux-arm": { 775 | "version": "0.13.8", 776 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.13.8.tgz", 777 | "integrity": "sha512-4/HfcC40LJ4GPyboHA+db0jpFarTB628D1ifU+/5bunIgY+t6mHkJWyxWxAAE8wl/ZIuRYB9RJFdYpu1AXGPdg==", 778 | "dev": true, 779 | "optional": true 780 | }, 781 | "esbuild-linux-arm64": { 782 | "version": "0.13.8", 783 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.8.tgz", 784 | "integrity": "sha512-X4pWZ+SL+FJ09chWFgRNO3F+YtvAQRcWh0uxKqZSWKiWodAB20flsW/OWFYLXBKiVCTeoGMvENZS/GeVac7+tQ==", 785 | "dev": true, 786 | "optional": true 787 | }, 788 | "esbuild-linux-mips64le": { 789 | "version": "0.13.8", 790 | "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.8.tgz", 791 | "integrity": "sha512-o7e0D+sqHKT31v+mwFircJFjwSKVd2nbkHEn4l9xQ1hLR+Bv8rnt3HqlblY3+sBdlrOTGSwz0ReROlKUMJyldA==", 792 | "dev": true, 793 | "optional": true 794 | }, 795 | "esbuild-linux-ppc64le": { 796 | "version": "0.13.8", 797 | "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.8.tgz", 798 | "integrity": "sha512-eZSQ0ERsWkukJp2px/UWJHVNuy0lMoz/HZcRWAbB6reoaBw7S9vMzYNUnflfL3XA6WDs+dZn3ekHE4Y2uWLGig==", 799 | "dev": true, 800 | "optional": true 801 | }, 802 | "esbuild-netbsd-64": { 803 | "version": "0.13.8", 804 | "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.8.tgz", 805 | "integrity": "sha512-gZX4kP7gVvOrvX0ZwgHmbuHczQUwqYppxqtoyC7VNd80t5nBHOFXVhWo2Ad/Lms0E8b+wwgI/WjZFTCpUHOg9Q==", 806 | "dev": true, 807 | "optional": true 808 | }, 809 | "esbuild-openbsd-64": { 810 | "version": "0.13.8", 811 | "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.8.tgz", 812 | "integrity": "sha512-afzza308X4WmcebexbTzAgfEWt9MUkdTvwIa8xOu4CM2qGbl2LanqEl8/LUs8jh6Gqw6WsicEK52GPrS9wvkcw==", 813 | "dev": true, 814 | "optional": true 815 | }, 816 | "esbuild-sunos-64": { 817 | "version": "0.13.8", 818 | "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.13.8.tgz", 819 | "integrity": "sha512-mWPZibmBbuMKD+LDN23LGcOZ2EawMYBONMXXHmbuxeT0XxCNwadbCVwUQ/2p5Dp5Kvf6mhrlIffcnWOiCBpiVw==", 820 | "dev": true, 821 | "optional": true 822 | }, 823 | "esbuild-windows-32": { 824 | "version": "0.13.8", 825 | "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.13.8.tgz", 826 | "integrity": "sha512-QsZ1HnWIcnIEApETZWw8HlOhDSWqdZX2SylU7IzGxOYyVcX7QI06ety/aDcn437mwyO7Ph4RrbhB+2ntM8kX8A==", 827 | "dev": true, 828 | "optional": true 829 | }, 830 | "esbuild-windows-64": { 831 | "version": "0.13.8", 832 | "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.13.8.tgz", 833 | "integrity": "sha512-76Fb57B9eE/JmJi1QmUW0tRLQZfGo0it+JeYoCDTSlbTn7LV44ecOHIMJSSgZADUtRMWT9z0Kz186bnaB3amSg==", 834 | "dev": true, 835 | "optional": true 836 | }, 837 | "esbuild-windows-arm64": { 838 | "version": "0.13.8", 839 | "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.8.tgz", 840 | "integrity": "sha512-HW6Mtq5eTudllxY2YgT62MrVcn7oq2o8TAoAvDUhyiEmRmDY8tPwAhb1vxw5/cdkbukM3KdMYtksnUhF/ekWeg==", 841 | "dev": true, 842 | "optional": true 843 | }, 844 | "escalade": { 845 | "version": "3.1.1", 846 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 847 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 848 | "dev": true 849 | }, 850 | "estree-walker": { 851 | "version": "2.0.2", 852 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 853 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" 854 | }, 855 | "fill-range": { 856 | "version": "7.0.1", 857 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 858 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 859 | "dev": true, 860 | "requires": { 861 | "to-regex-range": "^5.0.1" 862 | } 863 | }, 864 | "fsevents": { 865 | "version": "2.3.2", 866 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 867 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 868 | "dev": true, 869 | "optional": true 870 | }, 871 | "function-bind": { 872 | "version": "1.1.1", 873 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 874 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 875 | "dev": true 876 | }, 877 | "get-caller-file": { 878 | "version": "2.0.5", 879 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 880 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 881 | "dev": true 882 | }, 883 | "get-intrinsic": { 884 | "version": "1.1.1", 885 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", 886 | "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", 887 | "dev": true, 888 | "requires": { 889 | "function-bind": "^1.1.1", 890 | "has": "^1.0.3", 891 | "has-symbols": "^1.0.1" 892 | } 893 | }, 894 | "glob-parent": { 895 | "version": "5.1.2", 896 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 897 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 898 | "dev": true, 899 | "requires": { 900 | "is-glob": "^4.0.1" 901 | } 902 | }, 903 | "has": { 904 | "version": "1.0.3", 905 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 906 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 907 | "dev": true, 908 | "requires": { 909 | "function-bind": "^1.1.1" 910 | } 911 | }, 912 | "has-symbols": { 913 | "version": "1.0.2", 914 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", 915 | "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", 916 | "dev": true 917 | }, 918 | "has-tostringtag": { 919 | "version": "1.0.0", 920 | "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", 921 | "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", 922 | "dev": true, 923 | "requires": { 924 | "has-symbols": "^1.0.2" 925 | } 926 | }, 927 | "htmlparser2": { 928 | "version": "6.1.0", 929 | "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", 930 | "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", 931 | "dev": true, 932 | "requires": { 933 | "domelementtype": "^2.0.1", 934 | "domhandler": "^4.0.0", 935 | "domutils": "^2.5.2", 936 | "entities": "^2.0.0" 937 | } 938 | }, 939 | "is-binary-path": { 940 | "version": "2.1.0", 941 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 942 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 943 | "dev": true, 944 | "requires": { 945 | "binary-extensions": "^2.0.0" 946 | } 947 | }, 948 | "is-core-module": { 949 | "version": "2.8.0", 950 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", 951 | "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", 952 | "dev": true, 953 | "requires": { 954 | "has": "^1.0.3" 955 | } 956 | }, 957 | "is-docker": { 958 | "version": "2.2.1", 959 | "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", 960 | "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", 961 | "dev": true 962 | }, 963 | "is-expression": { 964 | "version": "4.0.0", 965 | "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", 966 | "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", 967 | "dev": true, 968 | "requires": { 969 | "acorn": "^7.1.1", 970 | "object-assign": "^4.1.1" 971 | } 972 | }, 973 | "is-extglob": { 974 | "version": "2.1.1", 975 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 976 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 977 | "dev": true 978 | }, 979 | "is-fullwidth-code-point": { 980 | "version": "3.0.0", 981 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 982 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 983 | "dev": true 984 | }, 985 | "is-glob": { 986 | "version": "4.0.3", 987 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 988 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 989 | "dev": true, 990 | "requires": { 991 | "is-extglob": "^2.1.1" 992 | } 993 | }, 994 | "is-number": { 995 | "version": "7.0.0", 996 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 997 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 998 | "dev": true 999 | }, 1000 | "is-promise": { 1001 | "version": "2.2.2", 1002 | "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", 1003 | "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", 1004 | "dev": true 1005 | }, 1006 | "is-reference": { 1007 | "version": "1.2.1", 1008 | "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", 1009 | "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", 1010 | "dev": true, 1011 | "requires": { 1012 | "@types/estree": "*" 1013 | } 1014 | }, 1015 | "is-regex": { 1016 | "version": "1.1.4", 1017 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", 1018 | "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", 1019 | "dev": true, 1020 | "requires": { 1021 | "call-bind": "^1.0.2", 1022 | "has-tostringtag": "^1.0.0" 1023 | } 1024 | }, 1025 | "is-wsl": { 1026 | "version": "2.2.0", 1027 | "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", 1028 | "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", 1029 | "dev": true, 1030 | "requires": { 1031 | "is-docker": "^2.0.0" 1032 | } 1033 | }, 1034 | "js-stringify": { 1035 | "version": "1.0.2", 1036 | "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", 1037 | "integrity": "sha1-Fzb939lyTyijaCrcYjCufk6Weds=", 1038 | "dev": true 1039 | }, 1040 | "jsonc-parser": { 1041 | "version": "2.3.1", 1042 | "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.3.1.tgz", 1043 | "integrity": "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==", 1044 | "dev": true 1045 | }, 1046 | "jstransformer": { 1047 | "version": "1.0.0", 1048 | "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", 1049 | "integrity": "sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM=", 1050 | "dev": true, 1051 | "requires": { 1052 | "is-promise": "^2.0.0", 1053 | "promise": "^7.0.1" 1054 | } 1055 | }, 1056 | "klona": { 1057 | "version": "2.0.4", 1058 | "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz", 1059 | "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==", 1060 | "dev": true 1061 | }, 1062 | "lru-cache": { 1063 | "version": "6.0.0", 1064 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 1065 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 1066 | "dev": true, 1067 | "requires": { 1068 | "yallist": "^4.0.0" 1069 | } 1070 | }, 1071 | "magic-string": { 1072 | "version": "0.25.9", 1073 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", 1074 | "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", 1075 | "requires": { 1076 | "sourcemap-codec": "^1.4.8" 1077 | } 1078 | }, 1079 | "nanoid": { 1080 | "version": "3.1.30", 1081 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", 1082 | "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==" 1083 | }, 1084 | "neo-async": { 1085 | "version": "2.6.2", 1086 | "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", 1087 | "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", 1088 | "dev": true 1089 | }, 1090 | "normalize-path": { 1091 | "version": "3.0.0", 1092 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 1093 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 1094 | "dev": true 1095 | }, 1096 | "object-assign": { 1097 | "version": "4.1.1", 1098 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 1099 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", 1100 | "dev": true 1101 | }, 1102 | "open": { 1103 | "version": "8.4.0", 1104 | "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", 1105 | "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", 1106 | "dev": true, 1107 | "requires": { 1108 | "define-lazy-prop": "^2.0.0", 1109 | "is-docker": "^2.1.1", 1110 | "is-wsl": "^2.2.0" 1111 | } 1112 | }, 1113 | "path-parse": { 1114 | "version": "1.0.7", 1115 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 1116 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 1117 | "dev": true 1118 | }, 1119 | "picocolors": { 1120 | "version": "1.0.0", 1121 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 1122 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" 1123 | }, 1124 | "picomatch": { 1125 | "version": "2.3.0", 1126 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", 1127 | "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", 1128 | "dev": true 1129 | }, 1130 | "postcss": { 1131 | "version": "8.3.11", 1132 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.11.tgz", 1133 | "integrity": "sha512-hCmlUAIlUiav8Xdqw3Io4LcpA1DOt7h3LSTAC4G6JGHFFaWzI6qvFt9oilvl8BmkbBRX1IhM90ZAmpk68zccQA==", 1134 | "requires": { 1135 | "nanoid": "^3.1.30", 1136 | "picocolors": "^1.0.0", 1137 | "source-map-js": "^0.6.2" 1138 | } 1139 | }, 1140 | "promise": { 1141 | "version": "7.3.1", 1142 | "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", 1143 | "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", 1144 | "dev": true, 1145 | "requires": { 1146 | "asap": "~2.0.3" 1147 | } 1148 | }, 1149 | "pug": { 1150 | "version": "3.0.2", 1151 | "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.2.tgz", 1152 | "integrity": "sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw==", 1153 | "dev": true, 1154 | "requires": { 1155 | "pug-code-gen": "^3.0.2", 1156 | "pug-filters": "^4.0.0", 1157 | "pug-lexer": "^5.0.1", 1158 | "pug-linker": "^4.0.0", 1159 | "pug-load": "^3.0.0", 1160 | "pug-parser": "^6.0.0", 1161 | "pug-runtime": "^3.0.1", 1162 | "pug-strip-comments": "^2.0.0" 1163 | } 1164 | }, 1165 | "pug-attrs": { 1166 | "version": "3.0.0", 1167 | "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", 1168 | "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", 1169 | "dev": true, 1170 | "requires": { 1171 | "constantinople": "^4.0.1", 1172 | "js-stringify": "^1.0.2", 1173 | "pug-runtime": "^3.0.0" 1174 | } 1175 | }, 1176 | "pug-code-gen": { 1177 | "version": "3.0.2", 1178 | "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.2.tgz", 1179 | "integrity": "sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg==", 1180 | "dev": true, 1181 | "requires": { 1182 | "constantinople": "^4.0.1", 1183 | "doctypes": "^1.1.0", 1184 | "js-stringify": "^1.0.2", 1185 | "pug-attrs": "^3.0.0", 1186 | "pug-error": "^2.0.0", 1187 | "pug-runtime": "^3.0.0", 1188 | "void-elements": "^3.1.0", 1189 | "with": "^7.0.0" 1190 | } 1191 | }, 1192 | "pug-error": { 1193 | "version": "2.0.0", 1194 | "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.0.0.tgz", 1195 | "integrity": "sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==", 1196 | "dev": true 1197 | }, 1198 | "pug-filters": { 1199 | "version": "4.0.0", 1200 | "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", 1201 | "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", 1202 | "dev": true, 1203 | "requires": { 1204 | "constantinople": "^4.0.1", 1205 | "jstransformer": "1.0.0", 1206 | "pug-error": "^2.0.0", 1207 | "pug-walk": "^2.0.0", 1208 | "resolve": "^1.15.1" 1209 | } 1210 | }, 1211 | "pug-lexer": { 1212 | "version": "5.0.1", 1213 | "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", 1214 | "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", 1215 | "dev": true, 1216 | "requires": { 1217 | "character-parser": "^2.2.0", 1218 | "is-expression": "^4.0.0", 1219 | "pug-error": "^2.0.0" 1220 | } 1221 | }, 1222 | "pug-linker": { 1223 | "version": "4.0.0", 1224 | "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", 1225 | "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", 1226 | "dev": true, 1227 | "requires": { 1228 | "pug-error": "^2.0.0", 1229 | "pug-walk": "^2.0.0" 1230 | } 1231 | }, 1232 | "pug-load": { 1233 | "version": "3.0.0", 1234 | "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", 1235 | "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", 1236 | "dev": true, 1237 | "requires": { 1238 | "object-assign": "^4.1.1", 1239 | "pug-walk": "^2.0.0" 1240 | } 1241 | }, 1242 | "pug-parser": { 1243 | "version": "6.0.0", 1244 | "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", 1245 | "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", 1246 | "dev": true, 1247 | "requires": { 1248 | "pug-error": "^2.0.0", 1249 | "token-stream": "1.0.0" 1250 | } 1251 | }, 1252 | "pug-runtime": { 1253 | "version": "3.0.1", 1254 | "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz", 1255 | "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==", 1256 | "dev": true 1257 | }, 1258 | "pug-strip-comments": { 1259 | "version": "2.0.0", 1260 | "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", 1261 | "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", 1262 | "dev": true, 1263 | "requires": { 1264 | "pug-error": "^2.0.0" 1265 | } 1266 | }, 1267 | "pug-walk": { 1268 | "version": "2.0.0", 1269 | "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", 1270 | "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==", 1271 | "dev": true 1272 | }, 1273 | "readdirp": { 1274 | "version": "3.6.0", 1275 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 1276 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 1277 | "dev": true, 1278 | "requires": { 1279 | "picomatch": "^2.2.1" 1280 | } 1281 | }, 1282 | "request-light": { 1283 | "version": "0.5.4", 1284 | "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.5.4.tgz", 1285 | "integrity": "sha512-t3566CMweOFlUk7Y1DJMu5OrtpoZEb6aSTsLQVT3wtrIEJ5NhcY9G/Oqxvjllzl4a15zXfFlcr9q40LbLVQJqw==", 1286 | "dev": true 1287 | }, 1288 | "require-directory": { 1289 | "version": "2.1.1", 1290 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 1291 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", 1292 | "dev": true 1293 | }, 1294 | "resolve": { 1295 | "version": "1.20.0", 1296 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", 1297 | "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", 1298 | "dev": true, 1299 | "requires": { 1300 | "is-core-module": "^2.2.0", 1301 | "path-parse": "^1.0.6" 1302 | } 1303 | }, 1304 | "rollup": { 1305 | "version": "2.58.0", 1306 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.58.0.tgz", 1307 | "integrity": "sha512-NOXpusKnaRpbS7ZVSzcEXqxcLDOagN6iFS8p45RkoiMqPHDLwJm758UF05KlMoCRbLBTZsPOIa887gZJ1AiXvw==", 1308 | "dev": true, 1309 | "requires": { 1310 | "fsevents": "~2.3.2" 1311 | } 1312 | }, 1313 | "rollup-plugin-external-globals": { 1314 | "version": "0.6.1", 1315 | "resolved": "https://registry.npmjs.org/rollup-plugin-external-globals/-/rollup-plugin-external-globals-0.6.1.tgz", 1316 | "integrity": "sha512-mlp3KNa5sE4Sp9UUR2rjBrxjG79OyZAh/QC18RHIjM+iYkbBwNXSo8DHRMZWtzJTrH8GxQ+SJvCTN3i14uMXIA==", 1317 | "dev": true, 1318 | "requires": { 1319 | "@rollup/pluginutils": "^4.0.0", 1320 | "estree-walker": "^2.0.1", 1321 | "is-reference": "^1.2.1", 1322 | "magic-string": "^0.25.7" 1323 | } 1324 | }, 1325 | "rollup-plugin-visualizer": { 1326 | "version": "5.6.0", 1327 | "resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.6.0.tgz", 1328 | "integrity": "sha512-CKcc8GTUZjC+LsMytU8ocRr/cGZIfMR7+mdy4YnlyetlmIl/dM8BMnOEpD4JPIGt+ZVW7Db9ZtSsbgyeBH3uTA==", 1329 | "dev": true, 1330 | "requires": { 1331 | "nanoid": "^3.1.32", 1332 | "open": "^8.4.0", 1333 | "source-map": "^0.7.3", 1334 | "yargs": "^17.3.1" 1335 | }, 1336 | "dependencies": { 1337 | "nanoid": { 1338 | "version": "3.3.4", 1339 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", 1340 | "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", 1341 | "dev": true 1342 | }, 1343 | "source-map": { 1344 | "version": "0.7.3", 1345 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", 1346 | "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", 1347 | "dev": true 1348 | } 1349 | } 1350 | }, 1351 | "sass": { 1352 | "version": "1.43.3", 1353 | "resolved": "https://registry.npmjs.org/sass/-/sass-1.43.3.tgz", 1354 | "integrity": "sha512-BJnLngqWpMeS65UvlYYEuCb3/fLxDxhHtOB/gWPxs6NKrslTxGt3ZxwIvOe/0Jm4tWwM/+tIpE3wj4dLEhPDeQ==", 1355 | "dev": true, 1356 | "requires": { 1357 | "chokidar": ">=3.0.0 <4.0.0" 1358 | } 1359 | }, 1360 | "sass-loader": { 1361 | "version": "12.2.0", 1362 | "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.2.0.tgz", 1363 | "integrity": "sha512-qducnp5vSV+8A8MZxuH6zV0MUg4MOVISScl2wDTCAn/2WJX+9Auxh92O/rnkdR2bvi5QxZBafnzkzRrWGZvm7w==", 1364 | "dev": true, 1365 | "requires": { 1366 | "klona": "^2.0.4", 1367 | "neo-async": "^2.6.2" 1368 | } 1369 | }, 1370 | "semver": { 1371 | "version": "7.3.5", 1372 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", 1373 | "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", 1374 | "dev": true, 1375 | "requires": { 1376 | "lru-cache": "^6.0.0" 1377 | } 1378 | }, 1379 | "source-map": { 1380 | "version": "0.6.1", 1381 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1382 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" 1383 | }, 1384 | "source-map-js": { 1385 | "version": "0.6.2", 1386 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", 1387 | "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==" 1388 | }, 1389 | "sourcemap-codec": { 1390 | "version": "1.4.8", 1391 | "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", 1392 | "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" 1393 | }, 1394 | "string-width": { 1395 | "version": "4.2.3", 1396 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 1397 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 1398 | "dev": true, 1399 | "requires": { 1400 | "emoji-regex": "^8.0.0", 1401 | "is-fullwidth-code-point": "^3.0.0", 1402 | "strip-ansi": "^6.0.1" 1403 | } 1404 | }, 1405 | "strip-ansi": { 1406 | "version": "6.0.1", 1407 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 1408 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 1409 | "dev": true, 1410 | "requires": { 1411 | "ansi-regex": "^5.0.1" 1412 | } 1413 | }, 1414 | "to-fast-properties": { 1415 | "version": "2.0.0", 1416 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", 1417 | "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", 1418 | "dev": true 1419 | }, 1420 | "to-regex-range": { 1421 | "version": "5.0.1", 1422 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1423 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1424 | "dev": true, 1425 | "requires": { 1426 | "is-number": "^7.0.0" 1427 | } 1428 | }, 1429 | "token-stream": { 1430 | "version": "1.0.0", 1431 | "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", 1432 | "integrity": "sha1-zCAOqyYT9BZtJ/+a/HylbUnfbrQ=", 1433 | "dev": true 1434 | }, 1435 | "typescript": { 1436 | "version": "4.4.4", 1437 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", 1438 | "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", 1439 | "dev": true 1440 | }, 1441 | "upath": { 1442 | "version": "2.0.1", 1443 | "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz", 1444 | "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==", 1445 | "dev": true 1446 | }, 1447 | "vite": { 1448 | "version": "2.6.10", 1449 | "resolved": "https://registry.npmjs.org/vite/-/vite-2.6.10.tgz", 1450 | "integrity": "sha512-XbevwpDJMs3lKiGEj0UQScsOCpwHIjFgfzPnFVkPgnxsF9oPv1uGyckLg58XkXv6LnO46KN9yZqJzINFmAxtUg==", 1451 | "dev": true, 1452 | "requires": { 1453 | "esbuild": "^0.13.2", 1454 | "fsevents": "~2.3.2", 1455 | "postcss": "^8.3.8", 1456 | "resolve": "^1.20.0", 1457 | "rollup": "^2.57.0" 1458 | } 1459 | }, 1460 | "void-elements": { 1461 | "version": "3.1.0", 1462 | "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", 1463 | "integrity": "sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=", 1464 | "dev": true 1465 | }, 1466 | "vscode-css-languageservice": { 1467 | "version": "5.1.7", 1468 | "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-5.1.7.tgz", 1469 | "integrity": "sha512-h4oafcZaGFe2VtbNIlkZDmLEP0GQha3E5Ct2YMH4p/p9xYC8yWDNQ5CD+VF3UnSijKPSKmA+oc4cKjhJBowGKw==", 1470 | "dev": true, 1471 | "requires": { 1472 | "vscode-languageserver-textdocument": "^1.0.1", 1473 | "vscode-languageserver-types": "^3.16.0", 1474 | "vscode-nls": "^5.0.0", 1475 | "vscode-uri": "^3.0.2" 1476 | }, 1477 | "dependencies": { 1478 | "vscode-languageserver-types": { 1479 | "version": "3.16.0", 1480 | "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz", 1481 | "integrity": "sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA==", 1482 | "dev": true 1483 | } 1484 | } 1485 | }, 1486 | "vscode-html-languageservice": { 1487 | "version": "4.1.0", 1488 | "resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-4.1.0.tgz", 1489 | "integrity": "sha512-QQrEKfpfbeglD8Jcai4fQDQ7vOJrN6LyiOs47Y6qAxnhve+ervw1kP2UCt9ohHe/6teNWJDYTGxLDgs5iAvitw==", 1490 | "dev": true, 1491 | "requires": { 1492 | "vscode-languageserver-textdocument": "^1.0.1", 1493 | "vscode-languageserver-types": "^3.16.0", 1494 | "vscode-nls": "^5.0.0", 1495 | "vscode-uri": "^3.0.2" 1496 | }, 1497 | "dependencies": { 1498 | "vscode-languageserver-types": { 1499 | "version": "3.16.0", 1500 | "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz", 1501 | "integrity": "sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA==", 1502 | "dev": true 1503 | } 1504 | } 1505 | }, 1506 | "vscode-json-languageservice": { 1507 | "version": "4.1.8", 1508 | "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-4.1.8.tgz", 1509 | "integrity": "sha512-0vSpg6Xd9hfV+eZAaYN63xVVMOTmJ4GgHxXnkLCh+9RsQBkWKIghzLhW2B9ebfG+LQQg8uLtsQ2aUKjTgE+QOg==", 1510 | "dev": true, 1511 | "requires": { 1512 | "jsonc-parser": "^3.0.0", 1513 | "vscode-languageserver-textdocument": "^1.0.1", 1514 | "vscode-languageserver-types": "^3.16.0", 1515 | "vscode-nls": "^5.0.0", 1516 | "vscode-uri": "^3.0.2" 1517 | }, 1518 | "dependencies": { 1519 | "jsonc-parser": { 1520 | "version": "3.0.0", 1521 | "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", 1522 | "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", 1523 | "dev": true 1524 | }, 1525 | "vscode-languageserver-types": { 1526 | "version": "3.16.0", 1527 | "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz", 1528 | "integrity": "sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA==", 1529 | "dev": true 1530 | } 1531 | } 1532 | }, 1533 | "vscode-jsonrpc": { 1534 | "version": "8.0.0-next.3", 1535 | "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.0-next.3.tgz", 1536 | "integrity": "sha512-2wRiBR5tZAXZ4UxIO4F0cT/zN6OpruoWO0vc7EpQZxVfumb0pYiSegB+PaOzXCuFQzh7YEshW/XMg4zTz3FGVQ==", 1537 | "dev": true 1538 | }, 1539 | "vscode-languageserver": { 1540 | "version": "8.0.0-next.3", 1541 | "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-8.0.0-next.3.tgz", 1542 | "integrity": "sha512-uxL/tKUa/gRdvQINVmMnK32d6LwfTPTvF7l1iZIFDuAdhGrQ+Po+4lS3w4hwQSeUmapM1WMELXNBFca/u3H5Uw==", 1543 | "dev": true, 1544 | "requires": { 1545 | "vscode-languageserver-protocol": "3.17.0-next.9" 1546 | } 1547 | }, 1548 | "vscode-languageserver-protocol": { 1549 | "version": "3.17.0-next.9", 1550 | "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.0-next.9.tgz", 1551 | "integrity": "sha512-DGkRmbI1hRBMY6HU6MOyza5AvYp0+HcbMf2qdmI98luyQJ26dOfHY5K38OS4hlTHhdJg9RypTQ/uBbLZehmn1Q==", 1552 | "dev": true, 1553 | "requires": { 1554 | "vscode-jsonrpc": "8.0.0-next.3", 1555 | "vscode-languageserver-types": "3.17.0-next.4" 1556 | } 1557 | }, 1558 | "vscode-languageserver-textdocument": { 1559 | "version": "1.0.2", 1560 | "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.2.tgz", 1561 | "integrity": "sha512-T7uPC18+f8mYE4lbVZwb3OSmvwTZm3cuFhrdx9Bn2l11lmp3SvSuSVjy2JtvrghzjAo4G6Trqny2m9XGnFnWVA==", 1562 | "dev": true 1563 | }, 1564 | "vscode-languageserver-types": { 1565 | "version": "3.17.0-next.4", 1566 | "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.0-next.4.tgz", 1567 | "integrity": "sha512-MraVkZDhfqa3ftnKW9rEDeqsV+ji8OrtEjx6mVjzVGm5U2XXT+mdqDWyQ+y0Gvb2/aa2oJJQyTAaDmRTUKiUbg==", 1568 | "dev": true 1569 | }, 1570 | "vscode-nls": { 1571 | "version": "5.0.0", 1572 | "resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-5.0.0.tgz", 1573 | "integrity": "sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA==", 1574 | "dev": true 1575 | }, 1576 | "vscode-pug-languageservice": { 1577 | "version": "0.27.24", 1578 | "resolved": "https://registry.npmjs.org/vscode-pug-languageservice/-/vscode-pug-languageservice-0.27.24.tgz", 1579 | "integrity": "sha512-GSvsFB+rPhAD7cBlEKCVNNsFGIaOnp/0zyLw3WpYbXY24vJZafXu1kHvtYaaQXJRnIhqp5EI5p+EqpdI3hTBnw==", 1580 | "dev": true, 1581 | "requires": { 1582 | "@volar/code-gen": "^0.27.24", 1583 | "@volar/shared": "^0.27.24", 1584 | "@volar/source-map": "^0.27.24", 1585 | "@volar/transforms": "^0.27.24", 1586 | "pug-lexer": "^5.0.1", 1587 | "pug-parser": "^6.0.0", 1588 | "vscode-languageserver": "^8.0.0-next.2" 1589 | } 1590 | }, 1591 | "vscode-typescript-languageservice": { 1592 | "version": "0.27.25", 1593 | "resolved": "https://registry.npmjs.org/vscode-typescript-languageservice/-/vscode-typescript-languageservice-0.27.25.tgz", 1594 | "integrity": "sha512-nxpJI9MnF2rn5rKL/032Qrsq3T9DgM3slK5fwZp3suNdo90JG2zFTs3Ola8n62k7+KWu4A775obxyb4wLIW6Gw==", 1595 | "dev": true, 1596 | "requires": { 1597 | "@volar/shared": "^0.27.24", 1598 | "semver": "^7.3.5", 1599 | "upath": "^2.0.1", 1600 | "vscode-languageserver": "^8.0.0-next.2", 1601 | "vscode-languageserver-textdocument": "^1.0.1" 1602 | } 1603 | }, 1604 | "vscode-uri": { 1605 | "version": "3.0.2", 1606 | "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.2.tgz", 1607 | "integrity": "sha512-jkjy6pjU1fxUvI51P+gCsxg1u2n8LSt0W6KrCNQceaziKzff74GoWmjVG46KieVzybO1sttPQmYfrwSHey7GUA==", 1608 | "dev": true 1609 | }, 1610 | "vscode-vue-languageservice": { 1611 | "version": "0.27.30", 1612 | "resolved": "https://registry.npmjs.org/vscode-vue-languageservice/-/vscode-vue-languageservice-0.27.30.tgz", 1613 | "integrity": "sha512-nPnUNCMqqHfxcCPLyLWvmgbNCgos3SwvPcl/CzAnMbqcjLtNZppsdI7bKX3EEj0Jbg6SGLQ9NanIvZaMI1bsUA==", 1614 | "dev": true, 1615 | "requires": { 1616 | "@volar/code-gen": "^0.27.24", 1617 | "@volar/html2pug": "^0.27.13", 1618 | "@volar/shared": "^0.27.24", 1619 | "@volar/source-map": "^0.27.24", 1620 | "@volar/transforms": "^0.27.24", 1621 | "@vscode/emmet-helper": "^2.7.0", 1622 | "@vue/compiler-dom": "^3.2.19", 1623 | "@vue/reactivity": "^3.2.19", 1624 | "@vue/shared": "^3.2.19", 1625 | "request-light": "^0.5.4", 1626 | "upath": "^2.0.1", 1627 | "vscode-css-languageservice": "^5.1.4", 1628 | "vscode-html-languageservice": "^4.0.7", 1629 | "vscode-json-languageservice": "^4.1.7", 1630 | "vscode-languageserver": "^8.0.0-next.2", 1631 | "vscode-languageserver-textdocument": "^1.0.1", 1632 | "vscode-pug-languageservice": "^0.27.24", 1633 | "vscode-typescript-languageservice": "^0.27.25" 1634 | } 1635 | }, 1636 | "vue": { 1637 | "version": "3.2.33", 1638 | "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.33.tgz", 1639 | "integrity": "sha512-si1ExAlDUrLSIg/V7D/GgA4twJwfsfgG+t9w10z38HhL/HA07132pUQ2KuwAo8qbCyMJ9e6OqrmWrOCr+jW7ZQ==", 1640 | "requires": { 1641 | "@vue/compiler-dom": "3.2.33", 1642 | "@vue/compiler-sfc": "3.2.33", 1643 | "@vue/runtime-dom": "3.2.33", 1644 | "@vue/server-renderer": "3.2.33", 1645 | "@vue/shared": "3.2.33" 1646 | }, 1647 | "dependencies": { 1648 | "@babel/parser": { 1649 | "version": "7.17.10", 1650 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.10.tgz", 1651 | "integrity": "sha512-n2Q6i+fnJqzOaq2VkdXxy2TCPCWQZHiCo0XqmrCvDWcZQKRyZzYi4Z0yxlBuN0w+r2ZHmre+Q087DSrw3pbJDQ==" 1652 | }, 1653 | "@vue/compiler-core": { 1654 | "version": "3.2.33", 1655 | "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.33.tgz", 1656 | "integrity": "sha512-AAmr52ji3Zhk7IKIuigX2osWWsb2nQE5xsdFYjdnmtQ4gymmqXbjLvkSE174+fF3A3kstYrTgGkqgOEbsdLDpw==", 1657 | "requires": { 1658 | "@babel/parser": "^7.16.4", 1659 | "@vue/shared": "3.2.33", 1660 | "estree-walker": "^2.0.2", 1661 | "source-map": "^0.6.1" 1662 | } 1663 | }, 1664 | "@vue/compiler-dom": { 1665 | "version": "3.2.33", 1666 | "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.33.tgz", 1667 | "integrity": "sha512-GhiG1C8X98Xz9QUX/RlA6/kgPBWJkjq0Rq6//5XTAGSYrTMBgcLpP9+CnlUg1TFxnnCVughAG+KZl28XJqw8uQ==", 1668 | "requires": { 1669 | "@vue/compiler-core": "3.2.33", 1670 | "@vue/shared": "3.2.33" 1671 | } 1672 | }, 1673 | "@vue/shared": { 1674 | "version": "3.2.33", 1675 | "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.33.tgz", 1676 | "integrity": "sha512-UBc1Pg1T3yZ97vsA2ueER0F6GbJebLHYlEi4ou1H5YL4KWvMOOWwpYo9/QpWq93wxKG6Wo13IY74Hcn/f7c7Bg==" 1677 | } 1678 | } 1679 | }, 1680 | "vue-router": { 1681 | "version": "4.0.15", 1682 | "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.15.tgz", 1683 | "integrity": "sha512-xa+pIN9ZqORdIW1MkN2+d9Ui2pCM1b/UMgwYUCZOiFYHAvz/slKKBDha8DLrh5aCG/RibtrpyhKjKOZ85tYyWg==", 1684 | "requires": { 1685 | "@vue/devtools-api": "^6.0.0" 1686 | } 1687 | }, 1688 | "vue-tsc": { 1689 | "version": "0.3.0", 1690 | "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-0.3.0.tgz", 1691 | "integrity": "sha512-zaDRZBxwRIz1XjhNP92FqugG71st6BUMnA2EwPeXrAyzbEYVRz6TezNFceYl3QYqqN8CtaxbqUhaQEDj/ntoCA==", 1692 | "dev": true, 1693 | "requires": { 1694 | "vscode-vue-languageservice": "^0.27.0" 1695 | } 1696 | }, 1697 | "with": { 1698 | "version": "7.0.2", 1699 | "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", 1700 | "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", 1701 | "dev": true, 1702 | "requires": { 1703 | "@babel/parser": "^7.9.6", 1704 | "@babel/types": "^7.9.6", 1705 | "assert-never": "^1.2.1", 1706 | "babel-walk": "3.0.0-canary-5" 1707 | } 1708 | }, 1709 | "wrap-ansi": { 1710 | "version": "7.0.0", 1711 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 1712 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 1713 | "dev": true, 1714 | "requires": { 1715 | "ansi-styles": "^4.0.0", 1716 | "string-width": "^4.1.0", 1717 | "strip-ansi": "^6.0.0" 1718 | } 1719 | }, 1720 | "y18n": { 1721 | "version": "5.0.8", 1722 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 1723 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 1724 | "dev": true 1725 | }, 1726 | "yallist": { 1727 | "version": "4.0.0", 1728 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 1729 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", 1730 | "dev": true 1731 | }, 1732 | "yargs": { 1733 | "version": "17.4.1", 1734 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.4.1.tgz", 1735 | "integrity": "sha512-WSZD9jgobAg3ZKuCQZSa3g9QOJeCCqLoLAykiWgmXnDo9EPnn4RPf5qVTtzgOx66o6/oqhcA5tHtJXpG8pMt3g==", 1736 | "dev": true, 1737 | "requires": { 1738 | "cliui": "^7.0.2", 1739 | "escalade": "^3.1.1", 1740 | "get-caller-file": "^2.0.5", 1741 | "require-directory": "^2.1.1", 1742 | "string-width": "^4.2.3", 1743 | "y18n": "^5.0.5", 1744 | "yargs-parser": "^21.0.0" 1745 | } 1746 | }, 1747 | "yargs-parser": { 1748 | "version": "21.0.1", 1749 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", 1750 | "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", 1751 | "dev": true 1752 | } 1753 | } 1754 | } 1755 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "code996", 3 | "version": "0.2.0", 4 | "description": "code996 是一个分析工具,它可以统计 Git 项目的 commit 时间分布,进而推导出这个项目的编码工作强度。", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vue-tsc --noEmit && vite build", 8 | "serve": "vite preview" 9 | }, 10 | "author": "digua", 11 | "license": "Unlicense", 12 | "dependencies": { 13 | "chart.xkcd": "^1.1.13", 14 | "vue": "^3.2.33", 15 | "vue-router": "^4.0.15" 16 | }, 17 | "devDependencies": { 18 | "@types/node": "^17.0.33", 19 | "@vitejs/plugin-vue": "^1.9.3", 20 | "rollup-plugin-external-globals": "^0.6.1", 21 | "rollup-plugin-visualizer": "^5.6.0", 22 | "sass": "^1.43.3", 23 | "sass-loader": "^12.2.0", 24 | "typescript": "^4.4.3", 25 | "vite": "^2.6.4", 26 | "vue-tsc": "^0.3.0" 27 | } 28 | } -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hellodigua/code996/91bb9b3016d1389949da9b4995c00d67adf953c9/public/favicon.ico -------------------------------------------------------------------------------- /public/fonts/vcr-osd.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hellodigua/code996/91bb9b3016d1389949da9b4995c00d67adf953c9/public/fonts/vcr-osd.ttf -------------------------------------------------------------------------------- /public/fonts/zpix.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hellodigua/code996/91bb9b3016d1389949da9b4995c00d67adf953c9/public/fonts/zpix.ttf -------------------------------------------------------------------------------- /public/fonts/zpix.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hellodigua/code996/91bb9b3016d1389949da9b4995c00d67adf953c9/public/fonts/zpix.woff2 -------------------------------------------------------------------------------- /public/preview/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hellodigua/code996/91bb9b3016d1389949da9b4995c00d67adf953c9/public/preview/1.png -------------------------------------------------------------------------------- /public/preview/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hellodigua/code996/91bb9b3016d1389949da9b4995c00d67adf953c9/public/preview/2.png -------------------------------------------------------------------------------- /public/preview/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hellodigua/code996/91bb9b3016d1389949da9b4995c00d67adf953c9/public/preview/3.png -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 15 | 16 | 19 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | import { router } from './router' 4 | 5 | const app = createApp(App) 6 | app.use(router) 7 | 8 | app.mount('#app') 9 | -------------------------------------------------------------------------------- /src/public/components/CommonFooter.vue: -------------------------------------------------------------------------------- 1 | 26 | 43 | -------------------------------------------------------------------------------- /src/public/components/GithubCorner.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/public/styles/common.scss: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #212121; 3 | color: #ccc; 4 | font-size: 16px; 5 | line-height: 1.75; 6 | font-family: 'Pixel', Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; 7 | } 8 | 9 | @font-face { 10 | font-family: 'vcr-osd'; 11 | // src: url('sources/fonts/vcr-osd.ttf'); 12 | // src: url('https://unpkg.com/code996@latest/public/fonts/vcr-osd.ttf'); 13 | src: url('https://fastly.jsdelivr.net/gh/hellodigua/cdn/fonts/vcr-osd.ttf'); 14 | font-display: swap; 15 | } 16 | 17 | @font-face { 18 | font-family: 'Pixel'; 19 | // src: url('sources/fonts/zpix.woff2') format('woff2'); 20 | // src: url('https://unpkg.com/code996@latest/public/fonts/zpix.woff2') format('woff2'); 21 | src: url('https://fastly.jsdelivr.net/gh/hellodigua/cdn/fonts/zpix.woff2') format('woff2'); 22 | font-display: swap; 23 | } 24 | 25 | @font-face { 26 | font-family: 'xkcd'; 27 | // src: url('sources/fonts/zpix.woff2') format('woff2'); 28 | // src: url('https://unpkg.com/code996@latest/public/fonts/zpix.woff2') format('woff2'); 29 | src: url('https://fastly.jsdelivr.net/gh/hellodigua/cdn/fonts/zpix.woff2') format('woff2'); 30 | font-display: swap; 31 | } 32 | 33 | ::selection { 34 | background: rgba(255, 255, 255, 0.2); 35 | } 36 | 37 | .container { 38 | padding: 40px 0; 39 | } 40 | 41 | .wrapper { 42 | width: 70%; 43 | margin: 0 auto; 44 | } 45 | 46 | .app { 47 | height: 100%; 48 | &-container { 49 | min-height: 100%; 50 | } 51 | } 52 | 53 | .footer { 54 | line-height: 2; 55 | background: #2a2a2a; 56 | text-align: center; 57 | margin-top: 3em; 58 | padding: 2em 0; 59 | font-size: 0.9em; 60 | p { 61 | display: flex; 62 | justify-content: center; 63 | align-items: center; 64 | a { 65 | display: contents; 66 | color: #de335e; 67 | } 68 | } 69 | } 70 | 71 | @media screen and (max-width: 700px) { 72 | .wrapper { 73 | width: 90%; 74 | margin: 0 5%; 75 | } 76 | 77 | .container { 78 | padding: 20px 0; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/public/styles/index.scss: -------------------------------------------------------------------------------- 1 | @import './reset.scss'; 2 | @import './common.scss'; 3 | @import './module-intro.scss'; 4 | @import './module-result.scss'; 5 | -------------------------------------------------------------------------------- /src/public/styles/module-intro.scss: -------------------------------------------------------------------------------- 1 | .intro { 2 | height: 100%; 3 | width: 100%; 4 | 5 | .banner { 6 | display: flex; 7 | flex-direction: column-reverse; 8 | justify-content: center; 9 | padding: 60px 0; 10 | width: 100%; 11 | background: #2a2a2a; 12 | &-wrapper { 13 | .logo-text { 14 | font-size: 7em; 15 | color: #de335e; 16 | font-family: vcr-osd; 17 | text-shadow: 0px 0px 0px rgba(255, 255, 255, 0), 10px 10px 0px rgba(0, 0, 0, 0.2); 18 | margin-bottom: 40px; 19 | } 20 | .p2 { 21 | font-size: 1.1em; 22 | margin-bottom: 40px; 23 | } 24 | .btn { 25 | display: inline-block; 26 | font-size: 1.1em; 27 | cursor: pointer; 28 | background-color: #212121; 29 | padding: 14px 40px; 30 | background-color: #de335e; 31 | color: #fff; 32 | box-shadow: 0px 0px 0px rgba(255, 255, 255, 0), 10px 10px 0px rgba(0, 0, 0, 0.2); 33 | transition: 0.3s all; 34 | &:hover { 35 | background-color: #ef406c; 36 | box-shadow: 0px 0px 0px rgb(255 255 255 / 0%), 5px 5px 0px rgb(0 0 0 / 20%); 37 | } 38 | } 39 | } 40 | } 41 | 42 | .main { 43 | padding-top: 5em; 44 | .item { 45 | display: flex; 46 | padding-bottom: 4em; 47 | &:last-child { 48 | padding-bottom: 0; 49 | } 50 | .left { 51 | width: 120px; 52 | min-width: 120px; 53 | } 54 | .icon-mark { 55 | font-size: 3.2em; 56 | color: #de335e; 57 | font-family: vcr-osd; 58 | background-color: #2a2a2a; 59 | text-shadow: 0px 0px 0px rgba(255, 255, 255, 0), 5px 5px 0px rgba(0, 0, 0, 0.2); 60 | width: 80px; 61 | height: 80px; 62 | text-align: center; 63 | line-height: 80px; 64 | } 65 | .p1 { 66 | font-size: 1.6em; 67 | font-weight: 500; 68 | color: #fff; 69 | line-height: 1; 70 | margin-bottom: 1.3em; 71 | } 72 | .p2 { 73 | font-size: 1.2em; 74 | font-weight: 500; 75 | color: #fff; 76 | } 77 | } 78 | } 79 | 80 | .markdown-body { 81 | flex: 1; 82 | width: 100%; 83 | font-family: 'Pixel', Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; 84 | background-color: transparent; 85 | color: #ddd; 86 | 87 | > :last-child { 88 | margin-bottom: 0 !important; 89 | } 90 | 91 | li { 92 | > p { 93 | margin-top: 16px; 94 | } 95 | + li { 96 | margin-top: 0.25em; 97 | } 98 | } 99 | 100 | p { 101 | margin-top: 0; 102 | margin-bottom: 10px; 103 | } 104 | 105 | pre, 106 | code { 107 | padding: 12px; 108 | overflow: auto; 109 | font-size: 85%; 110 | line-height: 1.2; 111 | background-color: #2a2a2a; 112 | border-radius: 6px; 113 | margin-top: 0; 114 | margin-bottom: 0; 115 | font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace; 116 | font-size: 12px; 117 | word-wrap: normal; 118 | } 119 | 120 | code { 121 | padding: 8px; 122 | } 123 | 124 | .overflow-x { 125 | width: 100%; 126 | overflow-x: auto; 127 | } 128 | 129 | a { 130 | color: #de335e; 131 | } 132 | 133 | ul { 134 | padding-left: 0; 135 | list-style: inside; 136 | margin-bottom: 3em; 137 | li { 138 | margin-bottom: 16px; 139 | } 140 | 141 | pre { 142 | display: table-caption; 143 | width: 100%; 144 | margin: 1em 0; 145 | } 146 | .todo { 147 | text-decoration: line-through; 148 | } 149 | } 150 | } 151 | } 152 | 153 | @media (max-width: 700px) { 154 | .intro { 155 | .wrapper { 156 | width: 90%; 157 | .logo-text { 158 | font-size: 17vw; 159 | margin-bottom: 10px; 160 | } 161 | } 162 | 163 | .main { 164 | display: block !important; 165 | 166 | .item { 167 | flex-direction: column; 168 | .left { 169 | margin-bottom: 20px; 170 | } 171 | .p1 { 172 | margin-bottom: 20px; 173 | } 174 | } 175 | } 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /src/public/styles/module-result.scss: -------------------------------------------------------------------------------- 1 | .result { 2 | height: 100%; 3 | width: 100%; 4 | 5 | .top-bar { 6 | padding: 40px 0; 7 | width: 100%; 8 | background: #2a2a2a; 9 | .wrapper { 10 | display: flex; 11 | flex-direction: row; 12 | justify-content: flex-start; 13 | align-items: flex-start; 14 | } 15 | .button { 16 | display: inline-block; 17 | font-size: 1em; 18 | cursor: pointer; 19 | padding: 10px 20px; 20 | background-color: #444; 21 | color: #fff; 22 | box-shadow: 0px 0px 0px rgb(255 255 255 / 0%), 8px 8px 0px rgb(0 0 0 / 20%); 23 | transition: 0.3s all; 24 | &:hover { 25 | background-color: #4a4a4a; 26 | box-shadow: 0px 0px 0px rgb(255 255 255 / 0%), 5px 5px 0px rgb(0 0 0 / 20%); 27 | } 28 | margin-right: 30px; 29 | } 30 | h1 { 31 | line-height: 48px; 32 | color: #999; 33 | font-family: vcr-osd; 34 | font-weight: normal; 35 | text-shadow: 0px 0px 0px rgba(255, 255, 255, 0), 6px 6px 0px rgba(0, 0, 0, 0.2); 36 | } 37 | } 38 | 39 | .main { 40 | padding-top: 0; 41 | &.wrapper { 42 | position: relative; 43 | } 44 | .title { 45 | margin-bottom: 20px; 46 | } 47 | } 48 | 49 | .top-result { 50 | h1 { 51 | font-size: 2em; 52 | color: #de335e; 53 | text-shadow: 0px 0px 0px rgb(255 255 255 / 0%), 6px 6px 0px rgb(0 0 0 / 20%); 54 | margin-bottom: 40px; 55 | } 56 | .result-line { 57 | display: flex; 58 | } 59 | .score-box { 60 | position: relative; 61 | display: inline-block; 62 | margin-right: 60px; 63 | } 64 | .score-number { 65 | display: inline-block; 66 | background-color: #de335e; 67 | color: #fff; 68 | font-size: 8em; 69 | text-shadow: 0px 0px 0px rgb(255 255 255 / 0%), 10px 10px 0px rgb(0 0 0 / 20%); 70 | box-shadow: 0px 0px 0px rgb(255 255 255 / 0%), 10px 10px 0px rgb(0 0 0 / 20%); 71 | font-family: 'vcr-osd'; 72 | line-height: 1; 73 | padding: 30px 30px; 74 | } 75 | .subtitle { 76 | position: absolute; 77 | right: -20%; 78 | bottom: 0; 79 | font-size: 1.2em; 80 | color: #fff; 81 | transform: rotate(-10deg); 82 | animation: subtitleAni 1s alternate infinite ease-in-out; 83 | } 84 | .content { 85 | font-size: 1em; 86 | .p1 { 87 | color: #de335e; 88 | font-size: 1.5em; 89 | } 90 | .p2 { 91 | color: #999; 92 | font-size: 0.9em; 93 | margin-left: 8px; 94 | } 95 | } 96 | .exp { 97 | margin-top: 40px; 98 | font-size: 0.85em; 99 | opacity: 0.46; 100 | } 101 | } 102 | 103 | .content { 104 | .section { 105 | display: flex; 106 | justify-content: space-between; 107 | .item { 108 | width: 48%; 109 | background-color: #2a2a2a; 110 | box-sizing: border-box; 111 | padding: 10px; 112 | margin-bottom: 40px; 113 | box-shadow: 0px 0px 0px rgb(255 255 255 / 0%), 10px 10px 0px rgb(0 0 0 / 10%); 114 | .bar-chart { 115 | width: 100%; 116 | background-color: #2a2a2a !important; 117 | } 118 | h2 { 119 | margin: 0; 120 | margin-left: 10px; 121 | font-weight: normal; 122 | } 123 | } 124 | } 125 | } 126 | 127 | .table-box { 128 | width: 100%; 129 | overflow: auto; 130 | margin-top: 10px; 131 | 132 | .table { 133 | width: 100%; 134 | border-collapse: collapse; 135 | border-spacing: 0; 136 | .l { 137 | min-width: 10em; 138 | } 139 | tr { 140 | border-bottom: 1px solid #555; 141 | td { 142 | padding: 10px; 143 | text-align: center; 144 | } 145 | } 146 | th { 147 | text-align: center; 148 | padding: 10px; 149 | border-bottom: 1px solid #999; 150 | } 151 | td { 152 | text-align: center; 153 | padding: 10px; 154 | } 155 | .active { 156 | color: #de335e; 157 | } 158 | } 159 | .tips { 160 | font-size: 14px; 161 | color: #999; 162 | margin-top: 10px; 163 | } 164 | } 165 | } 166 | 167 | @keyframes subtitleAni { 168 | from { 169 | transform: rotate(-12deg) scale(1); 170 | color: #ffffd1; 171 | } 172 | 173 | to { 174 | transform: rotate(-8deg) scale(1.2); 175 | color: #ffff6d; 176 | } 177 | } 178 | 179 | @media screen and (max-width: 700px) { 180 | .result { 181 | .top-bar { 182 | padding: 30px 0; 183 | .wrapper { 184 | flex-direction: column; 185 | .button { 186 | margin-bottom: 20px; 187 | } 188 | } 189 | } 190 | .result-line { 191 | flex-direction: column; 192 | .score-box { 193 | text-align: center; 194 | margin-bottom: 40px; 195 | display: flex; 196 | margin-right: 0; 197 | .score-number { 198 | margin: 0 auto; 199 | } 200 | .subtitle { 201 | right: 0; 202 | } 203 | } 204 | } 205 | .content { 206 | .section { 207 | width: 100%; 208 | flex-direction: column; 209 | .item { 210 | width: 100%; 211 | } 212 | } 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /src/public/styles/reset.scss: -------------------------------------------------------------------------------- 1 | html { 2 | height: 100%; 3 | box-sizing: border-box; 4 | } 5 | 6 | body { 7 | height: 100%; 8 | -moz-osx-font-smoothing: grayscale; 9 | -webkit-font-smoothing: antialiased; 10 | text-rendering: optimizeLegibility; 11 | font-size: 14px; 12 | } 13 | 14 | #app { 15 | height: 100%; 16 | } 17 | 18 | *, 19 | *:before, 20 | *:after { 21 | box-sizing: inherit; 22 | padding: 0; 23 | margin: 0; 24 | } 25 | 26 | a, 27 | a:focus, 28 | a:hover { 29 | cursor: pointer; 30 | color: inherit; 31 | outline: none; 32 | text-decoration: none; 33 | } 34 | 35 | div:focus { 36 | outline: none; 37 | } 38 | -------------------------------------------------------------------------------- /src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { Router, createRouter, createWebHashHistory } from 'vue-router' 2 | const Intro = () => import('@/view/intro/index.vue') 3 | const Result = () => import('@/view/result/index.vue') 4 | 5 | export const router = createRouter({ 6 | history: createWebHashHistory('/'), 7 | routes: [ 8 | { 9 | path: '/', 10 | name: 'index', 11 | component: Intro, 12 | meta: { title: 'code996' }, 13 | }, 14 | { 15 | path: '/result', 16 | name: 'result', 17 | component: Result, 18 | meta: { title: 'result | code996' }, 19 | }, 20 | ], 21 | }) 22 | 23 | function changeTitleGuide(router: Router) { 24 | router.beforeEach((to, from, next) => { 25 | const title = to.meta.title as string 26 | document.title = title 27 | next() 28 | }) 29 | } 30 | 31 | changeTitleGuide(router) 32 | -------------------------------------------------------------------------------- /src/sfc.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'chart.xkcd' 2 | -------------------------------------------------------------------------------- /src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { DefineComponent } from 'vue' 3 | const component: DefineComponent<{}, {}, any> 4 | export default component 5 | } 6 | -------------------------------------------------------------------------------- /src/typings/index.ts: -------------------------------------------------------------------------------- 1 | export interface TimeCount { 2 | /** 3 | * commit 时间 4 | */ 5 | time: string 6 | /** 7 | * commit 数量 8 | */ 9 | count: number 10 | } 11 | 12 | export interface CalcTimeCount extends TimeCount { 13 | /** 14 | * 分数 15 | */ 16 | score: number 17 | } 18 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './time' 2 | -------------------------------------------------------------------------------- /src/utils/time.ts: -------------------------------------------------------------------------------- 1 | export function formatTime(date: Date, fmt: string) { 2 | const o: any = { 3 | 'M+': date.getMonth() + 1, // 月份 4 | 'd+': date.getDate(), // 日 5 | 'h+': date.getHours(), // 小时 6 | 'm+': date.getMinutes(), // 分 7 | 's+': date.getSeconds(), // 秒 8 | 'q+': Math.floor((date.getMonth() + 3) / 3), // 季度 9 | S: date.getMilliseconds(), // 毫秒 10 | } 11 | if (/(y+)/.test(fmt)) { 12 | fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)) 13 | } 14 | for (var k in o) { 15 | if (new RegExp('(' + k + ')').test(fmt)) { 16 | fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)) 17 | } 18 | } 19 | return fmt 20 | } 21 | -------------------------------------------------------------------------------- /src/view/intro/index.vue: -------------------------------------------------------------------------------- 1 | 106 | 120 | 121 | -------------------------------------------------------------------------------- /src/view/result/components/BarChart.vue: -------------------------------------------------------------------------------- 1 | 4 | 41 | 42 | -------------------------------------------------------------------------------- /src/view/result/components/CompareTable.vue: -------------------------------------------------------------------------------- 1 | 20 | 29 | 30 | -------------------------------------------------------------------------------- /src/view/result/components/PieChart.vue: -------------------------------------------------------------------------------- 1 | 4 | 40 | 41 | -------------------------------------------------------------------------------- /src/view/result/core/hour.ts: -------------------------------------------------------------------------------- 1 | import { TimeCount } from '../../../typings' 2 | 3 | export function getHourResult(hourData: TimeCount[]) { 4 | const { openingTime, closingTime } = getWorkTimeRange(hourData) 5 | const { workHourPl } = getWorkingTime(hourData, openingTime) 6 | 7 | return { 8 | openingTime, 9 | closingTime, 10 | workHourPl, 11 | } 12 | } 13 | 14 | /** 15 | * 获取工作相关commit数据 16 | */ 17 | function getWorkTimeRange(hourData: TimeCount[]) { 18 | // 平方平均数(并非所有模型均适用, 只有在数值分布呈现正态分布时才适用,因此commit数量越多越准确) 19 | const quadraticValue = hourData.reduce((total, item) => total + item.count ** 2, 0) / hourData.length 20 | const standardValue = Math.sqrt(quadraticValue) 21 | const calcData = hourData.map((item: TimeCount, index: number) => { 22 | const score = item.count / standardValue 23 | return { 24 | ...item, 25 | score, 26 | prevScore: (item.count - (hourData[index - 1]?.count || item.count)) / standardValue, 27 | nextScore: ((hourData[index + 1]?.count || item.count) - item.count) / standardValue, 28 | } 29 | }) 30 | 31 | // 工作时间 32 | const workData = calcData.filter((item) => item.score >= 0.45) 33 | // 开工时间段 34 | const openingData = workData.filter((item) => +item.time >= 8 && +item.time <= 12) 35 | // 收工时间段 36 | const closingData = workData.filter((item) => +item.time >= 17 && +item.time <= 23) 37 | 38 | const openingTime = openingData.sort((a, b) => Number(a.time) - Number(b.time))[0] 39 | const closingTime = closingData.sort((a, b) => Number(b.time) - Number(a.time))[0] 40 | 41 | return { 42 | // 上班时间 43 | openingTime, 44 | // 下班时间 45 | closingTime, 46 | } 47 | } 48 | 49 | /** 50 | * 计算每日工作时间和加班时间 51 | * 劳动法规定:每日工作时间不超过八小时,同时大部分公司的标准工作时间为朝九晚六,共9小时 52 | * 因此定义工作时间为从开工时间算起的区间为9的时间段,加班时间为剩余时间 53 | */ 54 | function getWorkingTime(hourData: TimeCount[] = [], openingTime: TimeCount) { 55 | // 获取从开工时间算起的正常工作时间 56 | const workingTime = hourData.filter( 57 | (item) => +item.time >= +openingTime?.time && +item.time <= +openingTime?.time + 9 58 | ) 59 | const workingElseTime = hourData.filter((item) => !workingTime.includes(item)) 60 | const workingTimeCount = workingTime.reduce((total, item) => total + item.count, 0) 61 | const workingElseTimeCount = workingElseTime.reduce((total, item) => total + item.count, 0) 62 | 63 | // 获取效率最高的前 9 个小时(适用开源项目) 64 | const sortData = hourData.sort((a, b) => b.count - a.count) 65 | const top9Time = sortData.slice(0, 9) 66 | const top9ElseTime = sortData.slice(9, sortData.length + 1) 67 | const top9TimeCount = top9Time.reduce((total, item) => total + item.count, 0) 68 | const top9ElseTimeCount = top9ElseTime.reduce((total, item) => total + item.count, 0) 69 | 70 | const workHourPl = [ 71 | { time: '工作', count: workingTimeCount, timeCount: top9Time.length }, 72 | { time: '加班', count: workingElseTimeCount, timeCount: top9ElseTime.length }, 73 | ] 74 | 75 | return { workHourPl, workingTimeCount, workingElseTimeCount, top9TimeCount, top9ElseTimeCount } 76 | } 77 | -------------------------------------------------------------------------------- /src/view/result/core/index.ts: -------------------------------------------------------------------------------- 1 | import { useRouter } from 'vue-router' 2 | import { getHourResult } from './hour' 3 | import { getWeekResult } from './week' 4 | import { parseResult, parseWeekData } from './url-helper' 5 | import { getRandomText } from './utils' 6 | 7 | /** 8 | * 获取路由元信息 9 | */ 10 | export function getRoutesMeta() { 11 | const router = useRouter() 12 | const { query } = router.currentRoute.value 13 | 14 | const hourData = parseResult(query.hour as string) 15 | const weekData = parseWeekData(parseResult(query.week as string)) 16 | const timeRange = (query.time as string).split('_') 17 | const timeStr = `${timeRange[0]} ∼ ${timeRange[1]}` 18 | const totalCount = hourData.reduce((total, item) => total + item.count, 0) 19 | 20 | return { 21 | hourData, 22 | weekData, 23 | timeRange, 24 | timeStr, 25 | totalCount, 26 | } 27 | } 28 | 29 | /** 30 | * 获取分析结果 31 | */ 32 | export function getResult() { 33 | const { hourData, weekData, totalCount } = getRoutesMeta() 34 | const { openingTime, closingTime, workHourPl } = getHourResult(hourData) 35 | const { workDayTypeValue, workWeekPl } = getWeekResult(weekData) 36 | const { index996, index996Str, overTimeRadio, isStandard } = get996Index({ workHourPl, workWeekPl, hourData }) 37 | 38 | const MSG_TYPE = checkDataIsRight({ workHourPl, workWeekPl, index996, overTimeRadio }) 39 | 40 | const _openingTime = Number(openingTime?.time) 41 | const _closingTime = Number(closingTime?.time) % 12 42 | 43 | return { 44 | // 工作类型模板 45 | workingType: `${_openingTime || '?'}${_closingTime || '?'}${workDayTypeValue || '?'}`, 46 | workingTypeStr: `早 ${_openingTime || '?'} 晚 ${_closingTime || '?'} 一周 ${workDayTypeValue || '?'} 天`, 47 | openingTime, 48 | closingTime, 49 | workDayTypeValue, 50 | workHourPl, 51 | workWeekPl, 52 | totalCount, 53 | index996, 54 | index996Str, 55 | overTimeRadio, 56 | isStandard, 57 | MSG_TYPE, 58 | } 59 | } 60 | 61 | /** 62 | * 计算996指数 63 | */ 64 | export function get996Index({ workHourPl, workWeekPl, hourData }: any) { 65 | const y = workHourPl[0].count 66 | const x = workHourPl[1].count 67 | const m = workWeekPl[0].count 68 | const n = workWeekPl[1].count 69 | 70 | /** 71 | * 修正后的加班commit数量 72 | * 定义的每周加班时间:周一到周五的非工作时间+周末全天,因此以工作日加班时间为标准,进行数学修正 73 | * 定义:小时维度 x 加班时长 y 正常上班时长;天维度 m 工作日;n 周六周日 74 | */ 75 | const overTimeAmendCount = (x + (y * n) / (m + n)).toFixed(0) 76 | const totalCount = y + x 77 | 78 | // 加班commit百分比 79 | let overTimeRadio = Math.ceil((overTimeAmendCount / totalCount) * 100) 80 | 81 | if (overTimeRadio === 0 && hourData.length < 9) { 82 | overTimeRadio = getUn996Radio({ hourData, totalCount }) 83 | } 84 | 85 | // 996指数 86 | const index996 = overTimeRadio * 3 87 | 88 | // 是否为正常项目(开源项目计算不准确) 89 | const isStandard = index996 < 200 && totalCount > 50 90 | 91 | let index996Str = '' 92 | 93 | if (index996 <= 10) { 94 | index996Str = getRandomText(['令人羡慕的工作', '恭喜,你们没有福报', '你就是搬砖界的欧皇吧']) 95 | } else if (index996 > 10 && index996 <= 50) { 96 | index996Str = getRandomText(['你还有剩余价值']) 97 | } else if (index996 > 50 && index996 <= 90) { 98 | index996Str = getRandomText(['加油,老板的法拉利靠你了']) 99 | } else if (index996 > 90 && index996 <= 110) { 100 | index996Str = getRandomText(['你的福报已经修满了']) 101 | } else if (index996 > 110) { 102 | index996Str = getRandomText(['你们想必就是卷王中的卷王吧']) 103 | } 104 | 105 | return { index996, index996Str, overTimeRadio, isStandard } 106 | } 107 | 108 | /** 109 | * 计算不加班比例 110 | * 思路:周末一定是不加班的,周一到周五的工作时间一定是少于9h的 111 | * 因此模拟出上够9h的commit,然后算比例即可 112 | */ 113 | function getUn996Radio({ hourData, totalCount }: any) { 114 | const averageCommit = totalCount / hourData.length 115 | const mockTotalCount = averageCommit * 9 116 | const radio = Math.ceil((totalCount / mockTotalCount) * 100) - 100 117 | 118 | return radio 119 | } 120 | 121 | /** 122 | * 校验数据 123 | * 1. 项目数据伪造 124 | */ 125 | function checkDataIsRight(params: any) { 126 | const { workHourPl, workWeekPl } = params 127 | let MSG_TYPE: string = '' 128 | 129 | const total1 = workHourPl[0].count + workHourPl[1].count 130 | const total2 = workWeekPl[0].count + workWeekPl[1].count 131 | 132 | if (total1 !== total2) { 133 | MSG_TYPE = 'commit_is_fake' 134 | } 135 | 136 | return MSG_TYPE 137 | } 138 | -------------------------------------------------------------------------------- /src/view/result/core/table.ts: -------------------------------------------------------------------------------- 1 | import { getRoutesMeta, get996Index } from './index' 2 | import { getHourResult } from './hour' 3 | import { getWeekResult } from './week' 4 | 5 | export function getTableCore() { 6 | const { hourData, weekData } = getRoutesMeta() 7 | const { openingTime, closingTime, workHourPl } = getHourResult(hourData) 8 | const { workDayTypeValue, workWeekPl } = getWeekResult(weekData) 9 | const { index996, overTimeRadio, isStandard } = get996Index({ workHourPl, workWeekPl, hourData }) 10 | 11 | const openingTimeValue = Number(openingTime?.time) 12 | const closingTimeValue = Number(closingTime?.time) 13 | 14 | const tableConfig = [ 15 | { label: '日均工作时长', key: 'codeTime', unit: 'h' }, 16 | { label: '每周工作时长', key: 'weekTime', unit: 'h' }, 17 | { label: '每周加班时长', key: 'overtime', unit: 'h' }, 18 | { label: '加班时间占比', key: 'overTimeRadio', unit: '%' }, 19 | { label: '996指数', key: 'index996', unit: '' }, 20 | ] 21 | 22 | const attendance = closingTimeValue - openingTimeValue 23 | 24 | /** 25 | * 日均工作时长 26 | * 如果下班时间小于19点,那么默认只休息中午1.5小时 27 | * 否则加晚上加班餐1小时,按2.5小时算 28 | */ 29 | let codeTime = 0 30 | if (closingTimeValue <= 19) { 31 | codeTime = closingTimeValue - openingTimeValue - 1.5 32 | } else if (closingTimeValue > 19) { 33 | codeTime = closingTimeValue - openingTimeValue - 2.5 34 | } 35 | 36 | const weekTime = codeTime * workDayTypeValue 37 | const overtime = (overTimeRadio * 0.01 * weekTime).toFixed(1) 38 | 39 | const currConfig = { 40 | type: `${openingTimeValue || '?'}${closingTimeValue % 12 || '?'}${workDayTypeValue || '?'}`, 41 | attendance, 42 | codeTime, 43 | weekTime, 44 | overtime, 45 | overTimeRadio, 46 | index996, 47 | } 48 | 49 | let tableData: any[] = [ 50 | { type: '955', attendance: 8, codeTime: 6.5, weekTime: 32.5, overtime: -5, overTimeRadio: -11, index996: -33 }, 51 | { type: '965', attendance: 9, codeTime: 7.5, weekTime: 37.5, overtime: 0, overTimeRadio: 0, index996: 0 }, 52 | { type: '966', attendance: 9, codeTime: 7.5, weekTime: 45, overtime: 7.5, overTimeRadio: 16, index996: 48 }, 53 | { type: '995', attendance: 12, codeTime: 9.5, weekTime: 47.5, overtime: 10, overTimeRadio: 21, index996: 63 }, 54 | { type: '996', attendance: 12, codeTime: 9.5, weekTime: 57, overtime: 19.5, overTimeRadio: 34, index996: 100 }, 55 | { type: '997', attendance: 12, codeTime: 9.5, weekTime: 66.5, overtime: 29, overTimeRadio: 44, index996: 130 }, 56 | { type: '9126', attendance: 15, codeTime: 12.5, weekTime: 75, overtime: 37.5, overTimeRadio: 50, index996: 150 }, 57 | ] 58 | 59 | if (isStandard) { 60 | tableData = [...tableData, currConfig].sort((a, b) => a.index996 - b.index996) 61 | } 62 | 63 | return { 64 | tableConfig, 65 | tableData, 66 | index996, 67 | isStandard, 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/view/result/core/url-helper.ts: -------------------------------------------------------------------------------- 1 | import { useRouter } from 'vue-router' 2 | import { TimeCount } from '../../../typings' 3 | 4 | /** 5 | * 解析url参数为标准数据格式 6 | * @param str 分析参数 7 | * @returns 8 | */ 9 | export function parseResult(str: string = ''): TimeCount[] { 10 | let list: TimeCount[] = [] 11 | str.split(',').forEach((item) => { 12 | const arr = item.split('_') 13 | list.push({ 14 | time: arr[1], 15 | count: Number(arr[0]), 16 | }) 17 | }) 18 | 19 | return list 20 | } 21 | 22 | /** 23 | * 二次改造周维度数据 24 | * @param list 25 | * @returns 26 | */ 27 | export function parseWeekData(list: TimeCount[]): TimeCount[] { 28 | const templateList = [ 29 | { name: '周一', key: '1' }, 30 | { name: '周二', key: '2' }, 31 | { name: '周三', key: '3' }, 32 | { name: '周四', key: '4' }, 33 | { name: '周五', key: '5' }, 34 | { name: '周六', key: '6' }, 35 | { name: '周日', key: '7' }, 36 | ] 37 | return templateList.map((tem) => { 38 | const item = list.find((i) => i.time === tem.key) as TimeCount 39 | 40 | return { 41 | time: tem.name, 42 | count: item?.count || 0, 43 | } 44 | }) 45 | } 46 | 47 | /** 48 | * 检查路由参数是否合法并跳转 49 | */ 50 | export function checkUrlQueryAndRedirect(): void { 51 | const router = useRouter() 52 | const { query } = router.currentRoute.value 53 | 54 | if (!query.time || !query.hour || !query.week) { 55 | router.push({ 56 | name: 'index', 57 | query: { 58 | error: 'url_query_error', 59 | }, 60 | }) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/view/result/core/utils.ts: -------------------------------------------------------------------------------- 1 | import { TimeCount } from '../../../typings' 2 | 3 | /** 4 | * 计算总数量 5 | */ 6 | export function getTotalCount(data: TimeCount[]) { 7 | return data.reduce((total, item) => total + item.count, 0) 8 | } 9 | 10 | /** 11 | * 计算比例 12 | * @param element 分子 13 | * @param denominator 分母 14 | * @param decimal 小数位,默认2位 15 | * @returns 百分比 16 | */ 17 | export function getRadio(element: number, denominator: number, decimal: number = 2): number { 18 | return +((element / denominator) * 100).toFixed(decimal) 19 | } 20 | 21 | /** 22 | * 获取随机文本 23 | */ 24 | export function getRandomText(texts: string[] = []): string { 25 | return texts[Math.floor(Math.random() * texts.length)] 26 | } 27 | 28 | /** 29 | * 寻找最接近的数字 30 | */ 31 | export function findNear(num: number = 0, list: number[] = []): number { 32 | let min = Number.MAX_VALUE 33 | let index = 0 34 | for (let i = 0; i < list.length; i++) { 35 | const item = list[i] 36 | const diff = Math.abs(num - item) 37 | if (diff < min) { 38 | min = diff 39 | index = i 40 | } 41 | } 42 | return list[index] 43 | } 44 | -------------------------------------------------------------------------------- /src/view/result/core/week.ts: -------------------------------------------------------------------------------- 1 | import { getTotalCount, getRadio } from './utils' 2 | import { TimeCount } from '../../../typings' 3 | 4 | export function getWeekResult(weekData: TimeCount[]) { 5 | const workDayData = weekData.slice(0, 5) 6 | const saturdayData = weekData[5] 7 | const sundayData = weekData[6] 8 | // commit 总数 9 | const totalCount = getTotalCount(weekData) 10 | const commitCount = { 11 | workday: getTotalCount(workDayData), 12 | saturday: saturdayData.count, 13 | sunday: sundayData.count, 14 | } 15 | 16 | // commit 比例 17 | const commitRatio = { 18 | workday: getRadio(commitCount.workday, totalCount), 19 | saturday: getRadio(commitCount.saturday, totalCount), 20 | sunday: getRadio(commitCount.sunday, totalCount), 21 | } 22 | 23 | const workWeekPl = [ 24 | { time: '工作日', count: commitCount.workday }, 25 | { time: '周末', count: commitCount.saturday + commitCount.sunday }, 26 | ] 27 | 28 | const workDayType = getWorkDayType(commitRatio) 29 | const workDayTypeMap = [5, 6, 6, 7, 7] 30 | 31 | const workDayTypeValue = workDayTypeMap[workDayType - 1] 32 | 33 | return { 34 | totalCount, 35 | commitCount, 36 | commitRatio, 37 | 38 | workDayType, 39 | workDayTypeValue, 40 | workWeekPl, 41 | } 42 | } 43 | 44 | /** 45 | * 获取每周工作时长 46 | * @returns type 1: 每周5天 2: 每周6天 3: 大小周 4: 每周7天 5: 周末干活 47 | */ 48 | export function getWorkDayType(commitRatio: any): number { 49 | let type = 1 50 | if (commitRatio.workday >= 90) { 51 | type = 1 52 | } else if (commitRatio.workday >= 85 && commitRatio.workday < 90) { 53 | type = 2 54 | } else if (commitRatio.workday >= 79 && commitRatio.workday < 85) { 55 | type = 3 56 | } else if (commitRatio.workday >= 72 && commitRatio.workday < 79) { 57 | type = 4 58 | } else if (commitRatio.workday < 72) { 59 | type = 5 60 | } 61 | return type 62 | } 63 | -------------------------------------------------------------------------------- /src/view/result/index.vue: -------------------------------------------------------------------------------- 1 | 80 | 135 | 136 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "useDefineForClassFields": true, 5 | "module": "esnext", 6 | "moduleResolution": "node", 7 | "strict": true, 8 | "jsx": "preserve", 9 | "sourceMap": true, 10 | "resolveJsonModule": true, 11 | "esModuleInterop": true, 12 | "lib": ["esnext", "dom"], 13 | "paths": { 14 | "@/*": ["./src/*"] 15 | } 16 | }, 17 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.vue"] 18 | } 19 | -------------------------------------------------------------------------------- /userscript.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Gitlab 996 index statistic 3 | // @namespace http://996.icu/ 4 | // @version 0.1 5 | // @description work and life balance! 6 | // @author wanghsinche 7 | // @match https://*/* 8 | // @icon https://www.google.com/s2/favicons?sz=64&domain=gitlab.com 9 | // @grant none 10 | // @run-at document-end 11 | // ==/UserScript== 12 | 13 | (function () { 14 | 'use strict'; 15 | 16 | const meta = document.body.dataset; 17 | const projectId = meta?meta.projectId:null; 18 | const commitURL = `/api/v4/projects/${projectId}/repository/commits` 19 | const visualazation = 'https://hellodigua.github.io/code996/#/result' 20 | const mergeFlag = "Merge branch" 21 | 22 | const pannelId = 'my-pannel' 23 | 24 | let loading = false 25 | 26 | function print(...param) { 27 | const myPannel = document.getElementById(pannelId) 28 | myPannel.style.display = 'block' 29 | myPannel.innerText = param.toString() 30 | } 31 | 32 | 33 | 34 | async function getCommit(maxNum = 1000, page = 1) { 35 | if (maxNum < 1) { 36 | return [] 37 | } 38 | 39 | const perPage = 100 40 | const param = new URLSearchParams() 41 | param.set('per_page', perPage) 42 | param.set('page', page) 43 | const rawData = await fetch(`${commitURL}?${param.toString()}`).then(res => res.json()) 44 | 45 | const data = rawData.filter(el => !el.title.startsWith(mergeFlag)) 46 | 47 | if (rawData.length < perPage) { 48 | return data 49 | } 50 | print('processing... page ', page) 51 | const rest = await getCommit(maxNum - data.length, page + 1) 52 | return data.concat(rest) 53 | 54 | } 55 | 56 | async function processData() { 57 | const totalCommit = await getCommit() 58 | print('got the commits, start to analyze', totalCommit.length) 59 | const startTime = new Date(totalCommit.reduce((am, ele) => { 60 | if (!am) return ele.committed_date 61 | return am < ele.committed_date ? am : ele.committed_date 62 | }, null)) 63 | const endTime = new Date(totalCommit.reduce((am, ele) => { 64 | if (!am) return ele.committed_date 65 | return am > ele.committed_date ? am : ele.committed_date 66 | }, null)) 67 | 68 | // const timezone = Object.entries(totalCommit.reduce((am, ele)=>{ 69 | // const tz = ele.committed_date.split('+').pop() 70 | // am[tz] = (am[tz]||0)+1 71 | // return am 72 | // }, {})).reduce((am, ele)=>{ 73 | // if (ele[1] > am[1]){ 74 | // return ele 75 | // } 76 | // }, ['00:00', 0])[0] 77 | 78 | const byDayResult = totalCommit.reduce((am, ele) => { 79 | const day = new Date(ele.committed_date).getDay() 80 | am[day] = (am[day] || 0) + 1 81 | return am 82 | }, {}) 83 | 84 | const byHourResult = totalCommit.reduce((am, ele) => { 85 | const hour = new Date(ele.committed_date).getHours() 86 | am[hour] = (am[hour] || 0) + 1 87 | return am 88 | }, {}) 89 | // month start from 0 90 | const formattedStartTime = `${startTime.getFullYear()}-${startTime.getMonth()+1}-${startTime.getDate()}` 91 | const formattedEndTime = `${endTime.getFullYear()}-${endTime.getMonth()+1}-${endTime.getDate()}` 92 | 93 | const formattedDayResult = Object.entries(byDayResult).map(([day, freq]) => `${freq}_${day}`).join(',') 94 | const formattedHourResult = Object.entries(byHourResult).map(([hour, freq]) => `${freq}_${hour}`).join(',') 95 | 96 | const param = new URLSearchParams() 97 | param.set('time', `${formattedStartTime}_${formattedEndTime}`) 98 | param.set('week', formattedDayResult) 99 | param.set('hour', formattedHourResult) 100 | const finalLink = `${visualazation}?${param.toString()}` 101 | 102 | return finalLink 103 | } 104 | 105 | 106 | function buildGUI() { 107 | const myButton = document.createElement('button') 108 | myButton.id = 'my-button' 109 | myButton.className = 'gl-button btn btn-default' 110 | myButton.textContent = 'Get 996 Index' 111 | 112 | myButton.addEventListener('click', () => { 113 | if (loading) return 114 | 115 | loading = true 116 | processData().then(link => { 117 | 118 | const myPannel = document.getElementById(pannelId) 119 | const a = document.createElement('a') 120 | a.href = link 121 | a.textContent = ' the statistic result' 122 | a.target = 'blank' 123 | myPannel.innerHTML = 'got it! click the link to see ' 124 | myPannel.append(a) 125 | 126 | }, err => { 127 | print(err) 128 | }).finally(() => { 129 | loading = false 130 | }) 131 | }) 132 | 133 | 134 | const container = document.getElementsByClassName('shortcuts-find-file')[0].parentElement 135 | container.append(myButton) 136 | 137 | const myPannel = document.createElement('div') 138 | myPannel.id = 'my-pannel' 139 | myPannel.style.padding = '20px' 140 | myPannel.className = 'info-well' 141 | myPannel.style.display = 'none' 142 | 143 | const infoWell = document.getElementsByClassName('info-well')[0] 144 | 145 | infoWell.parentElement.insertBefore(myPannel, infoWell) 146 | 147 | } 148 | 149 | 150 | function main() { 151 | if (!projectId){ 152 | console.log('it isn\'t a gitlab project page, abort') 153 | return 154 | } 155 | 156 | const targetNode = document.getElementsByClassName('nav-block')[0]; 157 | 158 | // Options for the observer (which mutations to observe) 159 | const config = { attributes: false, childList: true, subtree: true }; 160 | 161 | // Callback function to execute when mutations are observed 162 | const callback = (mutationList, observer) => { 163 | let isChild = false 164 | for (const mutation of mutationList) { 165 | if (mutation.type === 'childList') { 166 | console.log('A child node has been added or removed.'); 167 | isChild = true 168 | } 169 | } 170 | if (isChild) { 171 | observer.disconnect(); 172 | buildGUI() 173 | } 174 | }; 175 | 176 | // Create an observer instance linked to the callback function 177 | const observer = new MutationObserver(callback); 178 | 179 | // Start observing the target node for configured mutations 180 | observer.observe(targetNode, config); 181 | 182 | } 183 | 184 | // launch the program 185 | main() 186 | 187 | 188 | 189 | 190 | })(); 191 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | import { resolve } from 'path' 4 | import { visualizer } from 'rollup-plugin-visualizer' 5 | import externalGlobals from 'rollup-plugin-external-globals' 6 | 7 | // https://vitejs.dev/config/ 8 | export default defineConfig({ 9 | plugins: [vue(), visualizer()], 10 | resolve: { 11 | alias: { 12 | '@': resolve(__dirname, './src'), 13 | }, 14 | }, 15 | base: './', 16 | build: { 17 | rollupOptions: { 18 | external: ['vue', 'vue-router', 'chart.xkcd'], 19 | plugins: [ 20 | externalGlobals({ 21 | vue: 'Vue', 22 | 'vue-router': 'VueRouter', 23 | 'chart.xkcd': 'chartXkcd', 24 | }), 25 | ], 26 | }, 27 | }, 28 | }) 29 | --------------------------------------------------------------------------------