当前位置: 首页 > 编程日记 > 正文

如何从头开始构建自己的Linux Dotfiles Manager

As a new linux 🐧 user, you might realize that there are a bunch of configuration files present in your system. These special files are called "dotfiles".

作为新的Linux用户,您可能会意识到系统中存在大量配置文件。 这些特殊文件称为“点文件”。

In this tutorial we will learn how to make a dotfiles manager and create a backup of these files on GitHub.

在本教程中,我们将学习如何制作一个dotfiles管理器以及如何在GitHub上创建这些文件的备份。

What are these .dotfiles you may ask? And why do we need them?

您可能会问这些.dotfiles是什么? 为什么我们需要它们?

Dotfiles are usually associated with specific programs installed on your system and are used to customize those programs/software.

点文件通常与系统上安装的特定程序相关联,并用于自定义那些程序/软件。

For example, if you have zsh as your default shell your will have a .zshrc file in your HOME directory. Some other examples include:

例如,如果将zsh作为默认外壳,则HOME目录中将具有.zshrc文件。 其他一些示例包括:

  1. .vimrc: this bad boi is used for configuring your VIM Editor.

    .vimrc :该错误的boi用于配置VIM编辑器。

  2. .bashrc: available by default, used for changing bash settings.

    .bashrc :默认情况下可用,用于更改bash设置。

  3. .bash_aliases: this file is generally used to store your command aliases.

    .bash_aliases :此文件通常用于存储命令别名。

  4. .gitconfig: stores configurations related to Git.

    .gitconfig :存储与Git相关的配置。

  5. .gitmessage: Used to provide a commit messsage template while using git commit.

    .gitmessage :用于在使用git commit时提供提交消息模板。

These .dotfiles change over time as you start customizing linux according to your needs.

当您开始根据需要定制Linux时,这些.dotfiles会随着时间而变化。

Creating a back-up of these files is necessary if in some case you mess up something 😬 and want to go back to a previous stable state. That's where VCS (Version Control Software) comes in.

如果在某些情况下您弄乱了某些东西并想回到以前的稳定状态,则必须创建这些文件的备份。 这就是VCS(版本控制软件)的出现。

Here, we will learn how to automate this task by writing a simple shell script and storing our dotfiles on GitHub.

在这里,我们将学习如何通过编写简单的shell脚本并将点文件存储在GitHub上来自动执行此任务。

lets do it rock
Source : giphy.com
资料来源:giphy.com

内容 (Contents)

  • First Steps, Visualizing the script

    第一步,可视化脚本

  • Getting Dependencies

    获取依赖

  • Start Coding, Module by Module

    按模块开始编码

  • Jazzing 💅🏽 up our script

    爵士💅🏽我们的剧本

  • The End Result

    最终结果

  • Summary, Take Aways

    摘要,带走

第一步 (First Steps)

Oh before we move any further, let's name our script: dotman, (dot)file (man)ager. Do you like it 😅 ?

在进一步操作之前,让我们命名脚本: dotman ,(dot)file(man)ager。 你喜欢😅吗?

Before we write our first line of code, we need to lay out our requirements and design for how our shell script should work.

在编写第一行代码之前,我们需要对我们的shell脚本应该如何工作进行布局和设计。

我们的要求 (Our Requirements)

We are going to make dotman simple & easy to use. It should be able to:

我们将使dotman简单易用。 它应该能够:

  1. Find dotfiles present inside our system 🔍.

    查找我们系统中存在的dotfile🔍。

  2. Differentiate between files present in our git repository to those on our system.

    将git存储库中存在的文件与系统上的文件区分开。

  3. Update our dotfiles repo (either push to remote or pull from it).

    更新我们的dotfiles存储库(推送到远程或从中拉出)。

  4. Be easy to use (we don't want 5 different arguments in a single script).

    易于使用(我们不想在一个脚本中使用5个不同的参数)。

让可视化 (Lets Visualize)

dotman-flowchart

获取依赖 (Getting Dependencies)

  1. Git We need Git, because we may want to go back to a previous version of our dotfile. Plus we are going to store our dotfiles in a VCS Host (GitHub/GitLab/Bitbucket/Gittea). Don't have Git Installed? Go through the following guide to learn how to install it according to your system.

    Git我们需要Git,因为我们可能想回到点文件的先前版本。 另外,我们将把点文件存储在VCS主机中(GitHub / GitLab / Bitbucket / Gittea)。 还没有安装Git吗? 仔细阅读以下指南,了解如何根据您的系统进行安装。

  2. Bash This is going to be available on your Linux/Unix/MacOS machines by default. Verify this by checking the version bash --version. It should be something like this. Don't worry about the version too much, as our script will work fine for Bash >=3.

    Bash默认情况下,它将在您的Linux / Unix / MacOS计算机上可用。 通过检查版本bash --version验证这一点。 应该是这样的。 不用太担心版本,因为我们的脚本对于Bash> = 3可以正常工作。

GNU bash, version 4.4.20(1)-release (i686-pc-linux-gnu)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

开始编码 (Start Coding)

So now we have everything setup. Fire up your favorite editor/IDE.

现在,我们已完成所有设置。 启动您喜欢的编辑器/ IDE。

coder chimpanzee
Source: giphy.com
资料来源:giphy.com

We need to declare a she bang to indicate we are going to invoke an interpreter for execution. In the start of the script include this line:

我们需要声明一个爆炸,以表明我们将调用解释器以执行。 在脚本的开头包含以下行:

#!/usr/bin/env bash

The command (program) env is executed as a new process which then calls the command that was provided as an argument.

命令(程序) env作为新进程执行,然后调用作为参数提供的命令。

In our case bash is automatically started by the env process. That is its env responsibility to find where is bash on our system and substitute its path in the script. You could replace bash with, for example, python or ruby.

在我们的情况下, bash由env进程自动启动。 这就是它的env责任找到哪里是bash在我们的系统和脚本替代它的路径。 您可以将bash替换为pythonruby

Now just change file permissions to make our script executable.

现在只需更改文件许可权即可使我们的脚本可执行。

chmod +x dotman.sh

We will be using the functional style of programming in this script, that is every piece of the task is going to be inside some function(). Let's follow the flow chart we visualized above and write our first function, init_check().

我们将在此脚本中使用编程的功能样式,即任务的每一部分都将放在某个function()内部。 让我们按照上面可视化的流程图并编写我们的第一个函数init_check()

We are going to rely only on 2 inputs from the user:

我们将仅依靠来自用户的2个输入:

  1. DOT_DEST: the location of repository in your local system.

    DOT_DEST :本地系统中存储库的位置。

  2. DOT_REPO: the url to the remote dotfile repo.

    DOT_REPO :远程点文件仓库的URL。

These 2 variables must be present inside your default shell config (.bashrc for e.g). We will learn how to do this later in this tutorial.

这两个变量必须存在于默认的shell配置中(例如.bashrc )。 我们将在本教程的后面部分学习如何执行此操作。

init_check() {# Check wether its a first time use or notif [[ -z ${DOT_REPO} && -z ${DOT_DEST} ]]; then# show first time setup menu# initial_setupelse# repo_check# managefi
}

The -z option is used to check whether a variable is set or not (that is, if its available to our script or not). If it is not, then we are going to invoke our initial_setup() function. Otherwise we will check if the repository is cloned and is present inside the DOT_DEST folder.

-z选项用于检查是否设置了变量(即,变量是否可用于我们的脚本)。 如果不是,那么我们将调用我们的initial_setup()函数。 否则,我们将检查存储库是否已克隆并且是否存在于DOT_DEST文件夹中。

Now let's code the initial_setup function:

现在,让我们编写initial_setup函数的代码:

initial_setup() {echo -e "\n\nFirst time use, Set Up d○tman"echo -e "....................................\n"read -p "Enter dotfiles repository URL : " -r DOT_REPOread -p "Where should I clone $(basename "${DOT_REPO}") (${HOME}/..): " -r DOT_DESTDOT_DEST=${DOT_DEST:-$HOME}if [[ -d "$HOME/$DOT_DEST" ]]; then# clone the repo in the destination directoryif git -C "${HOME}/${DOT_DEST}" clone "${DOT_REPO}"; thenadd_env "$DOT_REPO" "$DOT_DEST"echo -e "\ndotman successfully configured"goodbyeelse# invalid arguments to exit, Repository Not Foundecho -e "\n$DOT_REPO Unavailable. Exiting"exit 1fielseecho -e "\n$DOT_DEST Not a Valid directory"exit 1fi
}

Pretty basic, right? Now, let's go through this together and understand what's happening.

很基本吧? 现在,让我们一起经历一下,了解正在发生的事情。

  • The read startement is a shell bulitin which is used to take input from the terminal. The -p option specifies a prompt before taking an input.

    read开头是一个shell bulitin,用于从终端获取输入。 -p选项指定输入之前的提示。

  • The next line after read is called a Parameter Expansion, If the user doesn't input DOT_DEST then the default value is assigned as /home/username/ (If DOT_DEST is unset or null, the expansion of $HOME is substituted) Otherwise, the value entered by user is substituted.

    读取后的下一行称为Parameter Expansion ,如果用户未输入DOT_DEST,则默认值分配为/home/username/ (如果DOT_DEST未设置或为null,则替换$ HOME的扩展名)否则,则用户输入的值将被替换。

  • The -d inside the if statement checks whether the directory exists (or technically) the directory user provided is actually a valid path in our system or not.

    if语句中的-d检查目录是否存在(或从技术上来说)用户提供的目录实际上是我们系统中的有效路径。

  • The -C option is used in git to clone the repository to a user-specified path.

    git中使用-C选项将存储库克隆到用户指定的路径。

Now let's see how to export environment variables in the function add_env().

现在让我们看看如何在add_env()函数中导出环境变量。

add_env() {# export environment variablesecho -e "\nExporting env variables DOT_DEST & DOT_REPO ..."current_shell=$(basename "$SHELL")if [[ $current_shell == "zsh" ]]; thenecho "export DOT_REPO=$1" >> "$HOME"/.zshrcecho "export DOT_DEST=$2" >> "$HOME"/.zshrcelif [[ $current_shell == "bash" ]]; then# assume we have a fallback to bashecho "export DOT_REPO=$1" >> "$HOME"/.bashrcecho "export DOT_DEST=$2" >> "$HOME"/.bashrcelseecho "Couldn't export DOT_REPO and DOT_DEST."echo "Consider exporting them manually".exit 1fiecho -e "Configuration for SHELL: $current_shell has been updated."
}

Running echo $SHELL in your terminal will give you the path for your default shell. The basename command is used to print the "Name" of our SHELL (that is, the actual name without any leading /).

在终端中运行echo $SHELL将为您提供默认Shell的路径。 basename命令用于打印SHELL的“名称”(即,没有任何前导/的实际名称)。

> echo $SHELL
/usr/bin/zsh
> basename $SHELL
zsh
  • The export is a well-used statement: it lets you export :) environment variables.

    export是一个很好用的语句:它允许您导出:)环境变量。

  • >> is called a redirection operator, that is the output of the statement echo "export DOT_DEST=$2" is directed (appended) to the end of zshrc file.

    >>被称为重定向运算符,即语句echo“ export DOT_DEST = $ 2”的输出被定向(附加)到zshrc文件的末尾。

Now, once the user has completed the first time setup we need to show them the "manager" options.

现在,一旦用户完成了第一次设置,我们就需要向他们显示“经理”选项。

manage-menu-flowchart
manage() {while :doecho -e "\n[1] Show diff"echo -e "[2] Push changed dotfiles to remote"echo -e "[3] Pull latest changes from remote"echo -e "[4] List all dotfiles"echo -e "[q/Q] Quit Session"# Default choice is [1]read -p "What do you want me to do ? [1]: " -n 1 -r USER_INPUT# See Parameter ExpansionUSER_INPUT=${USER_INPUT:-1}case $USER_INPUT in[1]* ) show_diff_check;;[2]* ) dot_push;;[3]* ) dot_pull;;[4]* ) find_dotfiles;;[q/Q]* ) exit;;* )     printf "\n%s\n" "Invalid Input, Try Again";;esacdone
}
  • You are already familiar with read. The -n 1 option specifies what length of input is allowed, in our case the user can only input one character amongst 1, 2, 3, 4, q and Q.

    您已经熟悉read-n 1选项指定允许输入的长度,在本例中,用户只能输入1、2、3、4,q和Q中的一个字符。

Now we have to find all dotfiles in our HOME directory.

现在我们必须在我们的HOME目录中找到所有的点文件。

find_dotfiles() {printf "\n"readarray -t dotfiles < <( find "${HOME}" -maxdepth 1 -name ".*" -type f )printf '%s\n' "${dotfiles[@]}"
}

The function is divided into 2 parts:

该功能分为2部分:

  1. find

    find

    The find command you guessed right, searches for files and directories in our system. Let's understand it part by part.

    您猜对的find命令在我们的系统中搜索文件和目录。 让我们对它进行部分了解。

  • The -type f options specifies that we only want to search for regular files and not directories, character or block, or device files.

    -type f选项指定我们只想搜索常规文件,而不是目录,字符或块或设备文件。

  • The -maxdepth option tells find to descend at most 1 level (a non-negative integer) levels of directories below the starting-points. You could search sub-directories by replacing 1 with 2, 3 etc.

    -maxdepth选项告诉find在-maxdepth以下最多将-maxdepth 1级(非负整数)。 您可以通过将1替换为2、3等来搜索子目录。

  • -name takes a pattern(glob) for searching. For example you can search for all .py files: -name ".py".

    -name采用一个模式(全局)进行搜索。 例如,您可以搜索所有.py文件: -name ".py"

  1. readarray (also a synonym for mapfile)

    readarray (也是mapfile的同义词)

    reads lines from the standard input into the indexed array variable

    从标准输入读取行到索引数组变量

    dotfiles.

    dotfiles

    The

    -t option removes any trailing delimiter (default newline) from each line read.

    -t选项从读取的每一行中删除任何结尾的定界符(默认换行符)。

Note: If you have an older version of Bash (<4), readarray might not be present as a builtin. We can achieve the same functionality by using a while loop instead.

注意:如果您具有较旧的Bash版本(<4),则readarray可能不作为内置readarray出现。 我们可以通过使用while循环来实现相同的功能。

while read -r value; dodotfiles+=($value)
done < <( find "${HOME}" -maxdepth 1 -name ".*" -type f )

We are now going to make one of the most important functions in our script, diff_check.

现在,我们将在脚本中diff_check最重要的功能之一diff_check

diff_check() {if [[ -z $1 ]]; thendeclare -ag file_arrfi# dotfiles in repositoryreadarray -t dotfiles_repo < <( find "${HOME}/${DOT_DEST}/$(basename "${DOT_REPO}")" -maxdepth 1 -name ".*" -type f )# check length here ?for (( i=0; i<"${#dotfiles_repo[@]}"; i++))dodotfile_name=$(basename "${dotfiles_repo[$i]}")# compare the HOME version of dotfile to that of repodiff=$(diff -u --suppress-common-lines --color=always "${dotfiles_repo[$i]}" "${HOME}/${dotfile_name}")if [[ $diff != "" ]]; thenif [[ $1 == "show" ]]; thenprintf "\n\n%s" "Running diff between ${HOME}/${dotfile_name} and "printf "%s\n" "${dotfiles_repo[$i]}"printf "%s\n\n" "$diff"fifile_arr+=("${dotfile_name}")fidoneif [[ ${#file_arr} == 0 ]]; thenecho -e "\n\nNo Changes in dotfiles."returnfi
}show_diff_check() {diff_check "show"
}

Our goal here is to find the dotfiles already present in the repository and compare them with the one available in our HOME directory.

我们的目标是找到存储库中已经存在的点文件,并将其与我们HOME目录中可用的点文件进行比较。

  • The declare keyword lets us create variables. The -a option is used to create arrays and -g tells declare to make the variables available "globally" inside the script.

    使用declare关键字可以创建变量。 -a选项用于创建数组,而-g告诉声明使变量在脚本内“全局”可用。

  • ${#file_arr} gives us the length of the array.

    ${#file_arr}给出了数组的长度。

The next important command is diff which is used to compare files line-by-line. For example:

下一个重要的命令是diff ,它用于逐行比较文件。 例如:

> echo -e "abc\ndef\nghi" >> fileA.txt
> echo -e "abc\nlmn\nghi" >> fileB.txt
> cat fileA.txt
abc
def
ghi
> cat fileB.txt
abc
lmn
ghi
> diff -u fileA.txt fileB.txt
--- fileA.txt	2020-07-17 16:24:16.138172662 +0530
+++ fileB.txt	2020-07-17 16:24:26.686075270 +0530
@@ -1,3 +1,3 @@abc
-def
+lmnghi

The dot_push() function.

dot_push()函数。

dot_push() {diff_checkecho -e "\nFollowing dotfiles changed : "for file in "${file_arr[@]}"; doecho "$file"cp "${HOME}/$file" "${HOME}/${DOT_DEST}/$(basename "${DOT_REPO}")"donedot_repo="${HOME}/${DOT_DEST}/$(basename "${DOT_REPO}")"git -C "$dot_repo" add -Aecho -e "Enter Commit Message (Ctrl + d to save):"commit=$(</dev/stdin)git -C "$dot_repo" commit -m "$commit"# Run Git Pushgit -C "$dot_repo" push
}

We are overwriting files here by copying them to our dotfile repo using the cp command.

我们通过使用cp命令将文件复制到我们的dotfile存储库中来覆盖文件。

And finally the dot_pull() function:

最后是dot_pull()函数:

dot_pull() {# pull changes (if any) from the host repoecho -e "\nPulling dotfiles ..."dot_repo="${HOME}/${DOT_DEST}/$(basename "${DOT_REPO}")"echo -e "\nPulling changes in $dot_repo\n"git -C "$dot_repo" pull origin master
}

爵士💅🏼我们的剧本 (Jazzing 💅🏼 up our script)

Up until now we have achieved what we initially visualized. But you know what, something's missing ....... 🤔

到目前为止,我们已经实现了最初的可视化效果。 但是你知道吗,缺少什么.............

Colors

色彩

Colorful cat rainbow waves
Source: tenor.com
资料来源:tenor.com

There are a lot of ways to do that, but the popular one is using escape sequences. But we are going to use a tool called tput which is a human friendly interface to output colors according to the user's terminal. It is available by default in Linux/MacOS. Here is a short demo.

有很多方法可以做到这一点,但是流行的是使用转义序列 。 但是我们将使用称为tput的工具,该工具是人性化的界面,可以根据用户的终端输出颜色。 在Linux / MacOS中默认情况下可用。 这是一个简短的演示。

To print text in bold

粗体打印文本

echo "$(tput bold)This$(tput sgr0) word is bold"

To change background color.

更改背景颜色。

echo "$(tput setab 10)This text has green background$(tput sgr0)"

To change foreground color

更改前景色

echo "$(tput setaf 10)This text has blue color$(tput sgr0)"

You can also combine attributes.

您还可以组合属性。

echo "$(tput smul)$(tput setaf 10) This text is underlined & green $(tput rmul)$(tput sgr0)"

Let me leave this task with you: add your favorite colors in the script. Read this guide to learn and explore more about tput.

让我把这个任务留给您:在脚本中添加您喜欢的颜色。 阅读本指南可了解和探索有关tput的更多信息。

最终结果 (The End Result)

I hope you are still with me at the point. But it's the end :( and we have a nice looking dotfile manager now.

希望您现在还和我在一起。 到此为止:(和,我们现在有了一个漂亮的dotfile管理器。

Happy and excited kermit
Source: giphy.com
资料来源:giphy.com

Now just run the script (if you haven't already) to see it in action.

现在只需运行脚本(如果尚未运行)即可查看其运行情况。

./dotman.sh

You can see my version of dotman if you need a reference. Feel free to create any issues if you have any questions about this tutorial or email them to me directly.

如果需要参考,可以查看我的dotman版本。 如果您对本教程有任何疑问,请随时提出任何问题,或直接将其发送给我。

Bhupesh-V/dotman - GitHub

I have made it available as a template so you can use it to hack your own version of dotman.

我已经将其作为模板提供,因此您可以使用它来破解自己的dotman版本。

摘要 (Summary)

Let's summarize some important things we learned in this tutorial.

让我们总结一下我们在本教程中学到的一些重要知识。

  1. Use basename /path/to/dir/file/ to get the filename from a path.

    使用basename /path/to/dir/file/从路径获取文件名。

  2. Use git -C /path/to/clone/to clone https://repo.url to clone the repository to a different directory from the current working directory.

    使用git -C /path/to/clone/to clone https://repo.url将存储git -C /path/to/clone/to clone https://repo.url到与当前工作目录不同的目录。

  3. echo $SHELL can be used to determine what is your default shell.

    echo $SHELL可用于确定默认外壳程序是什么。

  4. Use find to search for files and folders in your Linux system.

    使用find在Linux系统中搜索文件和文件夹。

  5. The diff command is used to compare 2 files. Similar to git diff.

    diff命令用于比较2个文件。 类似于git diff

  6. Arrays declared inside a function are only accessible inside that function. Use the -g option to make them global, for example declare -ag file_arr.

    在函数内部声明的数组只能在该函数内部访问。 使用-g选项使它们成为全局declare -ag file_arr ,例如, declare -ag file_arr

  7. tput can be used to display colorized text on terminal.

    tput可用于在终端上显示彩色文本。

If you liked this tutorial, you can read more of my stuff at my blog. You can also connect with me on Twitter.

如果您喜欢本教程,则可以在Blog上内容。 您也可以在Twitter上与我联系。

Happy Learning 🖖

快乐学习🖖

翻译自: https://www.freecodecamp.org/news/build-your-own-dotfiles-manager-from-scratch/

相关文章:

D3.js、HTML5、canvas 开发专题

https://www.smartdraw.com/genogram/ http://www.mamicode.com/info-detail-1163777.html D3折线图 https://www.cnblogs.com/hwaggLee/p/5073885.html js-d3画图插件 http://www.xiaomlove.com/2014/06/29/d3-js简单画图-箭头连接随机圆圈/ 连线 http://www.decemberc…

单向链表JAVA代码

//单向链表类publicclassLinkList{ //结点类 publicclassNode{ publicObject data; publicNode next; publicNode(Object obj,Node next){ this.data obj; this.next next; } } Node head; //记录…

forkjoin rxjs_如何通过吃披萨来理解RxJS运算符:zip,forkJoin和Combine

forkjoin rxjs什么是RxJS&#xff1f; (What is RxJS?) Reactive programming is an asynchronous programming paradigm concerned with data streams and the propagation of change - Wikipedia响应式编程是一种与数据流和变更传播有关的异步编程范式 -Wikipedia RxJS is a…

SQLserver数据库操作帮助类SqlHelper

1 SqlHelper源码 using System; using System.Data; using System.Xml; using System.Data.SqlClient; using System.Collections; namespace SQL.Access {/// <summary>/// SqlServer数据访问帮助类/// </summary>public sealed class SqlHelper{#region 私有构造…

python框架之Flask基础篇(一)

一.第一个hello world程序 # codingutf-8 from flask import Flaskapp Flask(__name__)app.route(/) def hello_world():return Hello World!if __name__ __main__:app.run(debugTrue) 1.app参数的设置&#xff1a; 以下几种方式全部拿debug模式举例&#xff1a; .方式一&…

flask部署机器学习_如何开发端到端机器学习项目并使用Flask将其部署到Heroku

flask部署机器学习Theres one question I always get asked regarding Data Science:关于数据科学&#xff0c;我经常被问到一个问题&#xff1a; What is the best way to master Data Science? What will get me hired?掌握数据科学的最佳方法是什么&#xff1f; 什么会雇…

UVALive2678:Subsequence

UVALive2678:Subsequence 题目大意 给定一个数组A和一个整数S。求数组A中&#xff0c;连续且之和不小于S的连续子序列长度最小值。 要求复杂度:Ο(n) Solution 用变量L表示所选区间最左端下标&#xff0c;用变量R表示所选区间最右端下标&#xff0c;用变量sum表示所选区间的和。…

【BZOJ-3712】Fiolki LCA + 倍增 (idea题)

3712: [PA2014]Fiolki Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 303 Solved: 67[Submit][Status][Discuss]Description 化学家吉丽想要配置一种神奇的药水来拯救世界。吉丽有n种不同的液体物质&#xff0c;和n个药瓶&#xff08;均从1到n编号&#xff09;。初始时&am…

访问系统相册或调用摄像头

头文件&#xff1a;#import <MobileCoreServices/MobileCoreServices.h> 协议&#xff1a;<UINavigationControllerDelegate, UIImagePickerControllerDelegate> // 调用系统相册获取图片 - (IBAction)getImageFromAlbum:(id)sender {// 判断系统相册是否可用&…

unity镜像_通过镜像学习Unity Multiplayer Basics

unity镜像Unity is one of the most well-known and established engines for game development, and Mirror is a third-party, open source networking solution that allows you to add multiplayer to your games.Unity是最著名的游戏开发引擎之一&#xff0c;而Mirror是第…

java内存模型和线程安全

转载于:https://www.cnblogs.com/Michael2397/p/8397451.html

测试,发布,质量保障,用户体验

1.在实际项目中何时开始设计用户体验&#xff1a;用户的第一印象&#xff1b;从用户的角度考虑问题&#xff1b;软件啊服务始终要记住用户的选择&#xff1b;短期刺激和长期影响 2.测试经验交流&#xff1a;基本名词解释及分类&#xff1b;按测试设计的方法分类&#xff1b;按测…

UIImage存为本地文件与UIImage转换为NSData

UIImage *image"XXX"; //png格式 NSData *imagedataUIImagePNGRepresentation(image); //JEPG格式 //NSData *imagedataUIImageJEPGRepresentation(image); NSArray*pathsNSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES); NSString …

如何在JavaScript中实现链接列表

If you are learning data structures, a linked list is one data structure you should know. If you do not really understand it or how it is implemented in JavaScript, this article is here to help you. 如果您正在学习数据结构&#xff0c;则链表是您应该知道的一种…

SVG.path_不连续的线段

1、之前 用<path/>画的 线段等 都是连续的&#xff0c;想知道 是否能画 不连续的线段等 结论&#xff1a;可以 2、测试代码&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <svg width"1000" height"800" viewBo…

Leetcode 之Binary Tree Postorder Traversal(44)

后序遍历&#xff0c;比先序和中序都要复杂。访问一个结点前&#xff0c;需要先判断其右孩子是否被访问过。如果是&#xff0c;则可以访问该结点&#xff1b;否则&#xff0c;需要先处理右子树。 vector<int> postorderTraversal(TreeNode *root){vector<int> resu…

如何创建自己的ESLint配置包

ESLint is a powerful tool that helps you enforce consistent coding conventions and ensure quality in your JavaScript codebase. ESLint是一个功能强大的工具&#xff0c;可帮助您实施一致的编码约定并确保JavaScript代码库的质量。 Coding conventions are sometimes …

MySQL更新命令_UPDATE

创建测试表 mysql> CREATE TABLE product (-> proID int(11) NOT NULL AUTO_INCREMENT COMMENT 商品表主键,-> price decimal(10,2) NOT NULL COMMENT 商品价格,-> type int(11) NOT NULL COMMENT 商品类别(0生鲜,1食品,2生活),-> dtime datetime N…

KVC与KVO

1、键值编码KVC常用的KVC操作方法如下&#xff1a;• 动态设置&#xff1a; setValue:属性值 forKey:属性名&#xff08;用于简单路径&#xff09;、setValue:属性值 forKeyPath:属性路径&#xff08;用于复合路径&#xff0c;例如Person有一个Account类型的属性&#xff0c…

javaScript 工作必知(三) String .的方法从何而来?

String 我们知道javascript 包括&#xff1a;number&#xff0c;string&#xff0c;boolean,null,undefined 基本类型和Object 类型。 在我的认知中&#xff0c;方法属性应该是对象才可以具有的。 var str"hello,world";var sstr.subString(1,4);//ellalert(typeof…

s3 aws_您需要了解的有关AWS S3的所有信息

s3 awsThis article will provide an in-depth introduction to AWS S3 — the secure, scalable, and super cheap storage service from Amazon Web Services.本文将深入介绍AWS S3-来自Amazon Web Services的安全&#xff0c;可扩展和超便宜的存储服务。 If you have eve…

untitled与前端——初学

“前端” 啥&#xff1f; 百度百科&#xff1a; 就是制作一网页界面。比如360浏览器打开&#xff0c; 包括界面布局设计&#xff0c;搜索框&#xff0c;点击字或图标跳到另一个页面等。 软件Untitled 下载网址&#xff1a;http://www.jetbrains.com/ 下拉 点download&#xff0…

NSThread

NSThread是轻量级的多线程开发&#xff0c;使用起来也并不复杂&#xff0c;但是使用NSThread需要自己管理线程生命周期。 可以使用对象方法&#xff1a; (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument 直接将操作添加到线程中并…

异步发送邮件、短信、微信

用户创建订单的按钮点击后&#xff0c;服务器存储这个订单信息后&#xff0c;调用发送短信、邮件、微信的接口&#xff0c;发送消息。而发送短信、邮件、微信都要涉及第三方的处理&#xff0c;服务器又要发送一个新的包裹给一个新的服务器&#xff0c;告诉他帮我发一个信息出去…

英语面试简短问题_用简单的英语解释产品设计

英语面试简短问题Product design is the process you go through when you conceptualize and build a product.产品设计是概念化和构建产品时要经历的过程。 The path to building – hardware, software, or even simple prototypes – has different steps and approaches.…

6-12 二叉搜索树的操作集

6-12 二叉搜索树的操作集&#xff08;30 分&#xff09; 本题要求实现给定二叉搜索树的5种常用操作。 函数接口定义&#xff1a; BinTree Insert( BinTree BST, ElementType X ); BinTree Delete( BinTree BST, ElementType X ); Position Find( BinTree BST, ElementType X );…

iOS关于自定义rightBarButtonItem

在常见iOS开发中,我们常遇到这样的需求,如下: 我们需要自定义导航栏右侧按钮,常见的自定义包装按钮如下: //设置rightItem; UIButton *btn [UIButton buttonWithType:UIButtonTypeCustom]; btn.frame CGRectMake(0, 0, 40, 30); btn.selected NO; [btn setTitle:"管理&…

URL里汉字转码

URL里面不能包含中文。 解决办法&#xff1a;进行转码 NSString *urlStr[NSString stringWithFormat:kLotteryBar_putOutReviewUrl,_token,self.reviews_id,_User_Id,reviews_content]; urlStr[urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

electron.js_在使用Electron.js之前我希望知道的事情

electron.jsIn this article, Ill share how you can avoid some of the mistakes I made when learning about Electron.js &#x1f926;‍♂️. I hope it helps!在本文中&#xff0c;我将分享如何避免在学习Electron.js &#x1f926;‍&#x1f926;️时犯的一些错误。 希…

Entity Framework的启动速度优化

最近开发的服务放到IIS上寄宿之后&#xff0c;遇到一些现象&#xff0c;比如刚部署之后&#xff0c;第一次启动很慢&#xff1b;程序放置一会儿&#xff0c;再次请求也会比较慢。比如第一个问题&#xff0c;可以解释为初次请求某一个服务的时候&#xff0c;需要把程序集加载到内…