V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  FrankHB  ›  全部回复第 37 页 / 共 92 页
回复总数  1830
1 ... 33  34  35  36  37  38  39  40  41  42 ... 92  
2019-12-10 15:39:49 +08:00
回复了 leosirius666a 创建的主题 程序员 作为资深 markdown 程序员,语雀真实太好用了
@shintendo 实际上现在要求可编程的 Markdown 项目还是不少的,就是门槛不那么高罢了。不过由于一般用个 mdbook 什么的就能上,倒是使 LZ 说的这类不允许或者不方便自己部署的平台更加显得鸡肋而业余。

对比看,门槛高点的,比如 TeX 或者 Scribble ( https://docs.racket-lang.org/scribble/)之类的 DSL,跟传统意义上的编程明显更接近(或者根本上就是)。Markdown 的可编程性弱体现在没法通过自身可移植地直接扩展,要折腾实现罢了,但这方面也可以算得上是另一种意义上的门槛高。
2019-12-10 15:07:27 +08:00
回复了 leosirius666a 创建的主题 程序员 作为资深 markdown 程序员,语雀真实太好用了
看起来只是能管理内容,还管理不到资源所有权也定制不了流程……告辞。
SaaSS considered harmful.
@Torpedo 看你管啥叫稳定。
因为 Win32k.sys 的关系,Windows 的原生 GUI 组件在内核层面上就不可能保证排除不确定的稳定风险,有的还是可利用的安全漏洞——从 WinXP 到最近的 Win10 都有。
反过来,其它用户空间实现的方案可用性各有不同,但基本上只要内核相关路径上没明显的 bug,就没啥机会不稳定到整个系统挂掉,而至少能保证有机会让你能看到 GUI 意义上的“内部错误”。
当然,间接的问题像驱动之类要出事都跑不掉,不过系统厂商可以把这个锅甩掉……
@passerbytiny 文本界面就是基本的 UI,而且对程序员来讲通常还比其它种类的 UI 更重要;而这里残废的顺序刚好和 GUI 的可用性反过来。
2019-12-10 14:38:56 +08:00
回复了 vevlins 创建的主题 程序员 点赞多的都是小白文吗?
不一定,看不懂是一个问题,也有小部分可能是因为说得太详细了,又没什么值得提的错误,反而没什么好吐槽的了。

@liprais 小白文说到底是按读者反映评价的。专业圈子门槛高点,但灌水的比例未必少,专门到已出版的论文集里找文献都照样可能有大部分都是小白文的情况,更别说满世界找的预印本啥的了。
因为非得说人话把问题跟不知道上下文的围观群众说清楚,是得强迫过一遍不管自己有没有拎清楚的部分的,这时候使用的思路和原来不一定相同。所以有时候用旧的思路潜意识没想清楚就略过和漏掉的东西会重新浮出来,这很正常。
微信的问题是要么干脆不用,否则 Windows 日常也没法代替移动端,因为那个烧饼登录逻辑和功能残废的问题……( Windows 设备要抱起来扫码就算了 8,,,)
更扯的是要想要数据容易备份归档,光移动设备也不靠谱。
程序员日常使用?
……调试蓝屏?整驱动?
不折腾会日进内核的苟屁游戏。别的日常应用撑死开虚拟机。
2019-12-09 20:10:06 +08:00
回复了 zhxjdwh 创建的主题 程序员 E5 2678V3 洋垃圾值得捡吗
@zhxjdwh 真不够用会影响工作,那直接多申请几台机器不就好了。
要是搞不定服务器网络,最后给你多几台物理机,那是公司的事。
2019-12-09 17:46:21 +08:00
回复了 zhxjdwh 创建的主题 程序员 E5 2678V3 洋垃圾值得捡吗
@JoeoooLAI 这是大多数人员正常的默认思路,但对开发者来说,对自己的机器管控能力经常是强过专业 IT 对整个网络中单台机器的程度的,配置开发环境之类迟早也得自己经手负责;用公司的机器,除非是网络问题,要挂了一样不可能随便免除责任风险。(慢就怪电脑……不怕真给你上顶配让你没借口?)所以如果有可能(保密和安全策略另说),只要性能不是烂太多,我还是喜欢用自己的机器。
但是自己专门去配就免了,不说设备成本的问题,要不记入工作时间就是纯粹多找的工作量,还不方便在工位以外的地方用。
2019-12-09 15:58:24 +08:00
回复了 whoops 创建的主题 Python Python 作用域问题,int 型变量为什么会有些特殊呢
Typo:可变性绑定(non immutable binding) →非可变性绑定(immutable binding)
(草,错位了……)
2019-12-09 15:54:48 +08:00
回复了 whoops 创建的主题 Python Python 作用域问题,int 型变量为什么会有些特殊呢
多跑个题,考虑到语言设计者本身的理解偏差的话,真要深层挖起来这里其实是有点其它方面的意思的。
不同 C-like 这种直接在语法上明确区分构造而不会混淆的设计,Scheme 这种全局使用近似的语法却单独对顶级(top level) 上下文约定的设计显然会把语言搞复杂。
这样做的显然是有目的的。我的理解是,这是要同时支持 REPL 的解释党和编译党的妥协。
Scheme 的特殊规则首先是顶级的 define 在绑定已存在时和 set! 等价,也就是一个绑定构造(binding construct) 被替换为赋值。这在 REPL 加载同一个源文件时比较方便。(考虑到 define 首先总能被当作是个 绑定构造,倒不会引起 Python 那么大的混乱。)
与此相对,非顶级的内部定义(internal definition) 则被认为明确地只是绑定构造而不是赋值。这允许 define 被明确地被实现为 letrec* 这种可变性绑定(non immutable binding) 的语法糖。变量绑定的存在性和名称解析的错误的因果性使后者的语义中隐含一种顺序上的限制,保证内部定义能进行这样的语法变换。这实质上给允许“编译”提供一种保证。
Python 同样有这样琐碎的问题:如何保证变量绑定的存在性能在早期被确定?不像 Scheme 这种长期两派党争下可以有简单妥协,Python 一开始基本就是 CPython 一家说了算,而其中提供 LOAD_FAST/LOAD_DEREF 之类的实现细节是否容易被静态确定以及 CPython 的“编译”倾向混在一起,客观上加剧了语言设计上的混乱。
从语言设计的角度,这里主要的本质差异是变量绑定所在的上下文不同。
Scheme 这样的 LISP 变体中,提供绑定的上下文数据结构称为环境(environment) ,传统上是表示变量绑定映射的关联列表(associated list) ,但实际上不要求明确内部的具体数据结构实现,只要提供能确定名称对应的实体的接口即可。
如 Scheme 这种顶级绑定放在顶级环境和 letrec* 这样依赖的 lambda 的局部环境(local environment) 是原则上不一样的,前者是“全局”,后者是(闭包的)“局部”。
(对应地,Python 里有不同的 namespace ; Python 的 environment 概念只是绑定的集合。)
但区分不同环境的这种设计并非原则上必要。全局环境在实现中的唯一本质区别保证开放(open) 即不总是需要具有源代码局部就能确定有限集合的绑定,而闭包里的局部环境则不是(只要不是打算让一个翻译单元支持翻译半个闭包的语法构造)。然而谁也没说闭包环境中枚举绑定的操作就该是 deterministic 的,只要名称解析能保证 total (可终止)。因为,枚举所有变量绑定根本就不是一个环境需要支持的常规操作——至少被静态绑定的闭包的变量就不是。如果需要反射变量本身的信息,则需要其它和实现相关的辅助操作,如 MIT Scheme 的 procedure-enviornment。这种操作的存在会暴露一些脱离传统闭包语义的实现细节,可能影响用户程序的可观察行为而使语法变换不能保证语义等价,反而会阻碍编译(所以往往只是作为调试辅助接口来用)。
另一方面,允许语言设计这样区分环境的现实是,这些语言并没有把环境暴露给用户操作的一等对象(first-class object) ,即提供一等环境(first-class environment) 。也正因为是这样,区分底层的环境不会让语言特性的复杂性失控(比如至少需要提供完全不同的两套 eval ……更别说如 R5RS 的残废 eval 本身就已经够让编译党抓狂了,以至于 Stalin 这样的实现停留在 R4RS )。但这是以用户程序的表达能力缺失为代价的。例如,Scheme 的宏不能直接和用户定义的环境交互,也无法作为一等对象像过程这样的普通函数一样被作为参数传递或作为返回值。当然,提供宏来变通这种设计,本身就是隐含了“编译优先”的思路了。这某种意义上是一种过度优化,因为一等环境原则上不阻碍对闭包代码进行编译——本质上这里只是允许“尽早”而非严格静态确定绑定(如 J.Shutt 在 Kernel 语言中提供的 $let-safe )。
至于 Python 连宏都没有……就略过算了。
为啥要多在乎某些语言设计者的肤浅的个别理解呢?
2019-12-09 15:48:24 +08:00
回复了 whoops 创建的主题 Python Python 作用域问题,int 型变量为什么会有些特殊呢
@ethego 关于区分读写……如果一个语言不要求明确 identity 也不在显式类型系统上暴露(而要求用户需要保证 const correctness 之类的 type safe )的话,其实是很偏向实现细节且并不总是那么容易自然推理出来的东西。
很多用户都已经习惯了这些设计,实现也是这样搞的,reference 或者 spec 里反而不写出来了,这种风格我只能表示呵呵。要么直接写清楚,要么都不保证,哪个都比现在这种做法干净。
(包括 Scheme R7RS 比之前多明确某些特定的 variable 是不是具有 location,也有点设计过度了。)
2019-12-09 14:51:25 +08:00
回复了 whoops 创建的主题 Python Python 作用域问题,int 型变量为什么会有些特殊呢
@ethego 如果不说 Python,照常理当然应该这样(捕获变量和什么时候引入声明没逻辑上的依赖,本来就该正交),但 Python 在结果上就是不按这条路来有啥办法……
Python 不是个人作品,所以讲理由的时候还是按官方的正式文档来,况且尽管奇葩,现在的文档用的那套逻辑上确实能自圆其说。设计者另外的表示就算意图再明确,在文档修正前只能作为间接参考。(我怀疑 Py 烂摊子太多,根本就没人管得上这个。)
不会自主解决滚挂的,先 WSL 练手(还有一些特有问题能让你多练练……)。
2019-12-09 14:41:15 +08:00
回复了 zhxjdwh 创建的主题 程序员 E5 2678V3 洋垃圾值得捡吗
如果没有约定自备机器,提供机器一般是公司 IT 的职能流程的分内事。自己配机器接入工作环境还可能有安全问题。经过许可了嘛?
因为工作需要升级环境的成本原本也理应由公司承担。自己花钱给公司减负,是出资人吗。
除非只是你一个人这样(这种情况显然项目资源安排很有槽点……),公司提供编译服务器远程提交比较有效,资源也可以共享。
2019-12-09 14:21:26 +08:00
回复了 whoops 创建的主题 Python Python 作用域问题,int 型变量为什么会有些特殊呢
2019-12-09 14:19:33 +08:00
回复了 whoops 创建的主题 Python Python 作用域问题,int 型变量为什么会有些特殊呢
@FrankHB 我就是清楚“替换成列表没有问题的原因在于对于 list 成员的操作亦然属于只读 list 而不是写 list”(实际上还不仅是对 list )才有这里的奇葩规则混在一起的结论,因为真没发现能通过依赖这条路径就可以推出这里出的问题——这是目前 Python reference 里直接明确的东西。
反过来,即便认为和 immutability 直接扯上关系的推理更直白,也覆盖不了 reference 里已有的描述,特别是不能解释清楚什么时候出现具体什么错误,一样至少需要这里用到的名称解析规则。
所以需要改动 reference 才能支持你的推理。
(我其实我同意按你想要的说法在直觉上还更容易让人明白一点;但 Py 特么现在就用的不是这个理由,那就凉拌吧,我也就不去找麻烦了……)
GvR 的邮件里的说法不管是否正确地反映了他想要的东西,都不可能取代正式文档的表述(而且这人在 PL 的一般议题上误会和偷换概念不是没前科的,要他支持 PTC,大讲了一通 TCO 如何如何,最终却认怂 feel educated 了)。
至于“这道题”,这就是送分题(区分 mutable,或至少按默认局部作用域规则一致地 capture ),Python 在搞混 binding construct/assignment 的情况下继续找事情,所以说特别奇葩。

题外话,关于子对象 mutablity 一般应该怎么搞的问题还是挺麻烦的:
https://www.v2ex.com/t/626109#reply76
2019-12-09 05:04:26 +08:00
回复了 whoops 创建的主题 Python Python 作用域问题,int 型变量为什么会有些特殊呢
随便一刷新还有新回复……

@ethego 这说法明显有问题。算了,再过一遍原始问题好了……

LZ 的例子中为什么“替换成列表”就没有错误?看起来是纯粹的语义问题,但实际按 Python reference 理解,还就直接被语法上下文决定了。
注意 += 左边的 cnt 是个标识符,而 cnt[0] 不是。因此这两种情形直接被 assignment statement 的语法区别对待了,适用不同的语义规则:
执行 cnt += 1 会被解释为先限制 cnt 为局部变量再要求引用局部变量 cnt 的这个绑定构造,而被引用的局部变量 cnt 此时没有绑定成功自然失败;
执行 cnt[0] += 1 会被解释成不引入变量绑定的 augmented assignment statement,于是 cnt 就是先前 nearest enclosing scope 引入的变量。
这里 spec 中 Binding of names 一节所谓的 targets that are identifiers if occurring in an assignment 的 assignment 没说就不能是 augmented assignment statement,也没有链接到具体章节,后面 Assignment statements 这节还包含 Augmented assignment statements 这小节,所以这里所谓的 assignment 是包含 augmented assignment statement 的(乃至 3.8 新增的 assignment expression )——尽管 assignment_stmt 和 augmented_assignment_stmt 作为文法元素是并列的,也没有拿 normal assignment statement 以外就不适用来辩解的余地。
于是这跟什么列表是不是 immutable 没直接关系( Python 中什么东西是不是 immutable 根本取决于 object type,这里涉及的反正都没不允许 mutate 根本就不用管)。
只是因为恰巧这些奇葩的语义规则的组合导致了只能 read-only 可用的假象,所以 GvR 发现这里自己挖坑需要补。不过 其实根本也没反省到家,所以也就是多糊了个关键字而已。
(所谓想要照搬 Scheme 也是扯淡,虽然 Scheme 的 top-level 和 local 确实也有很二的问题,但 Scheme 里可没类似 += 的东西给一致性添乱,就算 SRFI-17 也不是这样整的。)

题外话:
虽然“未定义变量”的说法不那么靠谱(随手写 a = a 或者 a += 1 还真不一样,上下文相关),但 UnboundLocalError 这个错误就表示不可能和名称解析失败没关系——而且就实现提供的错误消息来说,还真有关系……
纠结实现,UNBOUNDLOCAL_ERROR_MSG 和 NAME_ERROR_MSG 是不同的错误消息。只有后者才会字面上纠结“定义”,画风是这样的:
UnboundLocalError: local variable 'cnt' referenced before assignment
NameError: name 'cnt' is not defined
然后 UnboundLocalError is a subclass of NameError,所以说成“未定义”,倒也算无可厚非。

另外,引起这样折腾的也并不只是 GvR 承认错误这么简单了:
https://stackoverflow.com/questions/30157655
(光是这个反直觉设计就不要指望“和大多数语言”一样了。)
2019-12-09 01:44:28 +08:00
回复了 whoops 创建的主题 Python Python 作用域问题,int 型变量为什么会有些特殊呢
@ipwx 基本意思分析对了,但引入了一些跟 Py 不见得有关的更麻烦的问题……不太容易直接说明白。
就干脆都过一遍吧。顺便当 FAQ 草稿。

首先,这里的问题,跟编译不编译没有关系。
所谓的编译原理只是顺带提到这些内容,因为这其实是语言设计而不是编译这种实现的先决知识,但没专门 PL 的同学就只能勉为其难一下了。

其次,这里的问题的知识背景,只要是典型的有所谓变量(variable) 的语言,纯解释实现一样普遍适用。
典型的这类语言中变量以源代码中的的特定片段,即变量名(variable name) ,通常以文本的形式提供,源代码中的实际表示通常就是字符串。
源代码的文本通过词法分析识别出作为词素(lexeme) 的实例,然后被分析归类成为某一类记号(token) ,这是附加语法用途的文本以外的构造,在语法分析中完成。
被作为变量名的记号是标识符。(有的语言在此之前还有预处理阶段,其中的类似的词素也叫标识符,但不属于记号—— 例如,C 的预处理记号在语法分析中被区分出表示变量名的普通的标识符记号,以及语法意义上的关键字。)
在典型的语言(排除文本宏替换这类 DSL )中,用户实际一般使用是和语法规则区分规定的语义规则明确的抽象,而非语法构造。
标识符在对应的语法处理之后就已经确定存在。(当然,语法上的处理不一定要求是全局 AOT 的形式,这个另当别论。)这和标识符表示什么含义是两回事。
用标识符去代替标识符指称的实体(这里是变量)讨论会显得稀里糊涂,因为实际的处理方式不唯一,而且经常依赖之后的语义处理过程,处理后的内容也没法一一对应(允许一一对应的平凡逻辑还浪费了语言允许的抽象能力,通常就是应该在语言设计中避免的)。

第三,大多数用户在这里没有区分清楚所谓“变量”所指的确切含义,于是稀里糊涂程度翻倍。
虽然不少语言设计中根本没说清楚什么叫变量,一般地,变量区分于其它语言概念的关键性质就是保证存在标识变量的变量名。
注意:
1.变量总是被命名。语言层面上没有所谓的“匿名变量”,因为这是逻辑上的自相矛盾。
2.变量名是标识符,但反过来不一定,因为标识符指称实体,但不一定命名变量。它可能是特殊的语法构造,如宏。
3.变量(的值)是不是支持可被修改,对是不是变量无关紧要。像纯函数式语言中就有不可修改的变量。(但是近来很多语言设计者会误用可修改的对象作为变量的含义,另当别论。)
4.有的语言中,函数名被单独区分,剩下的实体叫做对象(object) (注意先来后到,这和面向对象毫无关系),特指明确需要存储资源的、可以“储存”值(value) 并可能明确支持修改值的实体,如 C (题外话,ISO C 直接回避了“变量”的概念)。其它一些语言不强调这点,可以把函数也作为对象。
实际上严格定义(如 IEC 2382 )中变量可被形式化为命名变量的标识符、指称(denote) 的实体(entity) 和上下文信息的元组。
其中,上下文一般能明确被指称的实体在不同位置中不冲突,也就是源代码中允许引入相同的标识符指称不同实体。
为了消歧义,可以利用上下文中不同的作用域(scope) ,通过名称解析(name resolution) 明确某个标识符作为变量名无歧义的指称到底是同名变量的哪一个。这是语义分析中的一种基本操作。
而用户使用一个变量,既用的是变量名,也可以仅是变量指称的实体。日常所谓的“变量”可能只是指后者,都是严格意义上的变量。为了突出变量构成中的实体以外的作用,可以强调为变量绑定(variable binding) (这也可以是实现名称解析时使用的数据结构之一)。而绑定一个变量则指在程序中引入变量绑定的操作。
用户阅读源代码,看到的首先是语法上的标识符,然后也需要人肉做名称解析以完成可能需要的消歧义,以确定变量到底指称什么实体,才能明白含义。
人肉实现名称解析,它的结果在字面含义上,就是实体的引用(reference) 。
虽然一般用户不一定意识到这点,但实际上语言的机制比一般人直接见名知意复杂得多。这是因为语言的规则要求明确性,需要处理所有情形,又要和其它语法一致。
所以典型的语言中,这不是简单的语法替换过程,而是以标识符构成表达式(expression) ,对表达式求值(evaluate) 之后确定表达式具有的值(value) 。
标识符构成的表达式的求值具有这样的性质:若被求值的表达式中的标识符指称一个实体,则求值后表达式的值引用被指称的实体。
这个意义上,表达式的值同样也是所谓的引用(reference) 。
虽然具体语言设计中不一定提供一等引用(first-class reference) 给用户,但只要是通过表达式求值而不是直接语法替换的形式提供变量名称解析、同时需要区分变量同一性(identity) (基本上只要不是纯函数语言就不可能回避)的语言设计,不可能避免等价于这里的引用的概念。例如,C 没提供引用,但它有左值(lvalue) 。
所以语法意义上标识符确实就只是标识符,但唐突和对象或引用割裂开来,是无助于分清楚这些理由的。

最后,对比上面的通用设计框架,顺带看看 Python 的具体规定。(以下照搬 3.8 的文档,URL 略。)
2.3. Identifiers and keywords
Identifiers (also referred to as names) are described by the following lexical definitions.
...
[一坨具体语法略。]
……果然比上面说得还简单。
3.1. Objects, values and types
Objects are Python’s abstraction for data. All data in a Python program is represented by objects or by relations between objects. (In a sense, and in conformance to Von Neumann’s model of a “stored program computer,” code is also represented by objects.)
这里对象用的是存储实体的概念。
The value of some objects can change. Objects whose value can change are said to be mutable; objects whose value is unchangeable once they are created are called immutable. (The value of an immutable container object that contains a reference to a mutable object can change when the latter’s value is changed; however the container is still considered immutable, because the collection of objects it contains cannot be changed. So, immutability is not strictly the same as having an unchangeable value, it is more subtle.)
...
Python 不提供一等引用,但引用在语言规范中就没被回避。(否则一坨 reference-counting 就更没法说了。)
4.2. Naming and binding
Names refer to objects. Names are introduced by name binding operations.
The following constructs bind names: formal parameters to functions, import statements, class and function definitions (these bind the class or function name in the defining block), and targets that are identifiers if occurring in an assignment, for loop header, or after as in a with statement or except clause. The import statement of the form from ... import * binds all names defined in the imported module, except those beginning with an underscore. This form may only be used at the module level.
A target occurring in a del statement is also considered bound for this purpose (though the actual semantics are to unbind the name).
Each assignment or import statement occurs within a block defined by a class or function definition or at the module level (the top-level code block).
If a name is bound in a block, it is a local variable of that block, unless declared as nonlocal or global. If a name is bound at the module level, it is a global variable. (The variables of the module code block are local and global.) If a variable is used in a code block but not defined there, it is a free variable.
Each occurrence of a name in the program text refers to the binding of that name established by the following name resolution rules.
4.2.2. Resolution of names
A scope defines the visibility of a name within a block. If a local variable is defined in a block, its scope includes that block. If the definition occurs in a function block, the scope extends to any blocks contained within the defining one, unless a contained block introduces a different binding for the name.
When a name is used in a code block, it is resolved using the nearest enclosing scope. The set of all such scopes visible to a code block is called the block’s environment.
When a name is not found at all, a NameError exception is raised. If the current scope is a function scope, and the name refers to a local variable that has not yet been bound to a value at the point where the name is used, an UnboundLocalError exception is raised. UnboundLocalError is a subclass of NameError.
If a name binding operation occurs anywhere within a code block, all uses of the name within the block are treated as references to the current block. This can lead to errors when a name is used within a block before it is bound. This rule is subtle. Python lacks declarations and allows name binding operations to occur anywhere within a code block. The local variables of a code block can be determined by scanning the entire text of the block for name binding operations.
到这里为止,LZ 的问题也好引用的理解也罢,包括具体报错的理由,应该都比较明确了。
Python 的设计和一众小作坊设计一样共享一个经典糟粕——赋值这个依赖已有对象的(修改对象的值)操作和引入变量绑定这两种逻辑上根本不同(绑定原则上要求指定的变量绑定不存在,赋值要求变量绑定在之前必须存在)的操作混在一起了。
所以在人肉解析名称之前,读者还需要多做一次消歧义,先确定这到底是个真正(纯粹)的赋值,还是带变量绑定的所谓赋值。否则就可能出现 LZ 这样的稀里糊涂。
虽然这个例子里要消歧义很简单(都不用照抄 Python 实现的语义,重写 cnt = 0 成为类似 let cnt = 0 这样的伪码,总之能跟后面真正的赋值区分清楚即可),使用户一般性地被迫阅读至少整个块才能做到确定有哪些局部变量绑定是明显糟烂的设计。
(正常的设计中,变量绑定是单独的操作,这往往被设计成变量的初始化声明的语法单独提供。Python 文档在这方面倒有些自知之明,知道是 subtle,但实际上为了使“块中到处可用”也不需要这样的设计,把声明改成表达式即可。)
1 ... 33  34  35  36  37  38  39  40  41  42 ... 92  
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   962 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 29ms · UTC 21:37 · PVG 05:37 · LAX 14:37 · JFK 17:37
Developed with CodeLauncher
♥ Do have faith in what you're doing.