AI coding demo painting on texture1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68// --- 创建模型和画布纹理 ---
const canvas = document.createElement('canvas');
canvas.width = 1024;
canvas.height = 1024;
const context = canvas.getContext('2d');
context.fillStyle = '#ffffff';
context.fillRect(0, 0, canvas.width, canvas.height);
const texture = new THREE.CanvasTexture(canvas);
texture.minFilter = THREE.LinearFilter;
texture.magFilter = THREE.LinearFilter;
const material = new THREE.MeshStandardMaterial({
map: texture,
roughness: 0.8,
metalness: 0.2,
});
const geometry = new THREE.SphereGeometry(2, 64, 64);
const sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);
// --- 射线投射和鼠标事件 ---
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
let isPainting = false;
function onMouseMove(event) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
if (isPainting) {
paint();
}
}
function onMouseDown(event) {
isPainting = true;
paint();
}
function onMouseUp(event) {
isPainting = false;
}
window.addEventListener('mousemove', onMouseMove);
window.addEventListener('mousedown', onMouseDown);
window.addEventListener('mouseup', onMouseUp);
// --- 核心绘制函数 ---
function paint() {
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObject(sphere);
if (intersects.length > 0) {
const intersect = intersects[0];
const uv = intersect.uv;
const x = uv.x * canvas.width;
const y = (1 - uv.y) * canvas.height;
const brushRadius = 20;
context.fillStyle = '#ff0000'; // 红色笔刷
context.beginPath();
context.arc(x, y, brushRadius, 0, Math.PI * 2);
context.fill();
texture.needsUpdate = true;
}
}
EventBus
以发布订阅实现的消息中转 如
- eventbus = new Vue()
- ng emit on
…
常称事件总线
1 | class EventBus { |
Blender
Vue Router
面试补充(2026-07-22)
本节为后续补充,用于资深软件工程师基础面试复习;原文章此前只有标题信息。
Router 负责客户端导航,不负责服务端授权
Vue Router 将 URL 映射为组件树,并协调导航、历史记录、守卫和滚动等客户端行为。它能改善单页应用的页面组织和访问体验,但不能建立安全边界:
- 隐藏菜单、拒绝进入页面和不注册某条路由,只能减少客户端入口。
- 用户仍可绕过页面直接调用 API,服务端必须根据可信身份再次执行认证、授权和资源范围检查。
- 路由
meta是前端约定的数据,不是不可篡改的权限声明。
面试中应先把“认证是谁”“授权能做什么”“前端路由是否可见”三个问题分开。
Hash 与 HTML5 History
createWebHashHistory() 使用 URL 的 # 之后部分。fragment 不会作为 HTTP 请求路径发送给服务器,因此静态服务器通常不需要额外回退规则,但 URL 不够自然,也不适合依赖服务端理解完整路径的场景。
createWebHistory() 使用浏览器 History API,URL 更接近普通多页站点。直接访问或刷新 /devices/42 时,浏览器会向服务器请求这个路径,因此部署必须配置 SPA fallback:未知的前端路由返回入口 HTML;真实静态资源、API、下载文件和健康检查路径不能被错误重写为入口页面。
选择哪种模式不是 Vue 性能问题,而是 URL、部署环境、服务端配置和兼容性的取舍。
路由记录、参数、嵌套与懒加载
一条路由记录通常包含 path、component、children、name、meta 和 props 映射。需要注意:
- 动态参数
/devices/:id表示同一类页面的不同资源,不应为每台设备注册一条静态路由。 - 嵌套路由描述 URL 与 UI 的嵌套关系,父组件需要提供
<RouterView>作为子路由出口。 - 路由组件使用动态
import()可以按页面拆包,但拆得过细会增加请求和调度开销,应结合访问路径和产物分析决定。 - 优先通过
props将参数传给页面组件,可减少组件对全局route对象的耦合,便于复用和测试。 - 参数来自 URL,始终是外部输入。即使 TypeScript 给它声明了类型,也仍要校验格式和业务范围。
导航守卫的职责分层
守卫适合完成导航决策,而不适合塞入所有页面业务:
- 全局守卫处理登录态初始化、通用权限入口、租户或空间切换等跨页面规则。
- 路由独享守卫处理少数路由特有的进入条件。
- 组件内或 Composition API 守卫处理未保存编辑、当前资源切换和组件上下文相关行为。
守卫应返回导航结果或 Promise。Vue Router 4 中通常不再混用旧式 next() 回调,以免一次导航中重复调用或遗漏调用。不要为了面试机械背完整执行顺序;更重要的是能解释每类逻辑属于全局、路由还是组件,以及异常和取消如何收敛。
1 | import { createRouter, createWebHistory } from 'vue-router' |
这里使用 localStorage 只是为了突出守卫返回值,并不是完整的安全令牌存储方案。真实系统还需考虑 XSS、Cookie 属性、令牌刷新、退出失效和服务端会话策略。无论前端如何保存状态,设备 API 都必须在服务端重新鉴权。
登录、角色与动态路由
常见流程是:应用启动后恢复登录态,获取当前用户的能力集合,再生成菜单或通过 router.addRoute() 注册可访问页面。这个方案可以减少无权限页面暴露并支持插件式模块,但要处理:
- 刷新页面时,首次路由匹配可能早于权限路由加载,需要一个明确的初始化屏障。
- 退出登录或切换租户时要移除旧动态路由、缓存页面和领域状态,避免身份串线。
- 不要直接把后端返回的组件路径交给任意动态导入;应通过受控映射表把权限标识映射到本地组件。
- 菜单、路由和按钮最好消费同一份能力模型,减少三套条件逐渐不一致。
即使这些步骤全部正确,前端仍只完成体验层控制。服务端授权才决定用户能否读取某台设备、下发某类命令或查看某个空间的数据。
组件复用、请求竞态与缓存
从 /devices/1 导航到 /devices/2 时,路由记录和组件类型没有变化,Vue Router 可能复用同一组件实例,mounted 不会再次执行。页面应监听参数或使用 onBeforeRouteUpdate() 重新加载资源。
1 | import { onBeforeUnmount, ref, watch } from 'vue' |
真实代码还要区分主动取消和网络错误,并在写入状态前确认请求仍对应当前资源。若不能取消底层请求,可使用递增请求编号忽略迟到结果。
KeepAlive 缓存的是组件实例,不是 HTTP 响应缓存。缓存路由页后需要考虑:数据何时失效、订阅在 activated/deactivated 时如何暂停恢复、缓存上限和退出登录时怎样清理。用 :key="$route.fullPath" 强制每个 URL 生成实例虽然简单,却可能扩大缓存并掩盖状态所有权问题。
导航也可能被守卫取消、重定向或判定为重复。调用 router.push() 后若业务需要区分结果,应等待返回的 Promise,并用 Vue Router 提供的 navigation failure API 判断,而不是假设 URL 一定已经改变。
常见追问与回答边界
History 模式刷新为什么出现 404?
客户端导航时由 Router 接管 URL;刷新时是服务器直接收到深层路径。服务器若没有对应文件或 SPA fallback 就返回 404。修复时要排除 API 和静态资源路径,不能把所有 404 都改成 HTML 200。
路由守卫能否防止越权?
不能。它只能控制当前客户端应用如何导航。攻击者可以修改前端状态或直接请求 API,服务端必须执行授权。
为什么换了路由参数却没有重新请求?
相同路由记录通常复用组件实例,依赖 mounted 的加载逻辑不会重跑。应监听目标参数或使用路由更新守卫,并处理旧请求的取消或失效。
动态路由是否等于动态权限?
不等于。动态路由是客户端页面注册机制;权限模型来自可信后端,真正的资源和操作授权仍由服务端实施。
微前端 - Micro App
Web Component
w3c提出浏览器原生支持的组件规范 通过扩展HTMLElement定义html标签 嵌入内容和逻辑(shadow dom隔离)
- 接入简单不需要子应用改造
- 不支持ie
- Web Component沙箱隔离 性能较好
集成
1 | npm i @micro-zoe/micro-app -S |
主应用入口1
2
3
4// src/index.js
import microApp from '@micro-zoe/micro-app'
microApp.start()
contianer组件1
2
3
4
5
6
7
8
9
10
11<template>
<div>
<h1>子应用</h1>
<!--
name(必传):应用名称
url(必传):应用地址,会被自动补全为http://localhost:3000/index.html
baseroute(可选):基座应用分配给子应用的基础路由,就是上面的 `/my-page`
-->
<micro-app name='learnvue' url='http://localhost:8081/' baseroute="/dentition"></micro-app>
</div>
</template>
微前端-qiankun
微前端场景
- 老系统架构陈旧 重构难度大 部分需要与时俱进的功能得不到升级
- 不同模块需要多个团队参与 尤其专业和技术栈有差异
- A系统若干功能或页面被B系统引用
Techniques, strategies and recipes for building a modern web app with multiple teams that can ship features independently. — Micro Frontends
微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。
qiankun方案缺点
- 改造和适配成本高 如微应用打包、入口生命周期,以及router问题
- js沙箱性能问题
- 不支持激活多个微应用 不支持微应用保活
工作流
父应用:安装微前端组件 —> 预留容器dom —> 用组件提供的方法注册子系统
子应用:暴露生命周期钩子
1 | npm i qiankun -S |
register和start都在container的组件层级上 不一定是在顶级组件上 尤其在使用router和模块懒加载的应用中1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32<template>
<div id="viewport">
<div id="subapp-root"></div>
</div>
</template>
<script>
import { registerMicroApps, start } from 'qiankun'
export default {
name: '',
data () {
return {}
},
mounted () {
// 注册微应用
registerMicroApps([
{
name: 'learnvue', // app name registered
entry: '//localhost:8081',
container: '#viewport',
activeRule: '/dentition'
}
])
if (!window.qiankunStarted) {
window.qiankunStarted = true
start()
}
}
}
</script>
当微应用信息注册完之后,一旦浏览器的 url 发生变化,便会自动触发 qiankun 的匹配逻辑,所有 activeRule 规则匹配上的微应用就会被插入到指定的 container 中,同时依次调用微应用暴露出的生命周期钩子。
如果微应用不是直接跟路由关联的时候,你也可以选择手动加载微应用的方式:1
2
3
4
5
6
7import { loadMicroApp } from 'qiankun';
loadMicroApp({
name: 'app',
entry: '//localhost:7100',
container: '#yourContainer',
});
微应用webpack设置1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21const { defineConfig } = require('@vue/cli-service')
const packageName = require('./package.json').name;
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
port: 8081,
headers: {
// 微前端需要跨域
'Access-Control-Allow-Origin': '*'
}
},
configureWebpack: {
output: {
library: `${packageName}-[name]`, // [name]是打包时trunk名称的占位符
libraryTarget: 'umd', // Universal Module Definition通用模块定义
chunkLoadingGlobal: `webpackJsonp_${packageName}`,
}
}
})
暴露声明周期1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48//main.js
import Vue from 'vue'
import App from './App.vue'
import './public-path'
import router from './router'
Vue.config.productionTip = false
let instance = null;
function render(props = {}) {
const { container } = props;
instance = new Vue({
router,
render: h => h(App)
}).$mount(container ? container.querySelector('#app') : '#app')
}
// Running in qiankun
/* eslint-disable no-undef */
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
// Running standalone
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
export async function bootstrap() {
console.log('[vue] vue app bootstraped');
}
export async function mount(props) {
console.log('[vue] props from main framework', props);
render(props);
}
export async function unmount() {
instance.$destroy();
instance.$el.innerHTML = '';
instance = null;
}
export async function update(props) {
console.log('update props', props)
}
应用间通信
部署
troubleshooting
Uncaught TypeError: Cannot redefine property: $router
官网解决方法是将主应用window.Vue对象换个名字
我的选择是 微应用最好不要用router
Wasm OpenGL ES项目
Wasm + OpenGL ES
1 | git clone https://github.com/emscripten-core/emsdk.git |
issues error: building openssl:wasm32-emscripten failed with: BUILD_FAILED
查看了\vcpkg\buildtrees\openssl\install-wasm32-emscripten-dbg-err.log 内容是
1 | Trying to rename Makefile-333 -> Makefile: Permission denied |
怀疑其他线程访问导致写入失败
1 | set VCPKG_MAX_CONCURRENCY=1 |
The
FindBoostmodule is removed.
cmake 3.30 起移除了FindBoost模块 导致找不到BOOST_DIR Boost_FILESYSTEM_LIBRARY_DEBUG Boost_INCLUDE_DIR等, 实际上面的步骤中相关包已成功安装在D:\Workspace\Github\vcpkg\installed\wasm32-emscripten\include
make Ninja project
1 | mkdir build |

图形学相关的哪些过程适合放到wasm
在 Web3D 项目中,将图形学相关逻辑放入 WebAssembly (Wasm) 是一个极具战略意义的选择。核心原则是:“计算密集型、逻辑复杂、可复用 C++/C 代码”的部分放 Wasm,“渲染管线状态管理、高频 DOM 交互、简单着色器逻辑”保留在 JavaScript。
以下是具体适合放入 Wasm 的图形学内容分类及理由:
1. 几何处理与网格操作 (Geometry Processing)
这是 Wasm 最擅长的领域,通常涉及大量的数学运算和内存操作。
- 网格简化与重拓扑:如 Quadric Error Metrics (QEM)、边折叠算法。这些算法在 JS 中运行极慢,但在 Wasm 中可接近原生速度。
- UV 展开 (UV Unwrapping):复杂的图论算法(如最短路径树)用于将 3D 模型展平到 2D。
- 布尔运算 (Mesh Boolean):CSG (Constructive Solid Geometry) 运算,计算两个模型的交集、并集或差集。JS 实现通常非常卡顿,C++ 库(如 CGAL, libigl)移植到 Wasm 后性能提升巨大。
- 法线平滑与光照预处理:计算顶点法线、切空间基向量等。
2. 物理引擎与碰撞检测 (Physics & Collision)
虽然严格来说属于物理范畴,但它是实时渲染(尤其是刚体动力学)不可或缺的前置条件。
- 碰撞检测 (Broad/Narrow Phase):使用 BVH (Bounding Volume Hierarchy) 或 GJK/EPA 算法检测物体是否相交。
- 刚体动力学:位置更新、冲量计算、约束求解(如 HingeJoint, BallSocket)。
- 软体/布料模拟:基于质点弹簧系统或有限元方法 (FEM) 的模拟。
- 流体模拟 (SPH/FLIP):粒子系统的状态更新,涉及大量邻居搜索和插值计算。
案例:
rapier3d(Rust 编写的物理引擎编译为 Wasm) 是目前 WebGL 游戏的首选,比纯 JS 实现的物理引擎快 10-50 倍。
3. 程序化生成 (Procedural Generation)
这类算法通常递归深度大、分支多,且对 CPU 算力要求高。
- 地形生成:Perlin/Simplex 噪声分形、Voronoi 图、L-systems 树木生成。
- 植被分布:基于生态规则的自动铺草、树木种植算法。
- 纹理合成:在 GPU 之前先在 CPU 端生成复杂的纹理图案(如砖墙、木纹),避免加载巨大的图片资源。
- LOD (Level of Detail) 动态切换策略:根据相机距离实时计算最优的多边形数量。
4. 高级渲染辅助算法 (Advanced Rendering Helpers)
虽然最终的光栅化由 GPU 完成,但许多预处理步骤需要 CPU 参与。
- 光照烘焙 (Lightmap Baking):射线追踪 (Ray Tracing) 计算间接光照、环境光遮蔽 (AO)。在浏览器中做实时烘焙非常耗时,Wasm 可以加速这一过程。
- 阴影映射优化:级联阴影映射 (CSM) 的矩阵计算、PCSS (Percentage Closer Soft Shadows) 的采样计算。
- 体积渲染 (Volume Rendering):体绘制中的光线步进 (Ray Marching) 前的预处理,或体素化 (Voxelization) 过程。
- 全局光照 (GI) 预计算:如辐射度算法 (Radiosity) 的迭代计算。
5. 压缩与解码 (Compression & Decoding)
为了减少网络传输带宽,现代 3D 格式往往采用二进制压缩。
- 3D 模型解压:Draco (Google), KTX2 (Khronos) 等格式的解压缩。JS 实现通常很慢,Wasm 版可显著降低首屏加载时间。
- 纹理压缩解码:ASTC, ETC2, BC7 等 GPU 纹理格式的实时解码(如果需要动态修改纹理时)。
6. 计算机视觉与 AI 辅助 (Computer Vision & AI)
如果你的项目涉及 AR/VR 或智能交互。
- SLAM (即时定位与地图构建):特征点提取、位姿估计。
- 手势识别/动作捕捉:基于 OpenCV 或 MediaPipe 的骨骼跟踪算法。
- 神经渲染 (NeRF):虽然推理主要在 GPU,但前处理和数据流管理在 Wasm 中更高效。
⚠️ 什么【不】应该放在 Wasm 里?
为了避免“过度工程化”导致性能反而下降,以下部分建议保留在 JavaScript:
- 渲染循环控制 (Render Loop):
requestAnimationFrame的调度、帧率监控、简单的状态机逻辑。JS 在这里足够快,且更容易调试。
- Shader 代码管理:
- GLSL 字符串的拼接、编译、链接。虽然可以在 Wasm 中做,但 JS 直接操作
gl.createShader更直观,且 Shader 代码本身就在 GPU 上运行,CPU 端的处理开销微乎其微。
- GLSL 字符串的拼接、编译、链接。虽然可以在 Wasm 中做,但 JS 直接操作
- DOM 交互与 UI 绑定:
- 点击事件监听、UI 面板更新、Canvas 尺寸自适应。这些必须通过 JS 桥接 DOM API。
- 简单的材质属性设置:
- 如果仅仅是设置几个 Uniform 变量(如
time,color),直接在 JS 中调用gl.uniform*即可,不需要经过 Wasm 层中转。
- 如果仅仅是设置几个 Uniform 变量(如
💡 架构设计建议:混合模式
一个高性能的 Web3D 架构通常是 “JS 控制 + Wasm 计算” 的混合模式:
1 | [JavaScript 层] [WebAssembly 层 (C++/Rust)] |
关键优化点:
- 零拷贝 (Zero-Copy):利用
SharedArrayBuffer,让 JS 和 Wasm 直接读写同一块内存,避免每次调用都进行数组复制。 - 批量调用:不要每帧调用一次 Wasm 函数处理所有顶点,而是将一帧的数据打包成一个大数组,一次性传入 Wasm 处理,减少跨语言调用的开销。
总结
如果你需要做 Draco 解压、复杂的物理模拟、程序化地形生成、或者将现有的 C++ 图形库(如 Three.js 的某些底层算法)移植到 Web,那么将这些核心逻辑放入 Wasm 是绝对正确的选择。对于单纯的绘图指令下发,则应留在 JS 中以保持灵活性。
axios
相比fetch Api, axios 提供了更简洁、更直观的 API,使得发送 HTTP 请求和处理响应更加方便; 自动处理json对象(fetch 可以调用await response.json())1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17axios.post('/api/submit', this.editForm)
.then(response => {
console.log('Form submitted successfully:', response.data);
})
.catch(error => {
console.error('Error submitting form:', error);
});
axios.request({
url: '/api/submit',
method: 'post',
data: this.editForm
}).then(response => {
console.log('Form submitted successfully:', response.data);
}).catch(error => {
console.error('Error submitting form:', error);
});
instance1
2
3
4
5
6
7const instance = axios.create({ baseURL: '/api' });
// Works just like axios(config)
instance({
url: '/users',
method: 'get'
});
拦截器1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21// Add a request interceptor
axios.interceptors.request.use(function (config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
},
{ synchronous: true, runWhen: () => /* This function returns true */}
);
// Add a response interceptor
axios.interceptors.response.use(function onFulfilled(response) {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
return response;
}, function onRejected(error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error);
});
Python —— FastAPI
FastAPI与Express.js的区别
| 特性 | FastAPI | Express.js |
|---|---|---|
| 开发语言 | Python | JavaScript/TypeScript |
| 性能 | 基于Starlette和Pydantic,异步处理性能优异 | 基于Node.js事件循环,适合I/O密集型操作 |
| 类型提示 | 原生支持Python类型注解,自动生成API文档 | 需要TypeScript才能获得类型提示 |
| API设计 | 声明式路由,依赖注入系统 | 命令式路由,中间件链 |
| 自动文档 | 自动生成Swagger和ReDoc文档 | 需要第三方库如Swagger UI |
| 数据验证 | Pydantic自动数据验证 | 需要手动验证或使用第三方库 |
| 生态系统 | Python生态(NumPy, Pandas, OpenCV等) | npm生态系统 |
| 学习曲线 | 相对平缓,Python开发者容易上手 | 前端开发者熟悉,学习曲线适中 |
库和项目
1 | pip install "fastapi[standard]" "uvicorn[standard]" |
uvicorn是应用服务器 相当于tomcat
类似express.js 可以写一个main.py 然后执行。 fastapi没有初始化项目的命令行工具 可以考虑官方项目模板: Full Stack FastAPI Template
1 |
1 | my_fastapi_project/ |
WPF Prism
安装依赖1
2
3
4<ItemGroup>
<PackageReference Include="HandyControl" Version="3.5.1" />
<PackageReference Include="Prism.Unity" Version="8.1.97" />
</ItemGroup>
app.xmal中Wpf:Application替换成prism:PrismApplication1
2
3
4
5
6
7
8
9<prism:PrismApplication
x:Class="WpfApp1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1"
xmlns:prism="http://prismlibrary.com/">
<Application.Resources>
</Application.Resources>
</prism:PrismApplication>
标记中删除了StartupUri=”MainWindow.xaml”(否则生成两个实例)
cs代码实现两个抽象方法RegisterTypes和CreateShell1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32// 创建程序主窗口
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void RegisterTypes(IContainerRegistry container)
{
// 注册导航页面和ViewModel
container.RegisterForNavigation<MainWindow, MainWindowViewModel>();
// 注册单例服务
container.RegisterSingleton<IMyService, MyService>();
// 配置文件基础路径
string programData = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments);
programData = Path.Combine(programData, "xxxx");
// 从注册表读取配置路径
using (var key = Registry.LocalMachine.OpenSubKey($@"SOFTWARE\xxxx"))
{
if (key != null && key.GetValue("SolutionPath") != null)
{
programData = key.GetValue("SolutionPath").ToString();
}
}
// 初始化全局缓存
GlobalCache.Instance.FileBasePath = programData;
GlobalCache.Instance.InitPaths();
}