我不认为精神内耗有错, 我们只是需要一个自我修复的时间。修复不了那有如何, 那就让他变成新的特性

追求

我追求的是什么

是快乐么
依靠短视频算法刺激多巴胺分泌
活在信息茧房中的原子化的人
食欲、色欲、贪欲
欲望永远无法满足
廉价自足的快乐有什么错
人都是感性或理性的囚徒
追求快乐么

是痛苦么
无数次被伤害跌跌撞撞中成长
泪水与信念同样能洗涤心灵
直到内心再也波澜不惊
痛苦却同样深刻
理想和现实遥遥相隔
如果达成或放弃就不会痛苦了么
享受痛苦么

是金钱么
一切都可看做价值交易
拿时间去换取金钱
拿青春去换取金钱
连感情也可以当做价值交易
社会运转什么都需要钱
有钱了就会开心么
心气与内在体验多少钱也买不到
立场环境起点各不相同
没有资源的人注定失败么
无聊的游戏
我需要更多的钱

是爱情么
爱情总是会幻灭
到头来孑然一身
如何面对孤独的命题
美好的田园牧歌式的生活
就足够地安心了么
但世上没有无条件的爱
也没有人从始至终一路走过
得不到的就去否定么
我愿意相信爱

纯粹的精神么
与人连接自我价值与社会价值的实现
捍卫一个无法实现的梦
没有对错,都是多余的话
只是为了获得认可么
何等渺小
理想显得那么可笑却伟大
去认识更多的人吧

真实的东西就在眼前
去做想做且不违背本心的事
只可惜,我们的心,不够大胆
听够了训诫、谎言与说教
整片天空之下总是这样

没有人能帮你成为自己
也不需要得到什么答案
去得到见识更多直到明白真正需要什么
接受一切拥抱变化
真实勇敢地存在着

我有一个遗愿, 在死之前能写完100首诗, 将encrypted自动public, 至少证明我来过。

  • 家庭

    • 再去见曼如一面
    • 每年给父母钱
  • 个人

    • 写 100 首诗
    • 软考考证
    • 考研上南京邮电
    • 理财
  • 生活

    • 坚持跑步
    • 坚持写日志
    • 坚持阅读

OpenList 挂载注册网盘服务

下载OpenList

开源网盘聚合工具 AList 在 2025 年 6 月被贵州不够科技(贵州 bg 科技)收购, DeskTop版本付费¥39.99。 命令行开源版本免费。Openlist 是后发分叉的开源项目。

下载到本地,运行服务 openlist serve, 初始随机密码,默认5244端口
alt text

设置管理员admin密码:

1
./openlist admin set xxx

添加网盘

文档 https://doc.oplist.org/guide/drivers/baidu

NSSM 注册系统服务

https://nssm.cc/download

1
2
3
4
5
6
7
8
9
nssm install openlist "T:\T_FMediaD\openlist-windows-amd64\openlist.exe" server
nssm set openlist AppDirectory "T:\T_FMediaD\openlist-windows-amd64"
nssm set openlist DisplayName "openlist"
nssm set openlist Description "openlist 网盘聚合服务"
nssm set openlist Start SERVICE_AUTO_START

# launch
nssm start openlist
nssm status openlist

常用命令

1
2
3
4
5
6
nssm start openlist      # 启动
nssm stop openlist # 停止
nssm restart openlist # 重启
nssm status openlist # 查状态
nssm edit openlist # 重新打开配置窗口
nssm remove openlist confirm # 卸载服务

局域网访问, Windows 防火墙放行 5244 入站:

1
netsh advfirewall firewall add rule name="OpenList 5244" dir=in action=allow protocol=TCP localport=5244

RaiDrive挂载WebDav

alt text

还是重装最好, 一切从新

最近装了主机, 考虑迁移系统。 最后还是作罢,直接重装最好。 其实迁移也不麻烦, 旧系统上有我积累多年的文件和脚本, 习惯的配置。
我原先的分区很特别,有两个盘, 每个500G, 装了4个系统, 还有Wsl2(装了Win-KeX Seamless Mode),其实很少用。

原先的分区大概如下:

alt text

alt text

之前花了很多心思,但除了主系统都没怎么用:

第二个盘用的ventoy, 启动的步骤大概是先加载Ventoy, Ventoy能动态加载其他系统启动文件。
对于windows,我没用vhd/vhdx。 可以配置系统盘的efi做启动项, 第二个盘装Ventoy时额外预留了空间还装了个win 10, 同样配置Ventoy加载 win10 efi 作为启动项。
对于Linux,我没有用iso(不可持久化, 持久化需额外配置 persistence空间), 用 Linux vDisk, Virtual Box 生成制作vdi, 运行vtoyboot.sh 会生成一个 .vdi.vtoy, 之后根据这个创建一个vlink, 会得到 .vdi.vlink.vtoy, 放到启动配置里面就行了。 这样的好处是, 如果你想虚拟机打开, 只用把制作的 .vdi.vtoy 的后缀恢复.vdi 就可以直接打开虚拟机了。想用ventoy启动再恢复回来就行了。

alt text

我想来想去还是重新装个系统比较好, 不玩Ventoy了, 来回折腾没意思。 装一个clean的新系统。 还是win11, 记得之前还有纯净系统什么AtlasOS、ReviOS、Tiny10 我都玩过,包括黑苹果。

推荐一些工具, 装机必备:

  1. explorer patcher
  2. taskBarX
  3. groupy2
  4. powertoys
  5. HEU_KMS_Activator, https://hellowindows.cn/
  6. VSCode/Notion/Obsidian/Typora
  7. oh-my-powershell
  8. potplayer
  9. v2ray
  10. pot-app/Ztranslation
  11. NDM/IDM
  12. Chrome
  13. Bandizip
  14. Snipaste
  15. Alist/Openlist
  16. WindowTop
  17. gsudo/scoop/choco
    ….

如果AI 不是来解放生产力的,不能给让我们更加轻松自由,那么要AI又有何用?

最近高强度VibeCoding,其实也现在也不能叫VibeCoding, 也不能叫AI辅助研发, 也许以后这个名词会渐渐消失,因为这几年 AI成了新的开发范式, 什么Prompt、Context、SDD、TDD、Harness,写软件变成烧token,也不知道从什么时候开始的,大约是上大学那会新冠疫情22年底chatgpt开始出来的时候就开始用AI编程了,我记得很清楚, 之前用的sms-activate开通的GPT账号,之前注册要验证国外手机号。现在都没什么限制,google账号都行,google账号也可以邮箱注册。发展真快。

纯古法编程效率太低。之前为了找工作还每天坚持刷Leetcode,坚持了200多天,最近断了。我有时候觉得没有必要花大量的时间去琢磨哪些固定模板的算法。既然AI能完成同样的任务又快又好。是不是应该把精力放在更有价值的事情上。比如夯实基础技能,拓宽技术栈,如何让技术变现。

alt text

为了降本增效, 现在大部分代码都是AI来写。 但我感觉对开发者的要求反而更高了,你必须站在一个评审者决策者的角度去审查AI生成的代码。 你获取的信息更多、要处理AI给你的反馈更多, 反而更累, 有时候会跟不上AI产出的效率, 他是自动化的。 但人的精力有限, 只审查结果么,面向结果编程,代码和人一个能跑就行。质量如何保证可控?耐下心来审查每一行代码写法?

我对软件开发与自动化的看法

现在有了AI, 什么想法都能很快实现。谁都可以标榜说自己是全栈工程师。Human in the loop, 发挥个人的价值。 我的想法是真正的借助AI实现自动化,完全从工作中解放出来就好了。不是有个概念 OPC(One Person Company),一人公司, 让Agent做你的员工。

技术博客还有必要性么

我始终觉得网络是随机存取的工具,我们只需要索引方式的记忆。人的记忆和精力都很有限。存在过的东西不需要反复抽取,既然AI能帮我们具体化某些知识,重复耗时的工作让AI来做就行了。人可以承载到更高的层面的位置上。

lore

暂定个计划, 装台ITX, 我需要更多的生产力工具,笔记本根本不够用, 用了五年了还在服役
我还是有装机经验的, 之前装过服务器
预算8000 还是超了

2026 DDR5 内存条和固态太贵了,今年内存条大涨了5倍,16G内存条比1g黄金还贵, 存金条不如存内存条啊。 ε=(´ο`*))) 唉, 固态存储也翻2倍多了几乎。Whatever

ITX 主机配置

配件 名称 价格(咸鱼)
显卡 PNY GTX 4070 Super 12G 3600
CPU i5 12400f 6c12t 1100
主板 华硕ROGB660i D5 板U一起
散热 ID COOLING IS50X V3 板U一起
机箱 机械大师C25AIR ITX 10.2寸 270
内存 ROG 异极北极星 ddr5 CL36 16gx2 2166
硬盘 SanDisk SN7100S 2T m.2 PCIE4.0 2280 1200
电源 美商海盗船SFX 750W 白金Plus 全模组 368
风扇 ID COOLING 后9015 TF aRgb x1,前顶 8010 8cm x3 70
其他 硅脂、理线、音响、显示器 不计
合计 8774

升级考虑换U和散热i7-13700F(16核24线程),也没别的可以升级的了, 钱都花在显卡上, 主要想本地部署模型,3A游戏也够用。

标题

h1

h2

h3

h4

h5
h6

代码块

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
  /** 把代码块替换为 .monaco-block 容器,返回渲染任务 */
function createHost(block) {
var text = extractText(block.el);
var lang = inferLang(block.el);
var lines = Math.max(1, text.split('\n').length);
var host = document.createElement('div');
host.className = 'monaco-block';
// 提取代码块标题(hexo <figcaption>)
var caption = block.el.querySelector ? block.el.querySelector('figcaption') : null;
var title = caption && caption.textContent.trim() ? caption.textContent.trim() : '';
if (title) {
var titleBar = document.createElement('div');
titleBar.className = 'monaco-block-title';
titleBar.textContent = title;
host.appendChild(titleBar);
}
var height = title ? 30 : 0;
host.style.height = Math.min(520, lines * 20 + height + 32) + 'px';
host.setAttribute('data-monaco-lang', lang || 'plaintext');
var parent = block.el.parentNode;
parent.replaceChild(host, block.el);
return { host: host, text: text, lang: lang || 'plaintext' };
}

/** 懒加载 monaco(本地 vendor → CDN 兜底) */
function ensureMonaco() {
if (window.monaco) return Promise.resolve();
if (loadPromise) return loadPromise;

loadPromise = new Promise(function (resolve, reject) {
var css = document.createElement('link');
css.rel = 'stylesheet';
css.href = MONACO_BASE + '/editor/editor.main.css';
document.head.appendChild(css);

var script = document.createElement('script');
script.src = MONACO_BASE + '/loader.js';
script.onload = function () { bootMonaco(resolve, reject, MONACO_BASE); };
script.onerror = function () {
var s2 = document.createElement('script');
s2.src = MONACO_CDN + '/loader.js';
s2.onload = function () { bootMonaco(resolve, reject, MONACO_CDN); };
s2.onerror = function () { reject(new Error('monaco load failed')); };
document.head.appendChild(s2);
};
document.head.appendChild(script);
});
return loadPromise;
}

/**
* Hexo 脚本 - 自动在 generate/server 前加载说说数据
* 扫描 source/_talks/ 目录,渲染 Markdown,输出 source/_data/talks.json
* 支持局部加密:正文中用 <encrypt password="xxx">内容</encrypt> 标记加密片段
*/
const fs = require("fs");
const path = require("path");
const crypto = require("crypto");
const { marked } = require("marked");

const TALKS_DIR = path.join(hexo.base_dir, "source", "_talks");
const OUTPUT_FILE = path.join(hexo.base_dir, "source", "_data", "talks.json");

marked.setOptions({ gfm: true, breaks: true });

const ENC_ALGO = "aes-256-cbc";
const KEY_LENGTH = 32;
const IV_LENGTH = 16;
const PBKDF2_ITER = 100000;
const PBKDF2_DIGEST = "sha256";

function deriveKey(password, salt) {
return crypto.pbkdf2Sync(password, salt, PBKDF2_ITER, KEY_LENGTH, PBKDF2_DIGEST);
}

function encryptContent(text, password) {
const salt = crypto.randomBytes(16);
const key = deriveKey(password, salt);
const iv = crypto.randomBytes(IV_LENGTH);
const cipher = crypto.createCipheriv(ENC_ALGO, key, iv);
const enc = cipher.update(text, "utf8", "hex") + cipher.final("hex");
return salt.toString("hex") + "$" + iv.toString("hex") + "$" + enc;
}

function parseFrontMatter(raw) {
const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
if (!match) return { meta: {}, body: raw };
const meta = {};
for (const line of match[1].split("\n")) {
const idx = line.indexOf(":");
if (idx === -1) continue;
const key = line.slice(0, idx).trim();
let value = line.slice(idx + 1).trim();
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
value = value.slice(1, -1);
}
meta[key] = value;
}
return { meta, body: match[2].trim() };
}

function fixImagePath(html) {
return html.replace(/src="(?!https?:\/\/|\/|data:)([^"]*assets\/[^"]*)"/g, 'src="/$1"');
}

function renderMarkdown(text) {
if (!text) return "";
let html = marked.parse(text, { gfm: true, breaks: true });
html = typeof html === "string" ? html.trim() : String(html).trim();
return fixImagePath(html);
}

// 判断是否为全角字符(中文/日文/全角标点等占 2 个半角宽度,用于估算显示宽度)
function isFullWidthChar(ch) {
const code = ch.codePointAt(0);
return (
code >= 0x1100 && (
code <= 0x115f || // Hangul Jamo
code === 0x2329 || code === 0x232a || // 〈 〉
(code >= 0x2e80 && code <= 0xa4cf && code !== 0x303f) || // CJK 等
(code >= 0xac00 && code <= 0xd7a3) || // Hangul Syllables
(code >= 0xf900 && code <= 0xfaff) || // CJK 兼容表意文字
(code >= 0xfe10 && code <= 0xfe19) || // 全角竖排标点
(code >= 0xfe30 && code <= 0xfe6f) || // CJK 兼容字符
(code >= 0xff00 && code <= 0xff60) || // 全角 ASCII 形式
(code >= 0xffe0 && code <= 0xffe6) || // 全角货币符号等
(code >= 0x1f300 && code <= 0x1faff) || // Emoji
(code >= 0x20000 && code <= 0x3fffd)) // CJK 扩展 B 及以上
);
}

// 估算字符串的显示宽度(全角=2,半角=1)
function displayWidth(str) {
let w = 0;
for (const ch of String(str)) {
w += isFullWidthChar(ch) ? 2 : 1;
}
return w;
}

// 按原文每行生成马赛克:行数与原文一致、每行长度与对应行一致,行间用 <br> 分隔
function buildMosaicHtml(innerContent) {
const mosaicBase = "lorem ipsum dolor sit amet ";
const lines = String(innerContent)
.trim()
.split(/\r?\n/)
.filter((l) => l.trim().length > 0);
return lines
.map((line) => {
const w = Math.max(displayWidth(line), 2);
return mosaicBase.repeat(Math.ceil(w / mosaicBase.length)).substring(0, w);
})
.join("<br>");
}

/**
* 从原始 Markdown body 中提取 <encrypt>...</encrypt> 块,使用统一密码
* 返回 { cleanBody, sections }
*/
function processEncryptTags(rawBody, talkId, encryptPassword) {
const sections = [];
if (!encryptPassword) return { cleanBody: rawBody, sections };

const regex = /<encrypt>([\s\S]*?)<\/encrypt>/gi;
let idx = 0;

const cleanBody = rawBody.replace(regex, (fullMatch, innerContent) => {
const innerHtml = renderMarkdown(innerContent.trim());
const encrypted = encryptContent(innerHtml, encryptPassword);
const sectionId = talkId + "-" + idx;
idx++;
sections.push({ id: sectionId, encrypted: encrypted });

// 按原文行结构生成马赛克(每行宽度与对应行一致,行间 <br>,体现内容量与分行)
const mosaicHtml = buildMosaicHtml(innerContent);
return '<span class="talk-encrypt-blob" data-encrypt-id="' + sectionId + '"><span class="encrypt-mosaic">' + mosaicHtml + '</span></span>';
});

return { cleanBody, sections };
}

/**
* 聚合相邻 30 分钟内的说说(追加时长模式:组内最后一条 + 30 分钟内有新消息则并入并重置窗口),
* 合并后显示时间范围 HH:MM-HH:MM
*/
const AGGREGATE_WINDOW_MS = 30 * 60 * 1000;

function parseTalkTime(dateStr) {
const s = String(dateStr || "").trim();
const t = new Date(s.replace(" ", "T")).getTime();
return Number.isNaN(t) ? 0 : t;
}

function normalizeTime(timeStr) {
return String(timeStr || "").slice(0, 5);
}

function aggregateTalks(talks) {
const asc = [...talks].sort((a, b) => parseTalkTime(a.date) - parseTalkTime(b.date));
const groups = [];
for (const t of asc) {
const ts = parseTalkTime(t.date);
const last = groups.length ? groups[groups.length - 1] : null;
if (last && ts - last.lastTs <= AGGREGATE_WINDOW_MS) {
last.list.push(t);
last.lastTs = ts; // 窗口重新计算
} else {
groups.push({ lastTs: ts, list: [t] });
}
}
return groups
.map((g) => {
if (g.list.length === 1) {
return { ...g.list[0], timeStr: normalizeTime(g.list[0].timeStr) };
}
const first = g.list[0];
const lastT = g.list[g.list.length - 1];
const firstTime = normalizeTime(first.timeStr);
const lastTime = normalizeTime(lastT.timeStr);
const timeStr = firstTime && lastTime && firstTime !== lastTime
? `${firstTime}-${lastTime}`
: firstTime || lastTime;
return {
...first,
timeStr,
date: first.date,
dateStr: first.dateStr,
// 除最后一条外,每条消息末尾加换行图标(尽量插到 </p> 内,紧跟最后一个字)
content: g.list.map((x, i) => {
let c = x.content || "";
if (i < g.list.length - 1) {
c = /<\/p>\s*$/.test(c)
? c.replace(/<\/p>\s*$/, '<span class="talk-break"> ↵</span></p>')
: c + '<span class="talk-break"> ↵</span>';
}
return c;
}).join(""), // 文字+图片顺序拼接
tags: [...new Set(g.list.flatMap((x) => x.tags || []))],
encryptedSections: g.list.flatMap((x) => x.encryptedSections || []),
encrypted: g.list.some((x) => x.encrypted),
likes: g.list.reduce((s, x) => s + (x.likes || 0), 0),
// 方案 A:保留组内原始成员(每条含独立 id/content/图片/tags),
// 前端拆条展示,每条可独立编辑;加密段仍走顶层扁平化 encryptedSections 索引
members: g.list.map((x) => ({
id: x.id,
timeStr: normalizeTime(x.timeStr),
content: x.content,
image: x.image,
tags: x.tags || [],
})),
};
})
.sort((a, b) => String(b.date).localeCompare(String(a.date)));
}

function loadTalks() {
if (!fs.existsSync(TALKS_DIR)) {
fs.mkdirSync(TALKS_DIR, { recursive: true });
}

const encryptPassword = hexo.config.talks_encrypt && hexo.config.talks_encrypt.password
? hexo.config.talks_encrypt.password : "";

const files = fs.readdirSync(TALKS_DIR).filter((f) => path.extname(f) === ".md").sort();
let talks = [];
let hasAnyEncrypted = false;

for (const f of files) {
try {
const raw = fs.readFileSync(path.join(TALKS_DIR, f), "utf-8");
const { meta, body } = parseFrontMatter(raw);
const talkId = f.replace(/\.md$/, "");
const dateStr = meta.date || "";
const tags = meta.tags ? meta.tags.split(",").map((t) => t.trim()).filter(Boolean) : [];

const { cleanBody, sections } = processEncryptTags(body, talkId, encryptPassword);
const content = renderMarkdown(cleanBody);

if (sections.length > 0) hasAnyEncrypted = true;

talks.push({
id: talkId,
date: dateStr,
dateStr: dateStr.split(" ")[0] || dateStr,
timeStr: (dateStr.split(" ").slice(1).join(" ") || "").slice(0, 5),
city: meta.city || "",
weather: meta.weather || "",
temp: meta.temp || "",
image: meta.image || "",
tags: tags,
likes: parseInt(meta.likes) || 0,
comments: meta.comments !== "false",
encrypted: sections.length > 0,
encryptedSections: sections,
content: content,
});
} catch (err) {
hexo.log.warn(` ⚠ 解析说说 ${f} 失败: ${err.message}`);
}
}

talks.sort((a, b) => b.date.localeCompare(a.date));

// 聚合相邻 30 分钟内的说说(追加时长模式)
talks = aggregateTalks(talks);

const dataDir = path.dirname(OUTPUT_FILE);
if (!fs.existsSync(dataDir)) {
fs.mkdirSync(dataDir, { recursive: true });
}

// 比较时排除加密 hex(每次随机 salt/IV 会不同),避免死循环
function stableForCompare(json) {
return json.replace(/"[a-f0-9]{32}\$[a-f0-9]{32}\$[a-f0-9]+"/g, '"__ENC__"');
}

const newContent = JSON.stringify(talks, null, 2);
const oldContent = fs.existsSync(OUTPUT_FILE) ? fs.readFileSync(OUTPUT_FILE, "utf-8") : "";

if (stableForCompare(newContent) !== stableForCompare(oldContent)) {
fs.writeFileSync(OUTPUT_FILE, newContent, "utf-8");
hexo.log.info(`📢 说说: 加载了 ${talks.length} 条` + (hasAnyEncrypted ? "(含加密内容)" : ""));
}

return talks;
}

// 在 generate 和 server 之前自动生成数据
hexo.on("generateBefore", () => {
const talks = loadTalks();

// 关键:除了写文件,还要直接更新 Data 模型。
// hexo 的 site.data 来自 Data 模型(在 source.process() 阶段加载 _data/*.json 填充),
// generateBefore 触发时 Data 模型已经加载完,重新写文件不会让它生效。
// 这里把最新数据塞进 Data 模型,配合 generateBefore 之后的 locals.invalidate(),
// 渲染时 site.data.talks 就能拿到最新数据(即使 talks.json 被删除/过期)。
try {
const Data = hexo.model("Data");
Data.save({ _id: "talks", data: talks });
} catch (err) {
hexo.log.warn(` ⚠ 更新 Data 模型失败: ${err.message}`);
}
});

test

1
2
3
console.log('Hello from the post!')
console.log('Hello from the post!')
console.log('Hello from the post!')

test

1
console.log('Hello from the post!')

test
test
inline span

lorem ipsum
lorem ipsum dolor sit amet lorem ipsum dolor sit am
lore
lorem ipsum dolor
lorem
lorem ip
lorem ipsum dolor sit amet lorem ipsum dolor
lorem ipsu
lorem ipsum dolor sit ame
lorem ip
lorem ipsum dolor sit
lorem ipsum do

lorem ipsum
lorem ipsum dolor sit amet lore
lorem ipsum dolor sit amet lorem ipsum dol
lorem ipsum dolor
lorem ipsum
lorem i
lorem ip
lorem ipsum dolor sit
lorem ip