[
  {
    "path": "README.md",
    "content": "30min_guides\n============\n\n覃健祥的学习笔记，各种几十分钟入门的文档\n\n# 实操系列\n- [iOS开发60分钟入门手册](ios.md)\n- [Shell编程30分钟入门](shell.md)\n\n# 原理系列\n- [移动设备定位原理](how_does_mobile_device_get_location.md)\n\n# 业务规则总结（非技术）\n- [零售行业优惠规则](promotion_rule.md)\n"
  },
  {
    "path": "how_does_mobile_device_get_location.md",
    "content": "# 移动设备怎样定位\n## 现象\n### 没有GPS接收器的设备可以定位\n\n- 云翼的iPad 1代 Wifi版（型号MD292CH），在接入公司wifi的情况下，可在地图软件上定位到“我的位置”\n- 五福的三星手机，不开GPS模块，但接入了Wifi和移动运营商，可在百度地图上定位到“我的位置”\n\n### 不接入网络可以定位\n\n- 吴笑的iPhone 4S，关闭无线网和蜂窝数据（包括2G，3G），可以定位\n- 吴笑的车载导航，只有GPS接收器，没有任何网络接入，可以定位导航\n\n## 定位原理（先说理想空间里的几何模型，通信和经纬度后补）\n### 仅依靠GPS定位\nGPS接收器与卫星1通信，获得与卫星1（记为Sat_1）的距离（记为Dist_1）\nGPS接收器与卫星2通信，获得与卫星2（记为Sat_2）的距离（记为Dist_2）\n\n分别以Sat_1, Sat_2为圆心，Dist_1, Dist_2为半径，画一个球，两球相交得一个空心圆，接收器在这个空心圆上某一点。\n\n如果再有第三颗GPS卫星，同理画一个球，运气好的话，此球与空心圆有一个交点（相切），此时三颗星就可定位了。 如果不相切，球与圆圈有两个交点，排除一个不在地球表面的（可以理解为地球表面作为第四个球参与确定交点），剩下那个点即为接收机所在位置。\n\n（注：之前，我想的是：运气不好的话三颗星只能画三个球面，有两个交点，这就需要第四颗卫星来画第四个球了。后来查了资料，才知道这不对，再加上地球本身第四个球面，已经可以唯一确定接收机的位置了）\n\n### 仅依靠WIFI热点定位\n\nwifi的有效距离比较有限，可以不考虑地球曲面的影响，简单认为wifi热点跟要定位的移动终端在同一个平面上。把上面GPS定位原理的圆球改为圆圈，在水平面画圆圈。理论上，最好的情况下，两个wifi热点可定位成功（两个圆正好相切），不在同一直线上的三个wifi热点一定能找到唯一交点，定位成功。\n\n### 仅依靠GSM基站定位\n与wifi定位相同\n\n### 辅助定位\nAGPS"
  },
  {
    "path": "how_to_buy_car_seat.md",
    "content": "## 1 怎样挑选合适的安全座椅\n\n### 1.1 大小\n安全座椅跟衣服和鞋子一样，也分大小和使用年龄的，合适的大小能最好地发挥保护作用。\n\n按Britax美国的标准，分成以下几种类型：\n\n- 婴儿提篮（Infant Car Seats），适用于出生到13公斤\n- 可变座椅（Convertible Car Seats），适用于出生到32公斤\n- 增高垫（Booster），适用于11公斤到41公斤\n\nBritax在中国在欧洲和中国分得更细一些，有0+组、0+1组、1组、1+2+3组、2+3组这么多，上面的可变座椅（Convertible Car Seats）其实相当于0+1+2+3组，但中国区没卖的，只能从美国买了运回来。\n\n其它品牌的，适用体重范围有一点点差别，分组和安全标准都是非常接近的。\n\n\n厂商所说的适用范围，是从产品安全性能角度来说的，以婴儿提篮为例，厂家建议的最大体重是13公斤，就是说，14公斤的宝宝，再坐婴儿提篮就已经不安全了，超出了婴儿提篮的承重限制。实际上，根据中国的现实情况，13公斤的小孩基本都有两岁了，让他躺在婴儿提篮中是很难的，小孩自己会要求坐着，而不是躺着。\n\n__选购指南__\n\n- 如果你的宝宝在2岁以内（或者还在妈妈肚子里），建议购买可变座椅（Convertible Car Seats），如Britax Advocate 70。\n- 如果你的宝宝已经2岁以上，建议购买增高垫（Booster），如Britax Pinnacle 90。虽然2岁还可以继续坐Advocate 70，但Advocate 70最多只能用到70磅（32公斤），而Pinnacle 90最多能用到90磅（41公斤）\n- 如果你的宝宝在2岁以内，且预算充足（比方案1多awx 1600-2000元），可以买一个婴儿提篮（Infant Car Seats），和一个1+2+3组的可变座椅（Convertible Car Seats）。婴儿提篮可以让宝宝平躺在提篮里睡觉，到家后，如果宝宝还没睡醒，就把提篮卡扣打开，从汽车座椅上卸下来，直接拎回家，这样就不会打扰宝宝睡觉。\n\n### 1.2 汽车接口\n我把汽车接口这个因素放在第二，就是因为这个因素在安全座椅选购当中不是最重要的因素。如果你有耐心阅读下面的文字，又有强迫症一定要汽车和座椅的接口完美匹配，可以把本章读完，涨涨经验。\n\n如果你没耐心看下面的知识，只要能达到国外法定的安全标准就可以了，那么，买一个功能强大正在促销的就可以了（如本店推荐的Britax Advocate 70），不管你是什么车，都可以用安全带固定它。\n\n----- 下面开始科普安全座椅接口 -----\n\n安全座椅分三种固定方式：\n\n- LATCH\n- ISOFIX\n- 安全带\n\n有的品牌，可能会使用一些自己独创的名词，如标致308，宣传资料说是使用了Tti安全座椅接口，我去车上看过，其实就是LATCH。\n\n安全座椅接口太专业了，我见过不少网店的卖家错误描述这些概念。例如【洋码头海外旗舰店】：http://detail.tmall.hk/hk/item.htm?id=21211059448，他说：【最近几年的新车都会有配备儿童安全座椅ISOFIX接口或者LATCH接口，这两种接口其实都是一样的，在美国叫做LATCH，在欧洲叫做ISOFIX】，其实这是完全不正确的说法。\n\n#### 1.2.1 LATCH接口\nLATCH接口是美国标准，从美国买安全座椅，多半情况会买到这个接口的。\n\nLATCH是兼容ISOFIX的，如果车是LATCH接口的，买LATCH接口或者ISOFIX接口的座椅都可以。\n\n它是三个固定锚点，比ISOFIX多一个头部固定点（在后排座椅头枕的后面）。\n\n#### 1.2.2 ISOFIX接口\nISOFIX是欧洲标准，如果要买ISOFIX接口的座椅，最好是从德国或者英国买。美国网站也有，但款式少一些，优惠幅度应该也不如欧洲。\n\nISOFIX接口的汽车，比LATCH接口的少一个固定锚点，因此网上的官方文章都说，ISOFIX的车不能装LATCH的座椅，但在实践中，也可以在ISOFIX的车上使用LATCH的座椅，这是因为：\n\n- 可以直接使用安全带固定法。这是合法和安全的\n- 把LATCH座椅下面的两个带子固定到汽车的ISOFIX接口上之后，再用安全带固定一遍，双保险\n- 有人在后备箱里找到了一个锚点，把LATCH座椅头部那根带子拉到后备箱去固定了。相当于自己把ISOFIX的车子改造成LATCH接口了（就是有点山寨）\n\n#### 1.2.3 安全带固定\n有的车子两种接口都没，只能采用安全带固定。几乎所有的安全座椅都支持安全带固定。\n\n安全带固定也可以上ISOFIX、LATCH同时使用。比方说，车是LATCH接口，买了Britax Advocate 70安全座椅，就可以把LATCH的三个锚点全部接好，同时安全带也绑到安全座椅上去，这样双保险固定后，固若金汤。我就是这么干的\n\n#### 1.2.4 怎样知道我的车是什么接口\n- 最保险的办法是去你汽车的后排座椅上看，找到ISOFIX、LATCH的标志和挂钩\n- 看你的汽车说明书，但要小心，一款车型会有乞丐版、中配版、顶配版、特别版等等很多个版本，不同版本都是共享同一本说明书的，别看错了。或者打汽车品牌官方客服电话问问，不要找4S店客服。\n- 到汽车类网站上查询参数配置，这种方法准确度最低。网站的资料，准确度存在一些问题，安全座椅在中国是个冷门的东西，汽车网站没有动力把这个资料做得很准确。我就遇到过，汽车之家说本田思域全系标配LATCH接口，而我爬到朋友的车上看，ISOFIX和LATCH都没有。\n\n### 1.3 品牌\n#### 1.3.1 美国市场\n- Britax，百代适（又译：宝得适），专注母婴的品牌，英国品牌，线上线下都是排名第一的品牌\n- Eddie Bauer，埃迪堡，除了母婴，也做衣服鞋子，安全座椅是它收购来的\n- Maxi-Cosi，迈可适，荷兰品牌，线下超市和电商有售\n- Graco，葛莱，美国品牌，已在广东东莞生产。其鹦鹉螺3合1，常年139美元，适用于20到100磅，以较高的性价比力压Britax排名amazon销售第一\n\n#### 1.3.2 欧洲市场\n- CONCORD，协和/康科德\n- RECARO，里卡罗\n- STM，斯迪姆\n- Kiddy，可迪\n\n## 2 海淘费用（适用于美国代购）\n### 2.1 货款\n货款是通过Master或者Visa在信用卡里扣美元的。所以，货款计算方法是：\n\n> 美元价格 * 汇率（汇率按1美元=6.1人民币计算）\n\n#### 2.1.1 货物价格查询\n货物美元价格自行到美国网站查询，我一般在amazon, albeebaby买，地址：\n\n- http://www.albeebaby.com/\n- http://www.amazon.com/\n\n要注意，不同花色价格也不同的，特价的时候，通常也不是全部的花色都特价\n\n### 2.2 消费税\n消费税跟货款一样，由美国商家通过MasterCard/Visa收取，汇率也是6.1\n#### 2.2.1 免税州\n美国有的州是收消费税的，免税州不收。下单时用哪个州的地址，取决于使用哪个转运公司。我买安全座椅用360hitao，买耳温枪、包鞋子等小件就用友家。\n\n360hitao有三个仓库，分别是：\n\n- CA（加州），Amazon的货发到CA州收税，奶粉、米粉等食品免税。Albeebaby发到CA州不收税\n- DE（特拉华州），这个是免税州。无论哪个网站的东西，发到这里都不收税。这个州最近暴风雪天气，又因为黑五海淘的中国人多，已经爆仓不收货了\n- OR（俄勒冈州），这个也是免税州。\n\n#### 2.2.2 税率\n\n不同类目消费税也不同，安全座椅大约是9.5%-10%，即一个Britax Advocate 70 G3，在Amazon卖235美元，消费税大约是23美元。\n\n要知道精确的税是多少，到Amazon上下个单，填一个CA州的收货地址，Amazon会自动把税金算出来，单列，并累加到订单总金额中去的。\n\n#### 2.2.3 如何避免被税\n- 在Albeebaby买，发到CA、DE、OR三个州都不收税\n\n等等，为什么不能在amazon买发到免税州？且看下面的转运费部分，海淘真心比淘宝麻烦多了好嘛 -_-!\n\n### 2.3 转运费\n从商家到转运公司仓库，一般是免费的（Albeebaby满49美元免运费，安全座椅都不止49美元），如果达不到网站免运费的条件，就凑齐了再下单吧，习惯了国内的快递费，被美国网站收运费，会非常肉痛的。\n\n#### 2.3.1 美国-中国转运费\n转运公司按磅计费，一磅是454克，0.454公斤，不足一磅按一磅算。\n\n360hitao的运费价格在这里查询：\nhttp://www.360hitao.com/freight-calculate/?pagetype=fc\n\n如Britax Advocate 70的重量大概是26磅，黄金卡运费是854.92元。为什么不是标准运费呢？因为花500就可以买个黄金卡了，一个安全座椅的运费铁定超过500，所以，买个黄金卡，再通过支付宝支付剩下的354.92，就可以享受黄金卡的折扣了，可以省165.8元。\n\n#### 2.3.2 美国境内转运费\n360hitao在美国虽然有3个仓库，但只有CA（加州）的仓库有直飞中国的航班，所以，如果买安全座椅为了省消费税，收货地址写了DE或者OR州，那么就要再付给360hitao一笔美国境内转运费，价格是1美元1磅。一个安全座椅一般是25磅左右。\n\n对安全座椅来说，这个美国境内转运费都超过消费税了。所以，不值得发免税州。\n\n#### 2.3.3 体积费\n这个怎么算的我就不详细说了，我直接告诉你结果：安全座椅按体积运费非常非常不划算。360hitao按重收费，不收体积费，这就是我买选360hitao的原因。\n\n#### 2.3.4 汇率\n转运公司一般是美元报价（也有的人民币双币报价），收人民币（因为海淘的都是国内网民，支付宝收人民币便宜又方便，用Visa、Paypal的话，转运公司又要付一笔手续费）。\n\n如果你仔细计算，你会发现，转运公司使用的汇率不是6.1，而是高出一些的，例如360hitao就是6.38，去年是6.5，其它转运公司，6.3， 6.4，6.5的都的，6.1的良心企业暂时还没发现。\n\n### 2.4 中国海关关税\n安全座椅体积大，货值高，进关几乎必被征税。\n税金是126人民币，终于不用算汇率了，哦也！\n\n从海关出来，换成国内快递公司，这个国内快递公司的运费包含在转运公司的转运费里了，不再额外收费。\n"
  },
  {
    "path": "ios.md",
    "content": "iOS开发60分钟入门\n===============\n本文面向已有其它语言（如Java，C，PHP，Javascript）编程经验的iOS开发初学者，初衷在于让我的同事一小时内了解如何开始开发iOS App，学习目标包括：\n\n* 能使用Xcode IDE、模拟器\n* 能修改、调试已有iOS App\n* 能在已有应用内创建新模块\n* 能创建新应用\n* 能发布应用到App Store\n\n本文不包含任何高级的iOS开发知识，已学会iOS开发的同学不要看，看完这篇文章学会了的同学也不用再看了。\n\n\n## 不仅是学习一门新语言\n有过脚本开发经验的人（如Javascript，PHP，Shell）在刚开始学习iOS开发的时候，会觉得iOS开发的学习曲线比脚本语言要高，是的，这种感觉是对的。因为学iOS开发，不仅是学习一门新语言，它包括：\n\n* 一门语言：Objective-C\n* 一个框架：Cocoa Touch\n* 一个IDE：Xcode\n\n初学脚本语言通常不会来绘制图形界面、与人交互，iOS如果不做图形界面，像脚本语言一样处理文本操作数据库，就没啥意思了。\n\n所以，过去我写别的新手入门教程，通常都是写《XXX入门15分钟教程》，而iOS就要花数倍的时间来写了。\n\n## 环境准备\n做iOS开发一定要有苹果的软件环境：Mac OS操作系统、Objective-C编译器、设备模拟器等，开发工具倒不一定要用Xcode，只要是个源代码编辑工具就行（vim都行，只是没Xcode那么多功能）。\n\n\n### Mac OS\n拥有Mac OS环境最简单的方法是找一台苹果电脑，包括iMac, MacBook Pro, MacBook Air, Mac Mini，但不包括苹果的移动设备（iPod Touch, iPhone, iPad, iPad Mini，它们运行的是iOS系统，不是Mac OS），苹果电脑在出厂的时候就会预装Mac OS，目前最新版本是Mac OS X 10.8，主流的版本还有Mac OS X 10.6、Max OS X 10.7。\n\n如果囊中羞涩，可以借一台，或者上淘宝买个二手的。\n\n#### 黑苹果\n提到iOS开发入门，似乎没办法不说黑苹果。所谓黑苹果，就是把Mac OS改造后安装在非苹果的硬件上，这是违反DMCA法案的，黑苹果的更多资料，[可以在维基上找到](http://en.wikipedia.org/wiki/OSx86)\n\n苹果电脑价格高，国内软件开发者生存压力大，所以黑苹果在国内也有一些真实的存在，国外当然也有啦。\n\n黑苹果基本可以胜任iOS开发，但有一些问题：\n\n- 安装黑苹果是非法的\n- 个人行为苹果公司一般不会追究，但会遭同行的鄙视\n- 黑苹果超级难装，挑硬件。即使完全相同的型号，相同的批次，也有可能A机器装上了，B机器装不上\n- 黑苹果系统多少都存在一些使用上的问题，像驱动Bug啦、待机恢复蓝屏啦、上网浏览有问题啦\n- 黑苹果不能随意升级，可能升级一次safari就导致整个系统崩溃了\n\n上面这些虽然不会直接影响Xcode写代码、模拟器测试，但写着写着想上网查个东西的时候，safari不能翻页，确实挺影响心情的。所以，钱包允许的前提下，还是搞个苹果电脑省心一些。\n\n### Xcode 和 模拟器\nXcode可以在苹果官网免费下载：[Xcode下载地址](https://developer.apple.com/Xcode/index.php)\n\n安装Xcode时会自动安装iOS SDK和模拟器。\n\n这么强大的IDE居然是免费的，还是挺让人开心的。\n\n\n## 从改一个现成的应用开始吧\n学一门新软件开发技能，能够第一时间做出一个可运行的产品非常重要，有助于给自己正面激励，我上大学的时候，有很多次想学一门新语言，往往花了半个月，还沉浸在数据类型和语法字典里，连第一个Hello World都没做出来。\n\n这一次，就让我们从改一个现成的应用开始吧。\n\n### 下载\n首先，我们从苹果开发者中心下载一个示例代码回来。我选了[ToolBarSearch](https://developer.apple.com/library/ios/samplecode/ToolbarSearch/ToolbarSearch.zip)。\n\n在本文档的末尾，还有一些其它的网址可以下载开源iOS产品或者代码段，但我试了一下，还是Apple Sample Code最容易成功。\n\n下载回来的zip文件最好保存在\"下载\"或者\"文稿\"目录里，因为在Mac OS 10.8以前，有些目录（例如/var/private/tmp）在Finder中是看不到的，要通过Finder的“前往 > 前往文件夹”功能才能进入。\n\n### 打开\n有三种方式可以打开一个iOS Project\n#### 双击project文件\n打开Finder，进入刚刚下载解压的ToolBarSearch目录，找到ToolBarSearch.Xcodeproj文件，双击之，Xcode会自动启动，并打开这个项目\n\n#### 在Xcode里选择Project打开\n- 在Xcode没启动的情况下（如果Xcode已经启动了，就先按Command Q退出），启动Xcode，会弹出“Welcome to Xcode”的欢迎页，点击左下角的“Open Other”按钮，找到ToolBarSearch目录，双击ToolBarSearch目录，或者双击ToolBarSearch.Xcodeproj文件都可以\n\n- 如果Xcode处于打开状态，可以点击其菜单栏的File -> Open，或者File -> Open Recent，然后再选择要打开的项目\n\n#### 通过命令行打开\n在Mac OS 10.8以前，有些目录（例如/var/private/tmp），在Finder和Xcode的File > Open对话框中，点击鼠标是找不到的，这时候就要通过命令行终端来打开了。\n\n打开终端，执行：\n\n\tcd /ToolBarSearch的父目录/ToolBarSearch\n\topen -a Xcode\n\nopen -a是mac os的系统命令，除了iOS项目，别的项目也可以这样打开。\n\n### 运行刚下载的应用\n点击Xcode左上角的Run按钮（或者同时按下Comman和R键），Xcode会编译源码并在模拟器中运行这个应用。\n\n编译成功会在屏幕上淡淡地显示“Build Succeeded”。反之，失败就显示“Build Failed”且不启动模拟器。\n\n> 最新的Xcode编译后会报 `Compiling IB documents for earlier than iOS7 is no longer supported`， 此时需要手动点击报错，在面板中找到build for 选择合适的版本\n\n### 修改\n在模拟器上看到“Performed search using…”了吧，下面我们改掉它。\n\n- 在Xcode左上角的Run按钮下方，有一排小按钮，从左到右第三个是一个放大镜图标，鼠标移上去会显示“Show the Search Navigator”，点一下它，打开搜索界面，在它下方出现的Find输入框中输入“performed”\n\n- 搜索结果只有一条：ToolbarSearchViewController.m，点文件名下方被高亮的“Performed”字串，右侧代码编辑区会自动打开这个文件，并滚动屏幕，使包含“Performed”的这一行出现在编辑区的中间。\n\n- 修改双引号里的字串，随便改成啥，然后按“Command S”保存。\n\n当然，这些操作，你也可以在终端下通过grep和vim完成。\n\n### 运行修改后的应用\n按Command R运行，看看，是不是看到效果啦？\n\n是的，修改一个应用就这么简单。\n\n\n## Objective-C\nObjective-C是苹果应用软件（包括苹果电脑上的Mac OS App和移动设备上的iOS App）的开发语言。它是一种面向对象的编程语言。\n\n苹果公司还提供了一个软件，叫Interface Builder，简称IB，用于可视化的界面制作，就像用Dreamweaver做网页，或者像Visual Basic做桌面软件一样。后来IB就整合进了Xcode，成了Xcode的一部分。这篇文档不讲IB，只讲Objective-C，因为：\n\n- 基本上，每一本讲iOS开发的书（纸质书、电子书），都有大量的截图一步一步教如何用IB开发iOS应用，而讲Objective-C开发应用的书却没有那么多。\n- IB可以用来直观方便地画界面、设置控件属性、建立代码与控件的联系，但后台的业务逻辑和数据处理仍然要靠Objective-C，可见，不管用不用IB，Objective-C都是绕不过去的。\n\n### C的超集\nObjective-C扩展了ANSI C，是C的超集，也就是说：\n\n- 任何C源程序，不经修改，即可通过Objective-C编译器成功编译\n- Objective-C源程序中可以直接使用任何C语言代码\n\n除了面向对象有语法是SmallTalk风格的（下面会讲到），其它非面向对象的语法、数据类型，与C完全相同，所以本文就不再赘述。\n来看一个经典的Hello World示例吧：\n\n\t#import <Foundation/Foundation.h>\n\tint main(int argc, char *argv[]){\n\t\t@autoreleasepool{\n\t\t\tNSLog(@\"Hello World!\");\n\t\t}\n\t\treturn 0;\n\t}\n是不是仿佛穿越回了大一学习C语言的时代，看起来和C几乎没有区别，是吧？是的，因为还没用到它的面向对象特性，哈哈！\n\n### SmallTalk的消息传递语法风格\nObjective-C的面向对象语法源自SmallTalk，消息传递（Message Passing）风格。在源码风格方面，这是它与C Family语言（包括C/C++、Java、PHP）差别最大的地方。\n\n在Java、C++世界，我们调用一个对象的某方法，在Objective-C里，这称作给类型发送一个消息，这可不仅仅是文字游戏，他们的技术细节也是不同的。\n\n在Java里，对象和方法关系非常严格，一个方法必须属于一个类/对象，否则编译是要报错的。而在Objective-C里，类型和消息的关系比较松散，消息处理到运行时（runtime）才会动态决定，给类型发送一个它无法处理的消息，也只会抛出一个异常，而不会挂掉。\n\n\t[obj undefinedMethod];\n\n在代码里调用没定义的方法（这是Java世界的习惯说法啊，专业的叫法是，给obj对象传递它无法处理的消息），Xcode会警告，但编译能成功，运行的时候会出错。它会输出这样一个错误：\n\n\tTerminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSObject undefinedMethod]: unrecognized selector sent to instance 0x8871710'\n\n### 类似Java的OOP概念\nObjective-C中一些面向对象的概念，也可以在Java中找到类似的实现（只能说是类似，不是完全相同），我的读者基本都是Java和PHP程序员，我会在下文中尽量用Java的概念来类比。\n\nGoogleCode上有人整理了Java和Objective-C的概念、数据类型对应表，[参见这里](http://code.google.com/p/j2objc/wiki/JavaConversions)\n\n### 字符串\nObjective-C里有字符串是由双引号包裹，并在引号前加一个@符号，例如：\n\n\ttitle = @\"Hello\";\n\tif(title == @\"hello\") {}\n\nPHP程序员要注意，在这里不能用单引号，即使只有一个字符也不能用。Objective-C与Java、C一样，双引号表示字符串。\n\n### 函数调用\n前文述及，不涉及面向对象时，它和C是完全一样的。以下是几个函数调用的示例：\n\n#### 不带参数\n\n\tstartedBlock();\n\n#### 带参数\n\n\tNSLog(@\"decrypted string: %@\", str);\n\tCGRectMake(0,0,0,0);\n\n### 传递消息给类/实例方法\n\n#### 不带参数\n\n\t[obj method];\n\n对应的Java版本\n\n\tobj.method();\n\n#### 带一个参数：\n\n\t[counter increase:1];\n\n对应的Java版本\n\n\tcounter.increase(1);\n\n#### 带多个参数\n对C Family程序员来说，这是最难接受的，最反人类的：\n\t\n\t- (void) setColorToRed: (float)red Green: (float)green Blue:(float)blue {...} //定义方法\n\t[myObj setColorToRed: 1.0 Green: 0.8 Blue: 0.2]; //调用方法\n\n对应的Java版\n\n\tpublic void setColorToRedGreenBlue(float red, float green, float blue) {...}\n\tmyObj.setColorToRedGreenBlue(1.0, 0.8, 0.2);\n\n#### 消息嵌套\n\n\tUINavigationBar *bar = [[[UINavigationBar alloc] init] autorelease];\n\n对应的Java版\n\n\tUINavigationBar bar = UINavigationBar.alloc().init().autorelease();//Java没有指针，所以星号去掉了\n\n### 类\n\n#### 接口和实现\nObjective-C的类分为接口定义和实现两个部分。接口定义（Interface）放在头文件中，文件扩展名是.h，实现（implementation）放在实现文件中，文件扩展名是.m（也有.mm的扩展名，表示Objective-C和C++混编的代码）。\n\n`接口定义也可以写在.m文件中，但最好不要这么干`\n\n需要注意的是，与Objective-C的interface概念最接近的是C和C++里的头文件，它与implementation是成双成对出现的，作用是声明类的成员变量和方法。它与Java的interface概念完全不同：\n\n- Objective-C里，interface有且只有一个实现，Java的interface可以有0-N个实现\n- Objective-C里，interface可以定义成员属性，Java里不可以\n\n在Objective-C里，和Java的Interface概念相似的是Protocol，下文会讲到。\n\n请看示例：\n\nInterface\n\n\t@interface MyClass {\n    \tint memberVar1;\n    \tid  memberVar2;\n\t}\n\n\t-(return_type) instance_method1; \n\t-(return_type) instance_method2: (int) p1;\n\t-(return_type) instance_method3: (int) p1 andPar: (int) p2;\n\t@end\n\nImplementation\n\n\t@implementation MyClass {\n\t\tint memberVar3;\n\t}\n \n\t-(return_type) instance_method1 {\n    \t....\n\t}\n\t-(return_type) instance_method2: (int) p1 {\n    \t....\n\t}\n\t-(return_type) instance_method3: (int) p1 andPar: (int) p2 {\n    \t....\n\t}\n\t@end\n\n接口和实现以@interface、@implementation开头，都以@end结束。“@”符号在Objective-C中是个很神奇的符号。\n\n冒号也是方法名的一部分，method和method:是两个不同的方法名，不是overload，第二个带参数。\n\n上述代码对应的Java版：\n\n\tpublic class MyClass {\n\t\tprotected int memberVar1;\n\t\tprotected pointer memberVar2;\n\t\tprivate int memberVar3;\n\t\t\n\t\tpublic (return_type) instance_method1() {\n\t\t\t....\n\t\t}\n\t\t\n\t\tpublic (return_type) instance_method2(int p1) {\n\t\t\t....\n\t\t}\n\t\t\n\t\tpublic (return_type) instance_method3andPar(int p1, int p2) {\n\t\t\t....\n\t\t}\n\t}\n\n#### 私有方法和公开方法\n写在.h头文件里的方法都是公开的，Objective-C里没有私有方法的概念（没有你说个蛋啊，哈哈哈哈）。\n\n官方并没有提到Objective-C怎么实现私有方法，我查阅了stackoverflow，统一的答案是，要实现私有方法的效果只能借助Category，不过，根据我的测试，即使采用了Category，也不能阻止外部的代码调用这个“私有方法”，只是Xcode不支持“私有方法”的自动完成，并会有警告提示，运行的时候，还是会成功的。各位看官知道有这么回事就可以了，这里不深讲。\n\n#### 变量和属性\n\n#### 类方法和实例方法\n##### 类方法\n类方法就是Java、PHP里的Static Method，不用实例化就能调。类方法有一个加号前缀。\n示例：\n\n类定义\n\n\t@interface MyClass\n\t\t+(void) sayHello;\n\t@end\n\n\t@implementation MyClass\n \n\t+(void) sayHello {\n    \tNSLog(@\"Hello, World\");\n\t}\n\t@end\n\n使用\n\n\t[MyClass sayHello];\n\n##### 实例方法\n实例方法就是Java、PHP里的普通方法，必须实例化才能调。实例方法有一个减号前缀。\n示例：\n\n类定义\n\n\t@interface MyClass : NSObject\n\t-(void) sayHello;\n\t@end\n\n\t@implementation MyClass\n \n\t-(void) sayHello {\n    \tNSLog(@\"Hello, World\");\n\t}\n\t@end\n\n使用\n\n\tmycls = [MyClass new];\n\t[mycls sayHello];\n\n#### Selector\nselector就是一个方法指针，类似PHP里的动态方法名：\n\n\t<?php\n\tclass Hello {\n\t\tpublic function sayHello() {}\n\t\t\n\t\tpublic function test() {\n\t\t\t$fun_name = \"sayHello\";\n\t\t\t$this->$fun_name();\n\t\t}\n\t}\n\n在Objective-C里，selector主要用来做两类事情：\n\n##### 绑定控件触发的动作\n\n\t@implementation DemoViewController\n\t- (void)downButtonPressed:(id)sender {//响应“按钮被按下事件”的方法\n\t\tUIButton *button = (UIButton*)sender;\n\t\t[button setSelected:YES];\n\t}\n\t\n\t- (void)drawAnButton {\n\t\tUIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; \n\t\tbtn.frame = _frame; \n\t\tbtn.tag = 1;\n\t\tbtn.backgroundColor = [UIColor clearColor];\n\t\t[btn addTarget: self\n\t\t\t action: @selector(downButtonPressed:)\n\t\t\t forControlEvents: UIControlEventTouchUpInside];//当这个按钮被按下时，触发downButtonPressed:方法\n\t}\n\t@end\n\n##### 延时异步执行\n\n\t@implementation ETHotDealViewController\n\t- (void)viewDidLoad {\n\t\t\n\t\t//获取数据源\n\t\tHotDealDataSource *ds = [[HotDealDataSource alloc]init];\n\t\t[ds reload];\n\t\t_items = ds.items;\n\t\t\n\t\t[self performSelector: @selector(refreshTable)\n\t\t\t  withObject: self\n\t\t\t  afterDelay: 0.5];//延迟0.5秒调用refreshTable方法\n\t}\n\t\n\t-(void)refreshTable\n\t{\n\t\t[self.tableView reloadData];\n\t}\n\t@end\n\n这个例子中，获取数据源是通过ASIHTTP组件异步调用服务端HTTP接口，refreshTable要用到数据源返回回来的数据，如果不延迟0.5秒，就会立刻执行，执行的时候数据还在路上呢，页面就要变空白了。\n\n### 继承\n继承是写在Interface定义里面的。语法为：子类名在左，父类名在右，中间用冒号分隔。\n示例：\n\n\t@interface MyClass : NSObject\n\t@end\n\n对应的Java版本是：\n\n\tpublic class MyClass extends NSObject {\n\t}\n\n### 协议（Protocol）\n就是Java、PHP里的Interface。\n\n#### 协议的定义\n协议的定义用@protocol关键字：\n\n\t@protocol Printable\n\t\t-(void)print:(NSString)str;\n\t@end\n\n对应的Java版本是：\n\n\tpublilc interface Printable {\n\t\tpublic void print(String str);\n\t}\n\n##### 协议的继承\n协议本身也可以继承别的协议：\n\n\t@protocol Printable <NSObject>\n\t\t-(void)print:(NSString)str;\n\t@end\n\n对应的Java版本：\n\n\tpublic interface Printable extends NSObject {\n\t\tpublic void print (String str);\n\t}\n\n##### 可选方法\n协议可以包含可选方法，顾名思义，可选方法可以不被类实现：\n\n\t@protocol Printable\n\t@optional\n\t\t-(void)print:(NSString)str;\n\t@end\n\n加了@optional关键字，一个类在implements这个协议时，便可以不实现print:方法。\n\nJava里没有类似的实现，除了Collection里会有一些方法带有optional的注释，但Collection是个特例。\n\t\n#### 协议的实现\n一个类实现某些协议是写在Interface定义里面的。语法为：协议名用尖括号包裹，多个协议名用逗号隔开，协议写在父类的右边（如果没有父类就直接写在子类右边）。\n\n示例：\n\n\t@interface MyClass : NSObject <Printable, Drawable>\n\t@end\n\nPrintable, Drawablw就是两个协议。\n\n对应的Java版本是：\n\n\tpublic class MyClass extends NSObject implements Printable, Drawable {\n\t}\n\n### 分类（Category）\n分类可以给一个已经存在的类增加方法，而不用去改它的源码。Java和PHP中都没有类似的特性。\n\n比如说，NSObject是一个Objective-C内置的系统类，我们想给它增加toJson方法，就像这样：\n\n头文件：NSObject+Json.h\n\n\t@interface NSObject (Json)\n\t\t-(NSString)toJson;\n\t@end\n\t\n实现文件：NSObject+Json.m\n\n\t@implementation NSObject (Json)\n\t\t-(NSString)toJson {\n\t\t\t//...\n\t\t}\n\t@end\n\n使用的时候，只要包含NSObject+Json.h，实例化NSObject类，就可以使用toJson方法了：\n\n\timport \"NSObject+Json.h\"\n\t@implementation XYZController\n\t\t-(void)test {\n\t\t\tNSObject *obj = [[NSObject alloc]init];\n\t\t\tNSString *str = [obj toJson];\n\t\t}\n\t@end\n\n当然了，NSObject本来的那些方法依然还是可以用的，什么都没变，只是多了个toJson方法。看起来是不是和继承没太多差别呢（除了使用的时候实例化的是NSObject，而不是JsonObject）？再看一个继承实现不了的例子：\n\n头文件：NSObject+Json+XML.h\n\n\t@interface NSObject (Json)\n\t\t-(NSString)toJson;\n\t@end\n\t\n\t@interface NSObject (XML)\n\t\t-(NSString)toXML;\n\t@end\n\t\n实现文件：NSObject+Json+XML.m\n\n\t@implementation NSObject (Json)\n\t\t-(NSString)toJson {\n\t\t\t//...\n\t\t}\n\t@end\n\t\n\t@implementation NSObject (XML)\n\t\t-(NSString)toXML {\n\t\t\t//...\n\t\t}\n\t@end\n\n使用：\n\n\timport \"NSObject+Json+XML.h\"\n\t@implementation XYZController\n\t\t-(void)test {\n\t\t\tNSObject *obj = [[NSObject alloc]init];\n\t\t\tNSString *json = [obj toJson];\n\t\t\tNSString *xml = [obj toXML];\n\t\t}\n\t@end\n\n## Cocoa Touch\nCocoa是Mac OS App的开发框架，Cocoa Touch是iOS开发用的框架，Cocoa Touch和Cocoa大部分是一样的，只是Cocoa Touch多了一些移动设备特有的东西，如：触摸屏、加速度传感器、GPS定位。Cocoa中多任务、多窗口的特性，在Cocoa Touch中也是没有的（或者跟Cocoa不完全一样的）。\n\n就像学了Java语言还要再学一些Spring、Hibernate、Struts（或者其它类似的Java类库）才能开始做J2EE应用一样，学过Objective-C语言之后，也要再学习Cocoa Touch框架才能顺利地开发iOS应用。\n\n### 最常用设计模式之Delegate\nCocoa Touch大量使用Delegate（委派）设计模式。\n\n### 常用控件：按钮、文本块、图片、输入框\n### TableView\n### WebView\n### 导航条\n\n## Xcode\n\n### 运行\n快捷键：Comman R\n\n### 搜索\n#### 搜索文本\n#### 搜索文件\n### 新建文件/目录\n推荐在Finder中新建好的再添加进来\n### 断点\n\n## 模拟器和真机测试\n### 模拟器测试\n在Xcode中打开你的项目，在Xcode顶部工具栏的Stop按钮（Run按钮右边那个黑色正方形按钮）右边，有个下拉菜单，显示着 “ToolBarSearch > iPhone 5.0 Simulator” （即 你的应用英文名 > 当前选中的调试 ），点击这个下拉菜单，选中iPhone 5.0 Simulator（这里的5.0是指iOS版本，不是iPhone5的意思，如果你的项目是iPad应用，请选iPad 5.0 Simulator），再按“Run”按钮，Xcode就会自动把当前正在编辑开发的应用编译并安装到模拟器上。\n\n在模拟器上操作时，如果执行过程中遇到了你在Xcode里设置的断点，模拟器会暂停运行，并将当前活动窗口切换回Xcode，供你调试。\n\n在Xcode里增加或者取消了断点，不需要重新编译和安装应用即可生效。\n\n#### 切换被模拟的设备\n模拟器的“硬件”菜单，可以选择想要模拟什么设备，有iPad、iPhone可选。\n\n- Retina：表示视网膜屏，iPhone(Retina)代表iPhone4，iPhone4S\n- 4-Inch：表示4英寸的iPhone，iPhone(Retina 4-Inch)就是iPhone 5\n\n#### 切换模拟的iOS版本\n在模拟器的“版本”菜单，可以选择要模拟什么版本的iOS。设备和版本是彼此独立的，iPhone 4S可以有5.0，5.1，6.1几种iOS版本，当然了，iPhone 5不可能有4.3的iOS版本。\n\n#### 触摸屏\n用鼠标点击（不区分左右键）模拟器上的iPhone、iPad屏幕，就是在模拟用手指触摸iPhone，iPad的屏幕，可以实现一些触摸效果比如：\n\n- 鼠标单击 等于 手指轻触\n- 鼠标长按 等于 手指长按（例如你可以在模拟器上长按应用icon调出删除应用的确认框）\n- 鼠标按住拖动 等于 手指拖动\n- 双击和单击模拟器的Home键也等于双击和单击真机的Home键\n\n##### 多指手势\n多指手势比较复杂，在白苹果笔记本上可以模拟简单的双指手势，白苹果的触控板天然支持多指触摸，但要定位到模拟器的区域再响应多指手势就需要借助一些额外的键啦：\n\n- 按住Option键，再用两个手指去操作触摸板，可模拟双指拖动、旋转\n- 按住Option+Shift，可模拟双指合拢\n\n#### 输入法和键盘\n##### 输入中文\n手机上特有的输入法（比如九宫格输入法）不能模拟。模拟器默认的iOS软键盘只有英文输入，在测试应用的时候，我们要用到中文，有两个办法：\n\n- 使用剪贴板，在Mac OS里复制，再到模拟器运行的应用中的输入框上长按鼠标（模拟手指长按）3秒以上，等弹出“粘贴”的时候选择之，即可。\n- 在模拟器里，按Home键，找到Setting那个App icon（不是Mac OS顶部的模拟器菜单啊，那里没有Setting的），打开被模拟iOS设备的设置，依次点击”General - Keyboard - International Keyboards - Add New Keyboard…”，加个中文键盘，以后就可以使用被模拟iOS设备软件盘输入中文了，跟在iPhone/iPad真机上一样。\n\n#### 使用Mac电脑的键盘\n如果要输入大量文本，使用模拟器里的软键盘效率太低，这时候可以使用物理键盘，方法是：在Mac OS顶部的模拟器菜单栏，点击”硬件”菜单，勾选下拉菜单中的“模拟硬件键盘”。以后再用模拟器运行iOS应用时，点击iOS应用中的输入框，软键盘就不弹出来了，可直接使用Mac电脑的物理键盘输入。\n\n*注意*：\n\n- 模拟器中的iOS接管了物理键盘输入，所以，调用的是模拟器iOS的输入法，不是你的Mac电脑的输入法。打个比方，你的Mac OS装的是搜狗五笔，模拟器中iOS加了个拼音输入法（Add New Keyboard），那么，在iOS应用中输入中文会调用拼音输入法。\n- 要切换模拟器中iOS的中英文输入法，也只能按iOS设备软键盘上的小地球图标，按Mac电脑上的Command+空格键是不行的。\n\n#### 地理位置\n但Mac电脑没有定位用的硬件（GPS）和软件基础，因此模拟器不能自动获得当前的地理位置，不能用模拟器测试定位功能。（注意，虽然WiFi也可以独立定位——iPad WiFi版没有GPS也可以定位，但Mac电脑的WiFi不具备定位相关的软件）\n\n要在模拟器里测试依赖地理位置的功能（如”我附近的xx”），可以手工指定一个经纬度给模拟器，方法：在Mac电脑顶部的模拟器菜单，点击”调试 - 位置 - 自定位置”，会弹出一个对话框，在弹出的框内填入经纬度即可。\n\n如何获得经纬度？\n上谷歌地图（ditu.google.cn），在地图上找到你想要的位置（比如你想知道杭州大厦的位置，就在通过搜索框找到杭州大厦），点击右键，选择“这儿是什么”，搜索框中就会出现这个位置的经纬度了，前面是纬度，后面是经度。咱们天朝的版图，都是北纬和东经。\n\n#### 摄像头\nMac电脑有摄像头，但Mac OS没有设计API给iOS模拟器调用，所以，不能用模拟器测试对焦闪光灯等功能。\n\n要在模拟器上测试依赖照片的功能，可以在代码里做一个workaround，即当代码检测到摄像头不可用时，弹出一个照片选择器，让测试人员从相册里选择一幅照片，来进行后续的操作（如照片美化、人脸识别、条码扫描）。\n\n\n### 真机测试\n模拟器能验证你开发的iOS应用的大部分功能，但有些Mac设备上不具备的硬件，模拟器是不能模拟的。前文提到了一个绕过这些限制的办法，但获取当前位置、拍照、加速度感应这些是模拟不了的，一款应用发布给消费者之前，必须要在真实设备上验证过。\n\n将未提交App Store审核通过的应用安装到iOS设备上测试，有三种办法：\n\n- 加入苹果的Developer Program，成为付费会员，有了这个付费会员资格，就可以直接在Xcode中点击”Run”将刚刚改过的代码编译打包安装到开发测试用的iOS设备上。在iOS真机上操作被测试的程序能激活Xcode中设置的断点。\n- 越狱iOS设备。将iPhone和iPad越狱后，可以通过SSH直接上传Xcode编译好的ipa包（一个iOS App本质上就是一个ipa包）。\n- 越狱的iOS设备，配合破解过的Xcode，甚至可以实现和付费开发者计划一样的功能：在Xcode上点击”Run”，就自动编译安装到iOS设备上去运行了\n- 企业部署方案。就像阿里巴巴的[轩辕剑](http://xyj.im)一样，用iPhone/iPad访问这个网址，点击里面的轩辕剑链接就可以安装轩辕剑这个应用了。\n\n破解Xcode是违法行为（越狱是合法的），而且挑版本挑得厉害，不是所有Xcode版本都能破解，也不是所有Xcode的破解版都能和越狱的iOS配合好。越狱+SSH上传跟企业部署一样效率低（部署效率低，无法激活Xcode中的断点），只能用于QA验收，不适合开发自测。综上所述，最适合开发实时测试的就是第一个正规途径了。下面重点讲这个：\n\n#### 拥有一个开发者账号\n苹果的Developer Program分为个人开发者和公司开发者，分别是每年99美元和每年299美元，分别可以注册100台和500台苹果测试设备。这个台数限制在一个付费年度内不会清空，比如说，2013年4月1日付费成功的，付费会员资格在2014年3月31日之前有效，这期间，注册一台就少一个名额，哪怕这个设备注册进来用了之后一分钟马上又删掉了，减少的这个名额也不会回来。\n\n在交钱之前，最好问一下，周围的同事，有没有已经交了钱的。如果有，你只需要注册一个免费的Apple ID（就是你在App Store安装软件用的Apple ID），请他发个邀请邮件给你，把你的Apple ID加入他的团队就可以了，苹果会认为你们两个人是一个团队的，你们分别用自己的账号，共享100台设备的限额，这是合法的。\n\n#### 安装证书和私钥\n##### 证书\n不想看下面各种点击各种页面跳转的直接用浏览器访问[证书管理](https://developer.apple.com/ios/manage/certificates/team/index.action)，你要登录你就用Apple ID登录（前提是交过钱，或者找交了钱的人把你加入团队了）。\n>\n不嫌烦，或者想知道下次没我这个文档的时候怎么进证书管理吗？按这个步骤操作：\n\n- 进入 [苹果开发者中心](https://developer.apple.com/)\n- 点击iOS Dev Center\n- 点蓝色“Login”按钮，用你的Apple ID登录，登录成功会跳到 [开发者首页](https://developer.apple.com/devcenter/ios/index.action)\n- 点击右上角的[iOS Provisioning Portal](https://developer.apple.com/ios/manage/overview/index.action)（别找了，直接Command F搜索多好）\n- 点左侧菜单栏里的[Certificates](https://developer.apple.com/ios/manage/certificates/team/index.action)\n\n页面上有一个“Your Certificate”区域，下方有个Download圆角按钮，这是你的个人证书，下载下来。再下面一行，有一句“If you do not have the WWDR intermediate certificate installed, [click here to download now](https://developer.apple.com/certificationauthority/AppleWWDRCA.cer)”，这个是苹果的公共证书，也下下来。\n\n双击下载回来的证书，装证书时，会提示你输入密码，这是【钥匙串访问工具】在问你要你的Mac OS账号开机密码（相当于linux里面的sudo），不是Apple ID的密码，不要搞错了。\n\n##### 安装私钥\n如果你是和其它同事公用的账号，让他给你一个私钥即可，就是一个扩展名为p12的文件，双击之，钥匙串访问会自动出来，需要你输入一个密码，这个密码问给你p12文件的人要，不是你的Mac OS系统开机密码，也不是你的Apple ID密码。\n\n\n#### 将设备注册到Provisioning Portal\n\n- 打开Xcode，从Xcode的Window菜单中找到Organizer，打开之（Shift Command 2）。\n- 把iOS设备连上电脑，Organizer会自动识别出你的设备，并显示在左侧边栏。\n- 在Organizer左侧边栏找到你的设备，右键，点击“Add Device to Provisioning Portal”，然后等Organizer提示你操作成功即可。（选中设备后，右边设备详情区域会显示一个按钮“Use for Development”，点它也可以）。\n\n#### 到iOS真机上运行测试版程序\n回到Xcode主界面，在Stop按钮（Run按钮右边那个黑色正方形按钮）右边，有个下拉菜单，显示着 “ToolBarSearch > iPhone 5.0 Simulator” （即 你的应用英文名 > 当前选中的调试 ），点击这个下拉菜单，选中你的真机设备名，再按“Run”按钮，Xcode就会自动把当前正在编辑开发的应用编译并安装到真机上测试啦！\n\n#### 发布到App Store\n\n#### 打IPA包\nIPA包本质上是一个ZIP压缩包，只不过它有着特殊的目录结构，扩展名是ipa，制作方法如下：\n\n- 在Xcode中Build项目，快捷键Command B\n- 在左侧项目导航器中，展开Products文件夹，找到你要打包的应用，你的应用名.app，右键，选择show in finder\n- 到Finder中Copy这个.app目录（选中，按Command C），复制到一个你新建的名为Payload（区分大小写）的文件夹中\n- 找到你的应用Logo，即一个512 * 512像素的PNG文件，copy到与Payload一起（与Payload并列，不要放进Payload了），并重命名为iTunesArtwork（区分大小写，没有扩展名）\n- 将Payload目录、ItunesArtwork文件打成一个zip包，并更改扩展名为ipa\n- 双击这个ipa文件，会用iTunes打开，如果打开成功，且在iTunes里有应用Logo显示，就成功了                \n\n#### 批量自动打包\n除App Store外，还有许多其它的iOS应用市场（如91助手，同步推等等），如果一个应用需要发布到很多个应用市场，且他们的代码略有不同（比如说，统计代码不同），按上述方法手工修改源码再打包，再还原，比较容易出错。好消息是，Xcode是有命令行的，我们可以写一个shell脚本，先用se自动修改源码，再调用Xcode的命令行来编译以得到your——app.app目录，最后调用zip、mv等命令把上一个章节讲的ipa打包动作自动执行。\n\n## 阅读应用代码\n\n## 从头新建一个应用：Hello World\n\n## 其它\n### 代码里的控件尺寸\niOS App里的控件尺寸和字体大小都是指Point，Retina设备（iPhone 4，4S，5；the new Pad）和非Retina设备（iPhone 3GS，iPad，iPad 2）的Point数是一样的，尽管iPhone 4的分辨率是3GS的2倍。比如说，10point在Retina设备里是20 pixel，在非Retina设备（iPhone 3G）上则是10 pixel。\n\n项目成员间交流时，应使用Point，不要使用pixel。\n\n### SVN操作含有@符号的文件\niOS应用中经常出现xxxx@2x.png这样的文件名,它们是给retina设备用的高分辨率大图，用svn命令行操作它们的时候会被@符号干扰,解决方案是在svn命令末尾加上一个@符号,如:\n\t\n\tsvn del icon@2x.png@\n\tsvn info Default@2x.png@\n \n如果一次移动了几十个png文件再svn commit的,可以用shell批处理:\n\n\tsvn status | awk '($1==\"!\"){print $2}' | grep -v @ | xargs svn del\n上面这个命令是将文件名不包含@符号的,且已经不在硬盘上的文件从svn version controll中删掉\n\n\tfor file in `svn status | awk '($1==\"!\"){print $2}' `; do svn del $file\"@\"; done     \n\n上面这个命令是将文件名包含@符号的,且已经不在硬盘上的文件从svn version controll中删掉\n \nsvn add同上, 如法炮制即可.\n\n### Xcode中的代码结构与操作系统上的文件系统并不一致\n推荐在Finder里建好目录再到Xcode的Project Navigator中点击“Add Files to”添加到项目中\n\n### iPhone 5适配\niPhone 5与之前的iPhone不一样，采用了4寸Retina屏，所以它的Point数变成了320 * 568 points\n\n### 开源代码\n* [Apple官方的Sample Code](https://developer.apple.com/library/ios/navigation/#section=Resource%20Types&topic=Sample%20Code)\n* [维基百科上的开源iOS App](http://en.wikipedia.org/wiki/List_of_free_and_open_source_iOS_applications)\n* [iOS Opensource](http://www.iosopensource.com/) --Domain Parking了，以前可以下载Twitter和Wordpress客户端的\n* [code 4 app](http://code4app.com/)\n* [UI 4 app](http://ui4app.com/)， code4app的姐妹站\n\n### Objective-C教程\n- [Apple官方教程](http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html)\n- [Cocoa Dev Center](http://cocoadevcentral.com/d/learn_objectivec/)\n- [维基上的Objective-C语言简介](http://zh.wikipedia.org/wiki/Objective-C) --中文，十分钟可读完，推荐\n"
  },
  {
    "path": "promotion_rule.md",
    "content": "# 零售行业优惠规则分析\n## 1 优惠规则5要素\n### 1.1 满足优惠条件的动作\n这个要素，是指触发优惠规则的动作，主要包括买和满两种。\n\n__注__：\n\n- 在数学上，买是满的一种特殊情况，只不过做文本串分析时，要同时考虑到这两种文本描述。\n- 在电商行业，触发优惠的动作还包括：晒单、微博分享、微信关注、给好评、收藏、新用户注册、手机下单等行为，这里我只叙述与商品和订单相关的，与其它行为（注册、营销、手机下单等）相关的暂忽略。\n- 抽奖，中奖要看运气，所以这时也暂不讨论\n\n#### 1.1.1 买\n只要买就优惠，如买赠（买1送1）、买立减（买此商品立减5元）\n\n#### 1.1.2 满\n如满88减18\n\n\n### 1.2 优惠条件作用对象\n这个要素，是指满的对象（上文已解释，买其实是满的一种特殊情况，故此处叙述时合并），满什么条件，主要有三种：\n\n#### 1.2.1 订单金额（抵扣前金额）\n如满88元减18元\n\n#### 1.2.2 实付金额（抵扣后金额）\n如实付100元再返20元代金券\n\n#### 1.2.3 商品数量\n如买二送三，满2件每件165元，39元任选三件\n\n\n### 1.3 优惠方式\n这个要素是指，商家以什么方式给予消费者优惠。\n\n#### 1.3.1 减\n在订单金额中减去部分金额，如满减，买立减，实付减\n\n#### 1.3.2 折\n订单金额或者商品单价打个折扣。如满188打8折，第二件半价。\n\n折其实也是减的一种特殊情况，做文本串分析时当两种情况\n\n#### 1.3.3 送/赠\n订单中赠送，或者订单完成后再赠送。如买1送1，买奶粉送奶瓶，买奶粉送京券\n\n#### 1.3.4 换购\n满99元即可加1元换购超值礼品\n\n### 1.4 回馈内容\n#### 1.4.1 现金\n- 满减、满折就是减了现金\n\n#### 1.4.2 可折算成现金几无使用限制的卡/券/积分\n- 赠送天猫积分、集分宝也等于赠送现金\n- 京券、京东积分也等于现金\n\n#### 1.4.3 同主体商品\n这条是指，赠送的商品与消费者购买的商品是同一个商品（可能保质期和生产批次略有不同，但总体上价值是一样的）\n\n如一号店的德运全脂牛奶，买一升，赠一升，属于赠送同主体的商品。\n\n#### 1.4.4 其它小赠品\n如买鞋送袜子，买奶粉送奶粉勺。\n\n把同主体商品拿出来单独说，和其它小赠品区分开，是因为同主体商品有利于计算实际到手价，德运全指牛奶买1送1，就等于是5折了，但如果买1升德运牛奶送5克奥利奥饼干，就不方便衡量饼干的价值进而计算到手价。\n\n#### 1.4.5 不可折算成现金的卡/券/积分\n- 送有限制条件的满减券、折扣券\n- 送一号店积分\n- 送淘金币\n- 送航空公司里程等等\n\n这类回馈有的价值较高（如有限制条件的券），有的如同鸡肋（如淘金币、一号店积分）不好统一衡量价值，也不能拿来参与到手价计算\n\n\n### 1.5 是否有限制\n是否有限制也影响到手价的计算\n\n#### 1.5.1 有限制\n- 满150减15，每个订单仅限使用一次\n- 买1送1，每个收货地址仅限5件\n- 实付200再返10元，最高返200元\n\n#### 1.5.2 无限制\n这个不多解释了\n\n## 2 常用优惠规则\n上述5个因素，排列组合最多超过200种，但考虑到有些组合不可能存在，如“回馈内容”中的两种“赠品”只可能和“优惠方式”中的“送赠”组合，而不可能和“折、减”组合，实际常用的优惠方式约为几十种（有无限制我就不一一罗列了，读者朋友自行把下面优惠规则总数乘以二）：\n\n### 2.1 减折类（6种）\n满折类的优惠条件主要是满N件和满N元，一般不会跟“实付xx元”搭配：\n\n- 买立减（买一件）\n- 买立折（买一件）\n- 满N件减x元 \n- 满N件打x折\n- 满N元减x元\n- 满N元打x折\n\n#### 2.2 送（可折算现金）卡/券/积分、不可折算现金的卡/券/积分、其它小赠品（12种）\n- 买即送（买一件）\n- 满N件送xx\n- 满N元送xx\n- 实付N元送xx\n\n在有的促销文案里，送虚拟卡券积分也叫满返。\n\n以上四种场景乘以赠送的三种东西，就是12种。\n\n#### 2.3 换购（4种）\n- 买此商品即享换购资格\n- 满N件即享换购资格\n- 满N元即享换购资格\n- 实付N元即享换购资格\n\n#### 2.4 送同主体商品（3种）\n- 买N送M\n- 满N元再送M件\n- 实付N元再送M件"
  },
  {
    "path": "shell.md",
    "content": "Shell脚本编程30分钟入门\n====================\n## 什么是Shell脚本\n### 示例\n看个例子吧：\n\n\t#!/bin/sh\n\tcd ~\n\tmkdir shell_tut\n\tcd shell_tut\n\t\n\tfor ((i=0; i<10; i++)); do\n\t\ttouch test_$i.txt\n\tdone\n\n### 示例解释\n\n- 第1行：指定脚本解释器，这里是用/bin/sh做解释器的\n- 第2行：切换到当前用户的home目录\n- 第3行：创建一个目录shell_tut\n- 第4行：切换到shell_tut目录\n- 第5行：循环条件，一共循环10次\n- 第6行：创建一个test_0…9.txt文件\n- 第7行：循环体结束\n\nmkdir, touch都是系统自带的程序，一般在/bin或者/usr/bin目录下。for, do, done是sh脚本语言的关键字。\n\n### shell和shell脚本的概念\nshell是指一种应用程序，这个应用程序提供了一个界面，用户通过这个界面访问操作系统内核的服务。Ken Thompson的sh是第一种Unix Shell，Windows Explorer是一个典型的图形界面Shell。\n\nshell脚本（shell script），是一种为shell编写的脚本程序。业界所说的shell通常都是指shell脚本，但读者朋友要知道，shell和shell script是两个不同的概念。由于习惯的原因，简洁起见，本文出现的“shell编程”都是指shell脚本编程，不是指开发shell自身（如Windows Explorer扩展开发）。\n\n## 环境\nshell编程跟java、php编程一样，只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。\n\n### OS\n当前主流的操作系统都支持shell编程，本文档所述的shell编程是指Linux下的shell，讲的基本都是POSIX标准下的功能，所以，也适用于Unix及BSD（如Mac OS）。\n\n#### Linux\nLinux默认安装就带了shell解释器。\n\n#### Mac OS\nMac OS不仅带了sh、bash这两个最基础的解释器，还内置了ksh、csh、zsh等不常用的解释器。\n\n#### Windows上的模拟器\nwindows出厂时没有内置shell解释器，需要自行安装，为了同时能用grep, awk, curl等工具，最好装一个cygwin或者mingw来模拟linux环境。\n\n- [cygwin](http://www.cygwin.com)\n- [mingw](http://www.mingw.org)\n\n### 脚本解释器\n#### sh\n即Bourne shell，POSIX（Portable Operating System Interface）标准的shell解释器，它的二进制文件路径通常是/bin/sh，由Bell Labs开发。\n\n本文讲的是sh，如果你使用其它语言用作shell编程，请自行参考相应语言的文档。\n\n#### bash\nBash是Bourne shell的替代品，属GNU Project，二进制文件路径通常是/bin/bash。业界通常混用bash、sh、和shell，比如你会经常在招聘运维工程师的文案中见到：熟悉Linux Bash编程，精通Shell编程。\n\n在CentOS里，/bin/sh是一个指向/bin/bash的符号链接:\n\n\t[root@centosraw ~]# ls -l /bin/*sh\n\t-rwxr-xr-x. 1 root root 903272 Feb 22 05:09 /bin/bash\n\t-rwxr-xr-x. 1 root root 106216 Oct 17  2012 /bin/dash\n\tlrwxrwxrwx. 1 root root      4 Mar 22 10:22 /bin/sh -> bash\n\n但在Mac OS上不是，/bin/sh和/bin/bash是两个不同的文件，尽管它们的大小只相差100字节左右:\n\n\tiMac:~ wuxiao$ ls -l /bin/*sh\n\t-r-xr-xr-x  1 root  wheel  1371648  6 Nov 16:52 /bin/bash\n\t-rwxr-xr-x  2 root  wheel   772992  6 Nov 16:52 /bin/csh\n\t-r-xr-xr-x  1 root  wheel  2180736  6 Nov 16:52 /bin/ksh\n\t-r-xr-xr-x  1 root  wheel  1371712  6 Nov 16:52 /bin/sh\n\t-rwxr-xr-x  2 root  wheel   772992  6 Nov 16:52 /bin/tcsh\n\t-rwxr-xr-x  1 root  wheel  1103984  6 Nov 16:52 /bin/zsh\n\n#### 高级编程语言\n理论上讲，只要一门语言提供了解释器（而不仅是编译器），这门语言就可以胜任脚本编程，常见的解释型语言都是可以用作脚本编程的，如：Perl、Tcl、Python、PHP、Ruby。Perl是最老牌的脚本编程语言了，Python这些年也成了一些linux发行版的预置解释器。\n\n编译型语言，只要有解释器，也可以用作脚本编程，如C shell是内置的（/bin/csh），Java有第三方解释器Jshell，Ada有收费的解释器AdaScript。\n\n如下是一个PHP Shell Script示例（假设文件名叫test.php）：\n\n\t#!/usr/bin/php\n\t<?php\n\tfor ($i=0; $i < 10; $i++)\n\t        echo $i . \"\\n\";\n\n执行：\n\n\t/usr/bin/php test.php\n或者：\n\n\tchmod +x test.php\n\t./test.php\n\n## 如何选择shell编程语言\n### 熟悉 vs 陌生\n如果你已经掌握了一门编程语言（如PHP、Python、Java、JavaScript），建议你就直接使用这门语言编写脚本程序，虽然某些地方会有点啰嗦，但你能利用在这门语言领域里的经验（单元测试、单步调试、IDE、第三方类库）。\n\n新增的学习成本很小，只要学会怎么使用shell解释器（Jshell、AdaScript）就可以了。\n\n\n### 简单 vs 高级\n如果你觉得自己熟悉的语言（如Java、C）写shell脚本实在太啰嗦，你只是想做一些备份文件、安装软件、下载数据之类的事情，学着使用sh，bash会是一个好主意。\n\nshell只定义了一个非常简单的编程语言，所以，如果你的脚本程序复杂度较高，或者要操作的数据结构比较复杂，那么还是应该使用Python、Perl这样的脚本语言，或者是你本来就已经很擅长的高级语言。因为sh和bash在这方面很弱，比如说：\n\n- 它的函数只能返回字串，无法返回数组\n- 它不支持面向对象，你无法实现一些优雅的设计模式\n- 它是解释型的，一边解释一边执行，连PHP那种预编译都不是，如果你的脚本包含错误(例如调用了不存在的函数)，只要没执行到这一行，就不会报错\n\n### 环境兼容性\n如果你的脚本是提供给别的用户使用，使用sh或者bash，你的脚本将具有最好的环境兼容性，perl很早就是linux标配了，python这些年也成了一些linux发行版的标配，至于mac os，它默认安装了perl、python、ruby、php、java等主流编程语言。\n\n\n## 第一个shell脚本\n### 编写\n打开文本编辑器，新建一个文件，扩展名为sh（sh代表shell），扩展名并不影响脚本执行，见名知意就好，如果你用php写shell 脚本，扩展名就用php好了。\n\n输入一些代码，第一行一般是这样：\n\n\t#!/bin/bash\n\t#!/usr/bin/php\n\n“#!”是一个约定的标记，它告诉系统这个脚本需要什么解释器来执行。\n\n### 运行\n运行Shell脚本有两种方法：\n#### 作为可执行程序\n\n\tchmod +x test.sh\n\t./test.sh\n\n注意，一定要写成./test.sh，而不是test.sh，运行其它二进制的程序也一样，直接写test.sh，linux系统会去PATH里寻找有没有叫test.sh的，而只有/bin, /sbin, /usr/bin，/usr/sbin等在PATH里，你的当前目录通常不在PATH里，所以写成test.sh是会找不到命令的，要用./test.sh告诉系统说，就在当前目录找。\n\n通过这种方式运行bash脚本，第一行一定要写对，好让系统查找到正确的解释器。\n\n这里的\"系统\"，其实就是shell这个应用程序（想象一下Windows Explorer），但我故意写成系统，是方便理解，既然这个系统就是指shell，那么一个使用/bin/sh作为解释器的脚本是不是可以省去第一行呢？是的。\n\n#### 作为解释器参数\n这种运行方式是，直接运行解释器，其参数就是shell脚本的文件名，如：\n\n\t/bin/sh test.sh\n\t/bin/php test.php\n\n这种方式运行的脚本，不需要在第一行指定解释器信息，写了也没用。\n\n## 变量\n### 定义变量\n定义变量时，变量名不加美元符号（$），如：\n\n\tyour_name=\"qinjx\"\n\n注意，变量名和等号之间不能有空格，这可能和你熟悉的所有编程语言都不一样。\n\n除了显式地直接赋值，还可以用语句给变量赋值，如：\n\n\tfor file in `ls /etc`\n\n### 使用变量\n使用一个定义过的变量，只要在变量名前面加美元符号即可，如：\n\n\tyour_name=\"qinjx\"\n\techo $your_name\n\techo ${your_name}\n\n变量名外面的花括号是可选的，加不加都行，加花括号是为了帮助解释器识别变量的边界，比如下面这种情况：\n\n\tfor skill in Ada Coffe Action Java; do\n\t\techo \"I am good at ${skill}Script\"\n\tdone\n\n如果不给skill变量加花括号，写成echo \"I am good at $skillScript\"，解释器就会把$skillScript当成一个变量（其值为空），代码执行结果就不是我们期望的样子了。\n\n推荐给所有变量加上花括号，这是个好的编程习惯。IntelliJ IDEA编写shell script时，IDE就会提示加花括号。\n\n### 重定义变量\n已定义的变量，可以被重新定义，如：\n\n\tyour_name=\"qinjx\"\n\techo $your_name\n\t\n\tyour_name=\"alibaba\"\n\techo $your_name\n\t\n这样写是合法的，但注意，第二次赋值的时候不能写$your_name=\"alibaba\"，使用变量的时候才加美元符。\n\n## 注释\n以“#”开头的行就是注释，会被解释器忽略。\n\n### 多行注释\nsh里没有多行注释，只能每一行加一个#号。就像这样：\n\n\t#--------------------------------------------\n\t# 这是一个自动打ipa的脚本，基于webfrogs的ipa-build书写：https://github.com/webfrogs/xcode_shell/blob/master/ipa-build\n\t\n\t# 功能：自动为etao ios app打包，产出物为14个渠道的ipa包\n\t# 特色：全自动打包，不需要输入任何参数\n\t#--------------------------------------------\n\t\n\t##### 用户配置区 开始 #####\n\t#\n\t#\n\t# 项目根目录，推荐将此脚本放在项目的根目录，这里就不用改了\n\t# 应用名，确保和Xcode里Product下的target_name.app名字一致\n\t#\n\t##### 用户配置区 结束  #####\n\n如果在开发过程中，遇到大段的代码需要临时注释起来，过一会儿又取消注释，怎么办呢？每一行加个#符号太费力了，可以把这一段要注释的代码用一对花括号括起来，定义成一个函数，没有地方调用这个函数，这块代码就不会执行，达到了和注释一样的效果。\n\n## 字符串\n字符串是shell编程中最常用最有用的数据类型（除了数字和字符串，也没啥其它类型好用了，哈哈），字符串可以用单引号，也可以用双引号，也可以不用引号。单双引号的区别跟PHP类似。\n\n### 单引号\n\n\tstr='this is a string'\n\n单引号字符串的限制：\n\n- 单引号里的任何字符都会原样输出，单引号字符串中的变量是无效的\n- 单引号字串中不能出现单引号（对单引号使用转义符后也不行）\n \n### 双引号\n\n\tyour_name='qinjx'\n\tstr=\"Hello, I know your are \\\"$your_name\\\"! \\n\"\n\n- 双引号里可以有变量\n- 双引号里可以出现转义字符\n\n### 字符串操作\n#### 拼接字符串\n\t\n\tyour_name=\"qinjx\"\n\tgreeting=\"hello, \"$your_name\" !\"\n\tgreeting_1=\"hello, ${your_name} !\"\n\t\n\techo $greeting $greeting_1\n\n#### 获取字符串长度：\n\n\tstring=\"abcd\"\n\techo ${#string} #输出：4\n\n#### 提取子字符串\n\n\tstring=\"alibaba is a great company\"\n\techo ${string:1:4} #输出：liba\n\n#### 查找子字符串\n\n\tstring=\"alibaba is a great company\"\n\techo `expr index \"$string\" is`#输出：3，这个语句的意思是：找出字母i在这名话中的位置，要在linux下运行，mac下会报错\n\n#### 更多\n参见本文档末尾的参考资料中[Advanced Bash-Scripting Guid Chapter 10.1](http://tldp.org/LDP/abs/html/string-manipulation.html)\n\n## 数组\n\n## 管道\n\n## 条件判断\n\n## 流程控制\n和Java、PHP等语言不一样，sh的流程控制不可为空，如：\n\n\t<?php\n\tif (isset($_GET[\"q\"])) {\n\t\tsearch(q);\n\t}\n\telse {\n\t\t//do nothing\n\t}\n\n在sh/bash里可不能这么写，如果else分支没有语句执行，就不要写这个else。\n\n还要注意，sh里的if [ $foo -eq 0 ]，这个方括号跟Java/PHP里if后面的圆括号大不相同，它是一个可执行程序（和ls, grep一样），想不到吧？在CentOS上，它在/usr/bin目录下：\n\n\tll /usr/bin/[\n\t-rwxr-xr-x. 1 root root 33408 6月  22 2012 /usr/bin/[\n\n正因为方括号在这里是一个可执行程序，方括号后面必须加空格，不能写成if [$foo -eq 0]\n\n### if else\n#### if\n\n\tif condition\n\tthen\n\t\tcommand1 \n\t\tcommand2\n\t\t...\n\t\tcommandN \n\tfi\n\n写成一行（适用于终端命令提示符）：\n\n\tif `ps -ef | grep ssh`;  then echo hello; fi\n\t\n末尾的fi就是if倒过来拼写，后面还会遇到类似的\n\n#### if else\n\tif condition\n\tthen\n\t\tcommand1 \n\t\tcommand2\n\t\t...\n\t\tcommandN\n\telse\n\t\tcommand\n\tfi\n\n#### if else-if else\n\n\tif condition1\n\tthen\n\t\tcommand1\n\telif condition2\n\t\tcommand2\n\telse\n\t\tcommandN\n\tfi\n\n### for while\n#### for\n在开篇的示例里演示过了：\n\n\tfor var in item1 item2 ... itemN\n\tdo\n\t\tcommand1\n\t\tcommand2\n\t\t...\n\t\tcommandN\n\tdone\n\n写成一行：\n\n\tfor var in item1 item2 ... itemN; do command1; command2… done;\n\n#### C风格的for\n\n\tfor (( EXP1; EXP2; EXP3 ))\n\tdo\n\t\tcommand1\n\t\tcommand2\n\t\tcommand3\n\tdone\n\n#### while\n\twhile condition\n\tdo\n\t\tcommand\n\tdone\n\t\n#### 无限循环\n\n\twhile :\n\tdo\n\t\tcommand\n\tdone\n\n或者\n\n\twhile true\n\tdo\n\t\tcommand\n\tdone\n\n或者\n\n\tfor (( ; ; ))\n\n#### until\n\n\tuntil condition\n\tdo\n\t\tcommand\n\tdone\n\n### case\n\n\tcase \"${opt}\" in\n\t\t\"Install-Puppet-Server\" )\n\t\t\tinstall_master $1\n\t\t\texit\n\t\t;;\n\n\t\t\"Install-Puppet-Client\" )\n\t\t\tinstall_client $1\n\t\t\texit\n\t\t;;\n\n\t\t\"Config-Puppet-Server\" )\n\t\t\tconfig_puppet_master\n\t\t\texit\n\t\t;;\n\n\t\t\"Config-Puppet-Client\" )\n\t\t\tconfig_puppet_client\n\t\t\texit\n\t\t;;\n\n\t\t\"Exit\" )\n\t\t\texit\n\t\t;;\n\n\t\t* ) echo \"Bad option, please choose again\"\n\tesac\n\ncase的语法和C family语言差别很大，它需要一个esac（就是case反过来）作为结束标记，每个case分支用右圆括号，用两个分号表示break\n\n\n## 函数\n### 定义\n### 调用\n\n## 文件包含\n可以使用source和.关键字，如：\n\n\tsource ./function.sh\n\t. ./function.sh\n\n在bash里，source和.是等效的，他们都是读入function.sh的内容并执行其内容（类似PHP里的include），为了更好的可移植性，推荐使用第二种写法。\n\n包含一个文件和执行一个文件一样，也要写这个文件的路径，不能光写文件名，比如上述例子中:\n\n\t. ./function.sh\n\n不可以写作：\n\n\t. function.sh\n\n如果function.sh是用户传入的参数，如何获得它的绝对路径呢？方法是：\n\n\treal_path=`readlink -f $1`#$1是用户输入的参数，如function.sh\n\t. $real_path\n\n\n## 用户输入\n### 执行脚本时传入\n### 脚本运行中输入\n### select菜单\n\n## stdin和stdout\n\n## 常用的命令\nsh脚本结合系统命令便有了强大的威力，在字符处理领域，有grep、awk、sed三剑客，grep负责找出特定的行，awk能将行拆分成多个字段，sed则可以实现更新插入删除等写操作。\n\n### ps\n查看进程列表\n\n### grep\n#### 排除grep自身\n#### 查找与target相邻的结果\n\n### awk\n\n### sed\n#### 插入\n#### 替换\n#### 删除\n\n### xargs\n### curl\n\n## 综合案例\n\n\n## 参考资料\n- [Advanced Bash-Scripting Guide](http://tldp.org/LDP/abs/html/)，非常详细，非常易读，大量example，既可以当入门教材，也可以当做工具书查阅\n- [Unix Shell Programming](http://www.tutorialspoint.com/unix/unix-shell.htm)\n- [Linux Shell Scripting Tutorial - A Beginner's handbook](http://bash.cyberciti.biz/guide/Main_Page)\n"
  }
]