无论个人还是组织,在追求改变、进步、提升的过程中,要想取得实质性和长期的成功,大都需要从小到大、从慢到快、从局部到整体逐步地改变,也就是一点一滴、循序渐进的方式推进,从而最终达成目标。这就是进步的“进化论原则”,它是一个生物学规律,也是一个社会学定律。
其本质思想,是无论生物体生理,还是人的心理、社会文化、群体行为,都是具有惯性的,而要改变这种惯性,需要持续长时间的微小变化积累。正如矫正牙齿、骨骼的方式,需要长时间持续给予微小的力量来改变,若强力扭转,只会折断折损,而达不到矫正的目的。
一个人要想减脂成功,不是一下子严控饮食,突增运动量,突击能够达成;而是,每天形成一定的热量缺口,慢慢递进式的增加,到了一定程度,再调整方案,使得身体适应节奏,不会报复性反弹,从而稳步到达目的。
改变一个拖延的习惯,是通过把事情拆解为一般事务性和深度事务,从一般性事务的立即行动,自然过渡到需要深度思考的缓步行动,曾风靡全球的畅销书《原子习惯》说的即是这个道理。
占据经济学中重要位置的边际思想或边际分析理论,也是进化论原则的体现:
… 第四个概念是“边际”。边际就是一小步一小步的试错。经济学不相信一口能吃个胖子,也不期待有一个超级英雄从天而降拯救受苦受难的老百姓。经济学家相信社会要靠人们自己一步一步地改进。因为他们不相信突然有一天有一个理想社会降临,他们也就不会因它没有降临而失望。他们脚踏实地,更相信通过他们一小步一小步的前进,能够一点儿一点儿地改进这个社会,他们也会在每一小步的改进中充满成就感。
—— 《在庆祝茅于轼老师 90 寿辰午宴上的讲话》—— 盛洪 2019-1-26 《中评周刊》
一项社会改革能实现,必定是一个一个具体问题的解决,制度柔性的过渡,慢慢达成的;所有激进的方式,只会带来动荡、割裂和反弹。台湾土地改革,是世界公认的学习典范,与大陆共党残暴血腥的方式不同,国民政府在台湾的土地改革——“三七五减租”、“公地放领”、“耕者有其田”循序漸進的三部曲,是温和渐进式的改良,照顾到了各方利益,整个过程没有杀人流血,成功实现了和谐与蓬勃发展的良性结果,成为世界土地政策的学习榜样。已经灭亡和可预见必将灭亡共产主义国家,以及南美阿根廷、委内瑞拉等国的统治者,都企图以简单粗暴共产乌托邦思维改造社会,最后都是血流成河、贫困遍地、饥荒与仇恨交加的结局。
就在五十年前,新竹一帶的佃租率仍高達七○%,也就是說,農民一年的辛勤收穫,有七成要繳給地主。台北、台中、台南等七縣市,佃租率平均也高達五七%。
直到陳誠來到台灣。
一九四八年,國共內戰正在生死關頭,陳誠被任命為台灣省主席。
懷著「民有、民治、民享」社會公平的夢想,看見當時貧富差距如此懸殊的台灣農村,陳誠決意重新分配土地所有權。
但陳誠的改革,不同於其他第三世界國家,雖然也引起一些大地主不滿,但始終沒有造成血淚抗爭。最主要的原因是,他以循序漸進的三部曲:三七五減租、公地放領、耕者有其田,來完成改革大計,每一步都是溫和理性的財富重分配。
這些改革使台灣農業生產力大增,糧食比前一年增產三成,佃農收益比前一年增加四三%。不僅農村貧富差距縮小,台灣也自此有了邁向工業化的厚實基礎。—— 《土地改革第一波 陳誠》《天下雜誌》2012-06-25
年轻时,没明白这个道理,后来读了很多历史巨人的思想,结合实际的经验,方悟出其中的真谛。
宋美龄:推动社会的进步,只能一致渐进方式才能达到——
因復語張曰:「爾性太急切,且易衝動。爾當知世上有許多事,皆非躁急之舉動可以成功者,唯步驟一致漸進之行動,乃可得真正之進步;換言之,即全國人民程度進至適當之水平線後,仍將感效果之遲緩。然余之經驗告余,躁急者百分之力量,祇能得一分之收穫;而徒求快意一時之舉動,決不能致中國於富強,惟堅忍卓絕之苦幹,始能得理想中之成功。」 張聞言,頗感動,誠摯言日:「夫人,余已覺悟此舉…
——《西安事變回憶錄 》 宋美齡著 中華民國二十六年一月 中正文教基金會
胡适:所有伟大的变革,都是从解决一个个具体问题开始的,进步是点滴积累的结果,没有这种思维,人就永远陷入悲观中——
…社會是種種勢力造成的,改造社會須要改造社會的種種勢力。這種改造一定是零碎的改造,——一點一滴的改造,一尺一步的改造。無論你的志願如何宏大,理想如何徹底,計劃如何偉大,你總不能攏統的改造,你總不能不做這種「得寸進寸,得尺進尺」的工夫。所以我說:社會的改造是這種制度那種制度的改造,是這種思想那種思想的改造,是這個家庭那個家庭的改造,是這個學堂那個學堂的改造。
—— 《非個人主義的新生活》胡適 1920年1月15日上海《時事新報》
—— 《青年不要悲觀》胡適 1946年 发表于《現代文叢》
马英九:一步登天的激进主张,往往能诱惑人的不理性,带来的往往是灾难——
——《原鄉精神:台灣的典範故事》 馬英九著 天下遠見出版公司 2007年
项目中使用Firebase JWT库做Token验证,确实很好用,减少了很多繁琐的判断,不过要使用它自带的验证方法,命名就必须符合它的标准。
如,起始时间,过期时间等都需要按照它的标准命名:
$tokenData = [ 'iat' => $issuedAt, //Token核发时间,标准写法,名称固定为 iat 'exp' => $expirationTime, //Token过期时间 ,标准写法,名称固定为 exp ];
验证非常方便,只需要调用相应的异常结果就可以了,不必自己拆解出来做复杂的判断。
try { $decoded = JWT::decode($token, new Key($this->secretKey, 'HS256')); $decodeToken = (array)$decoded; } catch (ExpiredException $e) {//过期异常 $message = 'Token has expired'; $outData = ['code' => 401, 'message' => $message]; return json($outData); } catch (SignatureInvalidException $e) { //签名不正确,被篡改 $message = 'Invalid token signature'; $outData = ['code' => 401, 'message' => $message]; return json($outData); } catch (Exception $e) { //格式不符或者被篡改 $message = 'Token validation failed'; $message = 'Verify Fail: permission denied'; $outData = ['code' => 401, 'message' => $message]; return json($outData); }
最近项目中使用Fabric.js做图像动态标记,被有些小问题缠住,花了很多时间去琢磨,有些甚至弄了一两天才理明白,特此记录。
1.canvas的width、height与style.width、style.height须一致,否则画出图形会变形或只显示图像的一部分。
canvasRef.value.width = img.naturalWidth; canvasRef.value.height = img.naturalHeight; canvasRef.value.style.width = img.naturalWidth + 'px'; canvasRef.value.style.height = img.naturalHeight + 'px';
看资料,fabric的画布实际上有三层(下图来自:jb51)
2.可以创建离屏/静态画布,不必在页面中显示,整体绘制完毕后再通过图像对象输出。
const canvas = new fabric.StaticCanvas(null, { width: originWidth, height: originHeight });
离屏画布的节点引用设置为null,一样可以设置宽高。
3. 如果有背景图片,所有创建的元素都需要在创建背景图片的函数体内完成,不能在函数体外创建,否则导出的图片将背景不可见。就是这个问题,我困扰了两天,开始以为是跨域问题,背景图片格式的问题等等,后来发现原因在此。
nextTick( () => { canvasRef.value.width = img.naturalWidth; canvasRef.value.height = img.naturalHeight; canvasRef.value.style.width = img.naturalWidth + 'px'; canvasRef.value.style.height = img.naturalHeight + 'px'; let currentCanvas = new fabric.Canvas(canvasRef.value, { selectionColor: '#4fb8d3', selectionLineWidth: 0 }); fabric.Image.fromURL(imgUrl, (img) => { //必须将绘制的文本和图形放到这个背景图函数体内,否则无法显示背景图 currentCanvas.setBackgroundImage( img, currentCanvas.renderAll.bind(currentCanvas) ); currentCanvas.backgroundImage.scaleToWidth(currentCanvas.width); currentCanvas.backgroundImage.scaleToHeight(currentCanvas.height); for (let key in LocationObj) { let locationNum = LocationObj[key][0].bbox; let arr = locationNum.split(','); let numberArray = arr.map(Number); let rect = new fabric.Rect({ left: numberArray[0], top: numberArray[1], width: numberArray[2] - numberArray[0], height: numberArray[3] - numberArray[1], fill: 'transparent', stroke: 'rgb(235,64,64,0.9)', strokeWidth: 3, strokeDashArray: [5, 5] }); let text = new fabric.Text( ' ' + messageMap.value[key] + ' - ' + Number(LocationObj[key][0].conf) * 100 + '%' + ' ', { left: numberArray[0], // 文本的X坐标 top: numberArray[1] - 22, fontSize: 22, // 字体大小 textBackgroundColor: '#eb4040', // 文字背景颜色 textBackgroundColor: 'rgb(235,64,64,0.8)', hasControls: false, // 不显示控件 hasBorders: false, // 不显示边框 fontWeight: 'normal', fill: 'white', padding: 20, lineHeight: 3, textAlign: 'right', fontFamily: 'Arial,Microsoft YaHei' } ); currentCanvas.add(rect); currentCanvas.add(text); currentCanvas.renderAll(); // rect.set('selectable', false); // text.set('selectable', false); } downURL.value = currentCanvas.toDataURL({ format: 'png', quality: 0.9 }); downLink.value.download = 'X_RayImg.png'; }); }, { crossOrigin: 'Anonymous' } );