V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
rqxiao
V2EX  ›  程序员

问下一般电商网站中,下单和减库存是怎么设计的

  •  1
     
  •   rqxiao · 2020-09-03 14:01:13 +08:00 · 10149 次点击
    这是一个创建于 1534 天前的主题,其中的信息可能已经有所发展或是发生改变。

    1.下单 2.减钱 3.减库存

    这几个步骤如果出现瓶颈,一般用什么应对方案

    90 条回复    2021-01-15 09:16:47 +08:00
    kop1989
        1
    kop1989  
       2020-09-03 14:14:55 +08:00
    下单出库,然后异步支付。
    下单超时退库。
    针对下单出库环节,如果是特定场景(比如秒杀)可以用秒杀业务来解决。
    如果是普通场景,可以用分布式解决。
    比如 a 商店对应 a 数据库,b 商店对应 b 数据库。
    kop1989
        2
    kop1989  
       2020-09-03 14:24:02 +08:00
    至于说秒杀逻辑是怎样,可以 v 站搜索“一亿并发”帖子中我的回答。
    takemeaway
        3
    takemeaway  
       2020-09-03 16:41:45 +08:00   ❤️ 3
    @kop1989 第一步就错了,下单就出库? 我一个人就能把你库存给秒了。
    kop1989
        4
    kop1989  
       2020-09-03 16:47:30 +08:00
    @takemeaway #3 你可以秒,反过来我也可以封你的号。比如 12306
    takemeaway
        5
    takemeaway  
       2020-09-03 16:56:11 +08:00
    @kop1989 你没有做过电商系统吧? 还封号。。。
    12306 怎么比? 限制了一个号下一次一个座位,还必须身份证。
    真是懒得跟你扯
    kop1989
        6
    kop1989  
       2020-09-03 16:56:53 +08:00
    @takemeaway #5 要不大神您聊聊您的方案?
    pushback
        7
    pushback  
       2020-09-03 16:57:59 +08:00
    @kop1989 我做的流程都是支付完成才算出库
    kop1989
        8
    kop1989  
       2020-09-03 16:59:10 +08:00
    @pushback #7 那如何解决超发问题的呢?别人正在支付过程中,支付成功后,告诉说没货了,再自动退款?
    pushback
        9
    pushback  
       2020-09-03 17:00:11 +08:00
    @kop1989 redis 锁😂
    kop1989
        10
    kop1989  
       2020-09-03 17:02:46 +08:00
    @pushback 不太理解,支付是一个客户的异步行为,理论上讲能下单就应该能支付。那么不就会超发么?不管用什么技术,都阻拦不了用户的异步支付行为。最终只有两个选择,要么下单占库存,要么支付后退款。
    lcy630409
        11
    lcy630409  
       2020-09-03 17:06:47 +08:00
    楼上的不要吵
    A388
        12
    A388  
       2020-09-03 17:07:49 +08:00
    快点继续,楼上的。
    @pushback
    @kop1989
    看你们的结果
    lcy630409
        13
    lcy630409  
       2020-09-03 17:07:55 +08:00
    楼上的不要吵
    要看具体的运营策略
    一般三中
    1 、下订单扣库存 (后台定时任务 超时未支付返还库存)
    2 、支付成功扣库存
    3 、发货完成扣库存
    A388
        14
    A388  
       2020-09-03 17:10:27 +08:00
    @lcy630409 这样不会出现问题吗?比如一个商家卖 1000 件商品。我一次性下单 1000 件,但是就不支付。那岂不是影响商家正常销售了。
    Vegetable
        15
    Vegetable  
       2020-09-03 17:10:32 +08:00
    @pushback #7 你锁了不就等于出库了吗?
    pushback
        16
    pushback  
       2020-09-03 17:11:27 +08:00
    @kop1989 我个人对电商这块也很迷茫,因为之前做的都是无库存类的支付,比如 vip 、支付币、游戏充值这些。
    我上面所说的下单前含了一步对库存量和 redis 待支付订单键数进行比较,支付完成后扣除库存,删除待支付订单对应缓存,所以生产环境到现在还没发现什么问题
    pushback
        17
    pushback  
       2020-09-03 17:12:08 +08:00
    @Vegetable 对,我也没提反对意见啊,只是我们没有回库的操作
    kop1989
        18
    kop1989  
       2020-09-03 17:12:21 +08:00   ❤️ 3
    @Livid 浏览了一下,takemeaway 专业灌水+喷子
    lcy630409
        19
    lcy630409  
       2020-09-03 17:12:35 +08:00
    @A388 如果出现这种情况 冻结账号 封 ip,如果经常出现 调整为支付扣库存
    A388
        20
    A388  
       2020-09-03 17:16:53 +08:00
    @lcy630409 支付扣库存的话,又可能出现一个商品有可能支付了 1 万个人,结果就一个人抢到了。那岂不是要退 9999 的款。不然,就只能搞成串行
    hbolive
        21
    hbolive  
       2020-09-03 17:18:27 +08:00
    一般是支付扣库存,而支付是有时限的。至于特殊情况,秒杀之类的,要特殊分析。。
    Vegetable
        22
    Vegetable  
       2020-09-03 17:18:53 +08:00   ❤️ 3
    如果不考虑过于复杂的情况,下单了就是要减库存的,不然就会出现超卖的情况。你总不能在付款成功之后说没货在退款,这种体验太差了。

    拿淘宝来说,商品必须在一定时间时间内支付,否则订单就会取消。长的可以是 24 小时,短的也有 15 分钟的,根据商品的热度不同,这个时间的设置也不同。

    恶意刷库存实际上这不能算一个技术问题,起码从流程上去做没必要,更何况是冒着超卖的风险。交给商家去应对这个风险就好了,你限购不就完了
    lcy630409
        23
    lcy630409  
       2020-09-03 17:19:07 +08:00
    @A388 这个就是超卖问题了,Redis 出场吧~~
    hbolive
        24
    hbolive  
       2020-09-03 17:20:13 +08:00
    @A388 就算这种情况出现,老板也不会打码农板子的,只会去跟搞运营的说,这东西这么火,丫怎么才搞来一个?扣工资。。
    hpeng
        25
    hpeng  
       2020-09-03 17:22:42 +08:00 via iPhone
    先锁库存,扣钱才真实扣库存
    ylsc633
        26
    ylsc633  
       2020-09-03 17:22:56 +08:00
    昨天抢国庆 1 号的票 有这么个情况

    我看到其他票没了,去一个显示 有 的车次里!
    1. 可以点进去
    2. 可以选座位
    3. 重新打开标签页,打开 12306,查询车次,已经没票了
    4. 开始支付
    5. 显示没票了.....
    ksice
        27
    ksice  
       2020-09-03 17:23:12 +08:00
    @lcy630409 这个正解,超时设置
    kop1989
        28
    kop1989  
       2020-09-03 17:23:52 +08:00
    @A388 #14 恶意霸占商品是很容易区分的。可以通过运营手段来阻止。比如预防性质的限购,预约,缩短支付时限。比如事后惩罚性质的封号等等。
    takemeaway
        29
    takemeaway  
       2020-09-03 17:24:33 +08:00   ❤️ 7
    @kop1989 你可真逗,跟你不同意见就是喷你了。 那你来封我好了
    PopRain
        30
    PopRain  
       2020-09-03 17:25:17 +08:00
    @hbolive 以前小米手机新机发售,按你这个逻辑,可以源源不断的卖出了,不用”耍猴“
    A388
        31
    A388  
       2020-09-03 17:28:32 +08:00
    @lcy630409 我是觉得这 2 种情况,总有一个会出现
    hbolive
        32
    hbolive  
       2020-09-03 17:29:36 +08:00
    @PopRain 小米新机是抢购方式,跟传统售卖是不一样的,小米抢购,是一号限制一台,不允许下单多台,这时候下单就可以锁库存。
    A388
        33
    A388  
       2020-09-03 17:29:39 +08:00
    @kop1989 但是技术手段,确实没办法很好的解决。
    kop1989
        34
    kop1989  
       2020-09-03 17:31:56 +08:00
    @A388 #33 也是不可能解决的(只要是第三方支付,而不是只用余额)。
    promise2mm
        35
    promise2mm  
       2020-09-03 17:33:33 +08:00
    主要还是看运营策略:
    1. 如果允许少量超卖,支付扣库存即可 - 前提是有备货
    2. 如果不允许超卖,下单即锁库存
    3. 秒杀方案另论

    曾经有做了配置,运营可以根据实际情况在商品级别配置 1 或 2
    kop1989
        36
    kop1989  
       2020-09-03 17:33:39 +08:00
    @takemeaway #29 我看了你的记录,没有任何建设性意见,都是对别人的反驳,这难道不是灌水+喷子嘛😂,要不您提出一个又不超发,又不会被恶意站库存的商城方案来。
    Achiii
        37
    Achiii  
       2020-09-03 17:34:27 +08:00
    我们是发货才扣,会超卖
    securityCoding
        38
    securityCoding  
       2020-09-03 17:36:12 +08:00
    我的经验:
    1.下单
    预占库存,uid 限流(uid 下单次数+数量),商品信息可以提前预热(不走 redis,内存 cache),校验流程尽量提前进行拦截,实际上走到下单流程流量已经不大了
    2.减钱
    集群版 redis 锁,订单超时控制,收到回调一定不要漏了支付服务商订单校验
    3.减库存
    集群版 redis 锁,支付成功扣减库存 , 失败返还库存 ,这里可以抽象出一个高性能的独立库存服务
    stzz
        39
    stzz  
       2020-09-03 17:40:26 +08:00
    @kop1989 #10 兄弟,库存分可售库存和实际库存,下单扣可售库存不就行了。。。
    一般电商系统都是这么设计的吧。。
    securityCoding
        40
    securityCoding  
       2020-09-03 17:40:30 +08:00
    @kop1989 我这边的经验是抽象出了一个独立的库存服务出来 , 库存扣减带上超时 ack 参数 , 至于一个用户占很多库存的问题一般是通过运营策略来做(uid 细粒度限流策略)
    supermoonie
        41
    supermoonie  
       2020-09-03 17:43:02 +08:00 via iPhone
    我们是先支付创建订单,然后异步下订单,最后同步订单状态到各个系统
    kop1989
        42
    kop1989  
       2020-09-03 17:44:26 +08:00 via iPhone
    @stzz 无论你用何种技术,出哪个库,结果都是出库(扣减可售数量)。无非就是下单扣减和支付回调确认后扣减两种。优劣我上面都写清楚了。
    arthas2234
        43
    arthas2234  
       2020-09-03 17:59:51 +08:00
    我们这里是下单了就锁,过期未支付就还原,还有库存预警逻辑
    而支付的单更复杂,涉及退款流程
    whileFalse
        44
    whileFalse  
       2020-09-03 18:19:39 +08:00
    我记得淘宝以前是店主可设置下单即锁库存还是支付锁库存,现在不知道还是不是。

    秒杀活动都是下单锁库存的。
    rodrick
        45
    rodrick  
       2020-09-03 20:16:24 +08:00
    下单到出库中间多一道锁库存的操作我觉得是合理的,有时候确实也遇到过本来没抢到刷新一下又有货了,不知道是不是因为这个
    guog
        46
    guog  
       2020-09-03 20:22:54 +08:00 via Android
    @ylsc633 貌似查询票读的缓存,不一定准
    lscho
        47
    lscho  
       2020-09-03 20:26:52 +08:00 via iPhone
    肯定是下单扣库存的多。。。因为支付后扣库存存在的问题比较多,通过运营手段不好解决。

    而下单扣库存就好解决了,不管是风控还是限制单个账号购买数量(同 id 只能拍一个很常见吧)。然后一定时间内没有支付就取消订单释放库存。这应该是目前大电商平台通用的流程了。

    特殊场景另论。
    Macolor21
        48
    Macolor21  
       2020-09-03 21:38:41 +08:00 via iPhone
    @A388 所以秒杀业务有限购
    lxbu
        49
    lxbu  
       2020-09-03 22:02:11 +08:00
    最近也在做库存这块,有个问题想不通,A 下了一个订单有 1,2,3 三件商品,B 下了一个订单有 3,4 两件商品,AB 用户是同时下单,库存扣减是多件商品一个事务操作,那 A 在做库存扣减的时候,B 是不是就阻塞了
    PopRain
        50
    PopRain  
       2020-09-03 22:24:21 +08:00
    @lxbu 如果都按商品 ID 顺序(一定的顺序)去扣减,应该就不会阻塞
    yEhwG10ZJa83067x
        51
    yEhwG10ZJa83067x  
       2020-09-03 23:03:23 +08:00   ❤️ 1
    @kop1989 #18 你的这条回复真的是让人大跌眼镜,这位在你帖子也没有灌水和和喷你啊,你还去查人家发帖纪录,真实
    kop1989
        52
    kop1989  
       2020-09-03 23:24:06 +08:00
    @justrand #51 我的动机不需要你来揣测吧。事实上他是不是只反驳不出意见,是不是只是在灌水,如果是那我就没说错。
    l1ve
        53
    l1ve  
       2020-09-03 23:27:05 +08:00
    逻辑上:
    后台可以选择是下单减库存还是付款减库存

    技术上:
    一个对性能有点影响的方案可能是用锁来处理


    实际上(我自己是个卖家):
    又 TM 超卖了! 傻 X 平台!
    alfchin
        54
    alfchin  
       2020-09-04 00:47:29 +08:00 via iPhone
    @whileFalse 闲鱼可以设置,避免某些沙雕搞攻击
    huyi23
        55
    huyi23  
       2020-09-04 02:37:28 +08:00
    99%都是支付扣库存,什么超售?老板怕超售还是怕流失可能要买的用户?
    另外对于 1%秒杀商品,可以加层 redis 控制下库存就行。
    xuanbg
        56
    xuanbg  
       2020-09-04 08:33:33 +08:00
    仅仅从下单开始的话,正常情况下库存是需要有一定数量的预留用于退换货的,所以不需要锁,并不会导致超卖。付款后扣减即可。

    而且,从业务上来讲,超卖就超卖了。正常商品哪有没地方补货的,现在厂家代发货也是基操啊。
    leafre
        57
    leafre  
       2020-09-04 08:53:13 +08:00
    超不超卖,是并发减库存的问题,跟下单后减库或支付后减库无关。
    至于什么时候减库看业务场景取舍,大多数场景使用下单后减库,支付后减库防止恶意占库存
    sdxlh007
        58
    sdxlh007  
       2020-09-04 08:59:48 +08:00
    我在淘宝开的店是付款减库存的,因为如果拍下减库存,就像楼上说的,一个人就能把所有单秒了。。。然后竞争对手经常这么干,你还拿他没办法
    xianxiaobo
        59
    xianxiaobo  
       2020-09-04 09:03:57 +08:00
    @kop1989 你懂不懂什么是灌水,什么是喷子?灌水是回复跟主题一点关系都没有的内容。什么是喷子?喷子是问候你家人或者问候你的。建议去贴吧多学习学习。
    luhe
        60
    luhe  
       2020-09-04 09:09:14 +08:00
    虽然但是,takemeaway 在本帖的发言确实让人不适
    xuanbg
        61
    xuanbg  
       2020-09-04 09:09:27 +08:00
    @kop1989
    >那如何解决超发问题的呢?别人正在支付过程中,支付成功后,告诉说没货了,再自动退款?

    我想不出来什么情况下回没货。。。不能补货的吗?哦,补货会使发货时间变长,客户体验不好。体验好不好先不说,难道不能供应商代发货吗?你这个想法,真的做过电商?
    StopTheWorld
        62
    StopTheWorld  
       2020-09-04 09:13:57 +08:00
    @lxbu 3 这件商品上会有行锁,b 会堵塞。如果不加业务锁或者判断库存大于零再减库存就会超卖。
    garlics
        63
    garlics  
       2020-09-04 09:18:15 +08:00
    为什么楼里支持下单扣库存的人都默认超售是可以接受的?
    目前主流的都是下单锁库存吧,淘宝双 11 的时候经常见到“有人还未付款,若 15 分钟后仍未付款,您将有购买机会”。
    kop1989
        64
    kop1989  
       2020-09-04 09:23:13 +08:00   ❤️ 1
    @xuanbg #61 如果按照你的想法,京东自营也算是没做过电商的了。
    RedBeanIce
        65
    RedBeanIce  
       2020-09-04 09:35:59 +08:00
    @kop1989 #64 楼上的屁股好歪,支持你。
    lxbu
        66
    lxbu  
       2020-09-04 09:46:00 +08:00
    @StopTheWorld #62 用了乐观锁去做,倒不会超卖,但是并发起来了,就会死锁
    lxbu
        67
    lxbu  
       2020-09-04 09:47:18 +08:00
    @PopRain #50 如果并发起来了,阻塞的概率有点大,一般怎么解决呢
    xuanbg
        68
    xuanbg  
       2020-09-04 09:58:31 +08:00
    @garlics
    @kop1989

    京东自营这种超大型百货电商,自然是要支持不能超卖的,毕竟也有不少商品是不能超卖的。但对于一般的自营小电商,什么是超卖?不存在的。
    coala
        69
    coala  
       2020-09-04 10:00:08 +08:00
    下单就出库 这个问题
    做过京东拣货员 ,内部系统出现订单, 然后攒十几个 单子分给一个人,拣货员就可以拣货了, 的确有刚拣出货就退货的 ,打包员刚打包就退货的也有(京东出货速度很快)

    结合我京东购物的经验
    下订单扣库存,是肯定的
    下订单后,订单状态是未付款,超时的单子放弃,内部拣货系统刷不出未付款的, 付款成功的单子状态更改,内部拣货系统刷出单子 开始拣货, 猜测是这个流程 (下订单直接拣货打包,两小时超时的时候 货都打包好准备运了,感觉不太可能,这个时候货很难拦截了,基本到配送站才能拦截,我实际遇到的都到快递员手里了,问我还要不要退)
    azhi2007
        70
    azhi2007  
       2020-09-04 10:09:42 +08:00
    支付成功后才出库,下订单只是锁库存,这是产品的逻辑,技术吗不知道咋实现这个高并发
    ShundL
        71
    ShundL  
       2020-09-04 10:10:27 +08:00
    这种要看实际业务需要吧?像 shopnc 这种的电商系统,它是用户下单减库存,支付超时、订单取消就把库存量加回去,我觉得初期不用考虑那么复杂,又做不成淘宝那样的,顶多有活动时考虑一下并发超售问题。
    MrZZZ
        72
    MrZZZ  
       2020-09-04 10:13:43 +08:00
    马克,这个帖子挺有意思
    CoderGeek
        73
    CoderGeek  
       2020-09-04 10:35:09 +08:00
    看不懂楼上说的,
    1.下单锁库存(锁库存超买,闲置 黑名单)
    超时取消订单库存
    2.支付通知成功减库存
    调物流发货
    CoderGeek
        74
    CoderGeek  
       2020-09-04 10:36:45 +08:00
    出现啥瓶颈 按道理来说只有秒杀抢购商品锁库存防止超买这一步 (文章太多)
    剩下都是异步的了 理论上没有瓶颈
    cnlee
        75
    cnlee  
       2020-09-04 10:40:01 +08:00
    下单锁库存,支付完成后走出库流程
    YUyu101
        76
    YUyu101  
       2020-09-04 10:47:25 +08:00
    可以几种都设计,给个选项让商品选在购买的什么阶段才锁库存,有的商品允许超卖,有的不允许,这下运营总没话说了吧
    zjuster
        77
    zjuster  
       2020-09-04 10:50:30 +08:00
    这里有一个核心配置项的:下单减库存,还是支付减库存。前者有被同行恶意下单的风险,后者会超卖。通常这个选项是开放给商户的,即技术上两个都需要实现,因为某些场景和活动会出特定的库存管理策略。
    注意,这里的“减”都是 锁定库存,东西还在仓库里呢,出库才扣掉(有出库单据)

    每个方案平台可能都需要提前准备一些基础的措施,比如单用户限购、用户黑名单和恶意用户识别, 销量预测、低库存预警等。
    zjuster
        78
    zjuster  
       2020-09-04 10:53:44 +08:00
    @ylsc633 火车票的库存与普通电商库存难度高一个台阶。
    现在电商库存最复杂的是含区域限售(每个仓有自己的履约范围,多个仓有发货优先级,叠加预售可补逻辑)的全渠道库存管理

    火车票...我形容不了,太复杂了...
    leoskey
        79
    leoskey  
       2020-09-04 11:40:28 +08:00
    个人更支持下单减库存。对于恶意占用库存可以采取:
    1.可以对限制用户下单数
    2.用户恶意下单时限制用户的下单权限
    3.减少库存锁定(订单超时)时长

    如果能轻松处理退款,那支付后库存不足退款的方式更简单
    penll
        80
    penll  
       2020-09-04 11:41:47 +08:00
    肯定下单,就扣库存呗。
    防止恶意下单,就显示单次订单商品数量上限。还有,未支付订单上限,多次未支付下单,提示 xx 时间后,可再下单限制;
    zzw252
        81
    zzw252  
       2020-09-04 12:17:25 +08:00
    一般运营场景是对超卖敏感,所以会下单就扣减库存;少部分场景下对超卖不敏感(供应链很强能保证快速跟进补货,或其他可能),可能就会选择支付才扣减库存。具体要结合服务的场景来设计方案
    hi543
        82
    hi543  
       2020-09-04 12:37:56 +08:00
    别吵了,京东和天猫都是下单减库存。抢购的商品下单有效期只有十几分钟。普通商品 24H 。
    neptuno
        83
    neptuno  
       2020-09-04 13:28:35 +08:00
    下单扣虚拟库存吧,支付成功扣实际库存?
    gavincoder
        84
    gavincoder  
       2020-09-04 14:24:51 +08:00   ❤️ 1
    哈哈哈,我来总结一下:
    ①下单减库存,即当买家下单后,在商品的总库存中减去买家购买数量。下单减库存是最简单的减库存方式,也是控制最精确的一种,下单时直接通过数据库的事务机制控制商品库存,这样一定不会出现超卖的情况。但是你要知道,有些人下完单可能并不会付款。
    ②付款减库存,即买家下单后,并不立即减库存,而是等到有用户付款后才真正减库存,否则库存一直保留给其他买家。但因为付款时才减库存,如果并发比较高,有可能出现买家下单后付不了款的情况,因为可能商品已经被其他人买走了。
    (☆)预扣库存,这种方式相对复杂一些,买家下单后,库存为其保留一定的时间(如 10 分钟),超过这个时间,库存将会自动释放,释放后其他买家就可以继续购买。在买家付款前,系统会校验该订单的库存是否还有保留:如果没有保留,则再次尝试预扣;如果库存不足(也就是预扣失败)则不允许继续付款;如果预扣成功,则完成付款并实际地减去库存。
    sudoy
        85
    sudoy  
       2020-09-04 14:42:34 +08:00
    别的平台不大清楚,亚马逊电商系统是允许卖家设置最大购买数量的。不过亚马逊出来这个可能主要还是因为防止卖家之间相互恶搞、测试对方库存等等。一旦下单就锁库,给一定的时间完成支付,超时就取消锁库。
    typeday
        86
    typeday  
       2020-09-04 15:09:02 +08:00
    @gavincoder 京东就是 1 啊,所以会有人骂锁单狗。苏宁是 3 。
    leekafai
        87
    leekafai  
       2020-09-04 15:37:13 +08:00   ❤️ 2
    库存 已锁 已售

    可售=库存-已锁-已售
    下单,已锁+1
    支付成功,已锁-1,已售+1
    交易阻断,已锁-1
    falcon05
        88
    falcon05  
       2020-09-04 16:02:14 +08:00 via iPhone
    下单就减,然后锁定一段时间,典型的场景是在线卖电影票。
    Anjaxs
        89
    Anjaxs  
       2020-09-04 16:52:41 +08:00   ❤️ 1
    一般分为 实际库存(商品还没出库的数量), 虚拟库存(商品被购买了,但是还没出库), 锁定库存(有些商家需要预定的或者其他情况),可购库存(可以购买的数量)
    实际库存=虚拟库存+锁定库存+可购库存
    下订单:减可购库存, 加虚拟库存
    过时未付款:加可购库存, 减虚拟库存
    出库: 减虚拟库存, 减实际库存
    因为是 tob 的暂时还没有遇到瓶颈, 不过有用到 redis 锁
    d119
        90
    d119  
       2021-01-15 09:16:47 +08:00
    还是说一下吧,京东是哪种,淘宝是哪种,苏宁是哪一种,亚马逊是哪一种
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1807 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 16:49 · PVG 00:49 · LAX 08:49 · JFK 11:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.