在 Discourse 的社区中可能有多个用户账号为管理员或者有特殊权限的账号。 这个账号在 Discourse 的用户,然后 Staff 中可以快速找到。 作为管理员,有时候需要检查下你的 Discourse 是不是没有进行管理,有多长时间没有登录了。 这个选项能够让你对 Discourse 的用户管理员进行一些快速的过滤,删除一些可能涉及到权限泄露的问题。 https://www.isharkfly.com/t/discourse/15059
在 Discourse 的社区中可能有多个用户账号为管理员或者有特殊权限的账号。 这个账号在 Discourse 的用户,然后 Staff 中可以快速找到。 作为管理员,有时候需要检查下你的 Discourse 是不是没有进行管理,有多长时间没有登录了。 这个选项能够让你对 Discourse 的用户管理员进行一些快速的过滤,删除一些可能涉及到权限泄露的问题。 https://www.isharkfly.com/t/discourse/15059
3.2.0.beta2 版本是在 2023-10-16 发布的,根据官方的说法,主要添加了 3 个新功能。 官方的发布日志页面:3.2.0.beta2: Auto delete unused tags, custom date range for reports, new chat notifications, and more - announcements - Discourse Meta 自动删除标签功能 Discourse 会对没有使用的标签进行自动删除。 检查的频率是每天一次,删除的标准是如果标签没有被任何主题或者帖子使用的话。 配置的参数为: automatically clean 可以在配置界面中搜索上面的配置参数,然后进行配置。 自定义报表时间 可以在报表的时间上对时间进行自定义。 2484×300 27.9 KB 感觉对一般的网站来说,通常也不会每天去查看一下报表,只要不是特别情况,一般查看时间区间通常都是 7 天,1 个月这样子的。 数据太少,报表看不出东西,不过也感觉是锦上添花,有了也不是坏事。 添加 Revise 功能 意思就是你可以通知用户对帖子进行修改,这个是用过 PM(用户消息发送的)。 当用户接收到上面的消息的时候,并不意味着他们被审核的帖子就自动完成了。 管理员还需要对发布的内容再次通过才可以的。 感觉这个功能可能不会经常使用,很多社区对帖子的审核是非常宽松的,只要不是毫无意义的内容,这个审核功能通常没有使用。 https://www.isharkfly.com/t/discourse-3-2-0-beta2/15058
我们考虑最后应该使用的是 ZIP 方式的安装。 按照官方的说法如何设置运行 YouTrack 应该是非常简单的。 准备环境 根据官方的说法,我们需要做的就是下载 Zip 包,然后把 Zip 包解压到指定的目录中就可以了。 下载 当前官方的下载地址为:Get YouTrack: Issue Tracking and Project Management Tool 1 直接打开上面的链接,你的计算机将会尝试下载,这个时候可以拷贝下载链接,然后到服务器上用 wget 来进行下载。 wget https://download-cdn.jetbrains.com/charisma/youtrack-2023.2.19783.zip 下载的文件大小可能会有几百兆,需要的时间可能不一样。 解压 如果你的操作系统环境下没有装 unzip 的话,你需要运行下面的命令来安装一个 unzip。 dnf install unzip 随后,直接运行 unzip youtrack-2023.2.19783.zip 来进行解压。 创建文件夹 为了统一和方便,我们可以把解压后的文件夹移动到 /opt 下的 youtrack 文件夹。 运行的命令为: mv youtrack-2023.2.19783 /opt 确定所有需要的文件都在 /opt/youtrack 文件夹下。 启动运行 进入 /opt/youtrack/bin 目录后 直接运行 ./youtrack.sh run 就可以运行了。 需要注意的是,如果使用上面的命令来运行的话,你的 SSH 界面就会被占用。 如果你不希望 修改端口 YouTrack 默认使用的是 8080 端口,大概率情况下这个端口可能会被占用。 ./youtrack.sh configure --listen-port 9090 来为你的 YouTrack 设置运行端口为 9090,你也可以设置任何你自己喜欢的端口。 修改默认域名 修改默认域名的命令为:./youtrack.sh configure --base-url http://track.ossez.com 这里有个坑,默认域名前面需要有协议,如果你没有使用http 或者 https 的话上面的配置无法让你进行修改。 如果一切配置顺利的话,我们就可以通过浏览器看到下面的配置界面了。 然后单击下一步进行配置。 https://www.isharkfly.com/t/youtrack-linux/15051
在服务器上的开源许可证版本已经要过期了,想去更新下。 发现,JIRA 的所有服务器版本的支持马上就要结束了。 这就意味着,如果你部署的服务器版本的 JIRA 的话,你将没有办法对服务器进行更新。 貌似,必须使用 JIRA 提供的云服务版本,这对有数据安全需求,并且希望在本地服务器上部署的公司可不是好消息。 因为不是所有公司都愿意把数据放到云上面。 是时候要找一个替代方案了。 https://www.isharkfly.com/t/jira-2024/15049
在一个 maven 的项目中,我们需要知道我们的项目中使用的包可能有哪些冲突。 这个在 IntelliJ IDEA 中提供了贴心的查看。 选择 Maven 项目中的分析依赖。 随后,IntelliJ IDEA 将会打开一个依赖分析的标签页。 在这个标签页中,我们可以看到我们项目中导入的依赖有哪些冲突,并且这些冲突是怎么冲突的。 如上图中,带有感叹号的就是有冲突的依赖。 这个时候,我们可以选择过滤只看有冲突的包。 同时,我们还可以知道有冲突的包是怎么引入的,是那几个包的引入导致了冲突。 总结 不是所有的冲突都能够被解决的。 通过这个图,我至少能够知道版本之间的冲突是怎么产生的,并且 是哪些包导致了这些冲突。 这对我们后期对项目版本进行规范的时候可以提供更好的参考。 https://www.isharkfly.com/t/intellij-idea-maven/15046
在最近的实践中,有人突然问了一个问题: 在 Java 的 List 中可以存不同的数据类型吗? 这个问题突然给问到了,我们都知道 Java 中的 List 中存的是对象,通常我们定义都会这样的定义: List<String> testList = new ArrayList<>(); 这样我们就知道了 testList 中存的对象都是 String 字符串了。 解答 List 中是可以存不同的数据类型的。 但是在定义的时候需要定义成: List testList = new ArrayList<>();,不能为要使用的 List 指定数据类型。 当为我们使用的 List 不指定数据类型的话,所有存到 List 中的对象都会被转换为 Object 类型。 而当我门再从list 中取出该数据时,就会发现数据类型已经改变。 Objec t类是所有Java类的祖先。每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。 在不明确给出超类的情况下,Java会自动把Object作为要定义类的超类。 例如下面的代码: List testList = new ArrayList<>(); testList.add(1L); testList.add("iSharkFly"); testList.add(2); 因为我们没有为我们的 List 指定数据类型,那么这个 List 内是可以放任何数据类型的,你甚至可以放一个对象进去也没有问题的。 上面的代码编译器是不会报错的。 但是在 Get 对象的时候,编译器会明确的告诉你类型不匹配,我们 Get 的是一个 Object 对象,但是你尝试把 Object 对象转换为其他类型,这个时候编译器是不会让你通过的。 这个时候需要进行类型转换才可以。 把上面 Object 对象,强制类型转换下。 Long index0 = (Long) testList.get(0); String index1 = (String) testList.get(1); 强制类型 如果我们在定义 List 的时候,强制定义类型: List<String> testList = new ArrayList<>(); 那么上面的额代码就会出错了。 编译器会告诉你,在这里我们需要的是一个 String 类型,但是你提供的是 Long 或者其他不是 String 类型。 我们在把数据插入到 List 中的时候,需要把类型先转换一下。 使用下面的代码 testList.add(String.valueOf(1L) ); testList.add("iSharkFly"); testList.add(String.valueOf(2)); testList.forEach(e -> log.debug("{}", e)); 就可以完成类型的转换了。 实战 在实际的编码中,我们通常都会为我们的 List 指定数据类型。 这个数据类型可以是任何数据类型或者对象,这样可以保证我们的 List 中存的数据类型只有一种数据类型。 这样在后期的数据遍历和处理过程中,我们就不需要再对数据类型进行转换了,这是一个常规的操作。 简单来说就是:先对数据进行转换,后存储,再使用。 我们会尽量避免在使用的时候对数据进行转换,例如上面的情况,我们 List 对象中存的是对象,我们不知道我们的对象是 Stirng 还是 Long,这个时候要猜。 如在使用的时候进行数据类型转换,就比较容易出现类型转换方面的错误了,所以我们会先定义好。 https://www.isharkfly.com/t/java-list/15040
如果非要用一句话来描述下现在北美地区 IT 相关职位的求职现状就是:互相毫无意义的伤害,互相毫无意义的折磨。 感触 经历过一段时间的求职和招聘后,有下面的一些感触,不知道同学们是否同意呢? 发的简历都没认真看 发了不少简历,不少公司可能真的都没有认真看,直接就丢垃圾箱里面了。 有些公司还是非常奇葩的,每年都在不停的招人招人,每过 3 个月,同样的岗位就放出来一次,然后每次你投的简历,一点下文都没有。 如果要说个公司名称的话,Fidelity Investments 可能就是一个非常典型的代表了,常年在招聘网站上被刷屏,然后投的简历一点下文都没有。 这里说的没有下文就是没有收到拒绝消息,也没有收到进入下一步的消息,完全就是没有消息。 当然,这种公司不只它家一个,好多公司都是这样的,完全就是为了在招聘平台上刷存在感。 发简历到第一次响应的时间过长 不知道为什么,现在的公司从投简历到第一次响应的时间通常都在 1 周甚至 2 周以上。 以前,通常在 2 到 3 天,不管是不是需要,基本上都有个消息说希望了解下,或者直接就拒绝了。 目前来看,这个第一次获得反馈的消息通常要在 1 到 2 周,甚至有 3 周的。 等到 3 周后收到消息,连自己都忘了我申请过这个公司吗?然后就从邮件历史中去找这个公司的名字,然后发现,哇塞居然是 21 天前发的邮件或者提交的申请了。 屁大的公司也上来就做题 另一个感触比较深的就是不管公司大小,不管职位需要还是不需要,上来就做题。 题目有难的,有简单的。比较难的题目通常是比较复杂的算法,如果你没有刷题过的话,真的要在比较短时间内做出来是很有难度的。 别说出结果了,就算把代码跑通都不那么容易。等入职后就发现那些刷题一点屁用都没有,然后还在不停的刷呀刷。 有些题目简直就是令人发指,不仅仅是是算法,简直感觉就是在侮辱你智商。更恶心你的是给你面试的人自己都没有把代码跑通过,随意在上网找了个题目,让你去做。 个人认为这样的同事是非常不负责任的,在你让别人做题目之前,你是不是也应该花点时间看看让别人做的题目呢? 做题目是小事情,但是可以看到整个团队的精神面貌。 面试的过程就是这样的互相折磨的话,以后的日子也不好过。还真得 “谢谢” Google 又给创造了一个做题产业。 面着面着就没有下文了 有个公司很有意思的,公司在电子邮件中说的非常明确每一步的步骤是什么,时间点是什么。 这给人的感觉非常好,因为能够及时了解面试进程,避免大家的互相折磨。谁知道就是这么一个感觉比较好的公司,面着面着就没有下文了。 当把代码提交后,公司说需要更长的时间来查看,公司计划在 5 天后给出明确的消息,这都过去 30 天了,没有任何动静,就好像公司已经忘了这件事情了。 更有意思的是,一个公司经过第一轮的接触,感觉还不错,说把和你第一轮面谈的内容和公司反馈下,然后就一直没有什么动静,2 周或者 1 个月以后发了一个邮件过来说是很抱歉的通知你,你的这个职位公司预算取消了。 我去,在发布职位的时候难道都没有想明白的吗?如此随意? 当然,也有好的公司。我就经历过一个公司非常明确的告诉我,公司在第一轮后的结果会在 2 周以后,同时,这个结果公司也遵守了,不管结果是什么,有和没有是 2 回事情。 能够及时回复邮件的公司都已经算是好公司了。 总结 经过这段时间的面试和接触,整体感觉就是说是不少公司的面试过程很多时候都是表面化,至于能不能找到工作,主要是看看自己的运气了。 如果你运气好的话,可能会有比较多的机会。 关于刷题:很多人会在做题的时候被刷掉,其实大可不必感觉到什么,这些所谓的做题很多时候是自欺欺人的东西,如果你真喜欢计算机,你不但应该做题,还需要了解为什么是这样设计的。 如果是为了刷题而刷题,时间长了也就沦为了一个刷题的机器了,感觉这样总是缺少点灵魂。 关于简历 :不要因为一个公司的职位拒绝了你,你就说这个公司可能不适合我啥的,其实只是你的简历没有被送到正确的人的手上罢了。 作为求职的你来说,就是不停的投,如果这个公司还有其他职位,就投其他职位的,重复投也没啥大不了的,说不定就有人看到了,然后你就进入下一轮了。 提早准备总不是坏事,祝福所有人在求职路上总能碰到正确的人,都好运。 https://www.isharkfly.com/t/it/15039
在代码中,你可能会看到大量的 @Override 注解。 这个注解简单来说就是让编译器去读的,能够避免你在写代码的时候犯一些低级的拼写错误。 Java @Override 注解用来指定方法重写(Override),只能修饰方法并且只能用于方法重写,不能修饰其它的元素。 @Override 注解可以强制一个子类必须重写父类方法或者实现接口的方法。 用途 @Override 主要是为了让编译器用的,告诉编译器使用这个注解的方法是重写(Override)的方法。 因为 重写(Override)的特性是,参数和返回以及方法名都不能变。 如果在写代码的时候,因为方法名不小心敲错了,在没有 @Override 这个注解之前是比较难发现的,所以我们使用 @Override 能够告诉编译器,这里对 重写方法注意下。 必须吗 这个注解不是必须的,在 JDK 的早期版本,没有注解之前,我们对重新的方法通常都不没有任何标记。 这个会导致一些书写错误,没有办法在编译的阶段发现。 所以不用这个注解也没有关系,但用了这个注解通常能够让代码更加可读一些。 具体开始使用是从 JDK 1.5 版本开始的。 https://www.isharkfly.com/t/java-override/15038
公司是一个基础通讯类的公司,需要的职位是一个高级系统和软件工程师。 职位要求,是一个完全不怎么大众的语言:Elixir。 没听过,这就对了,这是一个函数式的语言,可以认为是 Erlang 的升级版本,Erlang 多用在交换机设备上的开发语言,这个语言其实还是比较小众的。 RabbitMQ 就是 Erlang 开发的,虽然 Erlang 在整个项目中的比例并不是很高。 职位需求 这个职位的需求就是使用 Elixir 语言来处理 HTTP 的 API。 这个 API 主要是用户电子邮件相关的内容,我不知道为什么他们选择 Elixir,可能主要还是比较好和现有的系统保持一致吧。 面试 整个面试的时间是 1 个小时。 在这一个小时中主要聊了下对 HTTP 的请求,API 的调用是不是熟悉。不管用的是什么语言,只要你写过 API,这部分还是比较容易说清楚的。 下一步就是在线的 Coding 了,这个在线的代码也是非常简单的,唯一麻烦的地方是 Elixir,因为从来没有接触过这个语言,突然在平台上要用 Elixir 这个语言还是有点懵逼的。 好在示例程序什么都比较简单,就是对照下 API 的调用文档,利用模拟的环境写几个 API 接口。 只要有示例程序,要写其他的还是很简单就完成了,因为对 API 的写法,不管什么语言都差不多。 好在他们提供了一个 API 的示例程序。 在这部,都已经顺利完成了所有的代码,也正确没有问题。 随后他们就提出是不是给我一个回家做的题目,要求是完成这个题目,然后尽快提交给他们。 回家做题 对于给出的题目,稍后我在下面的文章中给出。 如果你是使用其他的比较高级的语言,这个应该没有什么问题,可以说是非常简单的。 但是 Elixir 是一个函数式的语言,同时循环是不可变的,在这里哪怕是一个循环都要折腾半天。 本着,既然我答应你回家试试了,那么我就抱着一定要做出来的想法来做的,也在规定的时间把代码提交了。 结果 大概 1 周后,收到了他们比较客气的拒绝信。 理由是找到了更加合适的人了。 点评 找到更加合适的人,这个不足为奇。因为 Elixir 这个语言实在是非常小众的语言,有比较大的学习曲线。 不是说,你今天开始看文档,明天就能全部看明白的那种。 这个语言没有好的集成 IDE 开发环境,代码写起来不是那么友好,高级语言非常容易实现的东西,Elixir 需要比较多的步骤才能完成。 其实,对公司本身来说,这次面试并没有什么负面评价。主要原因是,在投简历的时候没有仔细看看需要的语言,主要是看了 API 编程能力。 通常来说,这个都不是什么问题。 唯一感觉有点不好的是,公司方面对面试者的反馈比较差。在我提交代码到对方邮箱后,没有任何邮件说邮件已经收到了。完全不知道邮件是不是已经发送过去了或者他们在进行评估什么的。 一般来说,2 到 3 天没有消息的话,感觉都不会非常靠谱,所以也没有抱有太大希望。 只是希望的是,他们应该可以通过更好的沟通让整个流程更加好,可惜他们没有做到,有点把面试当儿戏的意思。 题目和解答 Program 1 Using input_data1.txt, complete the code in file program1.exs You can install Elixir on a machine you work on, or you can use Try It Online or something similar. tio has an input section where you can paste in the input data. input_data1.txt (3.6 KB) 源代码如下: defmodule M do def read do IO.read(:stdio,:all) end def input_to_list( input ) do # turn single string into a list of input values String.split(input) end def calculate([head | tail], acc) do calculate( tail, head + acc ) end # finish def calculate( [], acc ) do acc end end IO.inspect M.read() |> M.input_to_list |> M.calculate(0) Program 2 Extending the technique of Program 1, write a program that given 3 lists, selects the greatest even value at each iteration and adds it to an accumulator. For example: [ 5, 8, 9, 2, 4, 7 ] [ 9, 1, 6, 7, 9, 6 ] [ 4, 4, 8, 6, 2, 4 ] sums the list: [ 4, 8, 8, 6, 4, 6 ] and a sum of 36 The lists to use are: [184, 89,…
最近项目中有关 JSON 的序列化和反序列化中,我们遇到了一个问题就是 category_id 我们在定义对象的时候使用的是 categoryId。 当程序进行反序列化的时候,我们获得的对象值为 NULL。 这是因为 jackson 提供了一个命名规则,如果你是希望进行这种类型的映射的话,那么需要把命名映射规则设置为:SNAKE_CASE objectMapper 对象初始化的时候设置 有 2 种设置方法,如果你希望你在 objectMapper 对象初始化的时候进行设置,那么需要添加下面的代码: objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); 那么这样,我们就等于告诉 objectMapper 在对对象进行序列化和反序列化的时候,使用 SNAKE_CASE 命名方式。 @JsonNaming 注解 可以在直接需要进行序列化和反序列化的类中使用: @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) 上面的代码就可以了。 这样的意思就是不管是不是全局设置了命名规则,只要用到了这个类的序列化和反序列化都会使用上面的规则来进行字段映射。 那种方式更好 对我们当前的项目来说,我们可能更加倾向使用注解的方式。 需要知道的是 objectMapper 对象的初始化可能在不同的服务类中被初始化多次。 当然如果你使用的是 Spring 的配置文件,那么可以一次配置完成。 延伸阅读 Jackson 中的配置方式,不仅仅只有上面我们提到的,还有下面的几种方式。 SNAKE_CASE:所有字母均为小写,并在名称元素之间使用下划线作为分隔符,例如 snake_case。 UPPER_CAMEL_CASE: 所有名称元素,包括第一个,都以大写字母开头,后跟小写字母,并且没有分隔符,例如 UpperCamelCase。 LOWER_CAMEL_CASE: 所有名称元素,包括第一个,都以小写字母开头,后跟小写字母,并且没有分隔符,例如 UpperCamelCase。 这个配置方式是默认的配置方式。 LOWER_CASE:所有字母均为小写字母,没有分隔符,例如 lowercase。 KEBAB_CASE:名称元素之间用连字符分隔,例如 kebab-case。 LOWER_DOT_CASE:所有字母均为小写字母,用点连接字符,例如 lower.case。 根据 Java 和 Json 的命名规范来说,其实大家都有点乱命名,但对一些比较规范的项目,通常单词之间我们使用下划线多。 我们并不太使用横杠的方式来处理命名。 所以,很多时候,你可能需要使用 SNAKE_CASE 来标记你的命名规则。 https://www.isharkfly.com/t/jackson-snake-case/15034