Warning: in_array() expects parameter 2 to be array, null given in /data/wwwroot/blog.catui.co/usr/themes/Plain/header.php on line 93

分类 CODE 下的文章

JavaScript之继承

前言

javascript-extend.jpg

在 JavaScript 中,最让人困扰的几根莫过于 this闭包作用域原型链,而却常常看又常常忘,最近又看了一下高程感觉清晰了很多,于是就想写在这里(水一篇文章)。

继承

在此之前,先看一下 mdn 上 new 的解释:

当代码 new Foo(...) 执行时,会发生以下事情:  
**一个继承自 Foo.prototype 的新对象被创建**。  
使用指定的参数调用构造函数 Foo ,并将 this 绑定到新创建的对象。new Foo 等同于 new Foo(),也就是没有指定参数列表,Foo 不带任何参数调用的情况。  
由构造函数返回的对象就是 new 表达式的结果。如果构造函数没有显式返回一个对象,则使用步骤1创建的对象。(一般情况下,构造函数不返回值,但是用户可以选择主动返回对象,来覆盖正常的对象创建步骤

原型链继承

function Parent () {
    this.name = 'Parent'
    this.children = []
}

Parent.prototype.getAttr = function () {
    console.log(this.name,this.children)
}

function Child () {}
Child.prototype = new Parent()

var instance = new Child()

instance.constructor == Parent //true
instance.getAttr() //Parent []

//此时所有引用实例共享属性
var instance2 = new Child()
instance.name = 'instance'
instance.children.push('instance')

child2.getAttr()//Parent ["instance"]

借用构造函数

此方法是使用 call 或者 apply 方法,将父类的构造函数 this 绑定到子类上,当实例化子类式调用父类构造函数并绑定 this。所以每个实例都有自己的一份拷贝。

function Parent(){
    this.name = 'Parent'
    this.children = []

    // 此时方法也需在父类构造函数中声明,每次都会生成一个全新的 func
    this.getAttr = function(){}
}


function Child(){
    Parent.call(this)
}

var instance = new Child()
var instance2 = new Child()

instance.children.push('instance1')
instance2.children.push('instance2')

//["instance1"] ["instance2"]
console.log(instance.children,instance2.children)

组合继承

function Parent(){
    this.name = 'Parent'
    this.children = []
    
    // 此时方法也需在父类构造函数中声明
    this.getAttr = function(){}
}

function Child(){
    Parent.call(this)
}

// 直接继承公共方方法
Child.prototype = new Parent()

// 修成原型链
Child.prototype.constructor = Child

// 此时继承自 Child.prototype 的新对象被创建
var instance = new Child()
var instance2 = new Child()

instance.children.push('instance1')
instance2.children.push('instance2')

//["instance1"] ["instance2"]
console.log(instance.children,instance2.children)

寄生继承

function Parent(){
    this.name = 'Parent'
    this.children = []
}

var instance = Object.create(Parent)

寄生 + 组合

function Parent(){
    this.name = 'Parent'
    this.children = []
}

function Child(){
    Parent.call(this)
}

var prototype = Object.create(Parent)

//继承原型
prototype.constructor = Child
Child.prototype = prototype

### ES6 中的继承

class Child extend Parent{}


### ES6 多继承

- mixins

function mixins(derivedCtor, baseCtors) {

baseCtors.forEach(baseCtor => {
    Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
        derivedCtor.prototype[name] = baseCtor.prototype[name];
    })
});

}
mixins(child,[parent,...other])

你喜爱 React 还是 Vue

react-vs-vue.jpg
你更喜欢 Vue 还是 React?
为什么呢?
是因为 Vue 的模板语法的简单粗暴还是 React 的 JSX 的 HTML in JS?

React 和 Vue 是当下比较流行的前端框架,前者由 Fackbook 开发并维护,推出 Virtual DOM 的概念,和全新的语法 —— JSX(允许在 JavaScript 中书写 HTML);
而 Vue 则出自于个人开发者 Evan You,出现与 React 之后,看看它自己这么说 Comparison with Other Frameworks,与 React 不同,它使用的是更简单的模板语法,双向绑定,更平缓的学习曲线。

本文将(仅)从语法层面比对他们的语法,最后再来判断哪个更优雅,直观或者简结。

模版 VS JSX

React 和 Vue 最大的区别就是 模板语法 和 JSX 了,模板语法 使用近乎与 HTML 相同,仅仅是多了一些指令和属性,学习起来更加轻松;JSX 就不多介绍了,可以点这里,看看官方的说明。

当然 JSX 不是必须,Vue 也可以写 JSX,这个就不在本文讨论范围内了:
React Without JSX
Vue-JSX
babel-plugin-transform-vue-jsx

// JSX
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      text: "I' JSX."
    };
  }
  render() {
    return <p onClick={say}>{this.state.text}</p>;
  }
  say() {
    console.log("hello JSX !");
  }
}


// template 单文件写法
<template>
  <p @click="say">{text}</p>
</template>
<script>
export default {
  data() {
    return { text: "I'm template" };
  },
  methods: {
    say() {
      console.log("hello template !");
    }
  }
};
</script>

STATE = {} VS daat => {}

在 React 中提倡的是不可变数据(immutable),无副作用,自上而下的单向数据流(props),只有当 props / state 改变时才会触发组件的渲染(render),即 setState 进行数据更新。Vue 则利用 Object.defineProperty 实现数据的双向绑定(响应式),只要数据更新,视图就随之更新。

// React
class ....{
  ...
  state = { a: 1 }
  ...
  this.setState({a:2})
  // 如果需要依赖上一次的状态进行更新
  this.setState((prevState, props) => { a: prevState.a + 1 })
}

// Vue
...
data = () =>{
  a: 1
}
...
this.a = 2;
...

高阶组件 HOC VS Mixins

Vue 与 React 都鼓励组件化应用,即将应用分拆成一个个功能明确的模块,每个模块之间可以通过合适的方式互相联系,即代码复用。
React 中代码复用的主要方式就是使用高阶组件(Higher-Order Components),当然你也可以使用 mixins,但官方并不推荐这样做。而 Vue 中主要方式是使用 mixins,这是因为在 Vue 中实现高阶组件并不像 React 中那样简单。

在 React 早期版本(ES5),也是使用 Mixins 的方式,当开始使用 ES6 编写 React 后便 不再提倡 Mixins,继而使用 HOC 的方式。

如果你想知道更多:

例子:接收一个 Url,在每次开始的时候发送一个请求,以渲染页面。

// React HOC
function withHttpComponent(Component, url) {
  return class extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        data: []
      };
    }
    componentDidMount() {
      axios(url)
        .then(data => {
          this.setState({ data });
        })
        .catch(err => {});
    }
    render() {
      return <Component data={this.state.data} {...this.props} />;
    }
  };
}
const Home = props => {
  return <div>{props.data}</div>;
};

const withHttpHome = withHttpComponent(Home, "/");

// React mixins
var withHttpMixins = {
  componentDidMount: function() {
    axios(this.state.url)
      .then(data => {
        this.setState({ data });
      })
      .catch(err => {});
  }
};

var withHttpHome = React.createClass({
  getInitialState: function() {
    return { url: "/", data: [] };
  },
  mixins: [withHttpMixins],
  render: function() {
    return <div>{props.data}</div>;
  }
});

//Vue HOC

// Vue mixins
var withHttpMixins = {
  data: () => {
    data: [];
  },
  mounted() {
    axios(this.url)
      .then(data => {
        this.data = data;
      })
      .catch(err => {});
  }
};
var Component = Vue.extend({
  data: () => {
    url: "/";
    data: [];
  },
  mixins: [withHttpMixins]
});

var withHttpHome = new Component();

插槽 VS 组合

// React 2种方法 props.children & props
class Component extends React.Component {
  render() {
    const Title = this.props.title;
    return (
      <div>
        <Title/>
        {this.props.children}
    </div>
    )
  }
}

const Title = <h1>I'm title.</h1>

class App extends React.Component {
  render() {
    return (
      <Component title={Title}>
        <p>I'm content.</p>
      </Component>
    );
  }
}


// Vue
Vue.component("my-component", {
  template: "<div><slot></slot></div>"
});

<template>
  <my-component>
    <p>I'm content.</p>
  </my-component>;
<template>

shouldComponentUpdate VS VUE

Optimization-Efforts

最后

i-love-react.jpeg

shallow copy and deep copy

浅复制和深复制的区别?

  • 浅复制(shallow copy):只复制指向某个对象的指针,而不复制对象本身,新旧对象u共享一块内存;
  • 深复制(deep copy):复制并创建一个一摸一样的对象,不共享内存,修改新对象,旧对象保持不变。

即最大的区别在于,复制过程中的值是否为引用传值

- 阅读剩余部分 -

初探 Progressive Web App

它是什么 ?

Progressive Web App, 简称 PWA,是提升 Web App 的体验的一种新方法,能给用户原生应用的体验。
PWA 的主要特点:

  • 可靠 - 即使在不稳定的网络环境下,也能瞬间加载并展现
  • 体验 - 快速响应,并且有平滑的动画响应用户的操作
  • 粘性 - 像设备上的原生应用,具有沉浸式的用户体验,用户可以添加到桌面
  • Progressive Web App Checklist

- 阅读剩余部分 -

webpack4 升级指南


全新的 webpack(4)来了,带来了全新的特性,更快的性能,更少的配置,先来体验一番吧!

为了方便起见, 以下

  • start 为 yarn start
  • build 为 yarn build
  • 注释内容皆为注释下一行

开始安装 webpack4

webpack4+ 后推崇cli方式

$ yarn add webpack webpack-cli
# "webpack": "^4.5.0",
# "webpack-cli": "^2.0.14",
  • 创建以下目录
└─src
|      index.js
│
│  index.html
│  package.json
│  README.md
│  yarn-error.log
│  yarn.lock
│  .gitignore

体验 webpack4 0 配置

entry :默认为 src/index 。
output:默认为 dist ,文件名默认为 main.js 。
mode:为 production 和 development (必选)。

  • 编辑 index.html / index.js 为:
//index.html
<!DOCTYPE html>
<html>
  <head>
      <title>初探 webpack4</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="./dist/main.js"></script>
  </body>
</html>
//index.js
console.log('webpack 4')

执行 webpack ,结果将输出在 dist 文件夹内,在浏览器中打开 index.html 将看到预期结果。

正式开始

一. webpack 4 必须安装 CLI

官方的介绍是这样的:
不安装将会报 error。

二. 默认提供 mode 选项
值为 development(开发环境) || production(生产环境)
不需要自行判断是生产环境还是开发环境,直接在配置下增加字段。
development:默认启用 热加载/缓存 等。
production: 默认启用代码压缩等功能。

mode: development || production

三. CommonsChunkPlugin 的弃用

// webpack3
new webpack.optimize.CommonsChunkPlugin({
      names: ['common','vendor'],
      filename: './common/[name].bundle.js',
      minChunks: 2,
    })
// webpack4
  optimization: {
    minimize: true,
    splitChunks: {
      maxAsyncRequests: 5,
      maxInitialRequests: 3,
      minChunks: 2,
      cacheGroups: {
        default: false,
        commons: {
          filename: './commons/[name].[hash:8].js',
          name: "commons",
          chunks: "initial",
          minChunks: 2
        },
      vendor: {
        test: /node_modules/,
        filename: './vendor/[name].[hash:8].js',
        name: "vendor",
        chunks: "initial",
        minChunks: 1
      }
    }
  }
}

四. extract-text-webpack-plugin 将不再支持
改用 MiniCssExtractPlugin 这个插件,具体内如可查看官方 Issue 。

yarn add mini-css-extract-plugin

配置如下:

const MiniCssExtractPlugin = require("mini-css-extract-plugin");

plugins:[
  ...
  new MiniCssExtractPlugin({
        filename: "./css/[name].[hash:8].css",
        //chunkFilename: "[name].css"
      })
]
....
modules: {
  ....
  rules: [
    {
    test: /\.css$/,
    use: [{
      loader: MiniCssExtractPlugin.loader,
      options: {
        //因为上面设置了 /css/ 目录 
        //Issue:https://github.com/webpack-contrib/mini-css-extract-plugin/issues/44#issuecomment-379059788
        publicPath: '../'
      }
    },
    {
      loader: 'css-loader',
        options: {
          minimize: true,
          outputPath: './css/',
        }
    },
    {loader: 'postcss-loader'},
  }]
}

总结

webpack4更改内容

change log

  1. entry :默认为 src/index
  2. output:默认为 dist
  3. 新增 mode:为 production 和 development (必选)
  4. 默认热加载
  5. 新增cli
  6. 生产环境默认开启了很多代码优化( minify,splite 等),即不需要 UglifyJsPlugin
  7. CommonsChunkPlugin 删除,改用 optimization.splitChunks

通俗易懂的理解 Redux

Use create-react-app,redux,reacr-redux

action

action => 是纯声明式的数据结构,只提供事件的所有要素,不提供逻辑,返回一个对象。
Action 的任务是描述它想做什么?

const changeTitle = () => ({
    type: 'CHANGE_TITLE',//告诉我们它想改变title,并返回改变的东西。
    newTitle: 'Hello Reducer'
});

reducer

reducer => 匹配action,返回新的state。
reducer 就是帮我们做action想做的事~如何去做,todo
(state, action) => newState

const initialState = {
  title: 'Hello world'
}
const Reducer = (state=initialState, action) => {
  switch(action.type) {
      case 'CHANGE_TITLE':
          return {
              title: action.newTitle//返回一个title覆盖原title,以改变title
          }
      default:
          return state;
  }
};

store

Store => 就是我们存取状态数据的地方,外加可以订阅状态数据改变时触发的事件。
所有的 state 都以一个对象树的形式储存在一个单一的 store 中。

  • 维持应用的 state;
  • 提供 getState() 方法获取 state;
  • 提供 dispatch(action) 方法更新 state;
  • 通过 subscribe(listener) 注册监听器;
const store = createStore(Reducer);
console.log(store.getState());//输出{title: "Hello world"}
store.dispath(changeTitle());
console.log(store.getState());//输出{title: "Hello reducer"}

use with react

Redux 和 React 之间没有关系。Redux 可以搭配 React、Angular 甚至纯 JS。但是 Redux 还是比较适合和 React 搭配的,因为 React 允许你以 state 的形式来描述界面,而 Redux 非常擅长控制 state 的变化。

create-react-app demo
rm -rf src/*
yarn add react-redux redux

新建src/index.js & src/app.js;

import React from 'react';
import ReactDOM from 'react-dom';

const Hello = () =><h1>'Hello world!!!'</h1>;

ReactDOM.render(
  <Heloo />,
  document.getElementById('root')
);

yarn start现在刷新浏览器你能看到Hello world

create store & reducer

所有容器组件都可以访问 Redux store,所以可以手动监听它。一种方式是把它以 props 的形式传入到所有容器组件中。但这太麻烦了,因为必须要用 store 把展示组件包裹一层,仅仅是因为恰好在组件树中渲染了一个容器组件。

建议的方式是使用指定的 React Redux 组件 <Provider> 来 魔法般的 让所有容器组件都可以访问 store,而不必显示地传递它。只需要在渲染根组件时使用即可。

//src/reducers/index.js
const initialState = {
  title: 'Hello world'
};

const Reducer = (state=initialState, action) => {
  switch(action.type) {
      case 'CHANGE_TITLE':
          return {
              title: 'Hello reducer'
          }
      default:
          return state;
  }
};
export default Reducer;
// src/components/index.js
import React from 'react';

const App = () =>(
  <div>
    <h1>hello world!</h1>
    <button>Change</button>
  </div>
);
export default App;
//src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';

import App from './components/'
import Reducer from './reducers/'

const store = createStore(Reducer);

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);
console.log(store.getState());//{title: "Hello world"}

connect

连接组件与store

import React from 'react';
import { connect } from 'react-redux';

const App = (props) =>(
  <div>
    {console.log(props)}
    <h1>hello world</h1>
    <button>Change</button>
  </div>
);
export default connect()(App);

如果你打开你的开发者工具控制台,你应该看到一条消息!

组件现在可以通过store的dispath函数改变'state'。

// src/components/index.js
import React from 'react';
import { connect } from 'react-redux';

class App extends React.Component{
  constructor(props){
    super(props);
    this.props.dispatch({type:'CHANGE_TITLE',title:'hello redux'})
  }
  render(){
    return(
      <div>
        <h1>hello world</h1>
        <button>Change</button>
       </div>
    )
  }
}
export default connect()(App);

现在title改变了!

To change

利用connect将state注入到组件(props)
点击按钮,hello world将变成 hello reducer

// src/component/index.js
import React from 'react';
import { connect } from 'react-redux';

class App extends React.Component{
  constructor(props){
    super(props);
  }
  render(){
    const {title, dispatch} = this.props;
    return(
      <div>
        <h1>{this.props.title}</h1>
        <button onClick={() => dispatch({type:'CHANGE_TITLE',title:'hello redux'})}>Change</button>
       </div>
    )
  }
}
function mapStateToProps(state) {
  return {
    title: state.title
  }
}
export default connect(mapStateToProps)(App);

create action

将action抽离,并注入到组件(props)中.

// src/actions/index.js
export const changeTitle = () => ({
  type: 'CHANGE_TITLE',
  newTitl: 'Hello Stark'
});
export const resetTitle = () => ({
  type: 'RESET_TITLE',
  newTitle: 'reset'
});

// src/components/index.js
import React from 'react';
import { connect } from 'react-redux';
import {bindActionCreators} from 'redux';
import * as action from '../actions/';

class App extends React.Component{
  constructor(props){
    super(props);
  }
  render(){
    const {title, changeTitle, resetTitle} = this.props;
    console.log(this.props)
    return(
      <div>
        <h1>{title}</h1>
        <button onClick={changeTitle}>Change</button>
        <button onClick={resetTitle}>Reset</button>
       </div>
    )
  }
}
function mapStateToProps(state) {
  return {
    title: state.title
  }
}
function mapActionCreatorsToProps(dispatch){
  return bindActionCreators(action, dispatch);//合并多个action
}
export default connect(mapStateToProps,mapActionCreatorsToProps)(App);
// src/reducers/index.js
const initialState = {
  title : 'Hello world'
};

const Reducer = (state=initialState, action) => {
  switch(action.type) {
      case 'CHANGE_TITLE':
          return {
              title : action.newTitle
          }
      case 'RESET_TITLE':
        return {
            title: action.newTitle
        }    
      default:
          return state;
  }
};
export default Reducer;

完整代码

完整代码

React-Redux-Example

REACT-REDUX 小例子

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';

import { createStore, combineReducers, bindActionCreators } from 'redux';
import { connect, Provider } from 'react-redux'
class Counter extends React.Component {
    constructor(props) {
        super(props)
    }
    render() {
        const { a, add,decrement  } = this.props
        return (
            <div>
                <p style={{background:'red'}} onClick={() => add(1)}>{a}</p>
            </div>
        )
    }
}
/***Action****/
function add(number) {
    return {
        type: 'ADD',
        number
    }
}
function decrement(number) {
    return {
        type: 'DECREMENT',
        number
    }
}
/***connect***/
     /***注入State***/
function mapStateToProps(state) {
    return {
        a: state.a
    }
}
      /***注入Dispatch***/
function actionCreatorsToProps(dispatch) {
    return bindActionCreators({ add, decrement }, dispatch)
}
let Hello = connect(mapStateToProps, actionCreatorsToProps)(Counter);
/***Reducer***/
const defaulState = { a: 1 }
const reducer = (state = defaulState, action) => {
    switch (action.type) {
        case 'TEST': console.log(state, action);
        case 'ADD': return {a: state.a + action.number}
        case 'DECREMENT': return state;
        default: return state;
    }
};

const store = createStore(reducer);

const render = () => {
    ReactDOM.render(
        <Provider store={store}>
            <Hello />
        </Provider>,
        document.getElementById('root')
    );
};

render();
store.getState()
registerServiceWorker();

干些有趣的事情

离开和进入页面时改变title

利用 Page Visibility,该规范定义了一种用于站点开发人员以编程方式确定页面的当前可见性状态以便开发功率和CPU高效的Web应用程序的手段。

  • Document接口

    1. Document.hidden
    • 如果默认视图中的 文件为空,在获取时,该hidden属性必须返回true。
    1. document.visibilityState:
    • visibilityState 属性
    • 返回当前视图状态,分别为:
      -- hidden

-- visible
-- prerender
-- unloaded

  1. visibilitychange事件

    • 当用户代理确定顶级浏览上下文包含 的文档的可见性 已更改时, 用户代理必须触发文档上的visibilitychange事件 。

效果如下:

DefaultTitle
Leave
ComeBack

Code:

var DefaultTitle=document.title;
    document.addEventListener('visibilitychange', function () {
        if (document.hidden) {
            document.title = '你要去哪裏呢~~~';
        }else {
            document.title = 'QwQ~~';
            setTimeout(function () {
                document.title = DefaultTitle;
            }, 2000)
        }
    })

Copy Or Paste恶搞

利用 Window.getSelection clipboardData.setData

  • 原理:监听copy事件,获取Copy内容,操作剪切板并加入Diy语句。

效果如下:

ComeBack

Code:

document.addEventListener('copy', function (e) {
        var word = window.getSelection ? window.getSelection().toString() : document.selection.createRange().text;
        if (word.length > 1) {
            DiyWord(e);
            console.log('商业转载请联系作者获得授权,非商业转载请注明出处,谢谢合作。');
        }
    });
    function DiyWord(e) {
        var clipboardData = e.clipboardData || window.clipboardData;
        if (clipboardData) {
            event.preventDefault();
            //window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
            var Hello = '(灬╹ω╹灬)人家这么可爱你这样做真的好么 ->此为粘贴';
            //clipboardData.setData('text/html', Hello);
            clipboardData.setData('text/plain', Hello);
        }
    }
    //更多有趣的使用姿势自行探索Ψ( ̄∀ ̄)Ψ

自定义log输出

孩子,lu多了吧 ~ _ ~

var _log = console.log;
    console.log = function() {
        _log.call(console, '%c' + [].slice.call(arguments).join(' '), 'color:transparent;text-shadow:0 0 14px rgba(0,0,0,.8);')
    };
    console.log('                                       .. .vr       \n                                     qBMBBBMBMY     \n                                    8BBBBBOBMBMv    \n                                  iMBMM5vOY:BMBBv    \n                  .r,             OBM;   .: rBBBBBY   \n                  vUL             7BB   .;7. LBMMBBM.  \n                 .@Wwz.           :uvir .i:.iLMOMOBM..  \n                  vv::r;             iY. ...rv,@arqiao. \n                   Li. i:             v:.::::7vOBBMBL.. \n                   ,i7: vSUi,         :M7.:.,:u08OP. .  \n                     .N2k5u1ju7,..     BMGiiL7   ,i,i.  \n                      :rLjFYjvjLY7r::.  ;v  vr... rE8q;.:,, \n                     751jSLXPFu5uU@guohezou.,1vjY2E8@Yizero. \n                     BB:FMu rkM8Eq0PFjF15FZ0Xu15F25uuLuu25Gi.   \n                   ivSvvXL    :v58ZOGZXF2UUkFSFkU1u125uUJUUZ,   \n                 :@kevensun.      ,iY20GOXSUXkSuS2F5XXkUX5SEv.  \n             .:i0BMBMBBOOBMUi;,        ,;8PkFP5NkPXkFqPEqqkZu.  \n           .rqMqBBMOMMBMBBBM .           @kexianli.S11kFSU5q5   \n         .7BBOi1L1MM8BBBOMBB..,          8kqS52XkkU1Uqkk1kUEJ   \n         .;MBZ;iiMBMBMMOBBBu ,           1OkS1F1X5kPP112F51kU   \n           .rPY  OMBMBBBMBB2 ,.          rME5SSSFk1XPqFNkSUPZ,.\n                  ;;JuBML::r:.:.,,        SZPX0SXSP5kXGNP15UBr.\n                      L,    :@huhao.      :MNZqNXqSqXk2E0PSXPE .\n                  viLBX.,,v8Bj. i:r7:,     2Zkqq0XXSNN0NOXXSXOU \n                :r2. rMBGBMGi .7Y, 1i::i   vO0PMNNSXXEqP@Secbone.\n                .i1r. .jkY,    vE. iY....  20Fq0q5X5F1S2F22uuv1M; \n        ');
preView