分享下我写不需要太严谨的项目的代码风格 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
dbfox

分享下我写不需要太严谨的项目的代码风格

  •  
  •   dbfox 2015 年 11 月 19 日 4791 次点击
    这是一个创建于 3811 天前的主题,其中的信息可能已经有所发展或是发生改变。

    public static Common.DB.ResultList GetList(Common.DB.NVCollection queryParams)
    {

    //string pageString = queryParams["page"] as string ?? "1"; //string psString = queryParams["pagesize"] as string ?? string.Empty; //string cidString = queryParams["cid"] as string ?? string.Empty; string sort = queryParams["sort"] as string ?? string.Empty; string cate = queryParams["cate"] as string ?? string.Empty; string type = queryParams["type"] as string ?? string.Empty; string ch = queryParams["ch"] as string ?? string.Empty; string kind = queryParams["kind"] as string ?? string.Empty; string andwhere = "1=1"; string rootKey = null; switch (type) { case "appsoft": rootKey = "iphones"; break; case "appgame": rootKey = "iphoneg"; break; case "azsoft": rootKey = "soft"; break; case "azgame": rootKey = "game"; break; } var pnvc = new Common.DB.NVCollection(); if (rootKey != null) { var pcate = DBCache.SoftCategoryCache.Get(rootKey); if (pcate != null) { andwhere += " and charIndex(@path,categoryPath)>0 "; pnvc["path"] = "/" + pcate.ID + "/"; } } if (ch == "az") { andwhere += " and (charIndex(@path1,categoryPath)>0 or charIndex(@path2,categoryPath)>0)"; pnvc["path1"] = "/" + DBCache.SoftCategoryCache.Get("game").ID + "/"; pnvc["path2"] = "/" + DBCache.SoftCategoryCache.Get("soft").ID + "/"; } else if (ch == "app") { andwhere += " and (charIndex(@path1,categoryPath)>0 or charIndex(@path2,categoryPath)>0)"; pnvc["path1"] = "/" + DBCache.SoftCategoryCache.Get("appgame").ID + "/"; pnvc["path2"] = "/" + DBCache.SoftCategoryCache.Get("appsoft").ID + "/"; } if (!string.IsNullOrEmpty(cate) && !string.IsNullOrEmpty(rootKey)) { var cateEnt = DBCache.SoftCategoryCache.Get(rootKey, cate); if (cateEnt != null) { andwhere += " and categoryid=@cid "; pnvc["cid"] = cateEnt.ID; } } int cid = (queryParams["cid"] as int?) ?? 0; if (cid > 0) { var cateEnt = DBCache.SoftCategoryCache.Get(cid); if (cateEnt != null) { andwhere += " and categoryid=@cid "; pnvc["cid"] = cateEnt.ID; } } string orderby = " id desc"; switch (sort) { case "new": orderby = " id desc"; break; case "hot": orderby = " viewTimes desc,id desc"; break; case "rank": orderby = " downWeekTimes desc,id desc"; break; default: break; } switch (kind) { case "number": andwhere += " and number>0"; orderby = " number desc,id desc "; break; case "hprec": andwhere += " and recommend=1 and homepage=1 and number=0 "; orderby = " viewtimes desc,id desc "; break; case "recnothp": andwhere += " and recommend=1 and hoepage=0 and number=0 "; orderby = " viewtimes desc,id desc "; break; case "rec": andwhere += " and recommend=1 "; break; case "all": break; case "normal": default: andwhere += " and recommend=0 and homepage=0 and number=0 "; //orderby = " id desc "; break; } int page = (queryParams["page"] as int?) ?? 1; if (page <= 0) { page = 1; } int pagesize = (queryParams["pagesize"] as int?) ?? 10; if (pagesize <= 0) { pagesize = 10; } Common.DB.ResultList result = new Common.DB.ResultList(pagesize); var dbh = Common.DB.Factory.Default; //List<Common.DB.NVCollection> list = new List<Common.DB.NVCollection>(pagesize); var query = Common.DB.Factory.DefaultPagerQuery; query.AbsolutePage = page; query.Fields = "id,name,version,viewtimes,categoryid"; query.PageSize = pagesize; query.Sort = orderby; query.Table = "soft"; query.Where = andwhere; string csql = query.GetCountQueryString(); string qsql = query.GetQueryString(); int rc = dbh.ExecuteScalar<int>(csql, pnvc); var ls = dbh.GetDataList(qsql, pnvc); int pc = Convert.ToInt32(Math.Ceiling((decimal)rc / (decimal)pagesize)); result.Page = page; result.PageCount = pc; result.RecordCount = rc; result.PageSize = pagesize; for (int i = 0; i < ls.Count; i++) { var o = ls[i]; var ent = new Common.DB.NVCollection(); var entcate = DBCache.SoftCategoryCache.Get((int)o["categoryid"]); ent["id"] = o["id"]; ent["name"] = o["name"]; ent["version"] = o["version"]; ent["cid"] = o["categoryid"]; ent["cpath"] = Services.PathService.GetListPath(entcate); ent["cname"] = entcate.Name; ent["path"] = Services.PathService.GetPath(entcate, (int)o["id"]); ent["dtimes"] = o["viewtimes"]; result.Add(ent); } return result; } 
    第 1 条附言    2015 年 11 月 19 日

    另外一种写法

    public static List<Result> GetList(int page,int pagesize,SortEnum sort)
    {

    }

    另外一种写法

    //查询参数
    public class QueryP
    {
    public int Page{get;set;}
    public int PageSize{get;set;}
    public SortEnum Sort{get;set;}

    }

    public static List<Result> GetList(QueryP query)
    {

    }

    第 2 条附言    2015 年 11 月 20 日
    KeyObjectCollection kvc = new KeyObjectCollection(); kvc["page"] = int.Parse(接收到传输过来的 Page); //这里是已经经过转换的,所以不用担心注入 kvc["追加日期参数"] = DateTime.Parse(接收参数); public static KeyObjectResultList GetList(KeyObjectCollection query) { int page = query["page"]as int; //把 object 类型拆箱,为 int 类型 DateTime 日期参数 = kvc["追加日期参数"] as DateTime; //日期类型 } 
    第 3 条附言    2015 年 11 月 20 日
    这样写,我能想到的缺点:

    ide 无法自动提示参数和类型,需要手工去写比较详细的注释和类型
    第 4 条附言    2015 年 11 月 20 日
    我代码可维护性非常好,不服来辩
    44 条回复    2015-11-23 13:40:16 +08:00
    dong3580
        1
    dong3580  
       2015 年 11 月 19 日
    C#?如果是 web 端,看起来一堆可以放到前端判断了,没必要浪费服务器资源,
    你这种写法。。。
    看不下去了,也不封个方法。。。
    wizardforcel
        2
    wizardforcel  
       2015 年 11 月 19 日 via Android
    能把一大堆 case 换成 dictionary 嘛
    jarlyyn
        3
    jarlyyn  
       2015 年 11 月 19 日
    这有什么分享的价值么……

    不是应该写一个类判断用户输入,一个类处理 sql 么。

    控制器里负责其他的么……

    数据库调一个字段名 /排序要遍历并修改所有相关的不相关的控制器结构。

    要杀了接受的程序员的节奏。
    vivisidea
        4
    vivisidea  
       2015 年 11 月 19 日
    我总觉得手动拼接 sql 的方式不仅容易出问题,而且难以维护
    jarlyyn
        5
    jarlyyn  
       2015 年 11 月 19 日
    @dong3580

    前端判断, ORZ ,收下我的膝盖吧……
    liujiangbei
        6
    liujiangbei  
       2015 年 11 月 19 日
    直接被 fire
    lifanxi
        7
    lifanxi  
       2015 年 11 月 19 日
    @dong3580 也许他前端判断了呢?但是不管前端有没有判断,服务器端总应该判断一次。前端判断是性能优化需求,但是服务器判断是正确性需求。
    dong3580
        8
    dong3580  
       2015 年 11 月 19 日
    @lifanxi
    也是也是,哈哈,拼接 sql 语句,不能忍,
    dbfox
        9
    dbfox  
    OP
       2015 年 11 月 19 日
    @jarlyyn 太繁琐,说了是不严谨,按照 传统规格去写,写死我了
    dbfox
        10
    dbfox  
    OP
       2015 年 11 月 19 日
    @dong3580
    @vivisidea

    很讨厌用框架,尤其是注重性能的地方
    dbfox
        11
    dbfox  
    OP
       2015 年 11 月 19 日
    dong3580
        12
    dong3580  
       2015 年 11 月 19 日
    @dbfox
    是的。 sql 语句的话如果自己抓东西,还是直接用 sql 语句快点。
    但是自己写也可以加参数嘛,你这样拼接代码就有问题,
    jarlyyn
        13
    jarlyyn  
       2015 年 11 月 19 日
    @dbfox

    和繁琐严谨有什么关系呢?

    只不过是把代码适当的区分开而已。能多些几行代码呢?

    我觉得,说到底是没被这样的代码坑过而已,又或者不知道这样的代码坑在哪罢了。
    bramblex
        14
    bramblex  
       2015 年 11 月 19 日   2
    @dbfox

    盲目相信自己写的东西“性能”比框架好是一种盲目且愚蠢的做法,框架本就是平衡多项考虑的工程产物。

    当然啦,如果你要自己造玩具当然可以乱来。我造玩具的时候乱来不是一点半点。
    longaiwp
        15
    longaiwp  
       2015 年 11 月 19 日
    @dbfox 这个写的我觉得真是要疯了啊
    wizardforcel
        16
    wizardforcel  
       2015 年 11 月 19 日
    @dong3580 后端不判断就等着被渗透吧

    @dbfox 过度追求执行效率而忽视开发效率是不对的 性能优化的一条重要原则就是 优化带来的性能提升至少要能抵消代码可读性的下降

    你以前用了一个数组存东西 后来发现用 set 会更好一点 这叫优化

    你以前用了至少执行几十次的一个循环 后来把循环展开了 这不叫优化 这叫作死
    JamesRuan
        17
    JamesRuan  
       2015 年 11 月 19 日
    函数太长,差评!
    lawrencexu
        18
    lawrencexu  
       2015 年 11 月 19 日
    C#和 Java 程序员被黑就是因为楼主这样的太多了。
    dbfox
        19
    dbfox  
    OP
       2015 年 11 月 20 日
    @lawrencexu
    @jarlyyn
    @lawrencexu
    @longaiwp
    @wizardforcel


    可能我表达的不够清楚还是不要管我内部怎么实现了,主要是在 方法的参数上


    如果是以前,我会这样定义方法:

    public static Common.DB.ResultList GetList(int page,int pagesize,string sort,string type,....)


    调用的时候,大家应该都知道,要进行繁琐的类型转换 int.Parse()

    需求一旦一改,增加一个参数或者改变一个参数,函数就被破坏掉了,或者要追加一个方法,同时要改变方法内部的实现


    public static Common.DB.ResultList GetList(int page,int pagesize,int cid,string sort,string type,....)




    后来我想可以增加一个参数类


    public class QueryParams
    {
    public int Page{get;set;}
    public int PageSize{get;set;}
    public string Sort{get;set;}
    public int Cid{get;set;}
    }



    这时候方法就变成这样:
    public static Common.DB.ResultList GetList(queryParams Query);

    增加参数,减少参数,都可以通过修改 QueryParams 的属性 和方法内部实现,而不用破坏方法对外的改变


    再后来,我发现这样还是比较繁琐,写得太严谨,反而很费时

    干脆把参数变更为 和 PHP 相似的 key-object 弱类型,返回值也是弱类型,这样开发效率高了很多倍

    在外部传入参数的时候
    KeyObjectCollection kvc = new KeyObjectCollection();
    kvc["page"] = int.Parse(接收到传输过来的 Page);//这里是已经经过转换的,所以不用担心注入

    public static KeyObjectResultList GetList(KeyObjectCollection query){

    int page = query["page"] as int; //把 object 类型拆箱,为 int 类型

    }

    我发现这样更灵活,更方便,这里我本来不想讨论我 sql 拼接,我之前也用过一些框架 entity framework 等,觉得真的不好用,而且我懒得深入学习这些东西,性能和开发效率还有项目的灵活性,都不太容易掌控,所以我不愿意去用,我当然能体会到一些 orm 的好处,但是带来的一些诟病也不少,不如直接我什么都不想,直接拼 sql 好了,诸位大神,也可以说说,你们怎么写的,顺便学习学习。

    我追求的东西其实也很简单:就是 - “简”,
    只有把项目尽可能做到非常简单,依赖的东西非常少,项目才省心。
    就像象棋,很少的规则,可以玩得很有意思。
    dbfox
        20
    dbfox  
    OP
       2015 年 11 月 20 日
    @bramblex 不仅仅是性能,还有框架无法实现的细节,框架也不够灵活,必要的时候还是 tmd 要用 sql

    生成出来一堆 code ,在追加字段,更改字段,删除某字段的时候,烦的一笔,发布项目更烦, entity framework 至少是这样
    jarlyyn
        21
    jarlyyn  
       2015 年 11 月 20 日
    @dbfox

    1.这和类型有什么关系?这是你的代码没有合适的函数话好不?正常代码不是主流程表逻辑,业务丢函数么?谁能一眼看清你这代码做了什么?你让以后接收修改你这程序的甚至是半年后的自己情何以堪?

    2.不要手工拼接 sql 和 orm 有什么关系? orm 是把数据模型化吧?对应手工拼接 Sql 的不是 prepara 么……

    所以说你需要好好研究下框架的代码,不是说框架代码有多优秀,而是看看成熟的代码怎么去处理这些坑。
    dbfox
        22
    dbfox  
    OP
       2015 年 11 月 20 日
    @jarlyyn

    1 、 我这里 应当算数据访问层,不太刻意追求分层,复杂的地方 会有封装,但绝不可以追求分层。可能我们不在一个领域

    2 、 prepara .net 下有这玩意儿?

    框架我一点都不喜欢,只想掌握最根本的东西,万变不离其宗
    jarlyyn
        23
    jarlyyn  
       2015 年 11 月 20 日
    @dbfox

    1.这个是所有代码最基本的地方,和你什么层没关系。和怎么写出一个可以维护的代码有关。

    2.prepara 是数据的事情。 mysql 可以,我查过 sqlserver 也可以。这个和.net 有什么关系?随便搜索一下

    https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.prepare(v=vs.110).aspx

    其他的不多说了。祝您写代码快乐。
    dbfox
        24
    dbfox  
    OP
       2015 年 11 月 20 日
    @jarlyyn

    听得我听腻歪,找张图片回复你吧:




    SqlCommand.Prepare
    对重复要执行的语句,使用这个方法可以提高执行效率。
    跟我拼接 sql 有毛关系???
    jarlyyn
        25
    jarlyyn  
       2015 年 11 月 20 日
    @dbfox

    好的,我犯贱。

    v2ex 是不能删帖子的。

    只怕您以后在 V2EX 找工作的话会暴露水平。

    祝一切顺风。
    ewBuyVmLZMZE
        26
    ewBuyVmLZMZE  
       2015 年 11 月 20 日
    这代码看得我尿崩。
    fwrq41251
        27
    fwrq41251  
       2015 年 11 月 20 日   1
    静态语言当成动态语言来用.缺点 LZ 也说了:"ide 无法自动提示参数和类型,需要手工去写比较详细的注释和类型".规模小的时候这样开发是会比较快速.可维护性好就不一定了,比如你的 queryParams 里的某个 field 的类型或者名字变化了,而用到这个 queryParams 的地方又很多,如果你定义了它的类型和名称用 IDE 可以很轻松的重构所有需要修改的地方,而像现在这样写,维护起来就比较痛苦了.这也是像 java 这样一种嗦的语言的优势所在.
    leassy
        28
    leassy  
       2015 年 11 月 20 日
    楼主写 C#啊,看着好亲切
    xujif
        29
    xujif  
       2015 年 11 月 20 日
    第一个阶段,拼接
    第二个阶段,参数封装
    第三个阶段, orm
    第四个阶段, orm+复杂查询,比如 mybatis 之类封装语句
    之后,基本就变成仓储模式,不关心数据放在哪里
    楼主既然是 c#,不用 linq 这等神器吗,就算不用 ef , linq to sql 也有不少 provider 可以用吧。
    msg7086
        30
    msg7086  
       2015 年 11 月 20 日
    说了半天其实就想说这个 KeyValuePair 的 Collection 拿来传参数?
    别闹了,看看这个吧: https://msdn.microsoft.com/en-us/library/dd264739.aspx

    至于拼接 SQL 我就不多吐槽了,大家已经吐了很多了
    不用关系代数而用字符串,这本来就是坏的编程风格了,都不用去看效率高低。

    总之我只希望初学者不要被这样的代码风格影响就好。
    iamppz
        31
    iamppz  
       2015 年 11 月 22 日
    写得非常好,请继续坚持







    坚持几年你就明白了
    dbfox
        32
    dbfox  
    OP
       2015 年 11 月 22 日
    @jarlyyn 不要激动,讨论个代码而已

    只是不明白你说的要怎么写,这样写代码之前,我也写过很多其它方式
    dbfox
        33
    dbfox  
    OP
       2015 年 11 月 22 日
    @msg7086
    不拼接 sql 你们怎么写?
    msg7086
        34
    msg7086  
       2015 年 11 月 23 日
    @dbfox 用关系代数啊。我相信这么多年了.net 应该有很多基于关系代数的库了吧。
    msg7086
        35
    msg7086  
       2015 年 11 月 23 日   1
    用 Ruby 给你写了一个简单的例子,基于 Rails 的。

    https://gist.github.com/msg7086/60e806bcccc00a49ecf4

    我不敢说我的代码是可维护性好的代码,但是至少比你的代码要可维护得多。

    比如说 Ruby 这边建议每个方法不应该超过 10 行,否则可维护性就会大大降低。我这边主函数将近 40 行,很明显的维护性就差很多。很多逻辑还可以抽离出来,使得结构更清晰。至于你这 180 行的函数我就不多说了,离讨论维护性这件事都差得很远。

    读你的代码,首先第一个问题就是不知道这个函数到底接受哪些参数。(也就是你说的,连 IDE 都猜不透你函数到底接受什么东西。)这就意味着,一,新人要用你代码的时候,完全不知道该怎么用;二,你自己参数如果写错一个字母,你根本发现不了。等出了错你就慢慢 debug 吧。

    其次是单函数结构。上面也说了,每个方法不应该超过 10 行。我们退一步讲,每个函数不应该超过 50 行好了。很多逻辑结构都可以抽出来做成单独的方法。看你这个 get_list ,应该是 Controller 方法吧,但是里面的很多逻辑是 Model 逻辑,应该放进 Model 类里。这样把函数拆开以后,还有一个好处就是做测试更方便了。
    我不知道你的代码有多少自动化测试,不过我这边做开发,除非是做了就扔的项目,否则全都有做自动化测试覆盖。测试的代码量至少应该要达到项目代码量的一半甚至更多(通常是和项目代码量相同的级别)。这样项目在发布出去以后, bug 要少得多,哪怕用多一倍的时间去写测试,最后也会比不写测试要节约更多更多的时间。

    最后就是拼接字符串,上面也说了不应该用字符串而应该用关系代数。用关系代数的话,可能会用到 ORM ,不过不用 ORM 应该也是可以做的,不知道 C#有没有可用的类库。但是用 C#不用 LINQ ,简直就是浪费了 C#在做 Web 上的最大优势之一了。(函数式, lambda ,延迟求值,匿名类,哪个不是超级好用的东西?)

    你看我用了关系代数以后,根本不需要写一堆 AND ,不需要分 anywhere 和 orderby ,不需要考虑 WHERE 和 ORDER 的执行顺序,甚至连分页都不用我考虑了因为有自动的分页插件,会自己往关系代数里注入合适的 LIMIT 子句。代码量轻松就掉了一半,开发速度更快了,而且出错的几率也下降了。

    如上面很多人所说,程序员必然要经过很多个阶段,去反思自己的问题,才能向前走。你现在到达了封装参数发请求的阶段,自然觉得现在的方法是很不错。然而等你将来有机会接触了更好的方法,或者发现现有方法的各种坑了以后,才会知道更好的方法到底好在哪里。

    把心态放平一些,然后多学习多看看吧。
    dbfox
        36
    dbfox  
    OP
       2015 年 11 月 23 日
    @jarlyyn

    我查了下,你说的是 参数化查询的意思,我的 sql 是参数化查询,已经封装到 dbh
    只是和 mysql 有区别,你们用的 ?,我这里用的 @ ,所以我这里不存在注入的问题
    andwhere += " and categoryid=@cid ";






    著作权归作者所有。
    商业转载请联系作者获得授权,非商业转载请注明出处。
    作者:余天升
    链接: http://www.zhihu.com/question/22953267/answer/23192081
    来源:知乎

    $stmt = $mysqli->prepare("DELETE FROM planet WHERE name = ?");
    $stmt->bind_param('s', "earth");
    $stmt->execute();



    @msg7086

    我真的不明白拼接 sql 怎么了?不拼接怎么写?
    dbfox
        37
    dbfox  
    OP
       2015 年 11 月 23 日
    @msg7086

    是的,要把参数写的很详细

    关系代数,是什么,我得去看看,.net 中似乎没这个东西,

    linq 还是算了吧,从 linq to sql 到 linq to entity 都用过,不好用,深有体会
    msg7086
        38
    msg7086  
       2015 年 11 月 23 日
    LINQ 就是关系代数的一种实现。

    PS: 我知道 LINQ to SQL 很难用。归根结底是因为 C#是一个比较静态的语言,不像 Ruby 那样可以玩各种奇技淫巧。
    dbfox
        39
    dbfox  
    OP
       2015 年 11 月 23 日
    @xujif

    linq ef linq to sql 这些东西都不好用,不用它也是有原因的
    xujif
        40
    xujif  
       2015 年 11 月 23 日
    @dbfox 虽然不用 c#好多年,建议能用强类型表示的还是用强类型,包括 linq ,能在编译期发现的问题就不要留到运行期。
    repus911
        41
    repus911  
       2015 年 11 月 23 日
    好在当年没有继续干 C#...

    可维护性很好?
    单元测试?抽象化或者函数拆分?再不济注释?

    你要是说实现一个底层实现 别人用用不知道你怎么实现也就算了 可你发出来并讨论可维护性...再接再厉
    wizardforcel
        42
    wizardforcel  
       2015 年 11 月 23 日 via Android
    @dbfox 你要说 linq (以及其他 orm )不好配置这个我倒是同意

    要说他不好用 返回的对象不比 resultset 好用的多嘛。
    dbfox
        43
    dbfox  
    OP
       2015 年 11 月 23 日
    @wizardforcel

    不是很喜欢生成的那一堆东西,频繁增删改字段的时候,你就知道有多么烦了
    dbfox
        44
    dbfox  
    OP
       2015 年 11 月 23 日
    @xujif
    @repus911

    开发方向不一样,某些类型的项目是不需要写的太严禁的,我就是把 C# 当 PHP 用了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3026 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 88ms UTC 14:11 PVG 22:11 LAX 07:11 JFK 10:11
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86