自动编码器在野外去除遮挡

Jetpack Compose is a upcoming declarative UI framework for Android with many new features provided by its compiler plugin and smart runtime. As a long-time Kotlin enthusiast, I was amazed when it was announced a year ago and still discover something new in there every now and then.

Jetpack Compose是即将发布的Android声明性UI框架,其编译器插件和智能运行时提供了许多新功能。 作为Kotlin的长期狂热者,一年前宣布它时,我感到非常惊讶,但仍然时不时地在其中发现新的东西。

However, the Compose story doesn’t end on “just” building UI. Even during the first talks describing magic behind the curtain, the library goal was defined as “to efficiently build and maintain tree-like data structures”. It opens a door to create your custom dynamic hierarchies (not necessarily tied to visuals) with all the benefits of caching and incremental updates.

但是,“撰写”的故事并不仅限于“仅”构建UI。 甚至在描述魔术背后的第一次演讲中,库的目标也被定义为“有效地构建和维护树状数据结构”。 它为创建具有缓存和增量更新的所有优势的自定义动态层次结构(不一定与视觉效果相关)打开了一扇门。

It is still quite hard to imagine tree structures dynamic enough to require Compose, practical enough to implement, and far enough from UI at the same time. After going back and forth, I decided to experiment with managing the structure of a webpage, similar to how SwiftUI was applied before.

很难想象树结构具有足够的动态性以要求Compose,足够实用以实现并且距UI足够远。 反复研究之后,我决定尝试管理网页的结构,类似于以前的 SwiftUI 应用程序 。

What exactly does it do? It allows you to define a webpage and user interactions in a Compose way, similar to its Android implementation. Of course, it is hard to port many concepts directly, as you can not, for example, use constraints for laying out elements. However, if you squint hard enough, it does look quite similar to how you could write it on mobile.

它到底是做什么的? 它允许您以Compose方式定义网页和用户交互,类似于其Android实现。 当然,很难直接移植许多概念,因为例如您不能使用约束来布置元素。 但是,如果您斜视了一下,它的确看起来与在移动设备上书写的方式非常相似。

The snippet above results in the following screen:

上面的代码段显示以下屏幕:

live on Heroku!在Heroku上试用它!

So what exactly happening here and how does it work?

那么,这里到底发生了什么以及它如何工作?

撰写网页 (Composing a Web page)

Managing the DOM is extremely close to the original goal Compose was created for. It is a tree-like structure of visual elements (check!) which is also highly dynamic, while updating with user input (check!!). The frontend community has produced many interesting solutions in JavaScript (including this one-pager), so it seems feasible to try Compose here as well. The only problem is: at the time of writing this article, none of its components actually work in the browser.

管理DOM非常接近Compose的最初目标。 它是视觉元素(检查!)的树状结构,具有很高的动态性,同时可以通过用户输入进行更新(检查!)。 前端社区已经用JavaScript(包括此pager )产生了许多有趣的解决方案,因此在这里尝试Compose似乎也是可行的。 唯一的问题是:在撰写本文时,它的所有组件实际上都无法在浏览器中工作。

As execution on the client wasn’t an option, I went for the same approach as SwiftWebUI author did: running it on a server. This is how it works:

由于无法在客户端上执行,因此我采用了与SwiftWebUI作者相同的方法:在服务器上运行它。 它是这样工作的:

  • Compose starts with some initial state which results in the server-side representation of a webpage.撰写以某种初始状态开始,该初始状态导致网页的服务器端表示。
  • This representation is sent to the client as commands of adding/removing/moving nodes through websocket. The client then changes the structure of the webpage according to commands received from the server.该表示作为通过websocket添加/删除/移动节点的命令发送给客户端。 然后,客户端根据从服务器接收的命令来更改网页的结构。
  • When a client event happens (for example click), it is sent to the server. Here, the state is updated with the new changes. It yields a different structure of the DOM, and these updates are sent to the client, refreshing the webpage.发生客户端事件(例如,单击)时,会将其发送到服务器。 在此,状态将通过新的更改进行更新。 它产生了DOM的不同结构,并将这些更新发送到客户端,刷新了网页。

This implementation still puts a lot of constraints on what we can do in terms of interactivity. For the scope of this experiment, however, it is more than enough.

这种实现方式在交互性方面仍然给我们带来了很多限制。 但是,对于本实验的范围,这已绰绰有余。

在服务器端组成 (Composing on the server side)

Compose is developed as a purely Android library, so many pieces won’t work for the server. Thankfully, developers have separated it into multiple packages and we can pick and choose whatever we want. For example, we have compose-runtime with under-the-hood machinery, ui module for basic interaction with Android systems, ui-material for implementation of material components and themes, and many more. The first one (the runtime) is what we need to adapt to make this project possible.

Compose是作为纯粹的Android库开发的,因此许多内容对服务器不起作用。 幸运的是,开发人员已将其分成多个包,我们可以选择所需的任何东西。 例如,我们使用compose-runtime ,用于与Android系统进行基本交互的ui模块,用于实现实质性组件和主题的ui-material等。 第一个(运行时)是我们需要进行调整以使该项目成为可能。

To launch the runtime in a server environment, we need to substitute everything that links it to Android with server counterparts. UI frameworks are often tied to the main thread and other platform specifics, so it may seem quite hard. In reality, it was super easy, barely an inconvenience: JetBrains is currently collaborating with Google to bring Compose to multiplatform, so most of the required expect / actual bindings were already there.

要在服务器环境中启动运行时,我们需要用服务器副本替换将其链接到Android的所有内容。 UI框架通常与主线程和其他平台特定联系在一起,因此似乎很难。 实际上,这非常容易,几乎没有任何麻烦 :JetBrains当前正在与Google合作,将Compose引入多平台,因此大多数所需的expect / actual绑定已经存在。

You can see the full list of required bindings here. To highlight, we mimic the main thread with a single thread CoroutineDispatcher and stub some other APIs based on their definition for desktop.

您可以在此处查看所需绑定的完整列表。 突出显示,我们用单线程CoroutineDispatcher模仿了主线程,并根据其对桌面的定义对一些其他API进行存根。

For the server environment, Ktor was the best choice. It is a web server developed by JetBrains which has perfect integration with coroutines and exposes configuration as expressive DSL. An additional package gives us websockets, and we can use feature extension API to integrate Compose into the server seamlessly.

对于服务器环境, Ktor是最佳选择。 它是由JetBrains开发的Web服务器,它与协程具有完美的集成,并将配置公开为可表达的DSL。 额外的软件包为我们提供了websocket,我们可以使用功能扩展API将Compose无缝集成到服务器中。

组成一棵树 (Composing a tree)

After the runtime is up and running, it is time to create a representation of a webpage on a server side. Running through the internals of already existing Compose elements, I ended up with the following structure:

运行时启动并运行之后,就该在服务器端创建网页的表示形式了。 通过已经存在的Compose元素的内部运行,我得到了以下结构:

sealed class HtmlNode {class Tag(val tag: String): HtmlNode() {private val children: List<HtmlNode> = mutableListOf()// wordy implementations copy-pasted from composefun insert(index: Int, instance: HtmlNode) fun move(from: Int, to: Int, count: Int)fun remove(index: Int, count: Int)}class Text() : HtmlNode() {var text: String? = null}
}

This representation of the DOM distinguishes two types of elements:

DOM的这种表示法区分两种类型的元素:

  • Tag, which contains the name of the HTML node and may have some children. Order of child nodes is manipulated through public methods with simple list operations.标记,其中包含HTML节点的名称,并且可能有一些子代。 子节点的顺序通过使用简单列表操作的公共方法进行操作。
  • Text, always a leaf node with text values only.文本,始终是仅包含文本值的叶节点。

These nodes can now be expressed as @Composable functions:

这些节点现在可以表示为@Composable函数:

@OptIn(ExperimentalComposeApi::class)
class ServerApplyAdapter(root: HtmlNode
) : AbstractApplier<HtmlNode>(root) {override fun insert(index: Int, instance: HtmlNode) {tag().insertAt(index, instance)}override fun remove(index: Int, count: Int) {tag().remove(index, count)}override fun move(from: Int, to: Int, count: Int) {tag().move(from, to, count)}override fun onClear() {// no-op}private fun tag(): HtmlNode.Tag =when (val node = current) {is HtmlNode.Tag -> nodeis HtmlNode.Text -> throw IllegalStateException("Only tag can have children")}
}@Composable
fun tag(tagName: String) {emit<HtmlNode.Tag, ServerApplyAdapter>(ctor = {  HtmlNode.Tag(tagName) },update = { },children = children)
}@Composable
fun text(value: String) {emit<HtmlNode.Text, ServerApplyAdapter>(ctor = {  HtmlNode.Text() },update = {set(value) { value -> this.value = value }})
}

We need an ApplyAdapter which controls how we add nodes to the tree. Here, we delegate to methods of aTag class for all operations. This adapter is then used with emit function to link @Composable functions to the tree by interacting with the composer. It has three parameters to control the resulting structure:

我们需要一个ApplyAdapter来控制如何将节点添加到树中。 在这里,我们为所有操作委托Tag类的方法。 然后,此适配器与emit函数一起使用,以通过与作曲者进行交互将@Composable函数链接到树。 它具有三个参数来控制结果结构:

  • Constructor, describing how the node is created. Every change in the captured parameter here will result in Compose recreating the node. tag function is the perfect example: in the browser, most tags have different representations. For instance, <input> actually has underlying type of HTMLInputElement, so, when changing tag to <div>, we need to create new HTMLDivElement to replace it.

    构造函数,描述如何创建节点。 此处捕获的参数的每次更改都会导致Compose重新创建节点。 tag功能就是一个很好的例子:在浏览器中,大多数标签具有不同的表示形式。 例如, <input>实际上具有HTMLInputElement基础类型,因此,将标记更改为<div> ,我们需要创建新的HTMLDivElement来替换它。

  • Update, defining how the element is updated. It is useful to avoid removing/adding the element every time a simple value update will suffice. text is a good example of this, we don’t need to replace the whole node every update, changing inner value instead.

    更新,定义如何更新元素。 避免每次简单的值更新就足以删除/添加元素,这很有用。 text就是一个很好的例子,我们不需要每次更新都替换整个节点,而是更改内部值。

  • Children, propagating other elements down the tree.孩子们,在树上传播其他元素。

Now we can use these definitions to build a simple structure from tags:

现在我们可以使用这些定义从标签构建一个简单的结构:

@Composable
fun Example() {tag("div") {tag("p") {text("Paragraph 1")}tag("p") {text("Paragraph 2")}tag("button") {text("A Button")}}
}

通过WebSocket编写 (Composing through a WebSocket)

After building the tree, the next tricky part is client-server communication. It consists of two parts: passing node updates to the client and sending events back.

构建树之后,下一个棘手的部分是客户端-服务器通信。 它由两部分组成:将节点更新传递给客户端并将事件发送回。

Node updates are mostly caused by client events in our case. For example, clicking on a button can display/hide an element:

在我们的案例中,节点更新主要是由客户端事件引起的。 例如,单击按钮可以显示/隐藏元素:

@Composable
fun Component(hasDiv: Boolean) {// Note that Component does not add anything to tree directly// Only calls to emit change "virtual DOM"// Here it is called from div -> tag -> emitif (hasDiv) {div() // <-- adding or removing node here based on parameter, updating tree}
}@Composable
fun Test() {// Changing this state results in re-execution of places it used invar hasDiv by state { false }// For example, state can be changed based on event from user (click)button(onClick = { hasDiv = !hasDiv })// This function will be re-invoked whenever hasDiv changes valueComponent(hasDiv)
}

Compose already does the diffing for tree changes (add/move/remove), so we can hook into ApplyAdapter methods and dispatch commands to the client from there. It also takes care of the initial state, which is sent to the client as a sequence of additions. Properties (like value in Text) are updated without calls to ApplyAdapter, but we can catch them through a custom setter.

Compose已经进行了差异更改(添加/移动/删除),因此我们可以使用ApplyAdapter方法并将命令从那里分发给客户端。 它还照顾初始状态,该初始状态作为添加序列发送到客户端。 属性(例如Text value )将在不调用ApplyAdapter情况下进行更新,但是我们可以通过自定义设置器捕获它们。

To make this work, every node needs to have access to a websocket connection. It would be quite annoying to pass it through each level of calls, and Compose has a utility just for that. Ambient allows us to propagate some elements without explicitly keeping them as parameters. It is used in Android to provide Context or Theme, so we will do a similar thing for the server:

为了使此工作有效,每个节点都必须有权访问websocket连接。 在每个级别的调用中传递它都会很烦人,而Compose为此提供了一个实用程序。 Ambient允许我们传播某些元素而无需明确地将它们保留为参数。 它在Android中用于提供ContextTheme ,因此我们将对服务器执行类似的操作:

private val CommandDispatcherAmbient = staticAmbientOf<RenderCommandDispatcher>()// Instantiate it
composition.setContent {Providers(CommandDispatcherAmbient provides commandDispatcher) {composable()}
}// Use it
@Composable
fun tag(tagName: String,children: @Composable() () -> Unit
) {val renderCommandDispatcher = CommandDispatcherAmbient.currentemit<HtmlNode.Tag, ServerApplyAdapter>(ctor = { HtmlNode.Tag(renderCommandDispatcher, tagName) },update = { },children = children)
}

The second part (client events) was a bit harder to tackle. The main problem is to make sure the event is propagated to the right node and there it invokes the right callback. After playing around with different ways of expressing them, I have settled on the following structure:

第二部分(客户事件)较难解决。 主要问题是确保事件传播到正确的节点,并在那里调用正确的回调。 在尝试了不同的表达方式后,我决定采用以下结构:

  • Each node now has a new id field, which serves as a method of matching them between client and server.

    现在,每个节点都有一个新的id字段,用作在客户端和服务器之间匹配它们的方法。

  • We introduce a new entity that is similar to CommandDispatcher but works the other way around, listening to websocket and distributing updates to events.

    我们引入了一个类似于CommandDispatcher的新实体,但以CommandDispatcher的方式工作,它监听websocket并将事件的更新分发。

  • Each event is defined with the following structure:每个事件都有以下结构定义:
object Click : Event {override val type: String = "click"object Payload : Event.Payload<Click> {override val descriptor: Click = Click}class Callback(override val onReceive: (payload: Payload) -> Unit) : Event.Callback<Click, Payload> {override val descriptor: Click = Click}
}@Composable
fun Test() {// usagevar counter by state { 0 }val clickEvent = Click.Callback { counter++ }tag(tagName = "button", events = listOf(clickEvent))
}

It consists of three parts: type serves as an identifier, Payload provides a way to pass values from the client in a type-safe way, and Callback invokes lambda with payload to update things in Compose world. All those elements are matched by descriptor, which ties them together inside the node.

它由三部分组成: type用作标识符, Payload提供一种以类型安全的方式从客户端传递值的方法,而Callback函数调用具有有效载荷的lambda来更新Compose世界中的事物。 所有这些元素都由descriptor匹配,该descriptor将它们在节点内绑定在一起。

This system is not ideal, but it is extensible (allows you to define custom events) and customizable (those events can be tied to any JS/Server code). You can also check out definitions of other events here or how to process them on the server or client.

这个系统不是理想的,但是它是可扩展的(允许您定义自定义事件)和可自定义的(那些事件可以绑定到任何JS / Server代码)。 您还可以在此处查看其他事件的定义,或如何在服务器或客户端上处理它们。

更好地构图 (Composing it better)

With the composition and events running, now it was the time to think about expanding functionality. On this stage, I created a couple of components which defined tags, but the parameters were getting a bit out of control:

随着组合和事件的运行,现在是时候考虑扩展功能了。 在这个阶段,我创建了几个定义标签的组件,但是参数有些失控了:

@Composable
fun input(value: String,type: String,onChange: (String) -> Unit,onKeyUp: (String) -> Unit
) {tag(tagName = 'input',attributes = mapOf('value' to value, 'type' to type),events = listOf(Change.Callback { onChange(it.value) }, KeyUp.Callback { onKeyUp(it.value) })
}

Experimenting with inline CSS, I realized that it required a much more flexible system. Looking for inspiration in original libraries, I found out that many similar cases were handled with Modifier instances, and it worked for me perfectly as well.

通过试验内联CSS,我意识到它需要一个更加灵活的系统。 在原始库中寻找灵感时,我发现许多类似的案例都是通过Modifier实例处理的,它对我也非常有效。

Modifiers create a linked list where elements are chained with others using Kotlin extension functions. Using them hides optional parameters from the signature in a type-safe way, converting the example above into this:

修饰符会创建一个链接列表,在其中使用Kotlin扩展功能将元素与其他元素链接在一起。 使用它们以类型安全的方式从签名中隐藏可选参数,将上面的示例转换为:

@Composable
fun input(type: String,value: String,modifier: Modifier = Modifier
) {tag(tagName = 'input',modifier = modifier.type(type).value(value))
}// usage
input(type = "text",value = "",modifier = Modifier.onChange { }
)

This system provides some basic modifiers, and later they can be extended with more concrete ones. For example, all HTML tag attributes are defined as a basic modifier of attribute(String, String). Later they are refined with more precise definitions, e.g. with type(String) on input and so on. Taking this further, we can provide scoping (flex parameters inside of display: flex parents) and type safety (enums or integers instead of strings as parameters).

该系统提供了一些基本的修饰符,以后可以使用更具体的修饰符进行扩展。 例如,所有HTML标记属性都定义为attribute(String, String)的基本修饰符。 后来用更精确的定义完善了它们,例如在输入上使用type(String)等。 进一步讲,我们可以提供作用域( display: flex内部的弹性参数display: flex父母)和类型安全性(枚举或整数而不是字符串作为参数)。

Jetpack Compose is much more than a UI toolkit made exclusively for Android. I can definitely see how it can be applied in multiplatform to power many Kotlin projects.

Jetpack Compose不仅限于专门为Android设计的UI工具包。 我绝对可以看到它如何在多平台中应用以支持许多Kotlin项目。

At the same time, API surface of the core functionality is very minimal. The compiler plugin takes the route of minimal invasion, providing restartable functions with cacheable calls transparently for the user. This is then leveraged by runtime with all the tree building functionality and other tooling. I am very surprised of all the new possibilities provided with such a small change to the language.

同时,API表面的核心功能非常少。 编译器插件采用了最小限度的入侵途径,为用户透明地提供可重新启动的功能以及可缓存的调用。 然后,运行时将其与所有树构建功能和其他工具一起利用。 只需对语言进行很小的更改,我就会为所有新的可能性感到惊讶。

The project was a huge learning experience for me, pushing the boundaries of what Compose can do on its current stage of development. The approach I have taken puts a barrier on many interactions, as it is relying on fast communication between client and server, which is not the case for the majority of users. It can certainly be improved with a browser runtime whenever Compose supports either JS or WASM in full.

该项目对我来说是一次巨大的学习经验,在当前的开发阶段突破了Compose可以做到的范围。 我采用的方法在许多交互方面都设置了障碍,因为它依赖于客户端和服务器之间的快速通信,而对于大多数用户而言,情况并非如此。 只要Compose完全支持JS或WASM,肯定可以通过浏览器运行时进行改进。

The source code is available on Github and is separated into 4 modules:

源代码在Github上可用,并分为4个模块:

  • runtime with updated actuals,

    具有更新的实际值的运行时 ,

  • server part as a Ktor feature,

    服务器部分作为Ktor功能,

  • browser runtime,

    浏览器运行时

  • and integration module, containing both server and client code with the “business logic” of the demo.

    和集成模块 ,包含服务器和客户端代码以及演示的“业务逻辑”。

You can try it yourself online, or play with the repo using deploy branch, which keeps prebuilt jar for compose-runtime.

您可以自己在线尝试,也可以使用deploy分支来使用repo,该分支保留了预构建的jar,以供compose-runtime使用。

You can find me on Twitter, where I am sharing random thoughts about Android, Kotlin, and other things I find exciting along the way.

您可以在 Twitter上 找到我 我在 这里分享有关Android,Kotlin以及沿途中其他令人兴奋的事物的随机想法。

翻译自: https://medium.com/@shikasd/composing-in-the-wild-145761ad62c3

自动编码器在野外去除遮挡


http://www.taodudu.cc/news/show-2732566.html

相关文章:

  • Python总结-学习方向和方法
  • 力扣LeetBook<链表>学习笔记
  • FLASK学习笔记
  • 英语单词学习总结
  • 为什么要做访问学者?
  • 脑机接口、开源和民主化增强意识的未来
  • 预测:深度学习未来的6种可能
  • Guitar Pro8最新2023中文免费吉他乐谱作曲练习工具
  • 【译文】学习深度学习的四个步骤
  • 超级节点MLN012-算法作曲
  • spotify mp3_创建无监督学习的Spotify播放列表
  • 机器学习诗词创作_通过机器学习创作音乐
  • 机器学习与网络安全(一)
  • tt作曲家简谱打谱软件_作曲家入门指南
  • 【机器学习】推荐几款很流行的面向 Javascript 的机器学习库
  • Guitar Pro2023吉他谱作曲和练习工具
  • mysql数据库教程级联_Mysql实现级联操作(级联更新、级联删除)
  • mysql 级联复制
  • 存储级联模块
  • oracle中删除级联方法,Oracle 外键级联删除
  • mybatis 级联查询
  • java级联_Java构造器:级联调用,调用兄弟构造器
  • OpenCV57:级联分类器的训练
  • html级联选择器,jquery实现 级联选择器
  • mysql级联更新_Mysql实现级联操作(级联更新、级联删除)(转)
  • java 级联删除_Mybatis 级联删除的实现
  • jpa级联添加_jpa级联(Cascade)操作
  • 级联分类
  • mysql级联是什么意思_MySql级联操作
  • oracle 允许级联删除,oracle系列--级联删除和级联更新

自动编码器在野外去除遮挡_在野外作曲相关推荐

  1. 图片还原去遮挡_如何把人像照片上的遮盖物去除看到原来人像?

    如何把人像照片上的遮盖物去除看到原来人像? 虽然目前的图像后期软件很强大,但恢复本来不存在的内容还是很困难的,那就不是恢复,而是画了.所以题主提到的的覆盖物遮挡的内容也是有一定前提条件的,当然遮挡物越 ...

  2. 野外偷拍_野外紧急设计

    关于本系列 本系列文章旨在为人们经常讨论但难以捉摸的软件体系结构和设计概念提供新的视角. 通过具体的示例,尼尔·福特为您提供了进化架构和紧急设计的敏捷实践的坚实基础. 通过将重要的架构和设计决策推迟到 ...

  3. 模糊图像处理 去除模糊_图像模糊如何工作

    模糊图像处理 去除模糊 定义 (Definition) Roughly speaking, blurring an image is make the image less sharp. This c ...

  4. 微信图片去除马赛克_照片怎么去水印,去除图片水印的简朴方式,微信公众号引流的21种方法...

    前几天办公室的小喵恰好提及要换手机壁纸的事情,说是想要把她偶像的照片设置成壁纸,然则照片上有水印,影响到壁纸的整体效果. 实在吧,这事儿很容易解决,把图片上的水印去掉较好啦~若是你不知道怎么在保证原图 ...

  5. 怎么去除php,php怎么去除字符_后端开发

    php怎么禁止访问.php文件_后端开发 php禁止访问的方法:首先在打开需要紧张访问的php文件:然后在该文件的头部添加代码为"$fromurl="//www.xxx.net/& ...

  6. js手机键盘遮挡_完美解决手机网页中输入框被输入法遮挡的问题

    之前要做一个弹出对话框,填写信息,发现在手机上看的时候,较后的输入框在填写信息时,输入框被输入法遮挡,只能盲填. 前提 1.弹出的对话框用display:fixed定位的 2.对话框大小固定 解决办法 ...

  7. python 去除str的引号 去除括号_用python进行图像修复与去除水印

    有时候我们在看知乎的时候,会突然发现一张很好看的图片,想据为己有,猥猥琐琐的准备长按图片保存,发现图片上居然带了水印,这个时候该怎么办呢?哈哈哈,直接裁剪掉不就好了吗~~~ 但是,作为一个新时代的程序 ...

  8. 怎么去除标题_未来健康家:怎么快速祛除甲醛

    原标题:未来健康家:怎么快速祛除甲醛 甲醛这个词大家并不陌生,特别会经常听说新买的房子装修后会有一种污染物叫做甲醛,还有新买的车也会有甲醛.那么我们应该怎样除甲醛呢? 自然通风促进挥发 通风和种植绿植 ...

  9. python字符计数怎样去除空格_去除python中的字符串空格的简单方法

    python编程中,我们在修改代码,遇到空格很多的情况下,我们要删除空格.本文小编整理了三种字符串去除空格的方法: 方法一:使用字符串函数replace,去除全部空格. 实例: >>> ...

最新文章

  1. 表贴3.3V稳压芯片 PL3500测试 低压差线性稳压器
  2. C++重载>>和<<输入和输出运算符)
  3. SQL语句之left join、right join、inner join的区别
  4. JavaScript动画知多少?
  5. java虚拟机手动内存分配_《深入理解java虚拟机》-垃圾收集器与内存分配策略
  6. 2020 豆瓣电影榜单出炉,直接在豆瓣上看电影吧
  7. MySql 集群/主从
  8. JAVA计算机毕业设计中药分类管理系统Mybatis+源码+数据库+lw文档+系统+调试部署
  9. 12月21诛仙服务器维护,12月24日全服停机更新维护公告
  10. Intent intent =new Intent(getActivity(),DeliverListActivity.class,Cannot resolve method'getActivity'
  11. python输入某年某月某日歌词_python求输入某年某月某日,判断这一天是这一年的第几天...
  12. 漫谈历法、闰年与闰月
  13. left join一对多只保留一条结果的解决方法
  14. 07_Python3.6+selenium2.53.6自动化测试_通过id定位百度输入框
  15. (初学)JDBC实现增删改查 一(Statement接口)
  16. SXSSFWorkbook 表格内换行
  17. python和java哪个好薪资高-Java和Python哪个薪资更高?
  18. 深度学习目标检测模型综述
  19. 宇宙最简单排序:桶排序
  20. 联想笔记本怎么开启vt模式?

热门文章

  1. 解决FFMPEG错误:height not divisible by 2 / width not divisible by 2
  2. Learn-设计模式系列-①七大原则
  3. 【渝粤教育】 国家开放大学2020年春季 1332中文学科论文写作 参考试题
  4. 仅需24小时,带你基于PaddleRec复现经典CTR预估算法
  5. 写代码时发现……还是Python牛逼
  6. 哈工大ltp词性标注列表和ICTCLAS词性列表
  7. 5.node.js中的事件循环
  8. 手把手带你分解 Vue 倒计时组件
  9. 完美解决:“已损坏,无法打开。 您应该将它移到废纸篓。”
  10. mui获取手机设备信息