├── .gitignore ├── LICENSE ├── README.md ├── package.json ├── src ├── 01-test.js ├── 01.js ├── 02-test.js ├── 02.js ├── 03.js ├── 04.js ├── 05.js ├── 06-test.js ├── 06.js ├── 07.js ├── 08.js ├── dest │ ├── 03.txt │ ├── 04.txt │ └── 05.json ├── files │ ├── test.css │ └── test.html └── test.html └── 编程语言实现模式.pdf /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.log 3 | node_modules 4 | coverage 5 | _book 6 | _site 7 | .publish -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 工业聚 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # language-implementation-patterns 2 | 《编程语言实现模式》的相关练习 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "language-implementation-patterns", 3 | "version": "1.0.0", 4 | "description": "《编程语言实现模式》的相关练习", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha **/*-test.js --recursive" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/Lucifier129/language-implementation-patterns.git" 12 | }, 13 | "keywords": [], 14 | "author": "", 15 | "license": "ISC", 16 | "bugs": { 17 | "url": "https://github.com/Lucifier129/language-implementation-patterns/issues" 18 | }, 19 | "homepage": "https://github.com/Lucifier129/language-implementation-patterns#readme", 20 | "devDependencies": { 21 | "expect": "^1.20.2", 22 | "mocha": "^3.2.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/01-test.js: -------------------------------------------------------------------------------- 1 | var expect = require('expect') 2 | var ListLexer = require('./01') 3 | 4 | describe('test ListLexer', () => { 5 | it('should work as expected', () => { 6 | let lexer = new ListLexer('[a, b]') 7 | let tokens = [] 8 | let token = lexer.nextToken() 9 | 10 | while (token.type !== ListLexer.EOF_TYPE) { 11 | tokens.push(token.toString()) 12 | token = lexer.nextToken() 13 | } 14 | 15 | expect(tokens).toEqual([ 16 | `<'[',LBRACK>`, 17 | `<'a',NAME>`, 18 | `<',',COMMA>`, 19 | `<'b',NAME>`, 20 | `<']',RBRACK>` 21 | ]) 22 | }) 23 | }) -------------------------------------------------------------------------------- /src/01.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 词法解析器 3 | * 4 | */ 5 | const EOF = -1 6 | const EOF_TYPE = 1 7 | 8 | class Lexer { 9 | constructor(input) { 10 | this.input = input // 输入的字符串 11 | this.index = 0 // 当前字符串的索引位置 12 | this.char = input[this.index] // 当前字符 13 | } 14 | consume() { // 向前移动一个字符 15 | this.index += 1 16 | if (this.index >= this.input.length) { // 判断是否到末尾 17 | this.char = EOF 18 | } else { 19 | this.char = this.input[this.index] 20 | } 21 | } 22 | match(char) { // 判断输入的 char 是否为当前的 this.char 23 | if (this.char === char) { 24 | this.consume() 25 | } else { 26 | throw new Error(`Expecting ${char}; Found ${this.char}`) 27 | } 28 | } 29 | } 30 | 31 | Lexer.EOF = EOF 32 | Lexer.EOF_TYPE = EOF_TYPE 33 | 34 | const NAME = 2 35 | const COMMA = 3 36 | const LBRACK = 4 37 | const RBRACK = 5 38 | const tokenNames = ['n/a', '', 'NAME', 'COMMA', 'LBRACK', 'RBRACK'] 39 | const getTokenName = index => tokenNames[index] 40 | 41 | // 判断输入字符是否为字母,即在 a-zA-Z 之间 42 | const isLetter = char => char >= 'a' && char <= 'z' || char >= 'A' && char <= 'Z' 43 | 44 | class ListLexer extends Lexer { 45 | constructor(input) { 46 | super(input) 47 | } 48 | isLetter() { 49 | return isLetter(this.char) 50 | } 51 | nextToken() { 52 | while (this.char !== EOF) { 53 | switch (this.char) { 54 | case ' ': 55 | case '\t': 56 | case '\n': 57 | case '\r': 58 | this.WS() 59 | break 60 | case ',': 61 | this.consume() 62 | return new Token(COMMA, ',') 63 | case '[': 64 | this.consume() 65 | return new Token(LBRACK, '[') 66 | case ']': 67 | this.consume() 68 | return new Token(RBRACK, ']') 69 | default: 70 | if (this.isLetter()) { 71 | return this.NAME() 72 | } 73 | throw new Error(`Invalid character: ${this.char}`) 74 | } 75 | } 76 | return new Token(EOF_TYPE, '') 77 | } 78 | WS() { // 忽略所有空白,换行,tab,回车符等 79 | while (this.char === ' ' || this.char === '\t' || this.char === '\n' || this.char === '\r') { 80 | this.consume() 81 | } 82 | } 83 | NAME() { // 匹配一列字母 84 | let name = '' 85 | while (this.isLetter()) { 86 | name += this.char 87 | this.consume() 88 | } 89 | return new Token(NAME, name) 90 | } 91 | } 92 | 93 | 94 | class Token { 95 | constructor(type, text) { 96 | this.type = type 97 | this.text = text 98 | } 99 | toString() { 100 | let tokenName = tokenNames[this.type] 101 | return `<'${this.text}',${tokenName}>` 102 | } 103 | } 104 | 105 | module.exports = ListLexer -------------------------------------------------------------------------------- /src/02-test.js: -------------------------------------------------------------------------------- 1 | var expect = require('expect') 2 | var { ListLexer, ListParser } = require('./02') 3 | 4 | describe('test ListLexer', () => { 5 | it('should not throw error', () => { 6 | let lexer = new ListLexer('[a, b = c]') 7 | let parser = new ListParser(lexer, 2) 8 | 9 | expect(() => { 10 | parser.list() 11 | }).toNotThrow() 12 | }) 13 | 14 | it('should not throw error too', () => { 15 | let lexer = new ListLexer('[a, b = c, [d, e]]') 16 | let parser = new ListParser(lexer, 2) 17 | 18 | expect(() => { 19 | parser.list() 20 | }).toNotThrow() 21 | 22 | }) 23 | 24 | it('should throw error', () => { 25 | let lexer = new ListLexer('[a, ,b = c]') 26 | let parser = new ListParser(lexer, 2) 27 | 28 | expect(() => { 29 | parser.list() 30 | }).toThrow(`Expecting name or list; Found <',',COMMA>`) 31 | }) 32 | 33 | it('should throw error too', () => { 34 | let lexer = new ListLexer('[a, /b = c]') 35 | let parser = new ListParser(lexer, 2) 36 | 37 | expect(() => { 38 | parser.list() 39 | }).toThrow(`Invalid character: /`) 40 | }) 41 | }) -------------------------------------------------------------------------------- /src/02.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 词法解析器 3 | * 在 01.js 的基础上,支持 LL(k), k > 1。递归下降解析 4 | * 5 | */ 6 | const EOF = -1 7 | const EOF_TYPE = 1 8 | 9 | class Lexer { 10 | constructor(input) { 11 | this.input = input // 输入的字符串 12 | this.index = 0 // 当前字符串的索引位置 13 | this.char = input[this.index] // 当前字符 14 | } 15 | consume() { // 向前移动一个字符 16 | this.index += 1 17 | if (this.index >= this.input.length) { // 判断是否到末尾 18 | this.char = EOF 19 | } else { 20 | this.char = this.input[this.index] 21 | } 22 | } 23 | match(char) { // 判断输入的 char 是否为当前的 this.char 24 | if (this.char === char) { 25 | this.consume() 26 | } else { 27 | throw new Error(`Expecting ${char}; Found ${this.char}`) 28 | } 29 | } 30 | } 31 | 32 | Lexer.EOF = EOF 33 | Lexer.EOF_TYPE = EOF_TYPE 34 | 35 | const NAME = 2 36 | const COMMA = 3 37 | const LBRACK = 4 38 | const RBRACK = 5 39 | const EQUALS = 6 40 | const tokenNames = ['n/a', '', 'NAME', 'COMMA', 'LBRACK', 'RBRACK', 'EQUALS'] 41 | const getTokenName = index => tokenNames[index] 42 | 43 | // 判断输入字符是否为字母,即在 a-zA-Z 之间 44 | const isLetter = char => char >= 'a' && char <= 'z' || char >= 'A' && char <= 'Z' 45 | 46 | class ListLexer extends Lexer { 47 | constructor(input) { 48 | super(input) 49 | } 50 | isLetter() { 51 | return isLetter(this.char) 52 | } 53 | nextToken() { 54 | while (this.char !== EOF) { 55 | switch (this.char) { 56 | case ' ': 57 | case '\t': 58 | case '\n': 59 | case '\r': 60 | this.WS() 61 | break 62 | case ',': 63 | this.consume() 64 | return new Token(COMMA, ',') 65 | case '[': 66 | this.consume() 67 | return new Token(LBRACK, '[') 68 | case ']': 69 | this.consume() 70 | return new Token(RBRACK, ']') 71 | case '=': 72 | this.consume() 73 | return new Token(EQUALS, '=') 74 | default: 75 | if (this.isLetter()) { 76 | return this.NAME() 77 | } 78 | throw new Error(`Invalid character: ${this.char}`) 79 | } 80 | } 81 | return new Token(EOF_TYPE, '') 82 | } 83 | WS() { // 忽略所有空白,换行,tab,回车符等 84 | while (this.char === ' ' || this.char === '\t' || this.char === '\n' || this.char === '\r') { 85 | this.consume() 86 | } 87 | } 88 | NAME() { // 匹配一列字母 89 | let name = '' 90 | while (this.isLetter()) { 91 | name += this.char 92 | this.consume() 93 | } 94 | return new Token(NAME, name) 95 | } 96 | } 97 | 98 | class Token { 99 | constructor(type, text) { 100 | this.type = type 101 | this.text = text 102 | } 103 | toString() { 104 | let tokenName = tokenNames[this.type] 105 | return `<'${this.text}',${tokenName}>` 106 | } 107 | } 108 | 109 | 110 | class Parser { 111 | constructor(lexer, k) { // lexer 词法解析类的实例,k 向前预读的 token 数量 112 | this.lexer = lexer 113 | this.k = k 114 | this.index = 0 115 | this.lookahead = Array.from(Array(k)) // 预读 token 列表 116 | this.lookahead.forEach(() => { // 调用 consume 方法填充列表 117 | this.consume() 118 | }) 119 | } 120 | consume() { 121 | this.lookahead[this.index] = this.lexer.nextToken() 122 | this.index = (this.index + 1) % this.k 123 | } 124 | getToken(n) { 125 | let index = (this.index + n - 1) % this.k 126 | return this.lookahead[index] 127 | } 128 | getTokenType(n) { 129 | return this.getToken(n).type 130 | } 131 | match(type) { 132 | let tokenType = this.getTokenType(1) 133 | if (tokenType === type) { 134 | this.consume() 135 | } else { 136 | throw new Error(`Expecting ${getTokenName(type)}; Found ${this.getToken()}`) 137 | } 138 | } 139 | } 140 | 141 | 142 | class ListParser extends Parser { 143 | list() { 144 | this.match(LBRACK) 145 | this.elements() 146 | this.match(RBRACK) 147 | } 148 | elements() { 149 | this.element() 150 | while (this.getTokenType(1) === COMMA) { 151 | this.match(COMMA) 152 | this.element() 153 | } 154 | } 155 | element() { 156 | let tokenType1 = this.getTokenType(1) 157 | let tokenType2 = this.getTokenType(2) 158 | 159 | if (tokenType1 === NAME && tokenType2 === EQUALS) { 160 | this.match(NAME) 161 | this.match(EQUALS) 162 | this.match(NAME) 163 | } else if (tokenType1 === NAME) { 164 | this.match(NAME) 165 | } else if (tokenType1 === LBRACK) { 166 | this.list() 167 | } else { 168 | throw new Error(`Expecting name or list; Found ${this.getToken(1)}`) 169 | } 170 | } 171 | } 172 | 173 | 174 | 175 | 176 | exports.ListLexer = ListLexer 177 | exports.ListParser = ListParser -------------------------------------------------------------------------------- /src/03.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | 4 | // 组合两个函数 5 | const compose = (f1, f2) => arg => f1(f2(arg)) 6 | 7 | // 连接两个函数 8 | const pipe = (f1, f2) => arg => f2(f1(arg)) 9 | 10 | const isFn = obj => typeof obj === 'function' 11 | 12 | const returnTrue = () => true 13 | 14 | // 判断输入字符是否为字母,即在 a-zA-Z 之间 15 | const isLetter = char => char >= 'a' && char <= 'z' || char >= 'A' && char <= 'Z' 16 | 17 | // 是空格或者其他分割符 18 | const isWhiteSpace = char => char === ' ' || char === '\t' || char === '\n' || char === '\r' 19 | 20 | const isNumber = char => !isNaN(Number(char.trim())) 21 | 22 | const charMap = { 23 | 'LETTER': isLetter, 24 | 'WHITE_SPACE': isWhiteSpace, 25 | 'NUMBER': isNumber, 26 | 'DOUBLE_QUOTES': '"', 27 | 'SINGLE_QUOTE': '\'', 28 | 'LEFT_BRACKET': '(', 29 | 'RIGHT_BRACKET': ')', 30 | 'LEFT_BRACE': '{', 31 | 'RIGHT_BRACE': '}', 32 | 'SLASH': '/', 33 | 'BACK_SLANT': '\\', 34 | 'WHIFFLETREE': '-', 35 | 'BANG': '!', 36 | 'COLON': ':', 37 | 'DOT': '.', 38 | 'POUND_KEY': '#', 39 | 'SEMICOLON': ';', 40 | 'AT_SYMBOL': '@', 41 | 'COMMA': ',', 42 | 'EQUAL_SYMBOL': '=', 43 | 'UNDERLINE': '_', 44 | 'PERSCENT_SYMBOL': '%', 45 | 'ASTERISK': '*', 46 | } 47 | 48 | const getCharPattern = char => { 49 | for (let key in charMap) { 50 | let value = charMap[key] 51 | if (isFn(value) && value(char)) { 52 | return { 53 | type: key, 54 | match: value, 55 | } 56 | } else if (char === value) { 57 | return { 58 | type: key, 59 | match: char => char === value, 60 | } 61 | } 62 | } 63 | 64 | // default 65 | return { 66 | type: 'UNKNOW', 67 | match: returnTrue 68 | } 69 | } 70 | 71 | class CharStream { 72 | constructor(input) { 73 | this.input = input 74 | this.index = 0 75 | } 76 | current() { 77 | return this.input[this.index] 78 | } 79 | next() { 80 | if (this.isEnd()) { 81 | return 82 | } 83 | this.index += 1 84 | return this.current() 85 | } 86 | test(char) { 87 | return char === this.current() 88 | } 89 | isEnd() { 90 | return this.index >= this.input.length 91 | } 92 | } 93 | 94 | class Token { 95 | constructor(type, text) { 96 | this.type = type 97 | this.text = text 98 | } 99 | toString() { 100 | return `${this.type}: ${this.text}` 101 | } 102 | length() { 103 | return this.text.length 104 | } 105 | } 106 | 107 | class TokenStream { 108 | constructor(input) { 109 | this.charStream = new CharStream(input) 110 | this.index = 0 111 | this.token = null 112 | } 113 | isEnd() { 114 | return this.charStream.isEnd() 115 | } 116 | current() { 117 | return this.token 118 | } 119 | next() { 120 | if (this.isEnd()) { 121 | return 122 | } 123 | let char = this.charStream.current() 124 | let { type, match } = getCharPattern(char) 125 | this.token = this.createToken(type, match) 126 | return this.current() 127 | } 128 | createToken(type, match) { 129 | let { charStream } = this 130 | let text = '' 131 | let char = charStream.current() 132 | while (!charStream.isEnd() && match(char)) { 133 | text += char 134 | char = charStream.next() 135 | } 136 | return new Token(type, text) 137 | } 138 | } 139 | 140 | 141 | // let cssFilePath = path.join(__dirname, 'files/test.css') 142 | // let content = fs.readFileSync(cssFilePath).toString() 143 | // let tokenStream = new TokenStream(content) 144 | 145 | // let result = '' 146 | // while (!tokenStream.isEnd()) { 147 | // let token = tokenStream.next().toString() 148 | // result += token + '\n' 149 | // } 150 | 151 | // const destPath = path.join(__dirname, 'dest/03.txt') 152 | // fs.writeFileSync(destPath, result) 153 | 154 | 155 | // const isClassSelector = 156 | 157 | // const syntaxMap = { 158 | // 'SELECTOR': ` 159 | // [DOT|POUND_KEY]LETTER 160 | // `, 161 | // } 162 | 163 | // class SyntaxStream { 164 | // constructor(input) { 165 | // this.tokenStream = new TokenStream(input) 166 | // this.tokens = [] 167 | // this.index = 0 168 | // } 169 | // isEnd() { 170 | // return this.tokenStream.isEnd() 171 | // } 172 | // getCurrentToken() { 173 | // return this.tokens[this.index] 174 | // } 175 | // getNextToken() { 176 | // if (this.isEnd()) { 177 | // return 178 | // } 179 | // let token = this.tokenStream.next() 180 | // this.tokens.push(token) 181 | // return token 182 | // } 183 | // isClassSelector() { 184 | // let offset = 0 185 | // let currentToken = this.getCurrentToken() 186 | // if (currentToken.type === 'DOT') { 187 | 188 | // } 189 | // } 190 | // } 191 | 192 | -------------------------------------------------------------------------------- /src/04.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | 4 | // 组合两个函数 5 | const compose = (f1, f2) => arg => f1(f2(arg)) 6 | 7 | // 连接两个函数 8 | const pipe = (f1, f2) => arg => f2(f1(arg)) 9 | 10 | const isFn = obj => typeof obj === 'function' 11 | 12 | const returnTrue = () => true 13 | 14 | // 判断输入字符是否为字母,即在 a-zA-Z 之间 15 | const isLetter = char => char >= 'a' && char <= 'z' || char >= 'A' && char <= 'Z' 16 | 17 | // 是空格或者其他分割符 18 | const isWhiteSpace = char => char === ' ' || char === '\t' || char === '\n' || char === '\r' 19 | 20 | // 是数字字符 0~9 21 | const isNumber = char => char >= '0' && char <= '9' 22 | 23 | // 检查 input 是否等于 char,value 为之前检查通过的 char 拼接起来的字符串 24 | const createMatch = (char, length) => (input, value) => { 25 | if (typeof length === 'number' && value.length === length) { 26 | return false 27 | } 28 | return input === char 29 | } 30 | 31 | const createFlatTokenizer = match => (input, start) => { 32 | if (!match.start) { 33 | let _match = match 34 | match = { 35 | start: _match, 36 | end() { 37 | return !_match.apply(null, arguments) 38 | } 39 | } 40 | } 41 | 42 | let offset = 0 43 | let item = input[start + offset] 44 | let value = [] 45 | 46 | if (!match.start(item, value)) { 47 | return 48 | } 49 | 50 | do { 51 | value.push(item) 52 | offset += 1 53 | item = input[start + offset] 54 | } while (!match.end(item, value)) 55 | 56 | return { 57 | value: value, 58 | start: start, 59 | end: start + offset 60 | } 61 | } 62 | 63 | const firstLayerPatterns = { 64 | 'LETTER': createFlatTokenizer(isLetter), 65 | 'WHITE_SPACE': createFlatTokenizer(isWhiteSpace), 66 | 'NUMBER': createFlatTokenizer(isNumber), 67 | 'DOUBLE_QUOTES': createFlatTokenizer(createMatch('"', 1)), 68 | 'SINGLE_QUOTE': createFlatTokenizer(createMatch('\'', 1)), 69 | 'LEFT_BRACKET': createFlatTokenizer(createMatch('(', 1)), 70 | 'RIGHT_BRACKET': createFlatTokenizer(createMatch(')', 1)), 71 | 'LEFT_BRACE': createFlatTokenizer(createMatch('{', 1)), 72 | 'RIGHT_BRACE': createFlatTokenizer(createMatch('}', 1)), 73 | 'SLASH': createFlatTokenizer(createMatch('/', 1)), 74 | 'BACK_SLANT': createFlatTokenizer(createMatch('\\', 1)), 75 | 'WHIFFLETREE': createFlatTokenizer(createMatch('-', 1)), 76 | 'BANG': createFlatTokenizer(createMatch('!', 1)), 77 | 'COLON': createFlatTokenizer(createMatch(':', 1)), 78 | 'DOT': createFlatTokenizer(createMatch('.', 1)), 79 | 'POUND_KEY': createFlatTokenizer(createMatch('#', 1)), 80 | 'SEMICOLON': createFlatTokenizer(createMatch(';', 1)), 81 | 'AT_SYMBOL': createFlatTokenizer(createMatch('@', 1)), 82 | 'COMMA': createFlatTokenizer(createMatch(',', 1)), 83 | 'EQUAL_SYMBOL': createFlatTokenizer(createMatch('=', 1)), 84 | 'UNDERLINE': createFlatTokenizer(createMatch('_', 1)), 85 | 'PERSCENT_SYMBOL': createFlatTokenizer(createMatch('%', 1)), 86 | 'ASTERISK': createFlatTokenizer(createMatch('*', 1)), 87 | 'LEFT_ANGLE_BRACKET': createFlatTokenizer(createMatch('<', 1)), 88 | 'RIGHT_ANGLE_BRACKET': createFlatTokenizer(createMatch('>', 1)), 89 | } 90 | 91 | function getFirstLayerToken(input, start) { 92 | for (let key in firstLayerPatterns) { 93 | let tokenizer = firstLayerPatterns[key] 94 | let token = tokenizer(input, start) 95 | if (token) { 96 | return Object.assign({type: key}, token) 97 | } 98 | } 99 | } 100 | 101 | function firstLayerTokenizer(input) { 102 | let index = 0 103 | let tokens = [] 104 | 105 | while (index < input.length) { 106 | let token = getFirstLayerToken(input, index) 107 | 108 | if (!token) { 109 | throw new Error(`Unknow char: ${input[index]}`) 110 | } 111 | 112 | tokens.push(token) 113 | 114 | index = token.end 115 | } 116 | 117 | return tokens 118 | } 119 | 120 | let cssFilePath = path.join(__dirname, 'files/test.css') 121 | let content = fs.readFileSync(cssFilePath).toString() 122 | let tokens = firstLayerTokenizer(content) 123 | 124 | const destPath = path.join(__dirname, 'dest/04.txt') 125 | fs.writeFileSync(destPath, JSON.stringify(tokens, null, 2)) -------------------------------------------------------------------------------- /src/05.js: -------------------------------------------------------------------------------- 1 | // 判断输入字符是否为字母,即在 a-zA-Z 之间 2 | const isLetter = char => char >= 'a' && char <= 'z' || char >= 'A' && char <= 'Z' 3 | 4 | // 是空格或者其他分割符 5 | const isWhiteSpace = char => char === ' ' || char === '\t' || char === '\n' || char === '\r' 6 | 7 | // 是数字字符 0~9 8 | const isNumber = char => char >= '0' && char <= '9' 9 | 10 | // 检查 input 是否等于 char,value 为之前检查通过的 char 拼接起来的字符串 11 | const createMatch = (char, length) => { 12 | let start = value => value === char 13 | let end = value => { 14 | if (typeof length === 'number' && value.length === length) { 15 | return true 16 | } 17 | return value !== char 18 | } 19 | return { start, end } 20 | } 21 | 22 | const defaultGetValue = (item, value) => value + item 23 | 24 | const createTokenizer = match => { 25 | let tokenizer = (input, start) => { 26 | let item = input[start] 27 | // if (match.test) { 28 | // console.log(item, start) 29 | // } 30 | if (!match.start(item)) { 31 | return 32 | } 33 | 34 | let value = '' 35 | 36 | if (match.getInitialValue) { 37 | value = match.getInitialValue(item) 38 | } 39 | 40 | let getValue = match.getValue || defaultGetValue 41 | let offset = 0 42 | 43 | if (match.first !== false) { 44 | value = getValue(item, value, offset) 45 | } 46 | 47 | if (match.check && match.check(value, offset, start) === false) { 48 | return 49 | } 50 | 51 | offset += 1 52 | item = input[start + offset] 53 | 54 | while (item !== undefined && !match.end(item, value)) { 55 | value = getValue(item, value, offset) 56 | offset += 1 57 | item = input[start + offset] 58 | if (match.check && match.check(value, offset, start) === false) { 59 | return 60 | } 61 | } 62 | 63 | if (item && match.last === true) { 64 | value = getValue(item, value, offset) 65 | offset += 1 66 | if (match.check && match.check(value, offset, start) === false) { 67 | return 68 | } 69 | } 70 | 71 | if (match.getFinalValue) { 72 | value = match.getFinalValue(value, offset, start) 73 | } 74 | 75 | return { 76 | value: value, 77 | start: start, 78 | end: start + offset 79 | } 80 | } 81 | 82 | return tokenizer 83 | } 84 | 85 | const patterns = { 86 | 'DOUBLE_QUOTES_STRING': createTokenizer({ 87 | last: true, 88 | start: char => char === '"', 89 | end: char => char === '"', 90 | }), 91 | 'SINGLE_QUOTES_STRING': createTokenizer({ 92 | last: true, 93 | start: char => char === '\'', 94 | end: char => char === '\'', 95 | }), 96 | 'NAME': createTokenizer({ 97 | start: isLetter, 98 | end: char => 99 | !isLetter(char) && 100 | !isNumber(char) && 101 | char !== '_' && 102 | char !== '-', 103 | }), 104 | 'NUMBER': createTokenizer({ 105 | start: isNumber, 106 | end: value => !isNumber(value), 107 | }), 108 | 'WHITE_SPACE': createTokenizer({ 109 | start: isWhiteSpace, 110 | end: value => !isWhiteSpace(value), 111 | }), 112 | 'LEFT_BRACKET': createTokenizer(createMatch('(', 1)), 113 | 'RIGHT_BRACKET': createTokenizer(createMatch(')', 1)), 114 | 'LEFT_BRACE': createTokenizer(createMatch('{', 1)), 115 | 'RIGHT_BRACE': createTokenizer(createMatch('}', 1)), 116 | 'SLASH': createTokenizer(createMatch('/', 1)), 117 | 'BACK_SLANT': createTokenizer(createMatch('\\', 1)), 118 | 'WHIFFLETREE': createTokenizer(createMatch('-', 1)), 119 | 'BANG': createTokenizer(createMatch('!', 1)), 120 | 'COLON': createTokenizer(createMatch(':', 1)), 121 | 'DOT': createTokenizer(createMatch('.', 1)), 122 | 'POUND_KEY': createTokenizer(createMatch('#', 1)), 123 | 'SEMICOLON': createTokenizer(createMatch(';', 1)), 124 | 'AT_SYMBOL': createTokenizer(createMatch('@', 1)), 125 | 'COMMA': createTokenizer(createMatch(',', 1)), 126 | 'EQUAL_SYMBOL': createTokenizer(createMatch('=', 1)), 127 | 'UNDERLINE': createTokenizer(createMatch('_', 1)), 128 | 'PERSCENT_SYMBOL': createTokenizer(createMatch('%', 1)), 129 | 'ASTERISK': createTokenizer(createMatch('*', 1)), 130 | 'LEFT_ANGLE_BRACKET': createTokenizer(createMatch('<', 1)), 131 | 'RIGHT_ANGLE_BRACKET': createTokenizer(createMatch('>', 1)), 132 | 'UNKNOW': createTokenizer({ 133 | start: () => true, 134 | end: () => true, 135 | }) 136 | } 137 | 138 | function getToken(input, start) { 139 | for (let key in patterns) { 140 | let tokenizer = patterns[key] 141 | let token = tokenizer(input, start) 142 | if (token) { 143 | return Object.assign({type: key}, token) 144 | } 145 | } 146 | } 147 | 148 | function tokenizer(input) { 149 | let index = 0 150 | let tokens = [] 151 | while (index < input.length) { 152 | let token = getToken(input, index) 153 | if (token) { 154 | tokens[tokens.length] = token 155 | index = token.end 156 | } 157 | } 158 | return tokens 159 | } 160 | 161 | 162 | const patterns1 = { 163 | 'RULE': createTokenizer({ 164 | last: true, 165 | getInitialValue: () => [], 166 | check: value => !!value, 167 | start: token => token.type === 'NAME', 168 | end: (token, value) => { 169 | return token.type === 'SEMICOLON' 170 | }, 171 | getValue: (token, value, offset) => { 172 | if (value.length === 0) { 173 | value.push(token) 174 | return value 175 | } 176 | 177 | let last = value[value.length - 1] 178 | if (value.length === 1 && last.type === 'NAME' && token.type !== 'COLON') { 179 | return 180 | } 181 | 182 | value.push(token) 183 | return value 184 | }, 185 | getFinalValue: tokens => tokens.map(token => token.value).join(''), 186 | }), 187 | // 'RULES': createTokenizer({ 188 | // test: true, 189 | // last: true, 190 | // start: token => token.type === 'LEFT_BRACE', 191 | // end: token => token.type === 'RIGHT_BRACE', 192 | // getValue: (item, value) => value + item.value, 193 | // }), 194 | 'SELECTOR': createTokenizer({ 195 | start: token => token.type !== 'LEFT_BRACE' && token.type !== 'WHITE_SPACE' && token.type !== 'SEMICOLON', 196 | end: token => token.type === 'WHITE_SPACE' || token.type === 'LEFT_BRACE', 197 | getValue: (item, value) => value + item.value, 198 | }), 199 | 'UNKNOW': createTokenizer({ 200 | start: () => true, 201 | end: () => true, 202 | getValue: (item) => item, 203 | }), 204 | } 205 | 206 | function getToken1(input, start) { 207 | for (let key in patterns1) { 208 | let tokenizer = patterns1[key] 209 | let token = tokenizer(input, start) 210 | if (token) { 211 | return Object.assign({type: key}, token) 212 | } 213 | } 214 | } 215 | 216 | function tokenizer1(input) { 217 | let index = 0 218 | let tokens = [] 219 | while (index < input.length) { 220 | let token = getToken1(input, index) 221 | if (token) { 222 | tokens[tokens.length] = token 223 | index = token.end 224 | } 225 | } 226 | return tokens 227 | } 228 | 229 | 230 | 231 | 232 | let fs = require('fs') 233 | let path = require('path') 234 | let cssFilePath = path.join(__dirname, 'files/test.css') 235 | let content = fs.readFileSync(cssFilePath).toString() 236 | let tokens = tokenizer(content) 237 | let tokens1 = tokenizer1(tokens) 238 | 239 | let destPath = path.join(__dirname, 'dest/05.json') 240 | fs.writeFileSync(destPath, JSON.stringify(tokens1, null, 2)) -------------------------------------------------------------------------------- /src/06-test.js: -------------------------------------------------------------------------------- 1 | var expect = require('expect') 2 | var parse = require('./06') 3 | 4 | var str = ` 5 | \`\`\`zk 6 | title : 有这些礼物搞定宅男并不难 7 | desc: 如果你喜欢的男生是个宅男/GEEK,总之就是闷得不行,让你一筹莫展?别着急,调调来帮你!趁着圣诞/新年之际,挑选一个戳中他的礼物表达你的心意,一定会有所进展! 8 | image : ![](//content.image.alimmdn.com/cms/sites/default/files/20151215/zk/4234cover.jpg) 9 | haha : 测试新字段 10 | hehe : 测试另一个新字段 11 | \`\`\` 12 | \`\`\`card 13 | id: 2419 14 | title: 游戏、电影的好伴侣:Sony MDR-HW700DS无线耳机 15 | desc: 投其所好最重要!可是游戏动漫都不懂,咋办?此时请默念,索尼大法好。它是和PS3/PS4等配合最好的多声道耳机,当然xbox系支持也不在话下,游戏迷神器,看电影也是效果拔群,是这个价位上效果最好的无线耳机。 16 | image: ![](//content.image.alimmdn.com/cms/sites/default/files/20150701/goodthing/c_old.jpg) 17 | \`\`\`` 18 | 19 | 20 | describe('test parse a special markdown block', () => { 21 | it('should parse correctly', () => { 22 | let result = parse(str) 23 | expect(result).toEqual([{ 24 | type: 'zk', 25 | data: { 26 | title: '有这些礼物搞定宅男并不难', 27 | desc: '如果你喜欢的男生是个宅男/GEEK,总之就是闷得不行,让你一筹莫展?别着急,调调来帮你!趁着圣诞/新年之际,挑选一个戳中他的礼物表达你的心意,一定会有所进展!', 28 | image: '![](//content.image.alimmdn.com/cms/sites/default/files/20151215/zk/4234cover.jpg)', 29 | haha: '测试新字段', 30 | hehe: '测试另一个新字段', 31 | } 32 | }, { 33 | type: 'card', 34 | data: { 35 | id: '2419', 36 | title: '游戏、电影的好伴侣:SonyMDR-HW700DS无线耳机', 37 | desc: '投其所好最重要!可是游戏动漫都不懂,咋办?此时请默念,索尼大法好。它是和PS3/PS4等配合最好的多声道耳机,当然xbox系支持也不在话下,游戏迷神器,看电影也是效果拔群,是这个价位上效果最好的无线耳机。', 38 | image: '![](//content.image.alimmdn.com/cms/sites/default/files/20150701/goodthing/c_old.jpg)' 39 | } 40 | }]) 41 | }) 42 | }) -------------------------------------------------------------------------------- /src/06.js: -------------------------------------------------------------------------------- 1 | const isWhiteSpace = char => ( 2 | char === ' ' || 3 | char === '\n' || 4 | char === '\r' || 5 | char === '\t' 6 | ) 7 | const isLetter = char => char >= 'a' && char <= 'z' || char >= 'A' && char <= 'Z' 8 | 9 | module.exports = parse 10 | 11 | function parse(inputs) { 12 | let groups = toGroup(inputs) 13 | let structure = toStructure(groups) 14 | return structure 15 | } 16 | 17 | function toGroup(inputs) { 18 | let index = 0 19 | let groups = [] 20 | let char = '' 21 | let ignoreWhiteSpace = () => { 22 | while (isWhiteSpace(char)) { 23 | char = inputs[index++] 24 | } 25 | } 26 | let getNext = () => { 27 | char = inputs[index++] 28 | } 29 | 30 | getNext() 31 | 32 | while (char != null) { 33 | ignoreWhiteSpace() 34 | 35 | if (char == null) { 36 | break 37 | } 38 | 39 | let value = '' 40 | 41 | while (char === '`') { 42 | value += char 43 | getNext() 44 | } 45 | 46 | if (value) { 47 | groups.push({ 48 | type: 'BACKQUOTE', 49 | value: value, 50 | }) 51 | continue 52 | } 53 | 54 | while (isLetter(char)) { 55 | value += char 56 | getNext() 57 | } 58 | 59 | if (value) { 60 | groups.push({ 61 | type: 'LETTER', 62 | value: value, 63 | }) 64 | continue 65 | } 66 | 67 | if (char === ':') { 68 | groups.push({ 69 | type: 'COLON', 70 | value: char, 71 | }) 72 | getNext() 73 | continue 74 | } 75 | 76 | groups.push({ 77 | type: 'UNKNOW', 78 | value: char, 79 | }) 80 | getNext() 81 | } 82 | 83 | return groups 84 | } 85 | 86 | function toStructure(groups) { 87 | let structure = [] 88 | let index = 0 89 | let currentItem = groups[0] 90 | 91 | let isBlockStart = () => { 92 | if (index >= groups.length) { 93 | return false 94 | } 95 | return ( 96 | groups[index].type === 'BACKQUOTE' && 97 | index + 1 < groups.length && 98 | groups[index + 1].type === 'LETTER' 99 | ) 100 | } 101 | 102 | let isPair = () => { 103 | if (index >= groups.length) { 104 | return false 105 | } 106 | return ( 107 | groups[index].type === 'LETTER' && 108 | index + 1 < groups.length && 109 | groups[index + 1].type === 'COLON' 110 | ) 111 | } 112 | 113 | let isBlockEnd = () => { 114 | if (index >= groups.length) { 115 | return false 116 | } 117 | return ( 118 | groups[index].type === 'BACKQUOTE' && 119 | groups[index].value.length === 3 120 | ) 121 | } 122 | 123 | while (index < groups.length) { 124 | while (isBlockStart()) { 125 | let block = { 126 | type: groups[index + 1].value, 127 | data: {}, 128 | } 129 | 130 | index += 2 131 | 132 | while (isPair()) { 133 | let key = groups[index].value 134 | let value = '' 135 | index += 2 136 | while (!isPair() && !isBlockEnd()) { 137 | if (index >= groups.length) { 138 | break 139 | } 140 | value += groups[index].value 141 | index += 1 142 | } 143 | block.data[key] = value 144 | } 145 | 146 | if (!isBlockEnd()) { 147 | throw new Error(`Expected \`\`\`, but get ${JSON.stringify(groups[index], null, 2)}`) 148 | } 149 | index += 1 150 | structure.push(block) 151 | } 152 | } 153 | return structure 154 | } -------------------------------------------------------------------------------- /src/07.js: -------------------------------------------------------------------------------- 1 | const SPACE = ' ' 2 | const TAB = '\t' 3 | const NEW_LINE = '\n' 4 | const ZERO = '0' 5 | const NINE = '9' 6 | const DOT = '.' 7 | const PLUS_SIGN = '+' 8 | const MINUS_SIGN = '-' 9 | const MULTIPLICATION_SIGN = '*' 10 | const DEVISION_SIGN = '/' 11 | const LEFT_PARENTHESE = '(' 12 | const RIGHT_PARENTHESE = ')' 13 | 14 | const NUMBER = 0 15 | const OPERAND = 1 16 | const UNKNOW = 2 17 | const PARENTHESE = 3 18 | const GROUPING = 4 19 | 20 | class Character { 21 | constructor(value) { 22 | this.value = value 23 | } 24 | isWhiteSpace() { 25 | switch (this.value) { 26 | case SPACE: 27 | case TAB: 28 | case NEW_LINE: 29 | return true 30 | default: 31 | return false 32 | } 33 | } 34 | isOperand() { 35 | switch (this.value) { 36 | case PLUS_SIGN: 37 | case MINUS_SIGN: 38 | case MULTIPLICATION_SIGN: 39 | case DEVISION_SIGN: 40 | return true 41 | default: 42 | return false 43 | } 44 | } 45 | isDigit() { 46 | return this.value >= ZERO && this.value <= NINE 47 | } 48 | isDot() { 49 | return this.value === DOT 50 | } 51 | isLeftParenthese() { 52 | return this.value === LEFT_PARENTHESE 53 | } 54 | isRightParenthese() { 55 | return this.value === RIGHT_PARENTHESE 56 | } 57 | } 58 | 59 | class Token { 60 | constructor(type, startIndex) { 61 | this.type = type 62 | this.startIndex = startIndex 63 | this.value = '' 64 | } 65 | add(character) { 66 | this.value += character 67 | } 68 | is(type) { 69 | return this.type === type 70 | } 71 | } 72 | 73 | class Tokenizer { 74 | constructor(input, output = []) { 75 | this.input = input 76 | this.output = output 77 | this.index = 0 78 | this.character = null 79 | } 80 | isNotEnd() { 81 | return this.index < this.input.length 82 | } 83 | next() { 84 | if (this.isNotEnd()) { 85 | return new Character(this.input[this.index++]) 86 | } else { 87 | return null 88 | } 89 | } 90 | peek(n = 0) { 91 | if (this.index + n < this.input.length) { 92 | return new Character(this.input[this.index + n]) 93 | } else { 94 | return null 95 | } 96 | } 97 | consume() { 98 | let character = this.next() 99 | while (character && character.isWhiteSpace()) { 100 | character = this.next() 101 | } 102 | this.character = character 103 | return !!this.character 104 | } 105 | createToken(type) { 106 | return new Token(type, this.index - 1) 107 | } 108 | handleNumber() { 109 | let token = this.createToken(NUMBER) 110 | token.add(this.character.value) 111 | 112 | let nextToken = this.peek() 113 | 114 | while (nextToken && (nextToken.isDigit() || nextToken.isDot())) { 115 | token.add(this.next().value) 116 | nextToken = this.peek() 117 | } 118 | 119 | if (token.value.split('.').filter(item => item === DOT).length > 1) { 120 | throw new Error('非法数字') 121 | } 122 | 123 | this.output.push(token) 124 | } 125 | handleOperand() { 126 | let token = this.createToken(OPERAND) 127 | token.add(this.character.value) 128 | this.output.push(token) 129 | } 130 | handleParenthese() { 131 | let token = this.createToken(PARENTHESE) 132 | token.add(this.character.value) 133 | this.output.push(token) 134 | } 135 | execute() { 136 | while (this.isNotEnd()) { 137 | if (!this.consume()) { 138 | return this.output 139 | } 140 | 141 | let character = this.character 142 | 143 | let isDigit = character.isDigit() 144 | if (isDigit) { 145 | this.handleNumber() 146 | continue 147 | } 148 | 149 | let isOperand = character.isOperand() 150 | let isDigitWithOperand = 151 | (character.value === PLUS_SIGN || character.value === MINUS_SIGN) && 152 | this.peek() && 153 | this.peek().isDigit() 154 | 155 | if (isDigitWithOperand) { 156 | this.handleNumber() 157 | continue 158 | } 159 | 160 | if (isOperand) { 161 | this.handleOperand() 162 | continue 163 | } 164 | 165 | let isParenthese = 166 | character.isLeftParenthese() || character.isRightParenthese() 167 | if (isParenthese) { 168 | this.handleParenthese() 169 | continue 170 | } 171 | } 172 | 173 | return this.output 174 | } 175 | } 176 | 177 | class Ast { 178 | constructor() { 179 | this.type = 'Program' 180 | this.body = [] 181 | } 182 | addNode(node) { 183 | this.body.push(node) 184 | } 185 | } 186 | 187 | class ExpressionStatement { 188 | constructor() { 189 | this.type = 'ExpressionStatement' 190 | this.operand = null 191 | this.left = null 192 | this.right = null 193 | } 194 | setOperand(operand) { 195 | this.operand = operand 196 | } 197 | setLeft(left) { 198 | this.left = left 199 | } 200 | setRight(right) { 201 | this.right = right 202 | } 203 | } 204 | 205 | class GroupingStatement { 206 | constructor() { 207 | this.type = 'GroupingStatement' 208 | this.body = [] 209 | } 210 | addNode(node) { 211 | this.body.push(node) 212 | } 213 | } 214 | 215 | class NumberLiteral { 216 | constructor(value) { 217 | this.type = 'NumberLiteral' 218 | this.value = value 219 | } 220 | } 221 | 222 | class Parser { 223 | constructor(input, output = []) { 224 | this.input = input 225 | this.output = new Ast() 226 | this.index = 0 227 | } 228 | isNotEnd() { 229 | return this.index < this.input.length 230 | } 231 | next() { 232 | if (this.isNotEnd()) { 233 | return this.input[this.index++] 234 | } else { 235 | null 236 | } 237 | } 238 | peek(n = 0) { 239 | if (this.index + n < this.input.length) { 240 | return this.input[this.index + n] 241 | } else { 242 | return null 243 | } 244 | } 245 | match(...args) { 246 | return args.every( 247 | (type, index) => (this.peek(index) ? this.peek(index).is(type) : false) 248 | ) 249 | } 250 | handleNumberLiteral() { 251 | let token = this.next() 252 | let previous = this.stack[this.stack.length - 1] 253 | 254 | if (!previous) { 255 | this.stack.push(new NumberLiteral(token.value)) 256 | return 257 | } 258 | 259 | if (!(previous instanceof ExpressionStatement)) { 260 | throw new Error('非法组合:数字前面必须是操作符') 261 | } 262 | 263 | if (previous instanceof ExpressionStatement) { 264 | let target = previous 265 | while (target.right instanceof ExpressionStatement) { 266 | target = target.right 267 | } 268 | target.right = new NumberLiteral(token.value) 269 | return 270 | } 271 | } 272 | 273 | handleExpressionStatement() { 274 | let token = this.next() 275 | let previous = this.stack[this.stack.length - 1] 276 | 277 | if (!previous) { 278 | throw new Error('操作符不能单独出现') 279 | } 280 | 281 | let isValid = 282 | previous instanceof NumberLiteral || 283 | previous instanceof ExpressionStatement || 284 | previous instanceof GroupingStatement 285 | 286 | if (!isValid) { 287 | throw new Error( 288 | `操作符前面的类型必须是数字,表达式或者分组,而不是${previous}` 289 | ) 290 | } 291 | 292 | if (token.value === PLUS_SIGN || token.value === MINUS_SIGN) { 293 | this.stack.pop() 294 | let expression = new ExpressionStatement() 295 | expression.setOperand(token.value) 296 | expression.setLeft(previous) 297 | this.stack.push(expression) 298 | return 299 | } 300 | 301 | if (token.value === MULTIPLICATION_SIGN || token.value === DEVISION_SIGN) { 302 | if (previous instanceof ExpressionStatement) { 303 | // example: 1 + (2 + 1) * 3 + 1 * 2 * 3 304 | if (previous.operand === PLUS_SIGN || previous.operand === MINUS_SIGN) { 305 | let expression = new ExpressionStatement() 306 | expression.setOperand(token.value) 307 | expression.setLeft(previous.right) 308 | previous.setRight(expression) 309 | return 310 | } 311 | 312 | // example: 1 * 2 * 3 313 | this.stack.pop() 314 | let expression = new ExpressionStatement() 315 | expression.setOperand(token.value) 316 | expression.setLeft(previous) 317 | this.stack.push(expression) 318 | return 319 | } 320 | 321 | if ( 322 | previous instanceof NumberLiteral || 323 | previous instanceof GroupingStatement 324 | ) { 325 | this.stack.pop() 326 | let expression = new ExpressionStatement() 327 | expression.setOperand(token.value) 328 | expression.setLeft(previous) 329 | this.stack.push(expression) 330 | return 331 | } 332 | 333 | throw new Error('不支持的操作') 334 | } 335 | } 336 | 337 | handleGroupingStatement() { 338 | let token = this.next() 339 | let previous = this.stack[this.stack.length - 1] 340 | let currentStack = this.stack 341 | let grouping = new GroupingStatement() 342 | this.stack = grouping.body 343 | while ( 344 | !(this.match(PARENTHESE) && this.peek().value === RIGHT_PARENTHESE) 345 | ) { 346 | this.handle() 347 | } 348 | this.next() 349 | this.stack = currentStack 350 | if (!grouping.body.length) { 351 | throw new Error('不支持空括号') 352 | } 353 | 354 | if (!previous) { 355 | this.stack.push(grouping) 356 | return 357 | } 358 | 359 | if (previous instanceof ExpressionStatement) { 360 | let target = previous 361 | while (target.right instanceof ExpressionStatement) { 362 | target = target.right 363 | } 364 | target.setRight(grouping) 365 | return 366 | } 367 | 368 | throw new Error('分组前面的符号非法') 369 | } 370 | 371 | // 1 * 2 + 2 + (3 + 4) * 2 * 3 / 2 372 | handle() { 373 | if (this.match(NUMBER)) { 374 | return this.handleNumberLiteral() 375 | } 376 | 377 | if (this.match(OPERAND)) { 378 | return this.handleExpressionStatement() 379 | } 380 | 381 | if (this.match(PARENTHESE)) { 382 | return this.handleGroupingStatement() 383 | } 384 | 385 | throw new Error(`非法 token:${this.next()}`) 386 | } 387 | execute() { 388 | while (this.isNotEnd()) { 389 | this.stack = this.output.body 390 | this.handle() 391 | } 392 | return this.output 393 | } 394 | } 395 | 396 | class Traverser { 397 | constructor(ast, visitor) { 398 | this.ast = ast 399 | this.visitor = visitor 400 | } 401 | handleArray(array, parent, layer) { 402 | array.forEach(node => this.handleNode(node, parent, layer)) 403 | } 404 | handleNode(node, parent, layer) { 405 | let enterMethod = `handle${node.type}Enter` 406 | let exitMethod = `handle${node.type}Exit` 407 | 408 | if (this.visitor[enterMethod]) { 409 | this.visitor[enterMethod](node, parent, layer) 410 | } 411 | 412 | if (node instanceof Ast) { 413 | this.handleArray(node.body, node, layer + 1) 414 | } 415 | 416 | if (node instanceof ExpressionStatement) { 417 | this.handleNode(node.left, node, layer + 1) 418 | this.handleNode(node.right, node, layer + 1) 419 | } 420 | 421 | if (node instanceof GroupingStatement) { 422 | this.handleArray(node.body, node, layer + 1) 423 | } 424 | 425 | if (this.visitor[exitMethod]) { 426 | this.visitor[exitMethod](node, parent, layer) 427 | } 428 | } 429 | execute() { 430 | this.handleNode(this.ast, null, 0) 431 | } 432 | } 433 | 434 | class Visitor { 435 | constructor(ast) { 436 | this.traverser = new Traverser(ast, this) 437 | this.output = null 438 | } 439 | execute() { 440 | this.traverser.execute() 441 | return this.output 442 | } 443 | } 444 | 445 | class XMLPrinter extends Visitor { 446 | constructor(ast) { 447 | super(ast) 448 | this.output = '' 449 | this.layer = 0 450 | } 451 | padStart(layer) { 452 | return ''.padStart(layer * 2, ' ') 453 | } 454 | handleProgramEnter(node, parent, layer) { 455 | this.output += this.padStart(layer) 456 | this.output += `\n` 457 | } 458 | handleProgramExit(node, parent, layer) { 459 | this.output += this.padStart(layer) 460 | this.output += `\n` 461 | } 462 | handleExpressionStatementEnter(node, parent, layer) { 463 | this.output += this.padStart(layer) 464 | this.output += `\n` 465 | } 466 | handleExpressionStatementExit(node, parent, layer) { 467 | this.output += this.padStart(layer) 468 | this.output += `\n` 469 | } 470 | handleNumberLiteralEnter(node, parent, layer) { 471 | this.output += this.padStart(layer) 472 | this.output += `${node.value}\n` 473 | } 474 | handleNumberLiteralExit(node, parent, layer) {} 475 | handleGroupingStatementEnter(node, parent, layer) { 476 | this.output += this.padStart(layer) 477 | this.output += `\n` 478 | } 479 | handleGroupingStatementExit(node, parent, layer) { 480 | this.output += this.padStart(layer) 481 | this.output += `\n` 482 | } 483 | } 484 | 485 | class Interpreter extends Visitor { 486 | constructor(ast) { 487 | super(ast) 488 | this.stack = [] 489 | } 490 | get output() { 491 | return this.stack[0] 492 | } 493 | set output(v) {} 494 | handleProgramEnter(node, parent, layer) {} 495 | handleProgramExit(node, parent, layer) {} 496 | handleExpressionStatementEnter(node, parent, layer) {} 497 | handleExpressionStatementExit(node, parent, layer) { 498 | let right = this.stack.pop() 499 | let left = this.stack.pop() 500 | let value = 0 501 | switch (node.operand) { 502 | case PLUS_SIGN: 503 | value = left + right 504 | break 505 | case MINUS_SIGN: 506 | value = left - right 507 | break 508 | case MULTIPLICATION_SIGN: 509 | value = left * right 510 | break 511 | case DEVISION_SIGN: 512 | value = left / right 513 | break 514 | } 515 | this.stack.push(value) 516 | } 517 | handleNumberLiteralEnter(node, parent, layer) { 518 | this.stack.push(Number(node.value)) 519 | } 520 | handleNumberLiteralExit(node, parent, layer) {} 521 | handleGroupingStatementEnter(node, parent, layer) {} 522 | handleGroupingStatementExit(node, parent, layer) {} 523 | } 524 | 525 | function test() { 526 | let expressiton = `1 + 2 + 3 * 4 + (5 + 6 * (7 + 8)) - 9/ 100 * 2 + 0.5 + -1.5` 527 | let tokenizer = new Tokenizer(expressiton) 528 | let parser = new Parser(tokenizer.execute()) 529 | parser.execute() 530 | 531 | let xmlPrinter = new XMLPrinter(parser.output) 532 | let interpreter = new Interpreter(parser.output) 533 | 534 | xmlPrinter.execute() 535 | interpreter.execute() 536 | console.log('ast', parser.output) 537 | console.log('result', interpreter.output) 538 | console.log('xml') 539 | console.log(xmlPrinter.output) 540 | document.documentElement.innerHTML = xmlPrinter.output 541 | } 542 | 543 | test() 544 | -------------------------------------------------------------------------------- /src/08.js: -------------------------------------------------------------------------------- 1 | const isWhiteSpace = character => { 2 | switch (character) { 3 | case ' ': 4 | case '\t': 5 | case '\r': 6 | return true 7 | default: 8 | return false 9 | } 10 | } 11 | 12 | const isOperand = character => { 13 | switch (character) { 14 | case '+': 15 | case '-': 16 | case '*': 17 | case '/': 18 | return true 19 | default: 20 | return false 21 | } 22 | } 23 | 24 | const isDigit = character => { 25 | return character >= '0' && character <= '9' 26 | } 27 | 28 | const isParenthese = character => { 29 | return character === '(' || character === ')' 30 | } 31 | 32 | const tokenizer = input => { 33 | let tokenList = [] 34 | let index = 0 35 | let character 36 | 37 | let next = () => { 38 | character = input[index++] 39 | } 40 | 41 | let peek = (n = 0) => { 42 | return input[index + n] 43 | } 44 | 45 | let ignoreWhiteSpace = () => { 46 | while (isWhiteSpace(character)) { 47 | next() 48 | } 49 | } 50 | 51 | let consume = () => { 52 | next() 53 | ignoreWhiteSpace() 54 | } 55 | 56 | let handleNumber = () => { 57 | let value = character 58 | let nextCharacter = peek() 59 | while (isDigit(nextCharacter) || nextCharacter === '.') { 60 | value += nextCharacter 61 | next() 62 | nextCharacter = peek() 63 | } 64 | tokenList.push({ 65 | type: 'number', 66 | value: value 67 | }) 68 | } 69 | 70 | let handleOperand = () => { 71 | let isNumber = (character === '-' || character === '+') && isDigit(peek()) 72 | if (isNumber) { 73 | return handleNumber() 74 | } 75 | tokenList.push({ 76 | type: 'operand', 77 | value: character 78 | }) 79 | } 80 | 81 | let handleParenthese = () => { 82 | tokenList.push({ 83 | type: 'parenthese', 84 | value: character 85 | }) 86 | } 87 | 88 | while (index < input.length) { 89 | consume() 90 | 91 | if (isOperand(character)) { 92 | handleOperand() 93 | continue 94 | } 95 | 96 | if (isDigit(character)) { 97 | handleNumber() 98 | continue 99 | } 100 | 101 | if (isParenthese(character)) { 102 | handleParenthese() 103 | continue 104 | } 105 | } 106 | 107 | return tokenList 108 | } 109 | 110 | const Program = 'Program' 111 | const ExpressionStatement = 'ExpressionStatement' 112 | const NumberLiteral = 'NumberLiteral' 113 | const GroupingStatement = 'GroupingStatement' 114 | 115 | function parser(input) { 116 | let ast = { 117 | type: Program, 118 | body: [] 119 | } 120 | let stack = ast.body 121 | let index = 0 122 | let token 123 | 124 | let next = () => { 125 | token = input[index++] 126 | } 127 | 128 | let peek = () => { 129 | return input[index] 130 | } 131 | 132 | let handleRight = (previous, right) => { 133 | let target = previous 134 | while (target.right && target.right.type === ExpressionStatement) { 135 | target = target.right 136 | } 137 | target.right = right 138 | } 139 | 140 | let handleNumber = () => { 141 | let previous = stack[stack.length - 1] 142 | if (!previous) { 143 | stack.push({ 144 | type: NumberLiteral, 145 | value: token.value 146 | }) 147 | return 148 | } 149 | 150 | if (previous.type !== ExpressionStatement) { 151 | throw new Error('非法组合:数字前面必须是操作符') 152 | } 153 | 154 | handleRight(previous, { 155 | type: NumberLiteral, 156 | value: token.value 157 | }) 158 | } 159 | 160 | let handleExpression = () => { 161 | let previous = stack[stack.length - 1] 162 | if (!previous) { 163 | throw new Error('操作符不能单独出现') 164 | } 165 | 166 | let isValid = 167 | previous.type === NumberLiteral || 168 | previous.type === ExpressionStatement || 169 | previous.type === GroupingStatement 170 | 171 | if (!isValid) { 172 | throw new Error('非法表达式') 173 | } 174 | 175 | if (token.value === '+' || token.value === '-') { 176 | stack.pop() 177 | let expression = { 178 | type: ExpressionStatement, 179 | operand: token.value, 180 | left: previous, 181 | right: null 182 | } 183 | stack.push(expression) 184 | return 185 | } else if (token.value === '*' || token.value === '/') { 186 | if (previous.type === ExpressionStatement) { 187 | if (previous.operand === '+' || previous.operand === '-') { 188 | let expression = { 189 | type: ExpressionStatement, 190 | operand: token.value, 191 | left: previous.right, 192 | right: null 193 | } 194 | previous.right = expression 195 | return 196 | } else if (previous.operand === '*' || previous.operand === '/') { 197 | stack.pop() 198 | let expression = { 199 | type: ExpressionStatement, 200 | operand: token.value, 201 | left: previous, 202 | right: null 203 | } 204 | stack.push(expression) 205 | return 206 | } 207 | } else if ( 208 | previous.type === NumberLiteral || 209 | previous.type === GroupingStatement 210 | ) { 211 | stack.pop() 212 | let expression = { 213 | type: ExpressionStatement, 214 | operand: token.value, 215 | left: previous, 216 | right: null 217 | } 218 | stack.push(expression) 219 | return 220 | } 221 | } 222 | 223 | throw new Error('不支持的操作') 224 | } 225 | 226 | let handleGrouping = () => { 227 | let grouping = { 228 | type: GroupingStatement, 229 | body: [] 230 | } 231 | 232 | let currentStack = stack 233 | stack = grouping.body 234 | 235 | let currentToken = token 236 | while ( 237 | currentToken && 238 | !(currentToken.type === 'parenthese' && currentToken.value === ')') 239 | ) { 240 | handler() 241 | currentToken = peek() 242 | } 243 | 244 | next() 245 | 246 | stack = currentStack 247 | 248 | if (!grouping.body.length) { 249 | throw new Error('不支持空括号') 250 | } 251 | 252 | let previous = stack[stack.length - 1] 253 | if (!previous) { 254 | stack.push(grouping) 255 | } 256 | 257 | if (previous.type === ExpressionStatement) { 258 | handleRight(previous, grouping) 259 | return 260 | } 261 | 262 | throw new Error('分组前面的符号非法') 263 | } 264 | 265 | let handler = () => { 266 | next() 267 | switch (token && token.type) { 268 | case 'number': 269 | handleNumber() 270 | break 271 | case 'operand': 272 | handleExpression() 273 | break 274 | case 'parenthese': 275 | handleGrouping() 276 | break 277 | } 278 | } 279 | 280 | while (index < input.length) { 281 | handler() 282 | } 283 | 284 | return ast 285 | } 286 | 287 | function traverser(ast, visitor) { 288 | let handleArray = (array, parent, layer) => { 289 | array.forEach(node => handleNode(node, parent, layer)) 290 | } 291 | let handleNode = (node, parent, layer) => { 292 | let enter = `on${node.type}Enter` 293 | let through = `on${node.type}Through` 294 | let exit = `on${node.type}Exit` 295 | 296 | if (visitor[enter]) { 297 | visitor[enter](node, parent, layer) 298 | } 299 | 300 | switch (node.type) { 301 | case Program: 302 | handleArray(node.body, node, layer + 1) 303 | break 304 | case ExpressionStatement: 305 | handleNode(node.left, node, layer + 1) 306 | if (visitor[through]) { 307 | visitor[through](node, parent, layer) 308 | } 309 | handleNode(node.right, node, layer + 1) 310 | break 311 | case GroupingStatement: 312 | handleArray(node.body, node, layer + 1) 313 | break 314 | case NumberLiteral: 315 | break 316 | default: 317 | throw new TypeError(node.type) 318 | } 319 | 320 | if (visitor[exit]) { 321 | visitor[exit](node, parent, layer) 322 | } 323 | } 324 | handleNode(ast, null, 0) 325 | } 326 | 327 | function toXML(ast, indent = 2) { 328 | let xml = '' 329 | let handleIndent = (layer = 0) => { 330 | if (indent > 0) { 331 | return '\n'.padEnd(layer * indent, ' ') 332 | } 333 | return '' 334 | } 335 | let visitor = { 336 | onProgramEnter(node, parent, layer) { 337 | xml += handleIndent(layer) + '' 338 | }, 339 | onProgramExit(node, parent, layer) { 340 | xml += handleIndent(layer) + '' 341 | }, 342 | onNumberLiteralEnter(node, parent, layer) { 343 | xml += handleIndent(layer) + '' 344 | xml += handleIndent(layer + 1) + node.value 345 | }, 346 | onNumberLiteralExit(node, parent, layer) { 347 | xml += handleIndent(layer) + '' 348 | }, 349 | onExpressionStatementEnter(node, parent, layer) { 350 | xml += handleIndent(layer) + `` 351 | }, 352 | onExpressionStatementExit(node, parent, layer) { 353 | xml += handleIndent(layer) + '' 354 | }, 355 | onGroupingStatementEnter(node, parent, layer) { 356 | xml += handleIndent(layer) + '' 357 | }, 358 | onGroupingStatementExit(node, parent, layer) { 359 | xml += handleIndent(layer) + '' 360 | } 361 | } 362 | traverser(ast, visitor) 363 | return xml 364 | } 365 | 366 | function toChinese(ast) { 367 | let string = '' 368 | let visitor = { 369 | onExpressionStatementThrough(node) { 370 | switch (node.operand) { 371 | case '+': 372 | string += ' 加 ' 373 | break 374 | case '-': 375 | string += ' 减 ' 376 | break 377 | case '*': 378 | string += ' 乘 ' 379 | break 380 | case '/': 381 | string += ' 除 ' 382 | break 383 | default: 384 | throw new Error(`unknow operand ${node.operand}`) 385 | } 386 | }, 387 | onNumberLiteralExit(node) { 388 | let value = node.value 389 | .split('') 390 | .map(item => item === '.' ? '点' : '零一二三四五六七八九'[item]) 391 | .join('') 392 | string += value 393 | }, 394 | onGroupingStatementEnter() { 395 | string += '(' 396 | }, 397 | onGroupingStatementExit() { 398 | string += ')' 399 | } 400 | } 401 | traverser(ast, visitor) 402 | return string 403 | } 404 | 405 | function evaluate(ast) { 406 | let stack = [] 407 | let visitor = { 408 | onExpressionStatementExit(node) { 409 | let right = stack.pop() 410 | let left = stack.pop() 411 | let value 412 | switch (node.operand) { 413 | case '+': 414 | value = left + right 415 | break 416 | case '-': 417 | value = left - right 418 | break 419 | case '*': 420 | value = left * right 421 | break 422 | case '/': 423 | value = left / right 424 | break 425 | default: 426 | throw new Error(`unknow operand ${node.operand}`) 427 | } 428 | stack.push(value) 429 | }, 430 | onNumberLiteralEnter(node) { 431 | stack.push(Number(node.value)) 432 | } 433 | } 434 | traverser(ast, visitor) 435 | return stack[0] 436 | } 437 | 438 | let expression = `1 + 2 + 3 * 4 + (5 + 6 * (7 + 8)) - 9/ 100 * 2 + 0.5 + -1.5` 439 | let tokenList = tokenizer(expression) 440 | console.log('tokenList', tokenList) 441 | 442 | let ast = parser(tokenList) 443 | console.log('ast', ast) 444 | 445 | let xml = toXML(ast) 446 | console.log('xml', xml) 447 | 448 | let result = evaluate(ast) 449 | console.log('result', result) 450 | 451 | let chinese = toChinese(ast) 452 | console.log('chinese', chinese) -------------------------------------------------------------------------------- /src/dest/03.txt: -------------------------------------------------------------------------------- 1 | DOT: . 2 | LETTER: s 3 | WHIFFLETREE: - 4 | LETTER: mod 5 | WHIFFLETREE: - 6 | LETTER: msg 7 | WHITE_SPACE: 8 | LEFT_BRACE: { 9 | WHITE_SPACE: 10 | 11 | LETTER: position 12 | COLON: : 13 | WHITE_SPACE: 14 | LETTER: absolute 15 | SEMICOLON: ; 16 | WHITE_SPACE: 17 | 18 | LETTER: top 19 | COLON: : 20 | WHITE_SPACE: 21 | NUMBER: 28 22 | LETTER: px 23 | SEMICOLON: ; 24 | WHITE_SPACE: 25 | 26 | LETTER: font 27 | WHIFFLETREE: - 28 | LETTER: size 29 | COLON: : 30 | WHITE_SPACE: 31 | NUMBER: 12 32 | LETTER: px 33 | SEMICOLON: ; 34 | WHITE_SPACE: 35 | 36 | LETTER: color 37 | COLON: : 38 | WHITE_SPACE: 39 | POUND_KEY: # 40 | NUMBER: 333 41 | SEMICOLON: ; 42 | WHITE_SPACE: 43 | 44 | LETTER: width 45 | COLON: : 46 | WHITE_SPACE: 47 | NUMBER: 278 48 | LETTER: px 49 | SEMICOLON: ; 50 | WHITE_SPACE: 51 | 52 | LETTER: z 53 | WHIFFLETREE: - 54 | LETTER: index 55 | COLON: : 56 | WHITE_SPACE: 57 | NUMBER: 999 58 | SEMICOLON: ; 59 | WHITE_SPACE: 60 | 61 | RIGHT_BRACE: } 62 | WHITE_SPACE: 63 | 64 | 65 | DOT: . 66 | LETTER: s 67 | WHIFFLETREE: - 68 | LETTER: mod 69 | WHIFFLETREE: - 70 | LETTER: msg 71 | WHITE_SPACE: 72 | DOT: . 73 | LETTER: msg 74 | WHIFFLETREE: - 75 | LETTER: area 76 | WHITE_SPACE: 77 | LEFT_BRACE: { 78 | WHITE_SPACE: 79 | 80 | LETTER: border 81 | COLON: : 82 | WHITE_SPACE: 83 | NUMBER: 1 84 | LETTER: px 85 | WHITE_SPACE: 86 | LETTER: solid 87 | WHITE_SPACE: 88 | POUND_KEY: # 89 | LETTER: e 90 | NUMBER: 3 91 | LETTER: e 92 | NUMBER: 3 93 | LETTER: e 94 | NUMBER: 3 95 | SEMICOLON: ; 96 | WHITE_SPACE: 97 | 98 | LETTER: background 99 | COLON: : 100 | WHITE_SPACE: 101 | POUND_KEY: # 102 | LETTER: fff 103 | SEMICOLON: ; 104 | WHITE_SPACE: 105 | 106 | LETTER: box 107 | WHIFFLETREE: - 108 | LETTER: shadow 109 | COLON: : 110 | WHITE_SPACE: 111 | NUMBER: 0 2 112 | LETTER: px 113 | WHITE_SPACE: 114 | NUMBER: 2 115 | LETTER: px 116 | WHITE_SPACE: 117 | LETTER: rgba 118 | LEFT_BRACKET: ( 119 | NUMBER: 0 120 | COMMA: , 121 | WHITE_SPACE: 122 | NUMBER: 0 123 | COMMA: , 124 | WHITE_SPACE: 125 | NUMBER: 0 126 | COMMA: , 127 | WHITE_SPACE: 128 | NUMBER: 0 129 | DOT: . 130 | NUMBER: 07 131 | RIGHT_BRACKET: ) 132 | SEMICOLON: ; 133 | WHITE_SPACE: 134 | 135 | WHIFFLETREE: - 136 | LETTER: moz 137 | WHIFFLETREE: - 138 | LETTER: box 139 | WHIFFLETREE: - 140 | LETTER: shadow 141 | COLON: : 142 | WHITE_SPACE: 143 | NUMBER: 0 2 144 | LETTER: px 145 | WHITE_SPACE: 146 | NUMBER: 2 147 | LETTER: px 148 | WHITE_SPACE: 149 | LETTER: rgba 150 | LEFT_BRACKET: ( 151 | NUMBER: 0 152 | COMMA: , 153 | WHITE_SPACE: 154 | NUMBER: 0 155 | COMMA: , 156 | WHITE_SPACE: 157 | NUMBER: 0 158 | COMMA: , 159 | WHITE_SPACE: 160 | NUMBER: 0 161 | DOT: . 162 | NUMBER: 07 163 | RIGHT_BRACKET: ) 164 | SEMICOLON: ; 165 | WHITE_SPACE: 166 | 167 | WHIFFLETREE: - 168 | LETTER: webkit 169 | WHIFFLETREE: - 170 | LETTER: box 171 | WHIFFLETREE: - 172 | LETTER: shadow 173 | COLON: : 174 | WHITE_SPACE: 175 | NUMBER: 0 2 176 | LETTER: px 177 | WHITE_SPACE: 178 | NUMBER: 2 179 | LETTER: px 180 | WHITE_SPACE: 181 | LETTER: rgba 182 | LEFT_BRACKET: ( 183 | NUMBER: 0 184 | COMMA: , 185 | WHITE_SPACE: 186 | NUMBER: 0 187 | COMMA: , 188 | WHITE_SPACE: 189 | NUMBER: 0 190 | COMMA: , 191 | WHITE_SPACE: 192 | NUMBER: 0 193 | DOT: . 194 | NUMBER: 07 195 | RIGHT_BRACKET: ) 196 | SEMICOLON: ; 197 | WHITE_SPACE: 198 | 199 | LETTER: filter 200 | COLON: : 201 | WHITE_SPACE: 202 | LETTER: progid 203 | COLON: : 204 | WHITE_SPACE: 205 | LETTER: DXImageTransform 206 | DOT: . 207 | LETTER: Microsoft 208 | DOT: . 209 | LETTER: Shadow 210 | LEFT_BRACKET: ( 211 | LETTER: Strength 212 | EQUAL_SYMBOL: = 213 | NUMBER: 2 214 | COMMA: , 215 | WHITE_SPACE: 216 | LETTER: Direction 217 | EQUAL_SYMBOL: = 218 | NUMBER: 135 219 | COMMA: , 220 | WHITE_SPACE: 221 | LETTER: Color 222 | EQUAL_SYMBOL: = 223 | SINGLE_QUOTE: ' 224 | POUND_KEY: # 225 | LETTER: e 226 | NUMBER: 3 227 | LETTER: e 228 | NUMBER: 3 229 | LETTER: e 230 | NUMBER: 3 231 | SINGLE_QUOTE: ' 232 | RIGHT_BRACKET: ) 233 | SEMICOLON: ; 234 | WHITE_SPACE: 235 | 236 | WHIFFLETREE: - 237 | LETTER: ms 238 | WHIFFLETREE: - 239 | LETTER: filter 240 | COLON: : 241 | WHITE_SPACE: 242 | DOUBLE_QUOTES: " 243 | LETTER: progid 244 | COLON: : 245 | LETTER: DXImageTransform 246 | DOT: . 247 | LETTER: Microsoft 248 | DOT: . 249 | LETTER: Shadow 250 | LEFT_BRACKET: ( 251 | LETTER: Strength 252 | EQUAL_SYMBOL: = 253 | NUMBER: 2 254 | COMMA: , 255 | WHITE_SPACE: 256 | LETTER: Direction 257 | EQUAL_SYMBOL: = 258 | NUMBER: 135 259 | COMMA: , 260 | WHITE_SPACE: 261 | LETTER: Color 262 | EQUAL_SYMBOL: = 263 | SINGLE_QUOTE: ' 264 | POUND_KEY: # 265 | LETTER: e 266 | NUMBER: 3 267 | LETTER: e 268 | NUMBER: 3 269 | LETTER: e 270 | NUMBER: 3 271 | SINGLE_QUOTE: ' 272 | RIGHT_BRACKET: ) 273 | DOUBLE_QUOTES: " 274 | SEMICOLON: ; 275 | WHITE_SPACE: 276 | 277 | RIGHT_BRACE: } 278 | WHITE_SPACE: 279 | 280 | 281 | DOT: . 282 | LETTER: s 283 | WHIFFLETREE: - 284 | LETTER: mod 285 | WHIFFLETREE: - 286 | LETTER: msg 287 | WHITE_SPACE: 288 | DOT: . 289 | LETTER: s 290 | WHIFFLETREE: - 291 | LETTER: msg 292 | WHIFFLETREE: - 293 | LETTER: base 294 | WHITE_SPACE: 295 | DOT: . 296 | LETTER: no 297 | WHIFFLETREE: - 298 | LETTER: msg 299 | WHIFFLETREE: - 300 | LETTER: tip 301 | WHITE_SPACE: 302 | LEFT_BRACE: { 303 | WHITE_SPACE: 304 | 305 | LETTER: height 306 | COLON: : 307 | WHITE_SPACE: 308 | NUMBER: 88 309 | LETTER: px 310 | SEMICOLON: ; 311 | WHITE_SPACE: 312 | 313 | LETTER: line 314 | WHIFFLETREE: - 315 | LETTER: height 316 | COLON: : 317 | WHITE_SPACE: 318 | NUMBER: 88 319 | LETTER: px 320 | SEMICOLON: ; 321 | WHITE_SPACE: 322 | 323 | LETTER: margin 324 | COLON: : 325 | WHITE_SPACE: 326 | NUMBER: 0 20 327 | LETTER: px 328 | SEMICOLON: ; 329 | WHITE_SPACE: 330 | 331 | LETTER: border 332 | WHIFFLETREE: - 333 | LETTER: bottom 334 | COLON: : 335 | WHITE_SPACE: 336 | NUMBER: 1 337 | LETTER: px 338 | WHITE_SPACE: 339 | LETTER: solid 340 | WHITE_SPACE: 341 | POUND_KEY: # 342 | LETTER: ccc 343 | SEMICOLON: ; 344 | WHITE_SPACE: 345 | 346 | LETTER: border 347 | WHIFFLETREE: - 348 | LETTER: bottom 349 | COLON: : 350 | WHITE_SPACE: 351 | NUMBER: 1 352 | LETTER: px 353 | WHITE_SPACE: 354 | LETTER: solid 355 | WHITE_SPACE: 356 | LETTER: rgba 357 | LEFT_BRACKET: ( 358 | NUMBER: 177 359 | COMMA: , 360 | WHITE_SPACE: 361 | NUMBER: 177 362 | COMMA: , 363 | WHITE_SPACE: 364 | NUMBER: 177 365 | COMMA: , 366 | WHITE_SPACE: 367 | DOT: . 368 | NUMBER: 20 369 | RIGHT_BRACKET: ) 370 | SEMICOLON: ; 371 | WHITE_SPACE: 372 | 373 | LETTER: text 374 | WHIFFLETREE: - 375 | LETTER: align 376 | COLON: : 377 | WHITE_SPACE: 378 | LETTER: center 379 | SEMICOLON: ; 380 | WHITE_SPACE: 381 | 382 | RIGHT_BRACE: } 383 | WHITE_SPACE: 384 | 385 | 386 | DOT: . 387 | LETTER: s 388 | WHIFFLETREE: - 389 | LETTER: mod 390 | WHIFFLETREE: - 391 | LETTER: msg 392 | WHITE_SPACE: 393 | DOT: . 394 | LETTER: no 395 | WHIFFLETREE: - 396 | LETTER: msgs 397 | WHITE_SPACE: 398 | LEFT_BRACE: { 399 | WHITE_SPACE: 400 | 401 | LETTER: height 402 | COLON: : 403 | WHITE_SPACE: 404 | NUMBER: 139 405 | LETTER: px 406 | SEMICOLON: ; 407 | WHITE_SPACE: 408 | 409 | RIGHT_BRACE: } 410 | WHITE_SPACE: 411 | 412 | 413 | DOT: . 414 | LETTER: s 415 | WHIFFLETREE: - 416 | LETTER: mod 417 | WHIFFLETREE: - 418 | LETTER: msg 419 | WHITE_SPACE: 420 | DOT: . 421 | LETTER: no 422 | WHIFFLETREE: - 423 | LETTER: set 424 | WHIFFLETREE: - 425 | LETTER: msg 426 | WHITE_SPACE: 427 | LEFT_BRACE: { 428 | WHITE_SPACE: 429 | 430 | LETTER: height 431 | COLON: : 432 | WHITE_SPACE: 433 | NUMBER: 68 434 | LETTER: px 435 | SEMICOLON: ; 436 | WHITE_SPACE: 437 | 438 | RIGHT_BRACE: } 439 | WHITE_SPACE: 440 | 441 | 442 | DOT: . 443 | LETTER: s 444 | WHIFFLETREE: - 445 | LETTER: mod 446 | WHIFFLETREE: - 447 | LETTER: msg 448 | WHITE_SPACE: 449 | DOT: . 450 | LETTER: msg 451 | WHIFFLETREE: - 452 | LETTER: btns 453 | COMMA: , 454 | WHITE_SPACE: 455 | 456 | DOT: . 457 | LETTER: s 458 | WHIFFLETREE: - 459 | LETTER: mod 460 | WHIFFLETREE: - 461 | LETTER: msg 462 | WHITE_SPACE: 463 | DOT: . 464 | LETTER: no 465 | WHIFFLETREE: - 466 | LETTER: msg 467 | WHIFFLETREE: - 468 | LETTER: btns 469 | WHITE_SPACE: 470 | LEFT_BRACE: { 471 | WHITE_SPACE: 472 | 473 | LETTER: height 474 | COLON: : 475 | WHITE_SPACE: 476 | NUMBER: 28 477 | LETTER: px 478 | SEMICOLON: ; 479 | WHITE_SPACE: 480 | 481 | RIGHT_BRACE: } 482 | WHITE_SPACE: 483 | 484 | 485 | DOT: . 486 | LETTER: s 487 | WHIFFLETREE: - 488 | LETTER: mod 489 | WHIFFLETREE: - 490 | LETTER: msg 491 | WHITE_SPACE: 492 | DOT: . 493 | LETTER: s 494 | WHIFFLETREE: - 495 | LETTER: msg 496 | WHIFFLETREE: - 497 | LETTER: base 498 | WHITE_SPACE: 499 | DOT: . 500 | LETTER: no 501 | WHIFFLETREE: - 502 | LETTER: msg 503 | WHIFFLETREE: - 504 | LETTER: btns 505 | COMMA: , 506 | WHITE_SPACE: 507 | 508 | DOT: . 509 | LETTER: s 510 | WHIFFLETREE: - 511 | LETTER: mod 512 | WHIFFLETREE: - 513 | LETTER: msg 514 | WHITE_SPACE: 515 | DOT: . 516 | LETTER: msg 517 | WHIFFLETREE: - 518 | LETTER: btns 519 | WHITE_SPACE: 520 | LEFT_BRACE: { 521 | WHITE_SPACE: 522 | 523 | LETTER: padding 524 | WHIFFLETREE: - 525 | LETTER: top 526 | COLON: : 527 | WHITE_SPACE: 528 | NUMBER: 10 529 | LETTER: px 530 | SEMICOLON: ; 531 | WHITE_SPACE: 532 | 533 | LETTER: padding 534 | WHIFFLETREE: - 535 | LETTER: bottom 536 | COLON: : 537 | WHITE_SPACE: 538 | NUMBER: 12 539 | LETTER: px 540 | SEMICOLON: ; 541 | WHITE_SPACE: 542 | 543 | RIGHT_BRACE: } 544 | WHITE_SPACE: 545 | 546 | 547 | DOT: . 548 | LETTER: s 549 | WHIFFLETREE: - 550 | LETTER: mod 551 | WHIFFLETREE: - 552 | LETTER: msg 553 | WHITE_SPACE: 554 | DOT: . 555 | LETTER: no 556 | WHIFFLETREE: - 557 | LETTER: msgs 558 | WHITE_SPACE: 559 | DOT: . 560 | LETTER: no 561 | WHIFFLETREE: - 562 | LETTER: msg 563 | WHIFFLETREE: - 564 | LETTER: btns 565 | WHITE_SPACE: 566 | LEFT_BRACE: { 567 | WHITE_SPACE: 568 | 569 | LETTER: margin 570 | WHIFFLETREE: - 571 | LETTER: left 572 | COLON: : 573 | WHITE_SPACE: 574 | NUMBER: 50 575 | LETTER: px 576 | SEMICOLON: ; 577 | WHITE_SPACE: 578 | 579 | RIGHT_BRACE: } 580 | WHITE_SPACE: 581 | 582 | 583 | DOT: . 584 | LETTER: s 585 | WHIFFLETREE: - 586 | LETTER: mod 587 | WHIFFLETREE: - 588 | LETTER: msg 589 | WHITE_SPACE: 590 | DOT: . 591 | LETTER: msg 592 | WHIFFLETREE: - 593 | LETTER: btns 594 | WHITE_SPACE: 595 | LEFT_BRACE: { 596 | WHITE_SPACE: 597 | 598 | LETTER: margin 599 | WHIFFLETREE: - 600 | LETTER: left 601 | COLON: : 602 | WHITE_SPACE: 603 | NUMBER: 30 604 | LETTER: px 605 | SEMICOLON: ; 606 | WHITE_SPACE: 607 | 608 | RIGHT_BRACE: } 609 | WHITE_SPACE: 610 | 611 | 612 | DOT: . 613 | LETTER: s 614 | WHIFFLETREE: - 615 | LETTER: mod 616 | WHIFFLETREE: - 617 | LETTER: msg 618 | WHITE_SPACE: 619 | DOT: . 620 | LETTER: msg 621 | WHIFFLETREE: - 622 | LETTER: btn 623 | WHITE_SPACE: 624 | LEFT_BRACE: { 625 | WHITE_SPACE: 626 | 627 | LETTER: color 628 | COLON: : 629 | WHITE_SPACE: 630 | POUND_KEY: # 631 | LETTER: fff 632 | SEMICOLON: ; 633 | WHITE_SPACE: 634 | 635 | LETTER: cursor 636 | COLON: : 637 | WHITE_SPACE: 638 | LETTER: pointer 639 | SEMICOLON: ; 640 | WHITE_SPACE: 641 | 642 | LETTER: float 643 | COLON: : 644 | WHITE_SPACE: 645 | LETTER: left 646 | SEMICOLON: ; 647 | WHITE_SPACE: 648 | 649 | LETTER: display 650 | COLON: : 651 | WHITE_SPACE: 652 | LETTER: inline 653 | SEMICOLON: ; 654 | WHITE_SPACE: 655 | 656 | LETTER: width 657 | COLON: : 658 | WHITE_SPACE: 659 | NUMBER: 82 660 | LETTER: px 661 | SEMICOLON: ; 662 | WHITE_SPACE: 663 | 664 | LETTER: height 665 | COLON: : 666 | WHITE_SPACE: 667 | NUMBER: 28 668 | LETTER: px 669 | SEMICOLON: ; 670 | WHITE_SPACE: 671 | 672 | LETTER: line 673 | WHIFFLETREE: - 674 | LETTER: height 675 | COLON: : 676 | WHITE_SPACE: 677 | NUMBER: 28 678 | LETTER: px 679 | SEMICOLON: ; 680 | WHITE_SPACE: 681 | 682 | LETTER: text 683 | WHIFFLETREE: - 684 | LETTER: align 685 | COLON: : 686 | WHITE_SPACE: 687 | LETTER: center 688 | SEMICOLON: ; 689 | WHITE_SPACE: 690 | 691 | LETTER: background 692 | COLON: : 693 | WHITE_SPACE: 694 | POUND_KEY: # 695 | NUMBER: 389 696 | LETTER: cff 697 | SEMICOLON: ; 698 | WHITE_SPACE: 699 | 700 | LETTER: position 701 | COLON: : 702 | WHITE_SPACE: 703 | LETTER: relative 704 | SEMICOLON: ; 705 | WHITE_SPACE: 706 | 707 | RIGHT_BRACE: } 708 | WHITE_SPACE: 709 | 710 | 711 | DOT: . 712 | LETTER: s 713 | WHIFFLETREE: - 714 | LETTER: mod 715 | WHIFFLETREE: - 716 | LETTER: msg 717 | WHITE_SPACE: 718 | DOT: . 719 | LETTER: msg 720 | WHIFFLETREE: - 721 | LETTER: setting 722 | WHIFFLETREE: - 723 | LETTER: btn 724 | WHITE_SPACE: 725 | LEFT_BRACE: { 726 | WHITE_SPACE: 727 | 728 | LETTER: left 729 | COLON: : 730 | WHITE_SPACE: 731 | NUMBER: 14 732 | LETTER: px 733 | SEMICOLON: ; 734 | WHITE_SPACE: 735 | 736 | RIGHT_BRACE: } 737 | WHITE_SPACE: 738 | 739 | 740 | DOT: . 741 | LETTER: s 742 | WHIFFLETREE: - 743 | LETTER: msg 744 | WHIFFLETREE: - 745 | LETTER: base 746 | WHITE_SPACE: 747 | DOT: . 748 | LETTER: no 749 | WHIFFLETREE: - 750 | LETTER: msg 751 | WHIFFLETREE: - 752 | LETTER: btns 753 | WHITE_SPACE: 754 | DOT: . 755 | LETTER: no 756 | WHIFFLETREE: - 757 | LETTER: use 758 | WHITE_SPACE: 759 | LEFT_BRACE: { 760 | WHITE_SPACE: 761 | 762 | LETTER: background 763 | COLON: : 764 | WHITE_SPACE: 765 | POUND_KEY: # 766 | LETTER: bcbcbc 767 | SEMICOLON: ; 768 | WHITE_SPACE: 769 | 770 | LETTER: cursor 771 | COLON: : 772 | WHITE_SPACE: 773 | LETTER: default 774 | SEMICOLON: ; 775 | WHITE_SPACE: 776 | 777 | RIGHT_BRACE: } 778 | WHITE_SPACE: 779 | 780 | 781 | DOT: . 782 | LETTER: s 783 | WHIFFLETREE: - 784 | LETTER: mod 785 | WHIFFLETREE: - 786 | LETTER: msg 787 | WHITE_SPACE: 788 | DOT: . 789 | LETTER: msg 790 | WHIFFLETREE: - 791 | LETTER: btn 792 | WHITE_SPACE: 793 | DOT: . 794 | LETTER: bg 795 | WHITE_SPACE: 796 | LEFT_BRACE: { 797 | WHITE_SPACE: 798 | 799 | LETTER: font 800 | WHIFFLETREE: - 801 | LETTER: size 802 | COLON: : 803 | WHITE_SPACE: 804 | NUMBER: 0 805 | SEMICOLON: ; 806 | WHITE_SPACE: 807 | 808 | LETTER: position 809 | COLON: : 810 | WHITE_SPACE: 811 | LETTER: absolute 812 | SEMICOLON: ; 813 | WHITE_SPACE: 814 | 815 | LETTER: top 816 | COLON: : 817 | WHITE_SPACE: 818 | NUMBER: 9 819 | LETTER: px 820 | SEMICOLON: ; 821 | WHITE_SPACE: 822 | 823 | LETTER: left 824 | COLON: : 825 | WHITE_SPACE: 826 | NUMBER: 10 827 | LETTER: px 828 | SEMICOLON: ; 829 | WHITE_SPACE: 830 | 831 | RIGHT_BRACE: } 832 | WHITE_SPACE: 833 | 834 | 835 | DOT: . 836 | LETTER: s 837 | WHIFFLETREE: - 838 | LETTER: mod 839 | WHIFFLETREE: - 840 | LETTER: msg 841 | WHITE_SPACE: 842 | DOT: . 843 | LETTER: msg 844 | WHIFFLETREE: - 845 | LETTER: btn 846 | WHITE_SPACE: 847 | DOT: . 848 | LETTER: title 849 | WHITE_SPACE: 850 | LEFT_BRACE: { 851 | WHITE_SPACE: 852 | 853 | LETTER: margin 854 | WHIFFLETREE: - 855 | LETTER: left 856 | COLON: : 857 | WHITE_SPACE: 858 | NUMBER: 10 859 | LETTER: px 860 | SEMICOLON: ; 861 | WHITE_SPACE: 862 | 863 | LETTER: color 864 | COLON: : 865 | WHITE_SPACE: 866 | POUND_KEY: # 867 | LETTER: FFF 868 | SEMICOLON: ; 869 | WHITE_SPACE: 870 | 871 | RIGHT_BRACE: } 872 | WHITE_SPACE: 873 | 874 | 875 | DOT: . 876 | LETTER: s 877 | WHIFFLETREE: - 878 | LETTER: mod 879 | WHIFFLETREE: - 880 | LETTER: msg 881 | WHITE_SPACE: 882 | DOT: . 883 | LETTER: msg 884 | WHIFFLETREE: - 885 | LETTER: setting 886 | WHIFFLETREE: - 887 | LETTER: btn 888 | WHITE_SPACE: 889 | DOT: . 890 | LETTER: title 891 | WHITE_SPACE: 892 | LEFT_BRACE: { 893 | WHITE_SPACE: 894 | 895 | LETTER: margin 896 | WHIFFLETREE: - 897 | LETTER: left 898 | COLON: : 899 | WHITE_SPACE: 900 | NUMBER: 0 901 | SEMICOLON: ; 902 | WHITE_SPACE: 903 | 904 | LETTER: color 905 | COLON: : 906 | WHITE_SPACE: 907 | POUND_KEY: # 908 | LETTER: FFF 909 | SEMICOLON: ; 910 | WHITE_SPACE: 911 | 912 | LETTER: display 913 | COLON: : 914 | WHITE_SPACE: 915 | LETTER: inline 916 | WHIFFLETREE: - 917 | LETTER: block 918 | SEMICOLON: ; 919 | WHITE_SPACE: 920 | 921 | LETTER: height 922 | COLON: : 923 | WHITE_SPACE: 924 | NUMBER: 28 925 | LETTER: px 926 | SEMICOLON: ; 927 | WHITE_SPACE: 928 | 929 | LETTER: width 930 | COLON: : 931 | WHITE_SPACE: 932 | NUMBER: 59 933 | LETTER: px 934 | SEMICOLON: ; 935 | WHITE_SPACE: 936 | 937 | LETTER: float 938 | COLON: : 939 | WHITE_SPACE: 940 | LETTER: left 941 | SEMICOLON: ; 942 | WHITE_SPACE: 943 | 944 | LETTER: padding 945 | WHIFFLETREE: - 946 | LETTER: left 947 | COLON: : 948 | WHITE_SPACE: 949 | NUMBER: 23 950 | LETTER: px 951 | SEMICOLON: ; 952 | WHITE_SPACE: 953 | 954 | LETTER: text 955 | WHIFFLETREE: - 956 | LETTER: align 957 | COLON: : 958 | WHITE_SPACE: 959 | LETTER: left 960 | SEMICOLON: ; 961 | WHITE_SPACE: 962 | 963 | LETTER: position 964 | COLON: : 965 | WHITE_SPACE: 966 | LETTER: absolute 967 | SEMICOLON: ; 968 | WHITE_SPACE: 969 | 970 | LETTER: left 971 | COLON: : 972 | WHITE_SPACE: 973 | NUMBER: 0 974 | SEMICOLON: ; 975 | WHITE_SPACE: 976 | 977 | LETTER: text 978 | WHIFFLETREE: - 979 | LETTER: decoration 980 | COLON: : 981 | WHITE_SPACE: 982 | LETTER: none 983 | SEMICOLON: ; 984 | WHITE_SPACE: 985 | 986 | RIGHT_BRACE: } 987 | WHITE_SPACE: 988 | 989 | 990 | DOT: . 991 | LETTER: s 992 | WHIFFLETREE: - 993 | LETTER: mod 994 | WHIFFLETREE: - 995 | LETTER: msg 996 | WHITE_SPACE: 997 | DOT: . 998 | LETTER: msg 999 | WHIFFLETREE: - 1000 | LETTER: clear 1001 | WHIFFLETREE: - 1002 | LETTER: btn 1003 | WHITE_SPACE: 1004 | DOT: . 1005 | LETTER: bg 1006 | WHITE_SPACE: 1007 | LEFT_BRACE: { 1008 | WHITE_SPACE: 1009 | 1010 | LETTER: width 1011 | COLON: : 1012 | WHITE_SPACE: 1013 | NUMBER: 12 1014 | LETTER: px 1015 | SEMICOLON: ; 1016 | WHITE_SPACE: 1017 | 1018 | LETTER: height 1019 | COLON: : 1020 | WHITE_SPACE: 1021 | NUMBER: 9 1022 | LETTER: px 1023 | SEMICOLON: ; 1024 | WHITE_SPACE: 1025 | 1026 | LETTER: background 1027 | COLON: : 1028 | WHITE_SPACE: 1029 | LETTER: url 1030 | LEFT_BRACKET: ( 1031 | SINGLE_QUOTE: ' 1032 | DOT: .. 1033 | SLASH: / 1034 | LETTER: img 1035 | SLASH: / 1036 | LETTER: msg 1037 | UNDERLINE: _ 1038 | LETTER: bg 1039 | UNDERLINE: _ 1040 | LETTER: d 1041 | NUMBER: 75 1042 | LETTER: a 1043 | NUMBER: 3 1044 | LETTER: e 1045 | NUMBER: 82 1046 | DOT: . 1047 | LETTER: png 1048 | SINGLE_QUOTE: ' 1049 | RIGHT_BRACKET: ) 1050 | WHITE_SPACE: 1051 | LETTER: no 1052 | WHIFFLETREE: - 1053 | LETTER: repeat 1054 | WHITE_SPACE: 1055 | NUMBER: 0 0 1056 | SEMICOLON: ; 1057 | WHITE_SPACE: 1058 | 1059 | UNDERLINE: _ 1060 | LETTER: background 1061 | COLON: : 1062 | WHITE_SPACE: 1063 | LETTER: url 1064 | LEFT_BRACKET: ( 1065 | SINGLE_QUOTE: ' 1066 | DOT: .. 1067 | SLASH: / 1068 | LETTER: img 1069 | SLASH: / 1070 | LETTER: msg 1071 | UNDERLINE: _ 1072 | LETTER: bg 1073 | UNDERLINE: _ 1074 | LETTER: skin 1075 | UNDERLINE: _ 1076 | LETTER: ie 1077 | NUMBER: 6 1078 | UNDERLINE: _ 1079 | NUMBER: 52137 1080 | LETTER: b 1081 | NUMBER: 6 1082 | LETTER: c 1083 | DOT: . 1084 | LETTER: png 1085 | SINGLE_QUOTE: ' 1086 | RIGHT_BRACKET: ) 1087 | WHITE_SPACE: 1088 | LETTER: no 1089 | WHIFFLETREE: - 1090 | LETTER: repeat 1091 | WHITE_SPACE: 1092 | NUMBER: 0 0 1093 | SEMICOLON: ; 1094 | WHITE_SPACE: 1095 | 1096 | RIGHT_BRACE: } 1097 | WHITE_SPACE: 1098 | 1099 | 1100 | DOT: . 1101 | LETTER: s 1102 | WHIFFLETREE: - 1103 | LETTER: mod 1104 | WHIFFLETREE: - 1105 | LETTER: msg 1106 | WHITE_SPACE: 1107 | DOT: . 1108 | LETTER: msg 1109 | WHIFFLETREE: - 1110 | LETTER: setting 1111 | WHIFFLETREE: - 1112 | LETTER: btn 1113 | WHITE_SPACE: 1114 | DOT: . 1115 | LETTER: bg 1116 | WHITE_SPACE: 1117 | LEFT_BRACE: { 1118 | WHITE_SPACE: 1119 | 1120 | LETTER: width 1121 | COLON: : 1122 | WHITE_SPACE: 1123 | NUMBER: 12 1124 | LETTER: px 1125 | SEMICOLON: ; 1126 | WHITE_SPACE: 1127 | 1128 | LETTER: height 1129 | COLON: : 1130 | WHITE_SPACE: 1131 | NUMBER: 10 1132 | LETTER: px 1133 | SEMICOLON: ; 1134 | WHITE_SPACE: 1135 | 1136 | LETTER: background 1137 | COLON: : 1138 | WHITE_SPACE: 1139 | LETTER: url 1140 | LEFT_BRACKET: ( 1141 | SINGLE_QUOTE: ' 1142 | DOT: .. 1143 | SLASH: / 1144 | LETTER: img 1145 | SLASH: / 1146 | LETTER: msg 1147 | UNDERLINE: _ 1148 | LETTER: bg 1149 | UNDERLINE: _ 1150 | LETTER: d 1151 | NUMBER: 75 1152 | LETTER: a 1153 | NUMBER: 3 1154 | LETTER: e 1155 | NUMBER: 82 1156 | DOT: . 1157 | LETTER: png 1158 | SINGLE_QUOTE: ' 1159 | RIGHT_BRACKET: ) 1160 | WHITE_SPACE: 1161 | LETTER: no 1162 | WHIFFLETREE: - 1163 | LETTER: repeat 1164 | WHITE_SPACE: 1165 | WHIFFLETREE: - 1166 | NUMBER: 15 1167 | LETTER: px 1168 | WHITE_SPACE: 1169 | NUMBER: 0 1170 | SEMICOLON: ; 1171 | WHITE_SPACE: 1172 | 1173 | RIGHT_BRACE: } 1174 | WHITE_SPACE: 1175 | 1176 | 1177 | DOT: . 1178 | LETTER: s 1179 | WHIFFLETREE: - 1180 | LETTER: msg 1181 | WHIFFLETREE: - 1182 | LETTER: base 1183 | WHITE_SPACE: 1184 | DOT: . 1185 | LETTER: noset 1186 | WHIFFLETREE: - 1187 | LETTER: msg 1188 | WHIFFLETREE: - 1189 | LETTER: tip 1190 | WHITE_SPACE: 1191 | LEFT_BRACE: { 1192 | WHITE_SPACE: 1193 | 1194 | LETTER: text 1195 | WHIFFLETREE: - 1196 | LETTER: align 1197 | COLON: : 1198 | WHITE_SPACE: 1199 | LETTER: left 1200 | SEMICOLON: ; 1201 | WHITE_SPACE: 1202 | 1203 | LETTER: height 1204 | COLON: : 1205 | WHITE_SPACE: 1206 | NUMBER: 28 1207 | LETTER: px 1208 | SEMICOLON: ; 1209 | WHITE_SPACE: 1210 | 1211 | LETTER: line 1212 | WHIFFLETREE: - 1213 | LETTER: height 1214 | COLON: : 1215 | WHITE_SPACE: 1216 | NUMBER: 28 1217 | LETTER: px 1218 | SEMICOLON: ; 1219 | WHITE_SPACE: 1220 | 1221 | LETTER: padding 1222 | COLON: : 1223 | WHITE_SPACE: 1224 | NUMBER: 20 1225 | LETTER: px 1226 | SEMICOLON: ; 1227 | WHITE_SPACE: 1228 | 1229 | LETTER: position 1230 | COLON: : 1231 | WHITE_SPACE: 1232 | LETTER: relative 1233 | SEMICOLON: ; 1234 | WHITE_SPACE: 1235 | 1236 | RIGHT_BRACE: } 1237 | WHITE_SPACE: 1238 | 1239 | 1240 | DOT: . 1241 | LETTER: s 1242 | WHIFFLETREE: - 1243 | LETTER: msg 1244 | WHIFFLETREE: - 1245 | LETTER: base 1246 | WHITE_SPACE: 1247 | DOT: . 1248 | LETTER: noset 1249 | WHIFFLETREE: - 1250 | LETTER: msg 1251 | WHIFFLETREE: - 1252 | LETTER: tip 1253 | WHITE_SPACE: 1254 | DOT: . 1255 | LETTER: msg 1256 | WHIFFLETREE: - 1257 | LETTER: setting 1258 | WHIFFLETREE: - 1259 | LETTER: btn 1260 | WHITE_SPACE: 1261 | LEFT_BRACE: { 1262 | WHITE_SPACE: 1263 | 1264 | LETTER: position 1265 | COLON: : 1266 | WHITE_SPACE: 1267 | LETTER: absolute 1268 | SEMICOLON: ; 1269 | WHITE_SPACE: 1270 | 1271 | LETTER: top 1272 | COLON: : 1273 | WHITE_SPACE: 1274 | NUMBER: 20 1275 | LETTER: px 1276 | SEMICOLON: ; 1277 | WHITE_SPACE: 1278 | 1279 | LETTER: right 1280 | COLON: : 1281 | WHITE_SPACE: 1282 | NUMBER: 20 1283 | LETTER: px 1284 | SEMICOLON: ; 1285 | WHITE_SPACE: 1286 | 1287 | LETTER: left 1288 | COLON: : 1289 | WHITE_SPACE: 1290 | LETTER: auto 1291 | SEMICOLON: ; 1292 | WHITE_SPACE: 1293 | 1294 | RIGHT_BRACE: } 1295 | WHITE_SPACE: 1296 | 1297 | 1298 | DOT: . 1299 | LETTER: s 1300 | WHIFFLETREE: - 1301 | LETTER: mod 1302 | WHIFFLETREE: - 1303 | LETTER: msg 1304 | WHITE_SPACE: 1305 | DOT: . 1306 | LETTER: msg 1307 | WHIFFLETREE: - 1308 | LETTER: arrow 1309 | WHITE_SPACE: 1310 | LEFT_BRACE: { 1311 | WHITE_SPACE: 1312 | 1313 | LETTER: position 1314 | COLON: : 1315 | WHITE_SPACE: 1316 | LETTER: absolute 1317 | SEMICOLON: ; 1318 | WHITE_SPACE: 1319 | 1320 | LETTER: z 1321 | WHIFFLETREE: - 1322 | LETTER: index 1323 | COLON: : 1324 | WHITE_SPACE: 1325 | NUMBER: 2 1326 | SEMICOLON: ; 1327 | WHITE_SPACE: 1328 | 1329 | LETTER: top 1330 | COLON: : 1331 | WHITE_SPACE: 1332 | WHIFFLETREE: - 1333 | NUMBER: 10 1334 | LETTER: px 1335 | SEMICOLON: ; 1336 | WHITE_SPACE: 1337 | 1338 | LETTER: display 1339 | COLON: : 1340 | WHITE_SPACE: 1341 | LETTER: inline 1342 | WHIFFLETREE: - 1343 | LETTER: block 1344 | SEMICOLON: ; 1345 | WHITE_SPACE: 1346 | 1347 | LETTER: width 1348 | COLON: : 1349 | WHITE_SPACE: 1350 | NUMBER: 0 1351 | SEMICOLON: ; 1352 | WHITE_SPACE: 1353 | 1354 | LETTER: height 1355 | COLON: : 1356 | WHITE_SPACE: 1357 | NUMBER: 0 1358 | SEMICOLON: ; 1359 | WHITE_SPACE: 1360 | 1361 | LETTER: line 1362 | WHIFFLETREE: - 1363 | LETTER: height 1364 | COLON: : 1365 | WHITE_SPACE: 1366 | NUMBER: 0 1367 | SEMICOLON: ; 1368 | WHITE_SPACE: 1369 | 1370 | LETTER: border 1371 | COLON: : 1372 | WHITE_SPACE: 1373 | NUMBER: 5 1374 | LETTER: px 1375 | WHITE_SPACE: 1376 | LETTER: dashed 1377 | WHITE_SPACE: 1378 | LETTER: transparent 1379 | SEMICOLON: ; 1380 | WHITE_SPACE: 1381 | 1382 | LETTER: border 1383 | WHIFFLETREE: - 1384 | LETTER: bottom 1385 | COLON: : 1386 | WHITE_SPACE: 1387 | NUMBER: 5 1388 | LETTER: px 1389 | WHITE_SPACE: 1390 | LETTER: solid 1391 | WHITE_SPACE: 1392 | POUND_KEY: # 1393 | LETTER: e 1394 | NUMBER: 3 1395 | LETTER: e 1396 | NUMBER: 3 1397 | LETTER: e 1398 | NUMBER: 3 1399 | SEMICOLON: ; 1400 | WHITE_SPACE: 1401 | 1402 | LETTER: font 1403 | WHIFFLETREE: - 1404 | LETTER: size 1405 | COLON: : 1406 | WHITE_SPACE: 1407 | NUMBER: 0 1408 | SEMICOLON: ; 1409 | WHITE_SPACE: 1410 | 1411 | LETTER: margin 1412 | WHIFFLETREE: - 1413 | LETTER: left 1414 | COLON: : 1415 | WHITE_SPACE: 1416 | NUMBER: 5 1417 | LETTER: px 1418 | SEMICOLON: ; 1419 | WHITE_SPACE: 1420 | 1421 | RIGHT_BRACE: } 1422 | WHITE_SPACE: 1423 | 1424 | 1425 | DOT: . 1426 | LETTER: s 1427 | WHIFFLETREE: - 1428 | LETTER: mod 1429 | WHIFFLETREE: - 1430 | LETTER: msg 1431 | WHITE_SPACE: 1432 | DOT: . 1433 | LETTER: msg 1434 | WHIFFLETREE: - 1435 | LETTER: arrow 1436 | WHITE_SPACE: 1437 | LETTER: em 1438 | WHITE_SPACE: 1439 | LEFT_BRACE: { 1440 | WHITE_SPACE: 1441 | 1442 | LETTER: position 1443 | COLON: : 1444 | WHITE_SPACE: 1445 | LETTER: absolute 1446 | SEMICOLON: ; 1447 | WHITE_SPACE: 1448 | 1449 | LETTER: top 1450 | COLON: : 1451 | WHITE_SPACE: 1452 | WHIFFLETREE: - 1453 | NUMBER: 4 1454 | LETTER: px 1455 | SEMICOLON: ; 1456 | WHITE_SPACE: 1457 | 1458 | LETTER: left 1459 | COLON: : 1460 | WHITE_SPACE: 1461 | WHIFFLETREE: - 1462 | NUMBER: 5 1463 | LETTER: px 1464 | SEMICOLON: ; 1465 | WHITE_SPACE: 1466 | 1467 | LETTER: display 1468 | COLON: : 1469 | WHITE_SPACE: 1470 | LETTER: block 1471 | WHITE_SPACE: 1472 | BANG: ! 1473 | LETTER: important 1474 | SEMICOLON: ; 1475 | WHITE_SPACE: 1476 | 1477 | LETTER: width 1478 | COLON: : 1479 | WHITE_SPACE: 1480 | NUMBER: 0 1481 | BANG: ! 1482 | LETTER: important 1483 | SEMICOLON: ; 1484 | WHITE_SPACE: 1485 | 1486 | LETTER: height 1487 | COLON: : 1488 | WHITE_SPACE: 1489 | NUMBER: 0 1490 | BANG: ! 1491 | LETTER: important 1492 | SEMICOLON: ; 1493 | WHITE_SPACE: 1494 | 1495 | LETTER: line 1496 | WHIFFLETREE: - 1497 | LETTER: height 1498 | COLON: : 1499 | WHITE_SPACE: 1500 | NUMBER: 0 1501 | SEMICOLON: ; 1502 | WHITE_SPACE: 1503 | 1504 | LETTER: font 1505 | WHIFFLETREE: - 1506 | LETTER: size 1507 | COLON: : 1508 | WHITE_SPACE: 1509 | NUMBER: 0 1510 | SEMICOLON: ; 1511 | WHITE_SPACE: 1512 | 1513 | LETTER: color 1514 | COLON: : 1515 | WHITE_SPACE: 1516 | POUND_KEY: # 1517 | NUMBER: 666 1518 | SEMICOLON: ; 1519 | WHITE_SPACE: 1520 | 1521 | LETTER: border 1522 | WHIFFLETREE: - 1523 | LETTER: top 1524 | COLON: : 1525 | WHITE_SPACE: 1526 | NUMBER: 5 1527 | LETTER: px 1528 | WHITE_SPACE: 1529 | LETTER: dashed 1530 | WHITE_SPACE: 1531 | LETTER: transparent 1532 | SEMICOLON: ; 1533 | WHITE_SPACE: 1534 | 1535 | LETTER: border 1536 | WHIFFLETREE: - 1537 | LETTER: left 1538 | COLON: : 1539 | WHITE_SPACE: 1540 | NUMBER: 5 1541 | LETTER: px 1542 | WHITE_SPACE: 1543 | LETTER: dashed 1544 | WHITE_SPACE: 1545 | LETTER: transparent 1546 | SEMICOLON: ; 1547 | WHITE_SPACE: 1548 | 1549 | LETTER: border 1550 | WHIFFLETREE: - 1551 | LETTER: right 1552 | COLON: : 1553 | WHITE_SPACE: 1554 | NUMBER: 5 1555 | LETTER: px 1556 | WHITE_SPACE: 1557 | LETTER: dashed 1558 | WHITE_SPACE: 1559 | LETTER: transparent 1560 | SEMICOLON: ; 1561 | WHITE_SPACE: 1562 | 1563 | LETTER: border 1564 | WHIFFLETREE: - 1565 | LETTER: bottom 1566 | COLON: : 1567 | WHITE_SPACE: 1568 | NUMBER: 5 1569 | LETTER: px 1570 | WHITE_SPACE: 1571 | LETTER: solid 1572 | WHITE_SPACE: 1573 | POUND_KEY: # 1574 | LETTER: fff 1575 | SEMICOLON: ; 1576 | WHITE_SPACE: 1577 | 1578 | RIGHT_BRACE: } 1579 | WHITE_SPACE: 1580 | 1581 | 1582 | DOT: . 1583 | LETTER: s 1584 | WHIFFLETREE: - 1585 | LETTER: mod 1586 | WHIFFLETREE: - 1587 | LETTER: msg 1588 | WHIFFLETREE: - 1589 | LETTER: shadow 1590 | WHITE_SPACE: 1591 | LEFT_BRACE: { 1592 | WHITE_SPACE: 1593 | 1594 | LETTER: background 1595 | COLON: : 1596 | WHITE_SPACE: 1597 | LETTER: url 1598 | LEFT_BRACKET: ( 1599 | SINGLE_QUOTE: ' 1600 | DOT: .. 1601 | SLASH: / 1602 | LETTER: img 1603 | SLASH: / 1604 | LETTER: blank 1605 | UNDERLINE: _ 1606 | NUMBER: 56 1607 | LETTER: a 1608 | NUMBER: 92 1609 | LETTER: bd 1610 | NUMBER: 4 1611 | DOT: . 1612 | LETTER: png 1613 | SINGLE_QUOTE: ' 1614 | RIGHT_BRACKET: ) 1615 | WHITE_SPACE: 1616 | LETTER: repeat 1617 | SEMICOLON: ; 1618 | WHITE_SPACE: 1619 | 1620 | UNDERLINE: _ 1621 | LETTER: background 1622 | COLON: : 1623 | WHITE_SPACE: 1624 | LETTER: url 1625 | LEFT_BRACKET: ( 1626 | SINGLE_QUOTE: ' 1627 | DOT: .. 1628 | SLASH: / 1629 | LETTER: img 1630 | SLASH: / 1631 | LETTER: blank 1632 | UNDERLINE: _ 1633 | LETTER: ie 1634 | NUMBER: 6 1635 | UNDERLINE: _ 1636 | LETTER: fadcce 1637 | NUMBER: 61 1638 | DOT: . 1639 | LETTER: png 1640 | SINGLE_QUOTE: ' 1641 | RIGHT_BRACKET: ) 1642 | WHITE_SPACE: 1643 | LETTER: repeat 1644 | SEMICOLON: ; 1645 | WHITE_SPACE: 1646 | 1647 | LETTER: position 1648 | COLON: : 1649 | WHITE_SPACE: 1650 | LETTER: absolute 1651 | SEMICOLON: ; 1652 | WHITE_SPACE: 1653 | 1654 | LETTER: width 1655 | COLON: : 1656 | WHITE_SPACE: 1657 | NUMBER: 100 1658 | PERSCENT_SYMBOL: % 1659 | SEMICOLON: ; 1660 | WHITE_SPACE: 1661 | 1662 | LETTER: height 1663 | COLON: : 1664 | WHITE_SPACE: 1665 | NUMBER: 100 1666 | PERSCENT_SYMBOL: % 1667 | SEMICOLON: ; 1668 | WHITE_SPACE: 1669 | 1670 | LETTER: left 1671 | COLON: : 1672 | WHITE_SPACE: 1673 | NUMBER: 0 1674 | SEMICOLON: ; 1675 | WHITE_SPACE: 1676 | 1677 | LETTER: top 1678 | COLON: : 1679 | WHITE_SPACE: 1680 | NUMBER: 0 1681 | SEMICOLON: ; 1682 | WHITE_SPACE: 1683 | 1684 | LETTER: z 1685 | WHIFFLETREE: - 1686 | LETTER: index 1687 | COLON: : 1688 | WHITE_SPACE: 1689 | NUMBER: 998 1690 | SEMICOLON: ; 1691 | WHITE_SPACE: 1692 | 1693 | RIGHT_BRACE: } 1694 | WHITE_SPACE: 1695 | 1696 | 1697 | DOT: . 1698 | LETTER: s 1699 | WHIFFLETREE: - 1700 | LETTER: msg 1701 | WHIFFLETREE: - 1702 | LETTER: firtip 1703 | WHITE_SPACE: 1704 | LEFT_BRACE: { 1705 | WHITE_SPACE: 1706 | 1707 | LETTER: color 1708 | COLON: : 1709 | WHITE_SPACE: 1710 | POUND_KEY: # 1711 | NUMBER: 333 1712 | SEMICOLON: ; 1713 | WHITE_SPACE: 1714 | 1715 | LETTER: font 1716 | WHIFFLETREE: - 1717 | LETTER: size 1718 | COLON: : 1719 | WHITE_SPACE: 1720 | NUMBER: 12 1721 | LETTER: px 1722 | SEMICOLON: ; 1723 | WHITE_SPACE: 1724 | 1725 | LETTER: text 1726 | WHIFFLETREE: - 1727 | LETTER: align 1728 | COLON: : 1729 | WHITE_SPACE: 1730 | LETTER: left 1731 | SEMICOLON: ; 1732 | WHITE_SPACE: 1733 | 1734 | RIGHT_BRACE: } 1735 | WHITE_SPACE: 1736 | 1737 | 1738 | DOT: . 1739 | LETTER: s 1740 | WHIFFLETREE: - 1741 | LETTER: mod 1742 | WHIFFLETREE: - 1743 | LETTER: msg 1744 | WHITE_SPACE: 1745 | DOT: . 1746 | LETTER: item 1747 | WHIFFLETREE: - 1748 | LETTER: msg 1749 | WHIFFLETREE: - 1750 | LETTER: content 1751 | WHITE_SPACE: 1752 | LEFT_BRACE: { 1753 | WHITE_SPACE: 1754 | 1755 | LETTER: display 1756 | COLON: : 1757 | WHITE_SPACE: 1758 | LETTER: inline 1759 | WHIFFLETREE: - 1760 | LETTER: block 1761 | SEMICOLON: ; 1762 | WHITE_SPACE: 1763 | 1764 | LETTER: vertical 1765 | WHIFFLETREE: - 1766 | LETTER: align 1767 | COLON: : 1768 | WHITE_SPACE: 1769 | LETTER: middle 1770 | SEMICOLON: ; 1771 | WHITE_SPACE: 1772 | 1773 | LETTER: width 1774 | COLON: : 1775 | WHITE_SPACE: 1776 | NUMBER: 166 1777 | LETTER: px 1778 | SEMICOLON: ; 1779 | WHITE_SPACE: 1780 | 1781 | UNDERLINE: _ 1782 | LETTER: width 1783 | COLON: : 1784 | WHITE_SPACE: 1785 | NUMBER: 162 1786 | LETTER: px 1787 | SEMICOLON: ; 1788 | WHITE_SPACE: 1789 | 1790 | LETTER: font 1791 | WHIFFLETREE: - 1792 | LETTER: size 1793 | COLON: : 1794 | WHITE_SPACE: 1795 | NUMBER: 12 1796 | LETTER: px 1797 | SEMICOLON: ; 1798 | WHITE_SPACE: 1799 | 1800 | ASTERISK: * 1801 | LETTER: margin 1802 | WHIFFLETREE: - 1803 | LETTER: top 1804 | COLON: : 1805 | WHITE_SPACE: 1806 | NUMBER: 6 1807 | LETTER: px 1808 | SEMICOLON: ; 1809 | WHITE_SPACE: 1810 | 1811 | UNDERLINE: _ 1812 | LETTER: margin 1813 | WHIFFLETREE: - 1814 | LETTER: top 1815 | COLON: : 1816 | WHITE_SPACE: 1817 | NUMBER: 4 1818 | LETTER: px 1819 | SEMICOLON: ; 1820 | WHITE_SPACE: 1821 | 1822 | RIGHT_BRACE: } 1823 | WHITE_SPACE: 1824 | 1825 | 1826 | DOT: . 1827 | LETTER: s 1828 | WHIFFLETREE: - 1829 | LETTER: mod 1830 | WHIFFLETREE: - 1831 | LETTER: msg 1832 | WHITE_SPACE: 1833 | DOT: . 1834 | LETTER: item 1835 | WHIFFLETREE: - 1836 | LETTER: msg 1837 | WHIFFLETREE: - 1838 | LETTER: content 1839 | WHITE_SPACE: 1840 | DOT: . 1841 | LETTER: default 1842 | WHIFFLETREE: - 1843 | LETTER: msg 1844 | WHIFFLETREE: - 1845 | LETTER: title 1846 | WHITE_SPACE: 1847 | LEFT_BRACE: { 1848 | WHITE_SPACE: 1849 | 1850 | LETTER: color 1851 | COLON: : 1852 | WHITE_SPACE: 1853 | POUND_KEY: # 1854 | NUMBER: 333 1855 | SEMICOLON: ; 1856 | WHITE_SPACE: 1857 | 1858 | LETTER: text 1859 | WHIFFLETREE: - 1860 | LETTER: decoration 1861 | COLON: : 1862 | WHITE_SPACE: 1863 | LETTER: none 1864 | SEMICOLON: ; 1865 | WHITE_SPACE: 1866 | 1867 | RIGHT_BRACE: } 1868 | WHITE_SPACE: 1869 | 1870 | 1871 | DOT: . 1872 | LETTER: s 1873 | WHIFFLETREE: - 1874 | LETTER: mod 1875 | WHIFFLETREE: - 1876 | LETTER: msg 1877 | WHITE_SPACE: 1878 | DOT: . 1879 | LETTER: item 1880 | WHIFFLETREE: - 1881 | LETTER: msg 1882 | WHIFFLETREE: - 1883 | LETTER: content 1884 | WHITE_SPACE: 1885 | DOT: . 1886 | LETTER: default 1887 | WHIFFLETREE: - 1888 | LETTER: msg 1889 | WHIFFLETREE: - 1890 | LETTER: title 1891 | COLON: : 1892 | LETTER: hover 1893 | WHITE_SPACE: 1894 | LEFT_BRACE: { 1895 | WHITE_SPACE: 1896 | 1897 | LETTER: text 1898 | WHIFFLETREE: - 1899 | LETTER: decoration 1900 | COLON: : 1901 | WHITE_SPACE: 1902 | LETTER: underline 1903 | SEMICOLON: ; 1904 | WHITE_SPACE: 1905 | 1906 | RIGHT_BRACE: } 1907 | WHITE_SPACE: 1908 | 1909 | 1910 | DOT: . 1911 | LETTER: s 1912 | WHIFFLETREE: - 1913 | LETTER: mod 1914 | WHIFFLETREE: - 1915 | LETTER: msg 1916 | DOT: . 1917 | LETTER: extend 1918 | WHITE_SPACE: 1919 | DOT: . 1920 | LETTER: item 1921 | WHIFFLETREE: - 1922 | LETTER: msg 1923 | WHIFFLETREE: - 1924 | LETTER: content 1925 | WHITE_SPACE: 1926 | LEFT_BRACE: { 1927 | WHITE_SPACE: 1928 | 1929 | ASTERISK: * 1930 | LETTER: margin 1931 | WHIFFLETREE: - 1932 | LETTER: top 1933 | COLON: : 1934 | WHITE_SPACE: 1935 | NUMBER: 0 1936 | SEMICOLON: ; 1937 | WHITE_SPACE: 1938 | 1939 | UNDERLINE: _ 1940 | LETTER: margin 1941 | WHIFFLETREE: - 1942 | LETTER: top 1943 | COLON: : 1944 | WHITE_SPACE: 1945 | NUMBER: 4 1946 | LETTER: px 1947 | SEMICOLON: ; 1948 | WHITE_SPACE: 1949 | 1950 | RIGHT_BRACE: } 1951 | WHITE_SPACE: 1952 | 1953 | 1954 | DOT: . 1955 | LETTER: s 1956 | WHIFFLETREE: - 1957 | LETTER: mod 1958 | WHIFFLETREE: - 1959 | LETTER: msg 1960 | WHITE_SPACE: 1961 | DOT: . 1962 | LETTER: cell 1963 | WHITE_SPACE: 1964 | LEFT_BRACE: { 1965 | WHITE_SPACE: 1966 | 1967 | LETTER: text 1968 | WHIFFLETREE: - 1969 | LETTER: overflow 1970 | COLON: : 1971 | WHITE_SPACE: 1972 | LETTER: ellipsis 1973 | SEMICOLON: ; 1974 | WHITE_SPACE: 1975 | 1976 | LETTER: white 1977 | WHIFFLETREE: - 1978 | LETTER: space 1979 | COLON: : 1980 | WHITE_SPACE: 1981 | LETTER: nowrap 1982 | SEMICOLON: ; 1983 | WHITE_SPACE: 1984 | 1985 | LETTER: overflow 1986 | COLON: : 1987 | WHITE_SPACE: 1988 | LETTER: hidden 1989 | SEMICOLON: ; 1990 | WHITE_SPACE: 1991 | 1992 | RIGHT_BRACE: } 1993 | WHITE_SPACE: 1994 | 1995 | 1996 | DOT: . 1997 | LETTER: s 1998 | WHIFFLETREE: - 1999 | LETTER: msg 2000 | WHIFFLETREE: - 2001 | LETTER: firtip 2002 | WHITE_SPACE: 2003 | DOT: . 2004 | LETTER: s 2005 | WHIFFLETREE: - 2006 | LETTER: msg 2007 | WHIFFLETREE: - 2008 | LETTER: content 2009 | WHITE_SPACE: 2010 | LEFT_BRACE: { 2011 | WHITE_SPACE: 2012 | 2013 | LETTER: position 2014 | COLON: : 2015 | WHITE_SPACE: 2016 | LETTER: relative 2017 | SEMICOLON: ; 2018 | WHITE_SPACE: 2019 | 2020 | RIGHT_BRACE: } 2021 | WHITE_SPACE: 2022 | 2023 | 2024 | DOT: . 2025 | LETTER: s 2026 | WHIFFLETREE: - 2027 | LETTER: mod 2028 | WHIFFLETREE: - 2029 | LETTER: msg 2030 | WHITE_SPACE: 2031 | DOT: . 2032 | LETTER: msg 2033 | WHIFFLETREE: - 2034 | LETTER: area 2035 | WHITE_SPACE: 2036 | DOT: . 2037 | LETTER: s 2038 | WHIFFLETREE: - 2039 | LETTER: msg 2040 | WHIFFLETREE: - 2041 | LETTER: item 2042 | WHITE_SPACE: 2043 | LEFT_BRACE: { 2044 | WHITE_SPACE: 2045 | 2046 | LETTER: font 2047 | WHIFFLETREE: - 2048 | LETTER: size 2049 | COLON: : 2050 | WHITE_SPACE: 2051 | NUMBER: 0 2052 | SEMICOLON: ; 2053 | WHITE_SPACE: 2054 | 2055 | LETTER: width 2056 | COLON: : 2057 | WHITE_SPACE: 2058 | NUMBER: 230 2059 | LETTER: px 2060 | SEMICOLON: ; 2061 | WHITE_SPACE: 2062 | 2063 | LETTER: text 2064 | WHIFFLETREE: - 2065 | LETTER: align 2066 | COLON: : 2067 | WHITE_SPACE: 2068 | LETTER: left 2069 | SEMICOLON: ; 2070 | WHITE_SPACE: 2071 | 2072 | LETTER: padding 2073 | COLON: : 2074 | WHITE_SPACE: 2075 | NUMBER: 15 2076 | LETTER: px 2077 | SEMICOLON: ; 2078 | WHITE_SPACE: 2079 | 2080 | LETTER: padding 2081 | WHIFFLETREE: - 2082 | LETTER: right 2083 | COLON: : 2084 | WHITE_SPACE: 2085 | NUMBER: 0 2086 | SEMICOLON: ; 2087 | WHITE_SPACE: 2088 | 2089 | RIGHT_BRACE: } 2090 | WHITE_SPACE: 2091 | 2092 | 2093 | DOT: . 2094 | LETTER: s 2095 | WHIFFLETREE: - 2096 | LETTER: mod 2097 | WHIFFLETREE: - 2098 | LETTER: msg 2099 | WHITE_SPACE: 2100 | DOT: . 2101 | LETTER: s 2102 | WHIFFLETREE: - 2103 | LETTER: msg 2104 | WHIFFLETREE: - 2105 | LETTER: item 2106 | WHITE_SPACE: 2107 | DOT: . 2108 | LETTER: item 2109 | WHIFFLETREE: - 2110 | LETTER: name 2111 | WHITE_SPACE: 2112 | LEFT_BRACE: { 2113 | WHITE_SPACE: 2114 | 2115 | LETTER: display 2116 | COLON: : 2117 | WHITE_SPACE: 2118 | LETTER: inline 2119 | WHIFFLETREE: - 2120 | LETTER: block 2121 | SEMICOLON: ; 2122 | WHITE_SPACE: 2123 | 2124 | LETTER: vertical 2125 | WHIFFLETREE: - 2126 | LETTER: align 2127 | COLON: : 2128 | WHITE_SPACE: 2129 | LETTER: middle 2130 | SEMICOLON: ; 2131 | WHITE_SPACE: 2132 | 2133 | LETTER: font 2134 | WHIFFLETREE: - 2135 | LETTER: weight 2136 | COLON: : 2137 | WHITE_SPACE: 2138 | LETTER: bold 2139 | SEMICOLON: ; 2140 | WHITE_SPACE: 2141 | 2142 | LETTER: width 2143 | COLON: : 2144 | WHITE_SPACE: 2145 | NUMBER: 48 2146 | LETTER: px 2147 | SEMICOLON: ; 2148 | WHITE_SPACE: 2149 | 2150 | LETTER: font 2151 | WHIFFLETREE: - 2152 | LETTER: size 2153 | COLON: : 2154 | WHITE_SPACE: 2155 | NUMBER: 12 2156 | LETTER: px 2157 | SEMICOLON: ; 2158 | WHITE_SPACE: 2159 | 2160 | UNDERLINE: _ 2161 | LETTER: margin 2162 | WHIFFLETREE: - 2163 | LETTER: top 2164 | COLON: : 2165 | WHITE_SPACE: 2166 | NUMBER: 2 2167 | LETTER: px 2168 | SEMICOLON: ; 2169 | WHITE_SPACE: 2170 | 2171 | RIGHT_BRACE: } 2172 | WHITE_SPACE: 2173 | 2174 | 2175 | DOT: . 2176 | LETTER: s 2177 | WHIFFLETREE: - 2178 | LETTER: mod 2179 | WHIFFLETREE: - 2180 | LETTER: msg 2181 | DOT: . 2182 | LETTER: extend 2183 | WHITE_SPACE: 2184 | DOT: . 2185 | LETTER: s 2186 | WHIFFLETREE: - 2187 | LETTER: msg 2188 | WHIFFLETREE: - 2189 | LETTER: item 2190 | WHITE_SPACE: 2191 | DOT: . 2192 | LETTER: item 2193 | WHIFFLETREE: - 2194 | LETTER: name 2195 | WHITE_SPACE: 2196 | LEFT_BRACE: { 2197 | WHITE_SPACE: 2198 | 2199 | UNDERLINE: _ 2200 | LETTER: margin 2201 | WHIFFLETREE: - 2202 | LETTER: left 2203 | COLON: : 2204 | WHITE_SPACE: 2205 | WHIFFLETREE: - 2206 | NUMBER: 15 2207 | LETTER: px 2208 | SEMICOLON: ; 2209 | WHITE_SPACE: 2210 | 2211 | RIGHT_BRACE: } 2212 | WHITE_SPACE: 2213 | 2214 | 2215 | DOT: . 2216 | LETTER: s 2217 | WHIFFLETREE: - 2218 | LETTER: mod 2219 | WHIFFLETREE: - 2220 | LETTER: msg 2221 | WHITE_SPACE: 2222 | DOT: . 2223 | LETTER: s 2224 | WHIFFLETREE: - 2225 | LETTER: msg 2226 | WHIFFLETREE: - 2227 | LETTER: item 2228 | WHITE_SPACE: 2229 | DOT: . 2230 | LETTER: item 2231 | WHIFFLETREE: - 2232 | LETTER: name 2233 | WHITE_SPACE: 2234 | DOT: . 2235 | LETTER: item 2236 | WHIFFLETREE: - 2237 | LETTER: name 2238 | WHIFFLETREE: - 2239 | LETTER: link 2240 | WHITE_SPACE: 2241 | LEFT_BRACE: { 2242 | WHITE_SPACE: 2243 | 2244 | LETTER: color 2245 | COLON: : 2246 | WHITE_SPACE: 2247 | POUND_KEY: # 2248 | NUMBER: 333 2249 | SEMICOLON: ; 2250 | WHITE_SPACE: 2251 | 2252 | LETTER: font 2253 | WHIFFLETREE: - 2254 | LETTER: weight 2255 | COLON: : 2256 | WHITE_SPACE: 2257 | LETTER: bold 2258 | SEMICOLON: ; 2259 | WHITE_SPACE: 2260 | 2261 | LETTER: text 2262 | WHIFFLETREE: - 2263 | LETTER: decoration 2264 | COLON: : 2265 | WHITE_SPACE: 2266 | LETTER: none 2267 | SEMICOLON: ; 2268 | WHITE_SPACE: 2269 | 2270 | LETTER: white 2271 | WHIFFLETREE: - 2272 | LETTER: space 2273 | COLON: : 2274 | WHITE_SPACE: 2275 | LETTER: nowrap 2276 | SEMICOLON: ; 2277 | WHITE_SPACE: 2278 | 2279 | LETTER: overflow 2280 | COLON: : 2281 | WHITE_SPACE: 2282 | LETTER: hidden 2283 | SEMICOLON: ; 2284 | WHITE_SPACE: 2285 | 2286 | RIGHT_BRACE: } 2287 | WHITE_SPACE: 2288 | 2289 | 2290 | DOT: . 2291 | LETTER: s 2292 | WHIFFLETREE: - 2293 | LETTER: mod 2294 | WHIFFLETREE: - 2295 | LETTER: msg 2296 | WHITE_SPACE: 2297 | DOT: . 2298 | LETTER: s 2299 | WHIFFLETREE: - 2300 | LETTER: msg 2301 | WHIFFLETREE: - 2302 | LETTER: item 2303 | WHITE_SPACE: 2304 | DOT: . 2305 | LETTER: item 2306 | WHIFFLETREE: - 2307 | LETTER: name 2308 | WHITE_SPACE: 2309 | DOT: . 2310 | LETTER: item 2311 | WHIFFLETREE: - 2312 | LETTER: name 2313 | WHIFFLETREE: - 2314 | LETTER: link 2315 | COLON: : 2316 | LETTER: hover 2317 | WHITE_SPACE: 2318 | LEFT_BRACE: { 2319 | WHITE_SPACE: 2320 | 2321 | LETTER: text 2322 | WHIFFLETREE: - 2323 | LETTER: decoration 2324 | COLON: : 2325 | WHITE_SPACE: 2326 | LETTER: underline 2327 | SEMICOLON: ; 2328 | WHITE_SPACE: 2329 | 2330 | RIGHT_BRACE: } 2331 | WHITE_SPACE: 2332 | 2333 | 2334 | DOT: . 2335 | LETTER: s 2336 | WHIFFLETREE: - 2337 | LETTER: mod 2338 | WHIFFLETREE: - 2339 | LETTER: msg 2340 | WHITE_SPACE: 2341 | DOT: . 2342 | LETTER: s 2343 | WHIFFLETREE: - 2344 | LETTER: msg 2345 | WHIFFLETREE: - 2346 | LETTER: item 2347 | WHITE_SPACE: 2348 | DOT: . 2349 | LETTER: item 2350 | WHIFFLETREE: - 2351 | LETTER: name 2352 | WHITE_SPACE: 2353 | LETTER: span 2354 | DOT: . 2355 | LETTER: item 2356 | WHIFFLETREE: - 2357 | LETTER: name 2358 | WHIFFLETREE: - 2359 | LETTER: link 2360 | COLON: : 2361 | LETTER: hover 2362 | WHITE_SPACE: 2363 | LEFT_BRACE: { 2364 | WHITE_SPACE: 2365 | 2366 | LETTER: color 2367 | COLON: : 2368 | WHITE_SPACE: 2369 | POUND_KEY: # 2370 | NUMBER: 666 2371 | SEMICOLON: ; 2372 | WHITE_SPACE: 2373 | 2374 | LETTER: text 2375 | WHIFFLETREE: - 2376 | LETTER: decoration 2377 | COLON: : 2378 | WHITE_SPACE: 2379 | LETTER: none 2380 | SEMICOLON: ; 2381 | WHITE_SPACE: 2382 | 2383 | RIGHT_BRACE: } 2384 | WHITE_SPACE: 2385 | 2386 | 2387 | DOT: . 2388 | LETTER: s 2389 | WHIFFLETREE: - 2390 | LETTER: mod 2391 | WHIFFLETREE: - 2392 | LETTER: msg 2393 | WHITE_SPACE: 2394 | DOT: . 2395 | LETTER: s 2396 | WHIFFLETREE: - 2397 | LETTER: msg 2398 | WHIFFLETREE: - 2399 | LETTER: item 2400 | WHITE_SPACE: 2401 | DOT: . 2402 | LETTER: item 2403 | WHIFFLETREE: - 2404 | LETTER: title 2405 | COLON: : 2406 | LETTER: visited 2407 | WHITE_SPACE: 2408 | LEFT_BRACE: { 2409 | WHITE_SPACE: 2410 | 2411 | LETTER: color 2412 | COLON: : 2413 | WHITE_SPACE: 2414 | POUND_KEY: # 2415 | NUMBER: 333 2416 | SEMICOLON: ; 2417 | WHITE_SPACE: 2418 | 2419 | RIGHT_BRACE: } 2420 | WHITE_SPACE: 2421 | 2422 | 2423 | DOT: . 2424 | LETTER: s 2425 | WHIFFLETREE: - 2426 | LETTER: mod 2427 | WHIFFLETREE: - 2428 | LETTER: msg 2429 | WHITE_SPACE: 2430 | DOT: . 2431 | LETTER: s 2432 | WHIFFLETREE: - 2433 | LETTER: msg 2434 | WHIFFLETREE: - 2435 | LETTER: item 2436 | WHITE_SPACE: 2437 | DOT: . 2438 | LETTER: item 2439 | WHIFFLETREE: - 2440 | LETTER: title 2441 | WHITE_SPACE: 2442 | LEFT_BRACE: { 2443 | WHITE_SPACE: 2444 | 2445 | LETTER: text 2446 | WHIFFLETREE: - 2447 | LETTER: decoration 2448 | COLON: : 2449 | WHITE_SPACE: 2450 | LETTER: none 2451 | SEMICOLON: ; 2452 | WHITE_SPACE: 2453 | 2454 | LETTER: color 2455 | COLON: : 2456 | WHITE_SPACE: 2457 | POUND_KEY: # 2458 | NUMBER: 333 2459 | SEMICOLON: ; 2460 | WHITE_SPACE: 2461 | 2462 | LETTER: outline 2463 | COLON: : 2464 | WHITE_SPACE: 2465 | LETTER: none 2466 | SEMICOLON: ; 2467 | WHITE_SPACE: 2468 | 2469 | RIGHT_BRACE: } 2470 | WHITE_SPACE: 2471 | 2472 | 2473 | DOT: . 2474 | LETTER: s 2475 | WHIFFLETREE: - 2476 | LETTER: mod 2477 | WHIFFLETREE: - 2478 | LETTER: msg 2479 | WHITE_SPACE: 2480 | DOT: . 2481 | LETTER: s 2482 | WHIFFLETREE: - 2483 | LETTER: msg 2484 | WHIFFLETREE: - 2485 | LETTER: item 2486 | WHITE_SPACE: 2487 | DOT: . 2488 | LETTER: title 2489 | WHIFFLETREE: - 2490 | LETTER: sns 2491 | COMMA: , 2492 | WHITE_SPACE: 2493 | 2494 | DOT: . 2495 | LETTER: s 2496 | WHIFFLETREE: - 2497 | LETTER: mod 2498 | WHIFFLETREE: - 2499 | LETTER: msg 2500 | WHITE_SPACE: 2501 | DOT: . 2502 | LETTER: s 2503 | WHIFFLETREE: - 2504 | LETTER: msg 2505 | WHIFFLETREE: - 2506 | LETTER: item 2507 | WHITE_SPACE: 2508 | DOT: . 2509 | LETTER: title 2510 | WHIFFLETREE: - 2511 | LETTER: sns 2512 | COLON: : 2513 | LETTER: visited 2514 | WHITE_SPACE: 2515 | LEFT_BRACE: { 2516 | WHITE_SPACE: 2517 | 2518 | LETTER: color 2519 | COLON: : 2520 | WHITE_SPACE: 2521 | POUND_KEY: # 2522 | NUMBER: 333 2523 | SEMICOLON: ; 2524 | WHITE_SPACE: 2525 | 2526 | LETTER: margin 2527 | WHIFFLETREE: - 2528 | LETTER: right 2529 | COLON: : 2530 | WHITE_SPACE: 2531 | NUMBER: 0 2532 | SEMICOLON: ; 2533 | WHITE_SPACE: 2534 | 2535 | RIGHT_BRACE: } 2536 | WHITE_SPACE: 2537 | 2538 | 2539 | DOT: . 2540 | LETTER: s 2541 | WHIFFLETREE: - 2542 | LETTER: mod 2543 | WHIFFLETREE: - 2544 | LETTER: msg 2545 | WHITE_SPACE: 2546 | DOT: . 2547 | LETTER: s 2548 | WHIFFLETREE: - 2549 | LETTER: msg 2550 | WHIFFLETREE: - 2551 | LETTER: item 2552 | WHITE_SPACE: 2553 | DOT: . 2554 | LETTER: title 2555 | WHIFFLETREE: - 2556 | LETTER: sns 2557 | WHIFFLETREE: - 2558 | LETTER: visited 2559 | COMMA: , 2560 | WHITE_SPACE: 2561 | 2562 | DOT: . 2563 | LETTER: s 2564 | WHIFFLETREE: - 2565 | LETTER: mod 2566 | WHIFFLETREE: - 2567 | LETTER: msg 2568 | WHITE_SPACE: 2569 | DOT: . 2570 | LETTER: s 2571 | WHIFFLETREE: - 2572 | LETTER: msg 2573 | WHIFFLETREE: - 2574 | LETTER: item 2575 | WHITE_SPACE: 2576 | DOT: . 2577 | LETTER: title 2578 | WHIFFLETREE: - 2579 | LETTER: sns 2580 | WHIFFLETREE: - 2581 | LETTER: visited 2582 | COLON: : 2583 | LETTER: visited 2584 | WHITE_SPACE: 2585 | LEFT_BRACE: { 2586 | WHITE_SPACE: 2587 | 2588 | LETTER: color 2589 | COLON: : 2590 | WHITE_SPACE: 2591 | POUND_KEY: # 2592 | NUMBER: 333 2593 | SEMICOLON: ; 2594 | WHITE_SPACE: 2595 | 2596 | RIGHT_BRACE: } 2597 | WHITE_SPACE: 2598 | 2599 | 2600 | DOT: . 2601 | LETTER: s 2602 | WHIFFLETREE: - 2603 | LETTER: msg 2604 | WHIFFLETREE: - 2605 | LETTER: firtip 2606 | WHITE_SPACE: 2607 | DOT: . 2608 | LETTER: s 2609 | WHIFFLETREE: - 2610 | LETTER: msg 2611 | WHIFFLETREE: - 2612 | LETTER: item 2613 | WHITE_SPACE: 2614 | DOT: . 2615 | LETTER: vertical 2616 | WHIFFLETREE: - 2617 | LETTER: line 2618 | WHITE_SPACE: 2619 | LEFT_BRACE: { 2620 | WHITE_SPACE: 2621 | 2622 | LETTER: vertical 2623 | WHIFFLETREE: - 2624 | LETTER: align 2625 | COLON: : 2626 | WHITE_SPACE: 2627 | LETTER: middle 2628 | SEMICOLON: ; 2629 | WHITE_SPACE: 2630 | 2631 | LETTER: display 2632 | COLON: : 2633 | WHITE_SPACE: 2634 | LETTER: inline 2635 | WHIFFLETREE: - 2636 | LETTER: block 2637 | SEMICOLON: ; 2638 | WHITE_SPACE: 2639 | 2640 | LETTER: width 2641 | COLON: : 2642 | WHITE_SPACE: 2643 | NUMBER: 0 2644 | SEMICOLON: ; 2645 | WHITE_SPACE: 2646 | 2647 | LETTER: height 2648 | COLON: : 2649 | WHITE_SPACE: 2650 | NUMBER: 12 2651 | LETTER: px 2652 | SEMICOLON: ; 2653 | WHITE_SPACE: 2654 | 2655 | LETTER: margin 2656 | COLON: : 2657 | WHITE_SPACE: 2658 | WHIFFLETREE: - 2659 | NUMBER: 2 2660 | LETTER: px 2661 | WHITE_SPACE: 2662 | NUMBER: 6 2663 | LETTER: px 2664 | WHITE_SPACE: 2665 | NUMBER: 0 9 2666 | LETTER: px 2667 | SEMICOLON: ; 2668 | WHITE_SPACE: 2669 | 2670 | ASTERISK: * 2671 | LETTER: margin 2672 | WHIFFLETREE: - 2673 | LETTER: top 2674 | COLON: : 2675 | WHITE_SPACE: 2676 | NUMBER: 0 2677 | SEMICOLON: ; 2678 | WHITE_SPACE: 2679 | 2680 | LETTER: overflow 2681 | COLON: : 2682 | WHITE_SPACE: 2683 | LETTER: hidden 2684 | SEMICOLON: ; 2685 | WHITE_SPACE: 2686 | 2687 | LETTER: border 2688 | WHIFFLETREE: - 2689 | LETTER: right 2690 | COLON: : 2691 | WHITE_SPACE: 2692 | NUMBER: 1 2693 | LETTER: px 2694 | WHITE_SPACE: 2695 | LETTER: solid 2696 | WHITE_SPACE: 2697 | POUND_KEY: # 2698 | LETTER: ccc 2699 | SEMICOLON: ; 2700 | WHITE_SPACE: 2701 | 2702 | LETTER: border 2703 | WHIFFLETREE: - 2704 | LETTER: right 2705 | COLON: : 2706 | WHITE_SPACE: 2707 | NUMBER: 1 2708 | LETTER: px 2709 | WHITE_SPACE: 2710 | LETTER: solid 2711 | WHITE_SPACE: 2712 | LETTER: rgba 2713 | LEFT_BRACKET: ( 2714 | NUMBER: 177 2715 | COMMA: , 2716 | WHITE_SPACE: 2717 | NUMBER: 177 2718 | COMMA: , 2719 | WHITE_SPACE: 2720 | NUMBER: 177 2721 | COMMA: , 2722 | WHITE_SPACE: 2723 | DOT: . 2724 | NUMBER: 50 2725 | RIGHT_BRACKET: ) 2726 | SEMICOLON: ; 2727 | WHITE_SPACE: 2728 | 2729 | RIGHT_BRACE: } 2730 | WHITE_SPACE: 2731 | 2732 | 2733 | DOT: . 2734 | LETTER: s 2735 | WHIFFLETREE: - 2736 | LETTER: mod 2737 | WHIFFLETREE: - 2738 | LETTER: msg 2739 | WHITE_SPACE: 2740 | DOT: . 2741 | LETTER: s 2742 | WHIFFLETREE: - 2743 | LETTER: msg 2744 | WHIFFLETREE: - 2745 | LETTER: item 2746 | WHITE_SPACE: 2747 | DOT: . 2748 | LETTER: item 2749 | WHIFFLETREE: - 2750 | LETTER: title 2751 | DOT: . 2752 | LETTER: comma 2753 | WHITE_SPACE: 2754 | LEFT_BRACE: { 2755 | WHITE_SPACE: 2756 | 2757 | LETTER: margin 2758 | WHIFFLETREE: - 2759 | LETTER: right 2760 | COLON: : 2761 | WHITE_SPACE: 2762 | NUMBER: 0 2763 | SEMICOLON: ; 2764 | WHITE_SPACE: 2765 | 2766 | RIGHT_BRACE: } 2767 | WHITE_SPACE: 2768 | 2769 | 2770 | DOT: . 2771 | LETTER: s 2772 | WHIFFLETREE: - 2773 | LETTER: mod 2774 | WHIFFLETREE: - 2775 | LETTER: msg 2776 | WHITE_SPACE: 2777 | DOT: . 2778 | LETTER: s 2779 | WHIFFLETREE: - 2780 | LETTER: msg 2781 | WHIFFLETREE: - 2782 | LETTER: item 2783 | WHITE_SPACE: 2784 | DOT: . 2785 | LETTER: item 2786 | WHIFFLETREE: - 2787 | LETTER: title 2788 | COLON: : 2789 | LETTER: hover 2790 | WHITE_SPACE: 2791 | LEFT_BRACE: { 2792 | WHITE_SPACE: 2793 | 2794 | LETTER: text 2795 | WHIFFLETREE: - 2796 | LETTER: decoration 2797 | COLON: : 2798 | WHITE_SPACE: 2799 | LETTER: underline 2800 | SEMICOLON: ; 2801 | WHITE_SPACE: 2802 | 2803 | RIGHT_BRACE: } 2804 | WHITE_SPACE: 2805 | 2806 | 2807 | DOT: . 2808 | LETTER: s 2809 | WHIFFLETREE: - 2810 | LETTER: msg 2811 | WHIFFLETREE: - 2812 | LETTER: firtip 2813 | WHITE_SPACE: 2814 | DOT: . 2815 | LETTER: s 2816 | WHIFFLETREE: - 2817 | LETTER: msg 2818 | WHIFFLETREE: - 2819 | LETTER: item 2820 | WHITE_SPACE: 2821 | DOT: . 2822 | LETTER: item 2823 | WHIFFLETREE: - 2824 | LETTER: title 2825 | DOT: . 2826 | LETTER: no 2827 | WHIFFLETREE: - 2828 | LETTER: underline 2829 | COLON: : 2830 | LETTER: hover 2831 | WHITE_SPACE: 2832 | LEFT_BRACE: { 2833 | WHITE_SPACE: 2834 | 2835 | LETTER: text 2836 | WHIFFLETREE: - 2837 | LETTER: decoration 2838 | COLON: : 2839 | WHITE_SPACE: 2840 | LETTER: none 2841 | SEMICOLON: ; 2842 | WHITE_SPACE: 2843 | 2844 | RIGHT_BRACE: } 2845 | WHITE_SPACE: 2846 | 2847 | 2848 | DOT: . 2849 | LETTER: s 2850 | WHIFFLETREE: - 2851 | LETTER: mod 2852 | WHIFFLETREE: - 2853 | LETTER: msg 2854 | WHITE_SPACE: 2855 | DOT: . 2856 | LETTER: s 2857 | WHIFFLETREE: - 2858 | LETTER: msg 2859 | WHIFFLETREE: - 2860 | LETTER: item 2861 | WHITE_SPACE: 2862 | DOT: . 2863 | LETTER: item 2864 | WHIFFLETREE: - 2865 | LETTER: blue 2866 | WHITE_SPACE: 2867 | LEFT_BRACE: { 2868 | WHITE_SPACE: 2869 | 2870 | LETTER: color 2871 | COLON: : 2872 | WHITE_SPACE: 2873 | POUND_KEY: # 2874 | NUMBER: 0360 2875 | LETTER: AF 2876 | SEMICOLON: ; 2877 | WHITE_SPACE: 2878 | 2879 | RIGHT_BRACE: } 2880 | WHITE_SPACE: 2881 | 2882 | 2883 | DOT: . 2884 | LETTER: s 2885 | WHIFFLETREE: - 2886 | LETTER: mod 2887 | WHIFFLETREE: - 2888 | LETTER: msg 2889 | WHITE_SPACE: 2890 | DOT: . 2891 | LETTER: s 2892 | WHIFFLETREE: - 2893 | LETTER: msg 2894 | WHIFFLETREE: - 2895 | LETTER: item 2896 | WHITE_SPACE: 2897 | DOT: . 2898 | LETTER: item 2899 | WHIFFLETREE: - 2900 | LETTER: orange 2901 | WHITE_SPACE: 2902 | LEFT_BRACE: { 2903 | WHITE_SPACE: 2904 | 2905 | LETTER: color 2906 | COLON: : 2907 | WHITE_SPACE: 2908 | POUND_KEY: # 2909 | LETTER: FF 2910 | NUMBER: 5757 2911 | SEMICOLON: ; 2912 | WHITE_SPACE: 2913 | 2914 | LETTER: margin 2915 | WHIFFLETREE: - 2916 | LETTER: right 2917 | COLON: : 2918 | WHITE_SPACE: 2919 | NUMBER: 1 2920 | LETTER: px 2921 | SEMICOLON: ; 2922 | WHITE_SPACE: 2923 | 2924 | RIGHT_BRACE: } 2925 | WHITE_SPACE: 2926 | 2927 | 2928 | DOT: . 2929 | LETTER: s 2930 | WHIFFLETREE: - 2931 | LETTER: mod 2932 | WHIFFLETREE: - 2933 | LETTER: msg 2934 | WHITE_SPACE: 2935 | DOT: . 2936 | LETTER: s 2937 | WHIFFLETREE: - 2938 | LETTER: msg 2939 | WHIFFLETREE: - 2940 | LETTER: item 2941 | WHITE_SPACE: 2942 | DOT: . 2943 | LETTER: item 2944 | WHIFFLETREE: - 2945 | LETTER: bold 2946 | WHITE_SPACE: 2947 | LEFT_BRACE: { 2948 | WHITE_SPACE: 2949 | 2950 | LETTER: font 2951 | WHIFFLETREE: - 2952 | LETTER: weight 2953 | COLON: : 2954 | WHITE_SPACE: 2955 | LETTER: bold 2956 | SEMICOLON: ; 2957 | WHITE_SPACE: 2958 | 2959 | RIGHT_BRACE: } 2960 | WHITE_SPACE: 2961 | 2962 | 2963 | DOT: . 2964 | LETTER: s 2965 | WHIFFLETREE: - 2966 | LETTER: mod 2967 | WHIFFLETREE: - 2968 | LETTER: msg 2969 | WHITE_SPACE: 2970 | DOT: . 2971 | LETTER: s 2972 | WHIFFLETREE: - 2973 | LETTER: msg 2974 | WHIFFLETREE: - 2975 | LETTER: exchange 2976 | COMMA: , 2977 | WHITE_SPACE: 2978 | 2979 | DOT: . 2980 | LETTER: s 2981 | WHIFFLETREE: - 2982 | LETTER: mod 2983 | WHIFFLETREE: - 2984 | LETTER: msg 2985 | WHITE_SPACE: 2986 | DOT: . 2987 | LETTER: s 2988 | WHIFFLETREE: - 2989 | LETTER: msg 2990 | WHIFFLETREE: - 2991 | LETTER: setting 2992 | COMMA: , 2993 | WHITE_SPACE: 2994 | 2995 | DOT: . 2996 | LETTER: s 2997 | WHIFFLETREE: - 2998 | LETTER: mod 2999 | WHIFFLETREE: - 3000 | LETTER: msg 3001 | WHITE_SPACE: 3002 | DOT: . 3003 | LETTER: s 3004 | WHIFFLETREE: - 3005 | LETTER: msg 3006 | WHIFFLETREE: - 3007 | LETTER: count 3008 | WHITE_SPACE: 3009 | LEFT_BRACE: { 3010 | WHITE_SPACE: 3011 | 3012 | LETTER: background 3013 | COLON: : 3014 | WHITE_SPACE: 3015 | LETTER: url 3016 | LEFT_BRACKET: ( 3017 | DOUBLE_QUOTES: " 3018 | DOT: .. 3019 | SLASH: / 3020 | LETTER: img 3021 | SLASH: / 3022 | LETTER: msg 3023 | UNDERLINE: _ 3024 | LETTER: bg 3025 | UNDERLINE: _ 3026 | LETTER: d 3027 | NUMBER: 75 3028 | LETTER: a 3029 | NUMBER: 3 3030 | LETTER: e 3031 | NUMBER: 82 3032 | DOT: . 3033 | LETTER: png 3034 | DOUBLE_QUOTES: " 3035 | RIGHT_BRACKET: ) 3036 | WHITE_SPACE: 3037 | LETTER: no 3038 | WHIFFLETREE: - 3039 | LETTER: repeat 3040 | SEMICOLON: ; 3041 | WHITE_SPACE: 3042 | 3043 | LETTER: position 3044 | COLON: : 3045 | WHITE_SPACE: 3046 | LETTER: absolute 3047 | SEMICOLON: ; 3048 | WHITE_SPACE: 3049 | 3050 | LETTER: display 3051 | COLON: : 3052 | WHITE_SPACE: 3053 | LETTER: inline 3054 | WHIFFLETREE: - 3055 | LETTER: block 3056 | SEMICOLON: ; 3057 | WHITE_SPACE: 3058 | 3059 | LETTER: height 3060 | COLON: : 3061 | WHITE_SPACE: 3062 | NUMBER: 16 3063 | LETTER: px 3064 | SEMICOLON: ; 3065 | WHITE_SPACE: 3066 | 3067 | LETTER: width 3068 | COLON: : 3069 | WHITE_SPACE: 3070 | NUMBER: 16 3071 | LETTER: px 3072 | SEMICOLON: ; 3073 | WHITE_SPACE: 3074 | 3075 | LETTER: outline 3076 | COLON: : 3077 | WHITE_SPACE: 3078 | LETTER: none 3079 | SEMICOLON: ; 3080 | WHITE_SPACE: 3081 | 3082 | LETTER: text 3083 | WHIFFLETREE: - 3084 | LETTER: decoration 3085 | COLON: : 3086 | WHITE_SPACE: 3087 | LETTER: none 3088 | SEMICOLON: ; 3089 | WHITE_SPACE: 3090 | 3091 | RIGHT_BRACE: } 3092 | WHITE_SPACE: 3093 | 3094 | 3095 | DOT: . 3096 | LETTER: s 3097 | WHIFFLETREE: - 3098 | LETTER: msg 3099 | WHIFFLETREE: - 3100 | LETTER: firtip 3101 | WHITE_SPACE: 3102 | DOT: . 3103 | LETTER: s 3104 | WHIFFLETREE: - 3105 | LETTER: msg 3106 | WHIFFLETREE: - 3107 | LETTER: exchange 3108 | WHITE_SPACE: 3109 | LEFT_BRACE: { 3110 | WHITE_SPACE: 3111 | 3112 | LETTER: top 3113 | COLON: : 3114 | WHITE_SPACE: 3115 | NUMBER: 20 3116 | LETTER: px 3117 | SEMICOLON: ; 3118 | WHITE_SPACE: 3119 | 3120 | LETTER: right 3121 | COLON: : 3122 | WHITE_SPACE: 3123 | NUMBER: 15 3124 | LETTER: px 3125 | SEMICOLON: ; 3126 | WHITE_SPACE: 3127 | 3128 | LETTER: background 3129 | WHIFFLETREE: - 3130 | LETTER: position 3131 | COLON: : 3132 | WHITE_SPACE: 3133 | NUMBER: 0 3134 | WHIFFLETREE: - 3135 | NUMBER: 23 3136 | LETTER: px 3137 | SEMICOLON: ; 3138 | WHITE_SPACE: 3139 | 3140 | RIGHT_BRACE: } 3141 | WHITE_SPACE: 3142 | 3143 | 3144 | DOT: . 3145 | LETTER: s 3146 | WHIFFLETREE: - 3147 | LETTER: msg 3148 | WHIFFLETREE: - 3149 | LETTER: firtip 3150 | WHITE_SPACE: 3151 | DOT: . 3152 | LETTER: s 3153 | WHIFFLETREE: - 3154 | LETTER: msg 3155 | WHIFFLETREE: - 3156 | LETTER: exchange 3157 | DOT: . 3158 | LETTER: hide 3159 | WHITE_SPACE: 3160 | LEFT_BRACE: { 3161 | WHITE_SPACE: 3162 | 3163 | LETTER: background 3164 | WHIFFLETREE: - 3165 | LETTER: position 3166 | COLON: : 3167 | WHITE_SPACE: 3168 | WHIFFLETREE: - 3169 | NUMBER: 218 3170 | LETTER: px 3171 | WHITE_SPACE: 3172 | NUMBER: 0 3173 | SEMICOLON: ; 3174 | WHITE_SPACE: 3175 | 3176 | RIGHT_BRACE: } 3177 | WHITE_SPACE: 3178 | 3179 | 3180 | DOT: . 3181 | LETTER: s 3182 | WHIFFLETREE: - 3183 | LETTER: msg 3184 | WHIFFLETREE: - 3185 | LETTER: firtip 3186 | WHITE_SPACE: 3187 | DOT: . 3188 | LETTER: s 3189 | WHIFFLETREE: - 3190 | LETTER: msg 3191 | WHIFFLETREE: - 3192 | LETTER: setting 3193 | WHITE_SPACE: 3194 | LEFT_BRACE: { 3195 | WHITE_SPACE: 3196 | 3197 | LETTER: top 3198 | COLON: : 3199 | WHITE_SPACE: 3200 | NUMBER: 8 3201 | LETTER: px 3202 | SEMICOLON: ; 3203 | WHITE_SPACE: 3204 | 3205 | LETTER: right 3206 | COLON: : 3207 | WHITE_SPACE: 3208 | NUMBER: 10 3209 | LETTER: px 3210 | SEMICOLON: ; 3211 | WHITE_SPACE: 3212 | 3213 | LETTER: background 3214 | WHIFFLETREE: - 3215 | LETTER: position 3216 | COLON: : 3217 | WHITE_SPACE: 3218 | WHIFFLETREE: - 3219 | NUMBER: 80 3220 | LETTER: px 3221 | WHITE_SPACE: 3222 | NUMBER: 0 3223 | SEMICOLON: ; 3224 | WHITE_SPACE: 3225 | 3226 | RIGHT_BRACE: } 3227 | WHITE_SPACE: 3228 | 3229 | 3230 | DOT: . 3231 | LETTER: s 3232 | WHIFFLETREE: - 3233 | LETTER: msg 3234 | WHIFFLETREE: - 3235 | LETTER: firtip 3236 | WHITE_SPACE: 3237 | DOT: . 3238 | LETTER: s 3239 | WHIFFLETREE: - 3240 | LETTER: msg 3241 | WHIFFLETREE: - 3242 | LETTER: setting 3243 | COLON: : 3244 | LETTER: hover 3245 | WHITE_SPACE: 3246 | LEFT_BRACE: { 3247 | WHITE_SPACE: 3248 | 3249 | LETTER: background 3250 | WHIFFLETREE: - 3251 | LETTER: position 3252 | COLON: : 3253 | WHITE_SPACE: 3254 | WHIFFLETREE: - 3255 | NUMBER: 320 3256 | LETTER: px 3257 | WHITE_SPACE: 3258 | NUMBER: 0 3259 | SEMICOLON: ; 3260 | WHITE_SPACE: 3261 | 3262 | RIGHT_BRACE: } 3263 | WHITE_SPACE: 3264 | 3265 | 3266 | DOT: . 3267 | LETTER: s 3268 | WHIFFLETREE: - 3269 | LETTER: msg 3270 | WHIFFLETREE: - 3271 | LETTER: firtip 3272 | DOT: . 3273 | LETTER: extend 3274 | WHITE_SPACE: 3275 | DOT: . 3276 | LETTER: s 3277 | WHIFFLETREE: - 3278 | LETTER: msg 3279 | WHIFFLETREE: - 3280 | LETTER: setting 3281 | WHITE_SPACE: 3282 | LEFT_BRACE: { 3283 | WHITE_SPACE: 3284 | 3285 | LETTER: opacity 3286 | COLON: : 3287 | WHITE_SPACE: 3288 | NUMBER: 1 3289 | SEMICOLON: ; 3290 | WHITE_SPACE: 3291 | 3292 | LETTER: filter 3293 | COLON: : 3294 | WHITE_SPACE: 3295 | LETTER: none 3296 | SEMICOLON: ; 3297 | WHITE_SPACE: 3298 | 3299 | RIGHT_BRACE: } 3300 | WHITE_SPACE: 3301 | 3302 | 3303 | DOT: . 3304 | LETTER: s 3305 | WHIFFLETREE: - 3306 | LETTER: msg 3307 | WHIFFLETREE: - 3308 | LETTER: firtip 3309 | WHITE_SPACE: 3310 | DOT: . 3311 | LETTER: s 3312 | WHIFFLETREE: - 3313 | LETTER: msg 3314 | WHIFFLETREE: - 3315 | LETTER: count 3316 | WHITE_SPACE: 3317 | LEFT_BRACE: { 3318 | WHITE_SPACE: 3319 | 3320 | LETTER: top 3321 | COLON: : 3322 | WHITE_SPACE: 3323 | NUMBER: 0 3324 | SEMICOLON: ; 3325 | WHITE_SPACE: 3326 | 3327 | LETTER: right 3328 | COLON: : 3329 | WHITE_SPACE: 3330 | WHIFFLETREE: - 3331 | NUMBER: 8 3332 | LETTER: px 3333 | SEMICOLON: ; 3334 | WHITE_SPACE: 3335 | 3336 | LETTER: text 3337 | WHIFFLETREE: - 3338 | LETTER: align 3339 | COLON: : 3340 | WHITE_SPACE: 3341 | LETTER: center 3342 | SEMICOLON: ; 3343 | WHITE_SPACE: 3344 | 3345 | LETTER: color 3346 | COLON: : 3347 | WHITE_SPACE: 3348 | LETTER: white 3349 | SEMICOLON: ; 3350 | WHITE_SPACE: 3351 | 3352 | LETTER: background 3353 | WHIFFLETREE: - 3354 | LETTER: position 3355 | COLON: : 3356 | WHITE_SPACE: 3357 | WHIFFLETREE: - 3358 | NUMBER: 30 3359 | LETTER: px 3360 | WHITE_SPACE: 3361 | NUMBER: 0 3362 | SEMICOLON: ; 3363 | WHITE_SPACE: 3364 | 3365 | RIGHT_BRACE: } 3366 | WHITE_SPACE: 3367 | 3368 | 3369 | DOT: . 3370 | LETTER: s 3371 | WHIFFLETREE: - 3372 | LETTER: mod 3373 | WHIFFLETREE: - 3374 | LETTER: msg 3375 | DOT: . 3376 | LETTER: extend 3377 | WHITE_SPACE: 3378 | DOT: . 3379 | LETTER: s 3380 | WHIFFLETREE: - 3381 | LETTER: msg 3382 | WHIFFLETREE: - 3383 | LETTER: tips 3384 | WHITE_SPACE: 3385 | LEFT_BRACE: { 3386 | WHITE_SPACE: 3387 | 3388 | LETTER: padding 3389 | COLON: : 3390 | WHITE_SPACE: 3391 | NUMBER: 5 3392 | LETTER: px 3393 | WHITE_SPACE: 3394 | NUMBER: 20 3395 | LETTER: px 3396 | WHITE_SPACE: 3397 | NUMBER: 0 20 3398 | LETTER: px 3399 | SEMICOLON: ; 3400 | WHITE_SPACE: 3401 | 3402 | RIGHT_BRACE: } 3403 | WHITE_SPACE: 3404 | 3405 | 3406 | DOT: . 3407 | LETTER: s 3408 | WHIFFLETREE: - 3409 | LETTER: mod 3410 | WHIFFLETREE: - 3411 | LETTER: msg 3412 | DOT: . 3413 | LETTER: extend 3414 | WHITE_SPACE: 3415 | DOT: . 3416 | LETTER: s 3417 | WHIFFLETREE: - 3418 | LETTER: msg 3419 | WHIFFLETREE: - 3420 | LETTER: item 3421 | WHITE_SPACE: 3422 | LEFT_BRACE: { 3423 | WHITE_SPACE: 3424 | 3425 | LETTER: width 3426 | COLON: : 3427 | WHITE_SPACE: 3428 | NUMBER: 238 3429 | LETTER: px 3430 | SEMICOLON: ; 3431 | WHITE_SPACE: 3432 | 3433 | LETTER: padding 3434 | COLON: : 3435 | WHITE_SPACE: 3436 | NUMBER: 15 3437 | LETTER: px 3438 | WHITE_SPACE: 3439 | NUMBER: 0 3440 | SEMICOLON: ; 3441 | WHITE_SPACE: 3442 | 3443 | UNDERLINE: _ 3444 | LETTER: padding 3445 | WHIFFLETREE: - 3446 | LETTER: left 3447 | COLON: : 3448 | WHITE_SPACE: 3449 | NUMBER: 0 3450 | SEMICOLON: ; 3451 | WHITE_SPACE: 3452 | 3453 | UNDERLINE: _ 3454 | LETTER: padding 3455 | WHIFFLETREE: - 3456 | LETTER: right 3457 | COLON: : 3458 | WHITE_SPACE: 3459 | NUMBER: 0 3460 | SEMICOLON: ; 3461 | WHITE_SPACE: 3462 | 3463 | LETTER: font 3464 | WHIFFLETREE: - 3465 | LETTER: size 3466 | COLON: : 3467 | WHITE_SPACE: 3468 | NUMBER: 0 3469 | SEMICOLON: ; 3470 | WHITE_SPACE: 3471 | 3472 | LETTER: border 3473 | WHIFFLETREE: - 3474 | LETTER: bottom 3475 | COLON: : 3476 | WHITE_SPACE: 3477 | NUMBER: 1 3478 | LETTER: px 3479 | WHITE_SPACE: 3480 | LETTER: solid 3481 | WHITE_SPACE: 3482 | POUND_KEY: # 3483 | LETTER: ccc 3484 | SEMICOLON: ; 3485 | WHITE_SPACE: 3486 | 3487 | LETTER: border 3488 | WHIFFLETREE: - 3489 | LETTER: bottom 3490 | COLON: : 3491 | WHITE_SPACE: 3492 | NUMBER: 1 3493 | LETTER: px 3494 | WHITE_SPACE: 3495 | LETTER: solid 3496 | WHITE_SPACE: 3497 | LETTER: rgba 3498 | LEFT_BRACKET: ( 3499 | NUMBER: 177 3500 | COMMA: , 3501 | WHITE_SPACE: 3502 | NUMBER: 177 3503 | COMMA: , 3504 | WHITE_SPACE: 3505 | NUMBER: 177 3506 | COMMA: , 3507 | WHITE_SPACE: 3508 | DOT: . 3509 | NUMBER: 20 3510 | RIGHT_BRACKET: ) 3511 | SEMICOLON: ; 3512 | WHITE_SPACE: 3513 | 3514 | RIGHT_BRACE: } 3515 | WHITE_SPACE: 3516 | 3517 | 3518 | DOT: . 3519 | LETTER: s 3520 | WHIFFLETREE: - 3521 | LETTER: mod 3522 | WHIFFLETREE: - 3523 | LETTER: msg 3524 | DOT: . 3525 | LETTER: extend 3526 | WHITE_SPACE: 3527 | DOT: . 3528 | LETTER: vertical 3529 | WHIFFLETREE: - 3530 | LETTER: line 3531 | WHITE_SPACE: 3532 | LEFT_BRACE: { 3533 | WHITE_SPACE: 3534 | 3535 | LETTER: display 3536 | COLON: : 3537 | WHITE_SPACE: 3538 | LETTER: none 3539 | SEMICOLON: ; 3540 | WHITE_SPACE: 3541 | 3542 | RIGHT_BRACE: } 3543 | WHITE_SPACE: 3544 | 3545 | 3546 | DOT: . 3547 | LETTER: s 3548 | WHIFFLETREE: - 3549 | LETTER: mod 3550 | WHIFFLETREE: - 3551 | LETTER: msg 3552 | DOT: . 3553 | LETTER: extend 3554 | WHITE_SPACE: 3555 | DOT: . 3556 | LETTER: item 3557 | WHIFFLETREE: - 3558 | LETTER: msg 3559 | WHIFFLETREE: - 3560 | LETTER: content 3561 | WHITE_SPACE: 3562 | LEFT_BRACE: { 3563 | WHITE_SPACE: 3564 | 3565 | LETTER: margin 3566 | WHIFFLETREE: - 3567 | LETTER: left 3568 | COLON: : 3569 | WHITE_SPACE: 3570 | NUMBER: 16 3571 | LETTER: px 3572 | SEMICOLON: ; 3573 | WHITE_SPACE: 3574 | 3575 | LETTER: vertical 3576 | WHIFFLETREE: - 3577 | LETTER: align 3578 | COLON: : 3579 | WHITE_SPACE: 3580 | LETTER: top 3581 | SEMICOLON: ; 3582 | WHITE_SPACE: 3583 | 3584 | LETTER: width 3585 | COLON: : 3586 | WHITE_SPACE: 3587 | NUMBER: 174 3588 | LETTER: px 3589 | SEMICOLON: ; 3590 | WHITE_SPACE: 3591 | 3592 | UNDERLINE: _ 3593 | LETTER: margin 3594 | WHIFFLETREE: - 3595 | LETTER: top 3596 | COLON: : 3597 | WHITE_SPACE: 3598 | NUMBER: 0 3599 | SEMICOLON: ; 3600 | WHITE_SPACE: 3601 | 3602 | RIGHT_BRACE: } 3603 | WHITE_SPACE: 3604 | 3605 | -------------------------------------------------------------------------------- /src/files/test.css: -------------------------------------------------------------------------------- 1 | .s-mod-msg { 2 | position: absolute; 3 | top: 28px; 4 | font-size: 12px; 5 | color: #333; 6 | width: 278px; 7 | z-index: 999; 8 | } 9 | 10 | .s-mod-msg .msg-area { 11 | border: 1px solid #e3e3e3; 12 | background: #fff; 13 | box-shadow: 0 2px 2px rgba(0, 0, 0, 0.07); 14 | -moz-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.07); 15 | -webkit-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.07); 16 | filter: progid: DXImageTransform.Microsoft.Shadow(Strength=2, Direction=135, Color='#e3e3e3'); 17 | -ms-filter: "progid:DXImageTransform.Microsoft.Shadow(Strength=2, Direction=135, Color='#e3e3e3')"; 18 | } 19 | 20 | .s-mod-msg .s-msg-base .no-msg-tip { 21 | height: 88px; 22 | line-height: 88px; 23 | margin: 0 20px; 24 | border-bottom: 1px solid #ccc; 25 | border-bottom: 1px solid rgba(177, 177, 177, .20); 26 | text-align: center; 27 | } 28 | 29 | .s-mod-msg .no-msgs { 30 | height: 139px; 31 | } 32 | 33 | .s-mod-msg .no-set-msg { 34 | height: 68px; 35 | } 36 | 37 | .s-mod-msg .msg-btns, 38 | .s-mod-msg .no-msg-btns { 39 | height: 28px; 40 | } 41 | 42 | .s-mod-msg .s-msg-base .no-msg-btns, 43 | .s-mod-msg .msg-btns { 44 | padding-top: 10px; 45 | padding-bottom: 12px; 46 | } 47 | 48 | .s-mod-msg .no-msgs .no-msg-btns { 49 | margin-left: 50px; 50 | } 51 | 52 | .s-mod-msg .msg-btns { 53 | margin-left: 30px; 54 | } 55 | 56 | .s-mod-msg .msg-btn { 57 | color: #fff; 58 | cursor: pointer; 59 | float: left; 60 | display: inline; 61 | width: 82px; 62 | height: 28px; 63 | line-height: 28px; 64 | text-align: center; 65 | background: #389cff; 66 | position: relative; 67 | } 68 | 69 | .s-mod-msg .msg-setting-btn { 70 | left: 14px; 71 | } 72 | 73 | .s-msg-base .no-msg-btns .no-use { 74 | background: #bcbcbc; 75 | cursor: default; 76 | } 77 | 78 | .s-mod-msg .msg-btn .bg { 79 | font-size: 0; 80 | position: absolute; 81 | top: 9px; 82 | left: 10px; 83 | } 84 | 85 | .s-mod-msg .msg-btn .title { 86 | margin-left: 10px; 87 | color: #FFF; 88 | } 89 | 90 | .s-mod-msg .msg-setting-btn .title { 91 | margin-left: 0; 92 | color: #FFF; 93 | display: inline-block; 94 | height: 28px; 95 | width: 59px; 96 | float: left; 97 | padding-left: 23px; 98 | text-align: left; 99 | position: absolute; 100 | left: 0; 101 | text-decoration: none; 102 | } 103 | 104 | .s-mod-msg .msg-clear-btn .bg { 105 | width: 12px; 106 | height: 9px; 107 | background: url('../img/msg_bg_d75a3e82.png') no-repeat 0 0; 108 | _background: url('../img/msg_bg_skin_ie6_52137b6c.png') no-repeat 0 0; 109 | } 110 | 111 | .s-mod-msg .msg-setting-btn .bg { 112 | width: 12px; 113 | height: 10px; 114 | background: url('../img/msg_bg_d75a3e82.png') no-repeat -15px 0; 115 | } 116 | 117 | .s-msg-base .noset-msg-tip { 118 | text-align: left; 119 | height: 28px; 120 | line-height: 28px; 121 | padding: 20px; 122 | position: relative; 123 | } 124 | 125 | .s-msg-base .noset-msg-tip .msg-setting-btn { 126 | position: absolute; 127 | top: 20px; 128 | right: 20px; 129 | left: auto; 130 | } 131 | 132 | .s-mod-msg .msg-arrow { 133 | position: absolute; 134 | z-index: 2; 135 | top: -10px; 136 | display: inline-block; 137 | width: 0; 138 | height: 0; 139 | line-height: 0; 140 | border: 5px dashed transparent; 141 | border-bottom: 5px solid #e3e3e3; 142 | font-size: 0; 143 | margin-left: 5px; 144 | } 145 | 146 | .s-mod-msg .msg-arrow em { 147 | position: absolute; 148 | top: -4px; 149 | left: -5px; 150 | display: block !important; 151 | width: 0 !important; 152 | height: 0 !important; 153 | line-height: 0; 154 | font-size: 0; 155 | color: #666; 156 | border-top: 5px dashed transparent; 157 | border-left: 5px dashed transparent; 158 | border-right: 5px dashed transparent; 159 | border-bottom: 5px solid #fff; 160 | } 161 | 162 | .s-mod-msg-shadow { 163 | background: url('../img/blank_56a92bd4.png') repeat; 164 | _background: url('../img/blank_ie6_fadcce61.png') repeat; 165 | position: absolute; 166 | width: 100%; 167 | height: 100%; 168 | left: 0; 169 | top: 0; 170 | z-index: 998; 171 | } 172 | 173 | .s-msg-firtip { 174 | color: #333; 175 | font-size: 12px; 176 | text-align: left; 177 | } 178 | 179 | .s-mod-msg .item-msg-content { 180 | display: inline-block; 181 | vertical-align: middle; 182 | width: 166px; 183 | _width: 162px; 184 | font-size: 12px; 185 | *margin-top: 6px; 186 | _margin-top: 4px; 187 | } 188 | 189 | .s-mod-msg .item-msg-content .default-msg-title { 190 | color: #333; 191 | text-decoration: none; 192 | } 193 | 194 | .s-mod-msg .item-msg-content .default-msg-title:hover { 195 | text-decoration: underline; 196 | } 197 | 198 | .s-mod-msg.extend .item-msg-content { 199 | *margin-top: 0; 200 | _margin-top: 4px; 201 | } 202 | 203 | .s-mod-msg .cell { 204 | text-overflow: ellipsis; 205 | white-space: nowrap; 206 | overflow: hidden; 207 | } 208 | 209 | .s-msg-firtip .s-msg-content { 210 | position: relative; 211 | } 212 | 213 | .s-mod-msg .msg-area .s-msg-item { 214 | font-size: 0; 215 | width: 230px; 216 | text-align: left; 217 | padding: 15px; 218 | padding-right: 0; 219 | } 220 | 221 | .s-mod-msg .s-msg-item .item-name { 222 | display: inline-block; 223 | vertical-align: middle; 224 | font-weight: bold; 225 | width: 48px; 226 | font-size: 12px; 227 | _margin-top: 2px; 228 | } 229 | 230 | .s-mod-msg.extend .s-msg-item .item-name { 231 | _margin-left: -15px; 232 | } 233 | 234 | .s-mod-msg .s-msg-item .item-name .item-name-link { 235 | color: #333; 236 | font-weight: bold; 237 | text-decoration: none; 238 | white-space: nowrap; 239 | overflow: hidden; 240 | } 241 | 242 | .s-mod-msg .s-msg-item .item-name .item-name-link:hover { 243 | text-decoration: underline; 244 | } 245 | 246 | .s-mod-msg .s-msg-item .item-name span.item-name-link:hover { 247 | color: #666; 248 | text-decoration: none; 249 | } 250 | 251 | .s-mod-msg .s-msg-item .item-title:visited { 252 | color: #333; 253 | } 254 | 255 | .s-mod-msg .s-msg-item .item-title { 256 | text-decoration: none; 257 | color: #333; 258 | outline: none; 259 | } 260 | 261 | .s-mod-msg .s-msg-item .title-sns, 262 | .s-mod-msg .s-msg-item .title-sns:visited { 263 | color: #333; 264 | margin-right: 0; 265 | } 266 | 267 | .s-mod-msg .s-msg-item .title-sns-visited, 268 | .s-mod-msg .s-msg-item .title-sns-visited:visited { 269 | color: #333; 270 | } 271 | 272 | .s-msg-firtip .s-msg-item .vertical-line { 273 | vertical-align: middle; 274 | display: inline-block; 275 | width: 0; 276 | height: 12px; 277 | margin: -2px 6px 0 9px; 278 | *margin-top: 0; 279 | overflow: hidden; 280 | border-right: 1px solid #ccc; 281 | border-right: 1px solid rgba(177, 177, 177, .50); 282 | } 283 | 284 | .s-mod-msg .s-msg-item .item-title.comma { 285 | margin-right: 0; 286 | } 287 | 288 | .s-mod-msg .s-msg-item .item-title:hover { 289 | text-decoration: underline; 290 | } 291 | 292 | .s-msg-firtip .s-msg-item .item-title.no-underline:hover { 293 | text-decoration: none; 294 | } 295 | 296 | .s-mod-msg .s-msg-item .item-blue { 297 | color: #0360AF; 298 | } 299 | 300 | .s-mod-msg .s-msg-item .item-orange { 301 | color: #FF5757; 302 | margin-right: 1px; 303 | } 304 | 305 | .s-mod-msg .s-msg-item .item-bold { 306 | font-weight: bold; 307 | } 308 | 309 | .s-mod-msg .s-msg-exchange, 310 | .s-mod-msg .s-msg-setting, 311 | .s-mod-msg .s-msg-count { 312 | background: url("../img/msg_bg_d75a3e82.png") no-repeat; 313 | position: absolute; 314 | display: inline-block; 315 | height: 16px; 316 | width: 16px; 317 | outline: none; 318 | text-decoration: none; 319 | } 320 | 321 | .s-msg-firtip .s-msg-exchange { 322 | top: 20px; 323 | right: 15px; 324 | background-position: 0 -23px; 325 | } 326 | 327 | .s-msg-firtip .s-msg-exchange.hide { 328 | background-position: -218px 0; 329 | } 330 | 331 | .s-msg-firtip .s-msg-setting { 332 | top: 8px; 333 | right: 10px; 334 | background-position: -80px 0; 335 | } 336 | 337 | .s-msg-firtip .s-msg-setting:hover { 338 | background-position: -320px 0; 339 | } 340 | 341 | .s-msg-firtip.extend .s-msg-setting { 342 | opacity: 1; 343 | filter: none; 344 | } 345 | 346 | .s-msg-firtip .s-msg-count { 347 | top: 0; 348 | right: -8px; 349 | text-align: center; 350 | color: white; 351 | background-position: -30px 0; 352 | } 353 | 354 | .s-mod-msg.extend .s-msg-tips { 355 | padding: 5px 20px 0 20px; 356 | } 357 | 358 | .s-mod-msg.extend .s-msg-item { 359 | width: 238px; 360 | padding: 15px 0; 361 | _padding-left: 0; 362 | _padding-right: 0; 363 | font-size: 0; 364 | border-bottom: 1px solid #ccc; 365 | border-bottom: 1px solid rgba(177, 177, 177, .20); 366 | } 367 | 368 | .s-mod-msg.extend .vertical-line { 369 | display: none; 370 | } 371 | 372 | .s-mod-msg.extend .item-msg-content { 373 | margin-left: 16px; 374 | vertical-align: top; 375 | width: 174px; 376 | _margin-top: 0; 377 | } 378 | -------------------------------------------------------------------------------- /src/test.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /编程语言实现模式.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lucifier129/language-implementation-patterns/0dafeb3df60157bdce703f5cf1da5023873aa2f7/编程语言实现模式.pdf --------------------------------------------------------------------------------