tenggouwa 6 years ago
parent
commit
db37fdcd1a

+ 21 - 0
README.md

@@ -0,0 +1,21 @@
+# vue-project
+
+> A Vue.js project
+
+## Build Setup
+
+``` bash
+# install dependencies
+npm install
+
+# serve with hot reload at localhost:8080
+npm run dev
+
+# build for production with minification
+npm run build
+
+# build for production and view the bundle analyzer report
+npm run build --report
+```
+
+For detailed explanation on how things work, checkout the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).

+ 35 - 0
build/build.js

@@ -0,0 +1,35 @@
+require('./check-versions')()
+
+process.env.NODE_ENV = 'production'
+
+var ora = require('ora')
+var rm = require('rimraf')
+var path = require('path')
+var chalk = require('chalk')
+var webpack = require('webpack')
+var config = require('../config')
+var webpackConfig = require('./webpack.prod.conf')
+
+var spinner = ora('building for production...')
+spinner.start()
+
+rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
+  if (err) throw err
+  webpack(webpackConfig, function (err, stats) {
+    spinner.stop()
+    if (err) throw err
+    process.stdout.write(stats.toString({
+      colors: true,
+      modules: false,
+      children: false,
+      chunks: false,
+      chunkModules: false
+    }) + '\n\n')
+
+    console.log(chalk.cyan('  Build complete.\n'))
+    console.log(chalk.yellow(
+      '  Tip: built files are meant to be served over an HTTP server.\n' +
+      '  Opening index.html over file:// won\'t work.\n'
+    ))
+  })
+})

+ 48 - 0
build/check-versions.js

@@ -0,0 +1,48 @@
+var chalk = require('chalk')
+var semver = require('semver')
+var packageConfig = require('../package.json')
+var shell = require('shelljs')
+function exec (cmd) {
+  return require('child_process').execSync(cmd).toString().trim()
+}
+
+var versionRequirements = [
+  {
+    name: 'node',
+    currentVersion: semver.clean(process.version),
+    versionRequirement: packageConfig.engines.node
+  },
+]
+
+if (shell.which('npm')) {
+  versionRequirements.push({
+    name: 'npm',
+    currentVersion: exec('npm --version'),
+    versionRequirement: packageConfig.engines.npm
+  })
+}
+
+module.exports = function () {
+  var warnings = []
+  for (var i = 0; i < versionRequirements.length; i++) {
+    var mod = versionRequirements[i]
+    if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
+      warnings.push(mod.name + ': ' +
+        chalk.red(mod.currentVersion) + ' should be ' +
+        chalk.green(mod.versionRequirement)
+      )
+    }
+  }
+
+  if (warnings.length) {
+    console.log('')
+    console.log(chalk.yellow('To use this template, you must update following to modules:'))
+    console.log()
+    for (var i = 0; i < warnings.length; i++) {
+      var warning = warnings[i]
+      console.log('  ' + warning)
+    }
+    console.log()
+    process.exit(1)
+  }
+}

+ 9 - 0
build/dev-client.js

@@ -0,0 +1,9 @@
+/* eslint-disable */
+require('eventsource-polyfill')
+var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
+
+hotClient.subscribe(function (event) {
+  if (event.action === 'reload') {
+    window.location.reload()
+  }
+})

+ 90 - 0
build/dev-server.js

@@ -0,0 +1,90 @@
+require('./check-versions')()
+
+var config = require('../config')
+if (!process.env.NODE_ENV) {
+  process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
+}
+
+var opn = require('opn')
+var path = require('path')
+var express = require('express')
+var webpack = require('webpack')
+var proxyMiddleware = require('http-proxy-middleware')
+var webpackConfig = require('./webpack.dev.conf')
+
+// default port where dev server listens for incoming traffic
+var port = process.env.PORT || config.dev.port
+// automatically open browser, if not set will be false
+var autoOpenBrowser = !!config.dev.autoOpenBrowser
+// Define HTTP proxies to your custom API backend
+// https://github.com/chimurai/http-proxy-middleware
+var proxyTable = config.dev.proxyTable
+
+var app = express()
+var compiler = webpack(webpackConfig)
+
+var devMiddleware = require('webpack-dev-middleware')(compiler, {
+  publicPath: webpackConfig.output.publicPath,
+  quiet: true
+})
+
+var hotMiddleware = require('webpack-hot-middleware')(compiler, {
+  log: false,
+  heartbeat: 2000
+})
+// force page reload when html-webpack-plugin template changes
+compiler.plugin('compilation', function (compilation) {
+  compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
+    hotMiddleware.publish({ action: 'reload' })
+    cb()
+  })
+})
+
+// proxy api requests
+Object.keys(proxyTable).forEach(function (context) {
+  var options = proxyTable[context]
+  if (typeof options === 'string') {
+    options = { target: options }
+  }
+  app.use(proxyMiddleware(options.filter || context, options))
+})
+
+// handle fallback for HTML5 history API
+app.use(require('connect-history-api-fallback')())
+
+// serve webpack bundle output
+app.use(devMiddleware)
+
+// enable hot-reload and state-preserving
+// compilation error display
+app.use(hotMiddleware)
+
+// serve pure static assets
+var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
+app.use(staticPath, express.static('./static'))
+
+var uri = 'http://localhost:' + port
+
+var _resolve
+var readyPromise = new Promise(resolve => {
+  _resolve = resolve
+})
+
+console.log('> Starting dev server...')
+devMiddleware.waitUntilValid(() => {
+  console.log('> Listening at ' + uri + '\n')
+  // when env is testing, don't need open it
+  if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
+    opn(uri)
+  }
+  _resolve()
+})
+
+var server = app.listen(port)
+
+module.exports = {
+  ready: readyPromise,
+  close: () => {
+    server.close()
+  }
+}

+ 34 - 0
build/postcss.config.js

@@ -0,0 +1,34 @@
+exports.postfactory = function (opts) {
+  // console.log(111111);
+  return [
+  //css中引入内联样式表
+  // require('postcss-easy-import')(),
+  //css混合宏的使用
+  require('postcss-mixins')(),
+  //css的for循环插件  必须在postcss-simple-vars之前运行
+  require('postcss-for')(),
+  require('postcss-each')(),
+  //类似于sass语法的css变量定义 
+  require('postcss-simple-vars')({
+    variables:{
+      "main-color":"#d15050",
+    }
+  }),
+  //sass扩展语法
+  require('postcss-sass-extend')(),
+  //css媒体查询简写   https://github.com/postcss/postcss-media-minmax/blob/master/README-zh.md
+  // require('postcss-media-minmax')(),
+  //css层级写法  https://github.com/postcss/postcss-nested
+  require('postcss-nested')(),
+  //css选择器简写
+  require('postcss-selector-matches')(),
+  require('postcss-selector-not')(),
+  //css缩写与简写  crip的缩写列表 https://github.com/johnie/crip-css-properties
+  require('postcss-alias')(),
+  require('postcss-crip')(),
+  //css浏览器兼容(vue已内置)
+  // require('autoprefixer')({ browsers: ['last 2 versions'] }),
+  //css计算
+  require("postcss-calc")
+  ];
+}

+ 71 - 0
build/utils.js

@@ -0,0 +1,71 @@
+var path = require('path')
+var config = require('../config')
+var ExtractTextPlugin = require('extract-text-webpack-plugin')
+
+exports.assetsPath = function (_path) {
+  var assetsSubDirectory = process.env.NODE_ENV === 'production'
+    ? config.build.assetsSubDirectory
+    : config.dev.assetsSubDirectory
+  return path.posix.join(assetsSubDirectory, _path)
+}
+
+exports.cssLoaders = function (options) {
+  options = options || {}
+
+  var cssLoader = {
+    loader: 'css-loader',
+    options: {
+      minimize: process.env.NODE_ENV === 'production',
+      sourceMap: options.sourceMap
+    }
+  }
+
+  // generate loader string to be used with extract text plugin
+  function generateLoaders (loader, loaderOptions) {
+    var loaders = [cssLoader]
+    if (loader) {
+      loaders.push({
+        loader: loader + '-loader',
+        options: Object.assign({}, loaderOptions, {
+          sourceMap: options.sourceMap
+        })
+      })
+    }
+
+    // Extract CSS when that option is specified
+    // (which is the case during production build)
+    if (options.extract) {
+      return ExtractTextPlugin.extract({
+        use: loaders,
+        fallback: 'vue-style-loader'
+      })
+    } else {
+      return ['vue-style-loader'].concat(loaders)
+    }
+  }
+
+  // https://vue-loader.vuejs.org/en/configurations/extract-css.html
+  return {
+    css: generateLoaders(),
+    postcss: generateLoaders(),
+    less: generateLoaders('less'),
+    sass: generateLoaders('sass', { indentedSyntax: true }),
+    scss: generateLoaders('sass'),
+    stylus: generateLoaders('stylus'),
+    styl: generateLoaders('stylus')
+  }
+}
+
+// Generate loaders for standalone style files (outside of .vue)
+exports.styleLoaders = function (options) {
+  var output = []
+  var loaders = exports.cssLoaders(options)
+  for (var extension in loaders) {
+    var loader = loaders[extension]
+    output.push({
+      test: new RegExp('\\.' + extension + '$'),
+      use: loader
+    })
+  }
+  return output
+}

+ 20 - 0
build/vue-loader.conf.js

@@ -0,0 +1,20 @@
+var utils = require('./utils')
+var config = require('../config')
+var isProduction = process.env.NODE_ENV === 'production'
+var postcssConfig = require('./postcss.config.js')
+
+module.exports = {
+  loaders: utils.cssLoaders({
+    sourceMap: isProduction
+      ? config.build.productionSourceMap
+      : config.dev.cssSourceMap,
+    extract: isProduction
+  }),
+  transformToRequire: {
+    video: 'src',
+    source: 'src',
+    img: 'src',
+    image: 'xlink:href'
+  },
+  postcss:postcssConfig.postfactory
+}

+ 76 - 0
build/webpack.base.conf.js

@@ -0,0 +1,76 @@
+var path = require('path')
+var utils = require('./utils')
+var config = require('../config')
+var vueLoaderConfig = require('./vue-loader.conf')
+var webpack = require('webpack')
+
+function resolve (dir) {
+  return path.join(__dirname, '..', dir)
+}
+
+module.exports = {
+  entry: {
+    app: './src/main.js'
+  },
+  output: {
+    path: config.build.assetsRoot,
+    filename: '[name].js',
+    publicPath: process.env.NODE_ENV === 'production'
+      ? config.build.assetsPublicPath
+      : config.dev.assetsPublicPath
+  },
+  resolve: {
+    extensions: ['.js', '.vue', '.json'],
+    alias: {
+      '@': resolve('src')
+    }
+  },
+  module: {
+    rules: [
+      {
+        test: /\.vue$/,
+        loader: 'vue-loader',
+        options: vueLoaderConfig
+      },
+      {
+        test: /\.js$/,
+        loader: 'babel-loader',
+        include: [resolve('src'), resolve('test')]
+      },
+      // {
+      //   test:/\.css$/,
+      //   loader:"postcss-loader",
+
+      // },
+      {
+        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
+        loader: 'url-loader',
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('img/[name].[hash:7].[ext]')
+        }
+      },
+      {
+        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
+        loader: 'url-loader',
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('media/[name].[hash:7].[ext]')
+        }
+      },
+      {
+        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
+        loader: 'url-loader',
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
+        }
+      }
+    ]
+  },
+  // plugins:[
+  //   new webpack.LoaderOptionsPlugin({     
+  //       postcss:postcssConfig,     
+  //   })
+  // ]
+}

+ 35 - 0
build/webpack.dev.conf.js

@@ -0,0 +1,35 @@
+var utils = require('./utils')
+var webpack = require('webpack')
+var config = require('../config')
+var merge = require('webpack-merge')
+var baseWebpackConfig = require('./webpack.base.conf')
+var HtmlWebpackPlugin = require('html-webpack-plugin')
+var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
+
+// add hot-reload related code to entry chunks
+Object.keys(baseWebpackConfig.entry).forEach(function (name) {
+  baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
+})
+
+module.exports = merge(baseWebpackConfig, {
+  module: {
+    rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
+  },
+  // cheap-module-eval-source-map is faster for development
+  devtool: '#cheap-module-eval-source-map',
+  plugins: [
+    new webpack.DefinePlugin({
+      'process.env': config.dev.env
+    }),
+    // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
+    new webpack.HotModuleReplacementPlugin(),
+    new webpack.NoEmitOnErrorsPlugin(),
+    // https://github.com/ampedandwired/html-webpack-plugin
+    new HtmlWebpackPlugin({
+      filename: 'index.html',
+      template: 'index.html',
+      inject: true
+    }),
+    new FriendlyErrorsPlugin()
+  ]
+})

+ 120 - 0
build/webpack.prod.conf.js

@@ -0,0 +1,120 @@
+var path = require('path')
+var utils = require('./utils')
+var webpack = require('webpack')
+var config = require('../config')
+var merge = require('webpack-merge')
+var baseWebpackConfig = require('./webpack.base.conf')
+var CopyWebpackPlugin = require('copy-webpack-plugin')
+var HtmlWebpackPlugin = require('html-webpack-plugin')
+var ExtractTextPlugin = require('extract-text-webpack-plugin')
+var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
+
+var env = config.build.env
+
+var webpackConfig = merge(baseWebpackConfig, {
+  module: {
+    rules: utils.styleLoaders({
+      sourceMap: config.build.productionSourceMap,
+      extract: true
+    })
+  },
+  devtool: config.build.productionSourceMap ? '#source-map' : false,
+  output: {
+    path: config.build.assetsRoot,
+    filename: utils.assetsPath('js/[name].[chunkhash].js'),
+    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
+  },
+  plugins: [
+    // http://vuejs.github.io/vue-loader/en/workflow/production.html
+    new webpack.DefinePlugin({
+      'process.env': env
+    }),
+    new webpack.optimize.UglifyJsPlugin({
+      compress: {
+        warnings: false
+      },
+      sourceMap: true
+    }),
+    // extract css into its own file
+    new ExtractTextPlugin({
+      filename: utils.assetsPath('css/[name].[contenthash].css')
+    }),
+    // Compress extracted CSS. We are using this plugin so that possible
+    // duplicated CSS from different components can be deduped.
+    new OptimizeCSSPlugin({
+      cssProcessorOptions: {
+        safe: true
+      }
+    }),
+    // generate dist index.html with correct asset hash for caching.
+    // you can customize output by editing /index.html
+    // see https://github.com/ampedandwired/html-webpack-plugin
+    new HtmlWebpackPlugin({
+      filename: config.build.index,
+      template: 'index.html',
+      inject: true,
+      minify: {
+        removeComments: true,
+        collapseWhitespace: true,
+        removeAttributeQuotes: true
+        // more options:
+        // https://github.com/kangax/html-minifier#options-quick-reference
+      },
+      // necessary to consistently work with multiple chunks via CommonsChunkPlugin
+      chunksSortMode: 'dependency'
+    }),
+    // split vendor js into its own file
+    new webpack.optimize.CommonsChunkPlugin({
+      name: 'vendor',
+      minChunks: function (module, count) {
+        // any required modules inside node_modules are extracted to vendor
+        return (
+          module.resource &&
+          /\.js$/.test(module.resource) &&
+          module.resource.indexOf(
+            path.join(__dirname, '../node_modules')
+          ) === 0
+        )
+      }
+    }),
+    // extract webpack runtime and module manifest to its own file in order to
+    // prevent vendor hash from being updated whenever app bundle is updated
+    new webpack.optimize.CommonsChunkPlugin({
+      name: 'manifest',
+      chunks: ['vendor']
+    }),
+    // copy custom static assets
+    new CopyWebpackPlugin([
+      {
+        from: path.resolve(__dirname, '../static'),
+        to: config.build.assetsSubDirectory,
+        ignore: ['.*']
+      }
+    ])
+  ]
+})
+
+if (config.build.productionGzip) {
+  var CompressionWebpackPlugin = require('compression-webpack-plugin')
+
+  webpackConfig.plugins.push(
+    new CompressionWebpackPlugin({
+      asset: '[path].gz[query]',
+      algorithm: 'gzip',
+      test: new RegExp(
+        '\\.(' +
+        config.build.productionGzipExtensions.join('|') +
+        ')$'
+      ),
+      threshold: 10240,
+      minRatio: 0.8
+    })
+  )
+}
+
+if (config.build.bundleAnalyzerReport) {
+  var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
+  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
+}
+
+module.exports = webpackConfig

+ 6 - 0
config/dev.env.js

@@ -0,0 +1,6 @@
+var merge = require('webpack-merge')
+var prodEnv = require('./prod.env')
+
+module.exports = merge(prodEnv, {
+  NODE_ENV: '"development"'
+})

+ 38 - 0
config/index.js

@@ -0,0 +1,38 @@
+// see http://vuejs-templates.github.io/webpack for documentation.
+var path = require('path')
+
+module.exports = {
+  build: {
+    env: require('./prod.env'),
+    index: path.resolve(__dirname, '../dist/index.html'),
+    assetsRoot: path.resolve(__dirname, '../dist'),
+    assetsSubDirectory: 'static',
+    assetsPublicPath: '/',
+    productionSourceMap: true,
+    // Gzip off by default as many popular static hosts such as
+    // Surge or Netlify already gzip all static assets for you.
+    // Before setting to `true`, make sure to:
+    // npm install --save-dev compression-webpack-plugin
+    productionGzip: false,
+    productionGzipExtensions: ['js', 'css'],
+    // Run the build command with an extra argument to
+    // View the bundle analyzer report after build finishes:
+    // `npm run build --report`
+    // Set to `true` or `false` to always turn it on or off
+    bundleAnalyzerReport: process.env.npm_config_report
+  },
+  dev: {
+    env: require('./dev.env'),
+    port: 8080,
+    autoOpenBrowser: true,
+    assetsSubDirectory: 'static',
+    assetsPublicPath: '/',
+    proxyTable: {},
+    // CSS Sourcemaps off by default because relative paths are "buggy"
+    // with this option, according to the CSS-Loader README
+    // (https://github.com/webpack/css-loader#sourcemaps)
+    // In our experience, they generally work as expected,
+    // just be aware of this issue when enabling this option.
+    cssSourceMap: false
+  }
+}

+ 3 - 0
config/prod.env.js

@@ -0,0 +1,3 @@
+module.exports = {
+  NODE_ENV: '"production"'
+}

+ 21 - 0
index.html

@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>FX66</title>
+    <!-- <link rel="stylesheet" href="//at.alicdn.com/t/font_407855_jeeqd33yfnefjemi.css"> -->
+    <link rel="stylesheet" href="//at.alicdn.com/t/font_438855_ofee4hcmy90jxlxr.css">
+    <link rel="stylesheet" type="text/css" href="static/css/inputemail.css">
+  </head>
+  <body>
+    <div id="app"></div>
+    <!-- built files will be auto injected -->
+    <script type="text/javascript" src="static/jquery-3.2.1.min.js"></script>
+    <script type="text/javascript" src="static/emailAutoComplete.js"></script>
+    <script type="text/javascript" src="static/jquery.mCustomScrollbar.min.js"></script>
+    <script src="static/jquery.cookie.js"></script>
+    <script type="text/javascript" src="static/jquery.extension.js"></script>
+    <script src="static/jquery.mousewheel.js"></script>
+    <script type="text/javascript" src="static/app.js"></script>
+  </body>
+</html>

+ 79 - 0
package.json

@@ -0,0 +1,79 @@
+{
+  "name": "vue-project",
+  "version": "1.0.0",
+  "description": "A Vue.js project",
+  "author": "msy <550428854@qq.com>",
+  "private": true,
+  "scripts": {
+    "dev": "node build/dev-server.js",
+    "start": "node build/dev-server.js",
+    "build": "node build/build.js"
+  },
+  "dependencies": {
+    "echarts": "^3.7.2",
+    "element-ui": "1.4.6",
+    "vue": "2.3.3",
+    "vue-clipboard2": "^0.0.6",
+    "vue-router": "2.6.0"
+  },
+  "devDependencies": {
+    "autoprefixer": "7.1.2",
+    "axios": "0.16.2",
+    "babel-core": "6.22.1",
+    "babel-loader": "7.1.1",
+    "babel-plugin-transform-runtime": "6.22.0",
+    "babel-preset-env": "1.3.2",
+    "babel-preset-stage-2": "6.22.0",
+    "babel-register": "6.22.0",
+    "babel-runtime": "^6.26.0",
+    "chalk": "2.0.1",
+    "connect-history-api-fallback": "1.3.0",
+    "copy-webpack-plugin": "4.0.1",
+    "css-loader": "0.28.0",
+    "cssnano": "3.10.0",
+    "eventsource-polyfill": "0.9.6",
+    "express": "4.14.1",
+    "extract-text-webpack-plugin": "2.0.0",
+    "file-loader": "0.11.1",
+    "friendly-errors-webpack-plugin": "1.1.3",
+    "html-webpack-plugin": "2.28.0",
+    "http-proxy-middleware": "0.17.3",
+    "opn": "5.1.0",
+    "optimize-css-assets-webpack-plugin": "2.0.0",
+    "ora": "1.2.0",
+    "postcss": "6.0.9",
+    "postcss-alias": "2.0.0",
+    "postcss-calc": "6.0.0",
+    "postcss-crip": "2.0.1",
+    "postcss-each": "0.10.0",
+    "postcss-for": "2.1.1",
+    "postcss-loader": "2.0.6",
+    "postcss-mixins": "6.0.1",
+    "postcss-nested": "1.0.0",
+    "postcss-sass-extend": "0.0.1",
+    "postcss-selector-matches": "3.0.1",
+    "postcss-selector-not": "3.0.1",
+    "postcss-simple-vars": "4.0.0",
+    "rimraf": "2.6.0",
+    "semver": "5.3.0",
+    "shelljs": "0.7.6",
+    "url-loader": "0.5.8",
+    "vue-loader": "12.1.0",
+    "vue-style-loader": "3.0.1",
+    "vue-template-compiler": "2.3.3",
+    "webpack": "2.6.1",
+    "webpack-bundle-analyzer": "2.2.1",
+    "webpack-dev-middleware": "1.10.0",
+    "webpack-hot-middleware": "2.18.0",
+    "webpack-merge": "4.1.0"
+  },
+  "engines": {
+    "node": ">= 4.0.0",
+    "npm": ">= 3.0.0"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not ie <= 8"
+  ]
+}

+ 0 - 0
static/.gitkeep


+ 10341 - 0
static/app.js

@@ -0,0 +1,10341 @@
+if (!window.console || !window.console.log || !window.console.error) {
+    window.console = { log: function(x) { myalert(x) }, error: function(x) { myalert(x) } };
+}
+
+function array_diff(arr1, arr2) {
+    var diff = [];
+    for (var i = 0; i < arr1.length; i++) {
+        if (!in_array(arr2, arr1[i])) {
+            diff.push(arr1[i]);
+        }
+    }
+    return diff;
+}
+
+function array_equal(arr1, arr2) {
+    if (is_array(arr1) && is_array(arr2)) {
+        if (arr1.length != arr2.length) return false;
+        for (var i = 0; i < arr1.length; i++) {
+            if (!array_equal(arr1[i], arr2[i])) {
+                return false;
+            }
+        }
+        return true;
+    } else {
+        return arr1 == arr2;
+    }
+}
+
+function in_array(arr, value) {
+    for (var i = 0; i < arr.length; i++) {
+        if (array_equal(arr[i], value)) return true;
+    }
+    return false;
+}
+//*没有用到
+// function playmusic(url) {
+//     var id = "__music__embed__player__";
+//     var obj = document.getElementById(id);
+//     url = __baseurl__ + "js/music/" + encodeURI(url);
+//     if (obj == null) {
+//         var oDiv = document.createElement("DIV");
+//         oDiv.id = id;
+//         oDiv.style.position = "absolute";
+//         oDiv.style.width = "1px";
+//         oDiv.style.height = "1px";
+//         oDiv.style.top = "-2000px";
+//         document.body.appendChild(oDiv);
+//         obj = oDiv;
+//     }
+//     if (url.match(new RegExp("\\.wav$", 'ig'))) {
+//         playwav(obj, url);
+//     } else {
+//         playmp3swf(obj, url);
+//     }
+// }
+
+function isIE() {
+    var ua = navigator.userAgent.toLowerCase();
+    var s;
+    if (ua.match(new RegExp("msie\\s+([\\d.]+)", "ig"))) {
+        return true;
+    }
+    return false;
+}
+
+// function playwav(obj, url) {
+//     var html;
+//     if (isIE()) {
+//         html = '<embed name="music" height="1px" width="1px" src="' + url + '" />';
+//     } else {
+//         html = '<audio height="1px" width="1px" autoplay="true">';
+//         html += '<source name="music" src="' + url + '" type="audio/x-wav" />';
+//         html += '</audio>';
+//     }
+//     obj.innerHTML = html;
+// }
+
+// function playmp3swf(obj, url) {
+//     var url = escape(url);
+//     var html = '<embed type="application/x-shockwave-flash" wmode="transparent" ' + 'src="' + __baseurl__ + 'js/audio-player.swf" flashvars="audioUrl=' + url + '&autoPlay=true" height="1px" width="1px"></embed>';
+//     obj.innerHTML = html;
+// }
+
+function myalert(text) {
+    if (__javascript_debug__) {
+        //alert(text);
+    }
+}
+
+function GetText(value, unit) {
+    if (unit < 1) {
+        unit = -Math.floor(Math.log(unit) / Math.LN10);
+        var text = FormatNumber(value, unit);
+    } else if (unit == 1) {
+        var text = Math.floor(value) + ".0";
+    } else {
+        var text = value;
+    }
+    return text;
+}
+
+function triggerKeydown(code) {
+    var e = jQuery.Event("keydown");
+    e.keyCode = code;
+    $(document).trigger(e);
+}
+/*
+function Alert(obj, showFunction)
+{
+    var str = "";
+    var key;
+    if (typeof showFunction == "undefined")
+    {
+        showFunction = true;
+    }
+    if (typeof obj == 'object')
+    {
+        for (key in obj)
+        {
+            if (typeof key == 'string')
+            {
+                if (typeof obj[key] == 'function')
+                {
+                    if (showFunction)
+                    {
+                        str += key +" => (\n    "+Alert(obj[key])+"\n)\n";
+                    }
+                } else {
+                    str += key +" => (\n    "+Alert(obj[key])+"\n)\n";
+                }
+            }
+        }
+        return str;
+    } else {
+        if (typeof obj === "undefined")
+        {
+            return "undefined";
+        } else if (obj === null) {
+            return "null";
+        } else {
+            return obj.toString();
+        }
+    }
+}
+*/
+/*没有用到
+function url_concat(base, str)
+{
+    var last = base.charAt(base.length - 1);
+    if (base.indexOf("?") != -1)
+    {
+        if(last != "?") {
+            return base + "&" + str;
+        } else {
+            return base + str;
+        }
+    } else {
+        return base + "?" + str;
+    }
+}*/
+//controller里面作为判断
+function is_undefined(obj) {
+    return typeof obj === "undefined";
+}
+
+//object copy复制一份数据
+function object_copy(obj, copy_array) {
+    var newobj = {};
+    if (is_array(obj)) {
+        if (copy_array) {
+            return array_copy(obj);
+        } else {
+            return obj;
+        }
+    }
+    if (typeof obj == 'object') {
+        for (var key in obj) {
+            newobj[key] = object_copy(obj[key]);
+        }
+    } else {
+        return obj;
+    }
+    return newobj;
+}
+//深度拷贝
+function array_copy(arr) {
+    var copy = new Array(arr.length);
+    for (var i = 0; i < arr.length; i++) {
+        if (is_array(arr[i])) {
+            copy[i] = array_copy(arr[i]);
+        } else {
+            copy[i] = arr[i];
+        }
+    }
+    return copy;
+}
+//判断是否是数组
+function is_array(a) {
+    return Object.prototype.toString.call(a) === "[object Array]";
+}
+
+
+function ClassExtend(sub, base) {
+    //before:
+    //alert("before");
+    //alert(Alert(oparnet.prototype));
+    for (var property in base.prototype) {
+        sub.prototype[property] = base.prototype[property];
+    }
+    sub.prototype.constructor = sub;
+    //获得基类
+    sub.__parent = base;
+    if (!base.__sub) {
+        base.__sub = [];
+    }
+    //保存继承它的子类
+    base.__sub.push(sub);
+}
+
+function ClassNew(classname) {
+    var args = Array.prototype.slice.call(arguments, 1);
+    var _this = this;
+
+    function F() {
+        _this.parent = classname.apply(_this, args);
+        return _this.parent;
+    }
+    F.prototype = classname.prototype;
+    return new F();
+}
+
+function getClassName(obj) {
+    var str = obj.constructor.toString();
+    var regexp = new RegExp("function(\\s+)([^\\(]+)", "ig");
+    str = regexp.exec(str);
+    return $.trim(str[2]);
+}
+
+function sup(_this) {
+    var args = Array.prototype.slice.call(arguments, 1);
+    if (_this.constructor && _this.constructor.__parent) {
+        if (typeof _this.__counter === 'undefined') {
+            // It has not... perform the initilization
+            _this.__counter = 0;
+        }
+        _this.__counter++;
+        if (_this.__counter > 1) //不是第一次调用继承
+        {
+            var _parent = _this.constructor.__parent;
+            for (var i = 1; i < _this.__counter; i++) {
+                _parent = _parent.__parent;
+            }
+            args.unshift(_parent);
+            ClassNew.apply(_this, args);
+        } else {
+            args.unshift(_this.constructor.__parent);
+            ClassNew.apply(_this, args);
+        }
+    }
+}
+
+function Point(x, y, z) {
+    this.x = x;
+    this.y = y;
+    if (z !== undefined || z !== null) {
+        this.z = z;
+    }
+}
+
+function FormatNumber(srcStr, nAfterDot) {
+    var nten = Math.pow(10, nAfterDot);
+    srcStr = Math.round(parseFloat(srcStr) * nten) / nten;
+    srcStr = srcStr.toString();
+    var arr = srcStr.split(".");
+    if (arr[1] == null) {
+        return srcStr + "." + bulidZero(nAfterDot);
+    }
+    if (arr[1].length < nAfterDot) {
+        var offset = nAfterDot - arr[1].length;
+        srcStr += bulidZero(offset);
+
+    }
+    return srcStr;
+}
+
+function bulidZero(num) {
+    var srcStr = '';
+    for (var i = 0; i < num; i++) {
+        srcStr += "0";
+    }
+    return srcStr;
+}
+
+function array_copy1d(arr) {
+    var copy = new Array(arr.length);
+    for (var i = 0; i < arr.length; i++) {
+        copy[i] = arr[i];
+    }
+    return copy;
+}
+
+function array_copy2d(arr) {
+    var copy = new Array(arr.length);
+    for (var i = 0; i < arr.length; i++) {
+        var len = arr[i].length;
+        copy[i] = new Array(len);
+        for (var j = 0; j < len; j++) {
+            copy[i][j] = arr[i][j];
+        }
+    }
+    return copy;
+}
+
+
+//得到最大最小值
+function minmax(data, start_index, end_index) {
+    if (!start_index) start_index = 0;
+    if (!end_index) end_index = data.length - 1;
+
+    if (is_array(data[start_index])) {
+        return _minmax2d(data, start_index, end_index);
+    } else {
+        return _minmax1d(data, start_index, end_index);
+    }
+}
+//辅助minmax
+function _minmax2d(data, start_index, end_index) {
+    var max = -Infinity;
+    var min = Infinity;
+    var maxIndex="";
+    var minIndex="";
+
+    for (var i = start_index; i <= end_index; i++) {
+        for (var j = 0; j < data[i].length; j++) {
+            if (data[i][j] >= max) {
+                max = data[i][j];
+                maxIndex=[i,j];
+            }
+            if (data[i][j] < min){
+                min = data[i][j];
+                minIndex=[i,j]
+            } 
+        }
+    }
+    return [min, max,minIndex,maxIndex];
+}
+//辅助minmax
+function _minmax1d(data, start_index, end_index) {
+    var max = -Infinity;
+    var min = Infinity;
+    var maxIndex="";
+    var minIndex="";
+    for (var i = start_index; i <= end_index; i++) {
+        if (data[i] >= max) {
+            max = data[i];
+            maxIndex=i;
+        }
+        if (data[i] < min) {
+            min = data[i];
+            minIndex=i;
+        }
+    }
+    return [min, max,minIndex,maxIndex];
+}
+//画行
+function drawRow(ctx, point, len, color, width) {
+    var x = point.x;
+    var y = point.y;
+    if (isNaN(y)) {
+        debug("draw row y nan");
+    }
+    ctx.beginPath();
+    if (width) ctx.lineWidth = width;
+    if (color) ctx.strokeStyle = color;
+    ctx.moveTo(x, y + 0.5);
+    ctx.lineTo(x + len, y + 0.5);
+    ctx.closePath();
+    ctx.stroke();
+}
+
+//画列
+function drawCol(ctx, point, len, color, width) {
+    var x = point.x;
+    var y = point.y;
+    ctx.beginPath();
+    if (width) ctx.lineWidth = width;
+    if (color) ctx.strokeStyle = color;
+    ctx.moveTo(x + 0.5, y);
+    ctx.lineTo(x + 0.5, y + len);
+    ctx.closePath();
+    ctx.stroke();
+}
+//时间转换成日期格式
+function timeToDate(time, format, timezone) {
+    if (!format) format = "Y-m-d H:i:s";
+    if (!timezone) timezone = 0;
+
+    var date = new Date();
+    if (format.indexOf(".") == -1) // time no msecond
+    {
+        time *= 1000;
+    }
+    time += (date.getTimezoneOffset() + timezone * 60) * 60 * 1000;
+    date.setTime(time);
+    var y = date.getFullYear();
+    var m = date.getMonth() + 1;
+    var d = date.getDate();
+    var h = date.getHours();
+    var i = date.getMinutes();
+    var s = date.getSeconds();
+    var u = date.getMilliseconds();
+
+    format = time_replace(format, "Y", y);
+    format = time_replace(format, "m", m);
+    format = time_replace(format, "d", d);
+    format = time_replace(format, "H", h);
+    format = time_replace(format, "i", i);
+    format = time_replace(format, "s", s);
+    format = time_replace(format, "u", u, 3);
+    return format;
+}
+//时间标准模式
+function formatTime(time, p) {
+    var conf = Config.getInstance()
+    var unit = conf.Global.xunit[p]
+    if (unit) {
+        unit = unit * 60;
+        return Math.floor(time / unit) * unit
+    }
+    return time
+}
+//formatTime 辅助函数
+function time_replace(format, search, n, zero_number) {
+    if (typeof zero_number === "undefined") {
+        zero_number = 2;
+    }
+    if (n < 10) n = padingZero(n, zero_number) + n;
+    return format.replace(search, n);
+}
+//time_replace 辅助函数 
+function padingZero(n, zero_number) {
+    if (n < 0) {
+        return n;
+    }
+    var zn = zero_number - 1;
+    if (n > 0) {
+        var zero_current_num = Math.floor(Math.log(n) / Math.LN10) + 1;
+        zn = zero_number - zero_current_num;
+    }
+    var zero = "";
+    for (var i = 0; i < zn; i++) {
+        zero += "0";
+    }
+    return zero;
+}
+//在k线图上写内容
+function writeText(ctx, point, text, color, font) {
+    //console.log(window.do_drawText);
+    if (isIPhone() && window.do_drawText) {
+        //手机内容设置
+        text = text.toString();
+        if (color) ctx.strokeStyle = color;
+        do_drawText.call(ctx, text, point.x, point.y - 10, 9);
+    } //电脑内容设置
+    else if (ctx.fillText) {
+        if (color) ctx.fillStyle = color;
+        if (font) { ctx.font = font; } else { ctx.font = "normal small-caps normal 1.1em Arial" }
+        ctx.fillText(text, point.x, point.y);
+    } else {
+        if (color) ctx.strokeStyle = color;
+        if (font) { ctx.font = font; } else { ctx.font = "normal small-caps normal 1.1em Arial" }
+        ctx.strokeText(text, point.x, point.y);
+    }
+}
+/*
+ * 画带箭头的虚线
+ */
+
+function drawWithArrowheads(x1,y1,x2,y2,ctx){
+    // arbitrary styling
+    ctx.strokeStyle="#ff6600";
+    ctx.fillStyle="#ff6600";
+    ctx.lineWidth=1;
+    // draw the line
+    ctx.beginPath();
+    ctx.moveTo(x1,y1);
+    ctx.lineTo(x2,y2);
+    ctx.stroke();
+    // draw the starting arrowhead
+    var startRadians=Math.atan((y2-y1)/(x2-x1));
+    startRadians+=((x2>x1)?-90:90)*Math.PI/180;
+    this.drawArrowhead(ctx,x1,y1,startRadians);
+    // draw the ending arrowhead
+    var endRadians=Math.atan((y2-y1)/(x2-x1));
+    endRadians+=((x2>x1)?90:-90)*Math.PI/180;
+    drawArrowhead(ctx,x2,y2,endRadians);
+
+}
+function drawArrowhead(ctx,x,y,radians){
+    ctx.save();
+    ctx.beginPath();
+    ctx.translate(x,y);
+    ctx.rotate(radians);
+    ctx.moveTo(0,0);
+    ctx.lineTo(3,10);
+    ctx.lineTo(-3,10);
+    ctx.closePath();
+    ctx.restore();
+    ctx.fill();
+}
+
+/*
+ * 画虚线
+ * 
+ */
+function drawDashLine(context,x1,y1,x2,y2,pattern)  
+{  
+    pattern = pattern === undefined ? 5 : pattern;  
+    //得到斜边的总长度  
+    // calculate the delta x and delta y 
+    var dx = (x2 - x1); 
+    var dy = (y2 - y1); 
+    var distance = Math.floor(Math.sqrt(dx*dx + dy*dy)); 
+    var dashlineInteveral = (pattern <= 0) ? distance : (distance/pattern); 
+    var deltay = (dy/distance) * pattern; 
+    var deltax = (dx/distance) * pattern; 
+    // draw dash line 
+    context.beginPath(); 
+    context.lineWidth=0.7;
+    context.strokeStyle="#333";
+    for(var dl=0; dl<dashlineInteveral; dl++) { 
+        if(dl%2) { 
+           context.lineTo(x1 + dl*deltax, y1 + dl*deltay); 
+        } else { 
+           context.moveTo(x1 + dl*deltax, y1 + dl*deltay); 
+        } 
+    } 
+    context.stroke(); 
+}  
+//画canvas层的分割线 折线
+function drawLever(ctx,x,y,color,width,heigh){
+   ctx.beginPath();
+   ctx.strokeStyle = color;
+   //设置路径起点坐标
+   ctx.moveTo(x, y);
+   //定义中间点坐标1
+   ctx.lineTo(x+width, y);
+   //定义中间点坐标2
+    ctx.lineTo(x+width, y-heigh);
+     //按照绘制路径顺序连接各个坐标点
+    ctx.stroke();
+    //关闭绘制路径
+    ctx.closePath();
+}
+
+//画线
+function drawLine(ctx, X, Y, color, width) {
+    ctx.beginPath();
+    if (width) ctx.lineWidth = width;
+    if (color) ctx.strokeStyle = color;
+    ctx.moveTo(X[0], Y[0]);
+    var prevx = X[0];
+    var prevy = Y[0];
+    for (var i = 1; i < X.length; i++) {
+        if (prevx == X[i] && prevy == Y[i]) {
+            continue;
+        }
+        prevx = X[i];
+        prevy = Y[i];
+        ctx.lineTo(X[i], Y[i]);
+    }
+    ctx.stroke();
+}
+//plotLine plot画线
+function plotLine(ctx, p1, p2, color, width) {
+    ctx.beginPath();
+    if (width) ctx.lineWidth = width;
+    if (color) ctx.strokeStyle = color;
+    ctx.moveTo(p1.x, p1.y);
+    ctx.lineTo(p2.x, p2.y);
+    ctx.closePath();
+    ctx.stroke();
+}
+//debug打印信息
+function debug(msg) {
+    var d = $("#debug");
+    if (d) {
+        var time = (new Date()).getTime();
+        var msecond = time % 1000;
+        time = Math.floor(time / 1000);
+        d.append(time + "(" + msecond + ")" + ": " + msg + "<br />");
+    }
+}
+/*貌似没有用到
+function debugx(msg)
+{
+    var d = $("#debugx");
+    if (d)
+    {
+        var time = (new Date()).getTime();
+        var msecond = time % 1000;
+        time = Math.floor(time / 1000);
+        d.append(time + "("+ msecond +")" + ": " + msg + "<br />");
+    }
+}*/
+//得到当前时间
+function getTime() {
+    return (new Date()).getTime();
+}
+
+/*/从小到大排列的数组 没有使用
+function find_first_big(arr, match)
+{
+    //结束条件是:match >= arr[mid] && match <= arr[mid + 1], 也就是在 mid  和 mid + 1 的之间, 这样,mid + 1 就是first big
+    var start = 0;
+    var end  = arr.length - 1;
+    while (start <= end)
+    {
+        mid = Math.floor((end - start) / 2) + start;
+        if (mid + 1 > arr.length -1) //越界了, 只有在 start == end 的时候会发生,这个时候 mid = arr.length - 1
+        {
+            if (arr.length > 1)
+            {
+                if (arr[mid -1] >= match) //判断一下前面一个数字
+                {
+                    return mid - 1;
+                }
+            }
+            return arr[mid] >= match ? mid : -1;
+        }
+        if (match >= arr[mid] && match <= arr[mid + 1]) {
+                return match == arr[mid] ? mid : mid + 1;
+        } else if (arr[mid] < match) {
+            start = mid + 1;
+        } else { //macth
+            end = mid - 1
+        }
+    }
+    return -1;
+}*/
+////查找到第一个点
+function find_first_big_r(arr, match) {
+    //结束条件是:match >= arr[mid - 1] && match <= arr[mid + 1], 也就是在 mid  和 mid + 1 的之间, 这样,mid + 1 就是first big
+    var start = 0;
+    var end = arr.length - 1;
+    if (arr[end] > match) {
+        return end;
+    }
+    while (start <= end) {
+        mid = Math.floor((end - start) / 2) + start;
+        if (mid - 1 < 0) //最多有两个数据 start = 0, end = 0, 1
+        {
+            if (arr.length > 1) {
+                if (arr[1] >= match) {
+                    return 1;
+                }
+            }
+            return arr[0] >= match ? 0 : -1;
+        }
+        if (match >= arr[mid] && match <= arr[mid - 1]) {
+            return match == arr[mid] ? mid : mid - 1;
+        } else if (arr[mid] < match) {
+            end = mid - 1;
+        } else { //macth
+            start = mid + 1
+        }
+    }
+    return -1;
+}
+
+////判断兼容性 手机 pc的兼容性
+function check_textRender(canvas) {
+    //判断是否是iPhone 或者 ipad
+    if (isIPhone()) {
+        return false;
+    }
+    if (!canvas.get(0).getContext) {
+        return true;
+    }
+    var ctx = canvas.get(0).getContext('2d');
+       // ctx.drawImage('static/img/klogo.png',this.width, this.height); 
+    if (typeof ctx.strokeText == 'function' || ctx.fillText == 'function') {
+        return true
+    } else {
+        return false
+    }
+}
+
+//判断是否是iPhone 或者 ipad
+function isIPhone() //如果是iPhone,那么采用js库绘制, 已知的bug
+{
+    var agent = navigator.userAgent;
+    //agent = "Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_1_3 like Mac OS X; zh-cn) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7E18 Safari/528.16";
+    if (agent.toLowerCase().indexOf("iphone") >= 0 || agent.toLowerCase().indexOf("ipad") >= 0) {
+        return true;
+    }
+    return false;
+}
+
+//初始化标志位 对于空值做处理
+function init_obj(obj, c, p, default_value) {
+    if (typeof obj === "undefined") {
+        obj = {};
+    }
+    if (typeof obj[c] === "undefined") {
+        obj[c] = {};
+    }
+    if (typeof obj[c][p] === "undefined") {
+        obj[c][p] = default_value;
+    }
+    return obj;
+}
+
+//判断是否为object类型
+function is_object(obj, key) {
+    if (key) {
+        if (typeof obj[key] == "object") {
+            return true;
+        }
+        return false;
+    }
+    return (typeof obj == "object");
+}
+
+//FzmCookie  cookie 内容
+FzmCookie = {};
+//FzmCookie读函数 从cookie拿数据
+FzmCookie.read = function(name) {
+    var cookieValue = "",
+        search = name + "=";
+    if (document.cookie.length > 0) {
+        offset = document.cookie.indexOf(search);
+        if (offset != -1) {
+            if (offset > 0) {
+                //去除空格部分
+                var myoffset = offset;
+                while (myoffset > 0 && document.cookie.charAt(--myoffset) == ' ');
+                if (myoffset > 0 && document.cookie.charAt(myoffset) != ';') {
+                    return '';
+                }
+            }
+            offset += search.length;
+            end = document.cookie.indexOf(";", offset);
+            if (end == -1) {
+                end = document.cookie.length;
+            }
+            cookieValue = unescape(document.cookie.substring(offset, end))
+        }
+    }
+    return cookieValue;
+};
+//当前时间
+function now() {
+    return (new Date()).getTime();
+}
+//写cookie
+FzmCookie.write = function(name, value, hours, path, domain, secure) {
+    var expire = "";
+    if (domain == null) {
+        /*
+        domain = document.domain;
+        if (domain.indexOf(".") == -1) {
+            domain = '';
+        } else {
+            domain = "." + domain;
+        }
+        domain = domain ? "; domain=" + domain : "";
+        */
+    }
+    path = path ? path : "/";
+
+    if (hours != null) {
+        expire = new Date(now() + hours * 3600000);
+        expire = "; expires=" + expire.toGMTString();
+    }
+    document.cookie = name + "=" + escape(value) + expire + domain + "; path=" + path + ";";
+};
+//
+FzmCookie.del = function(name, domain, path) {
+    var expire = "";
+
+    if (domain == null) {
+        domain = domainName();
+        if (domain.indexOf(".") == -1) {
+            domain = '';
+        } else {
+            domain = "." + domain;
+        }
+        domain = domain ? "; domain=" + domain : "";
+    }
+
+    path = path ? path : "/";
+    value = "";
+    hours = "-10";
+    if (hours != null) {
+        expire = new Date(Fzm.clientTime() + hours * 3600000);
+        expire = "; expires=" + expire.toGMTString();
+    }
+    document.cookie = name + "=" + escape(value) + expire + domain + "; path=" + path + ";";
+};
+//更新cookie
+FzmCookie.update = function(name, value, hours, path, domain, secure) {
+    var v = Guidv4.get(name); //以guid中保存的值为准
+    if (!v) v = FzmCookie.read(name);
+    if (v == '') {
+        v = value;
+    }
+    Guidv4.update(name, v);
+    FzmCookie.write(name, v, hours, path, domain, secure);
+    return v;
+};
+//设置plot_area基本样式
+function set_style(name) {
+    var conf = Config.getInstance();
+    if (!name) {
+        name = conf.Global.style;
+    } else {
+        conf.Global.style = name;
+    }
+    conf.merge("Global.Candle.public", "Global.Candle." + name);
+    conf.merge("Global.Grid.public", "Global.Grid." + name);
+    //设置plot_area的背景颜色
+    $(conf.Global.canvasID).css("background", conf.Global.Grid.public.bgColor);
+   
+    // $(conf.Global.canvasID).css("background-image","url('static/img/Klogo.png')");
+    // $(conf.Global.canvasID).css("background-repeat","no-repeat");
+}
+
+/*//create_canvas创建canvas层 没有用
+function create_canvas()
+{
+    //
+    var conf = Config.getInstance();
+    var count = conf.Global.maxCanvasCount;
+    for (var i = 0; i < count; i++)
+    {
+        var id = conf.Global.canvasIDPerfix + i;
+        var tmp = $("<canvas id='"+id+"'></canvas>");
+        tmp.get(0).height = 1;
+        $(conf.Global.canvasID).append(tmp);
+    }
+}
+*/
+//显示加载
+function show_loading() {
+    var conf = Config.getInstance();
+    var id = conf.Global.ajaxloadingID;
+   
+    var view = HTML5StockChartAPI.API.controller.view;
+
+    var plotWidth = view.plotWidth;
+    var offsetHeight = $("#plot_area").offset().top;
+    var offsetWidth = $("#plot_area").offset().left;
+    var plotHeight = view.plotHeight;
+    $(id).css("top", offsetHeight + plotHeight / 2 - $(id).width() / 2);
+    $(id).css("left", offsetWidth + plotWidth / 2 - $(id).width() / 2);
+    $(id).show();
+    $("#background").css("top", offsetHeight + plotHeight / 2 - $(id).width() / 2-130);
+    $("#background").css("left",  offsetWidth+ plotWidth / 2 - $(id).width() / 2-130 );
+    // $(id).show();
+}
+//隐藏加载
+function hide_loading() {
+    var conf = Config.getInstance();
+    var id = conf.Global.ajaxloadingID;
+    $(id).hide();
+}
+//原来是放了一个矩形框在那里显示内容,现在做成六边形输入框update by fangxiao from 2016/7/1   次方法主要是为了价格标线来设置的
+function writeTextOption(ctx, point, value, option) {
+    if (option) {
+        if (option.bg) {
+           if(option.type=="price"){
+                ctx.fillStyle = option.bg.fillcolor;
+                ctx.fillRect(point.x+8,point.y-11,80,20);
+                ctx.fill();
+            }
+            else{
+                //画线
+                //做个六边形
+                ctx.strokeStyle = option.bg.color;
+                //ctx.strokeRect(point.x, point.y - option.bg.height / 2, option.bg.width , option.bg.height);
+                ctx.fillStyle = option.fillcolor;
+                ctx.lineWidth = 0.6; //设置线宽
+                var a = option.bg.width;
+                var b = option.bg.width / 2 * 0.3; //左小测
+                //ctx.strokeStyle=gradient;
+                //console.log(point.x);
+                //console.log(point.y);
+                //  ctx.strokeText(value, point.x+3,point.y+2.8,option.bg.width);
+                //ctx.translate(point.x+option.bg.width/2,point.y);
+                ctx.moveTo(point.x, point.y);//左边第一个点
+                ctx.lineTo(point.x + b, point.y + option.bg.height / 2);//左上角第一个点
+                ctx.lineTo(point.x + a - b, point.y + option.bg.height / 2);
+                ctx.lineTo(point.x + a, point.y);
+                ctx.lineTo(point.x + a - b, point.y - option.bg.height / 2);
+                ctx.lineTo(point.x + b, point.y - option.bg.height / 2);
+                ctx.lineTo(point.x, point.y);
+//              ctx.fillText(text, point.x, point.y);
+                ctx.closePath();
+                ctx.stroke();
+                ctx.fill();
+
+//              ctx.fillRect(point.x, point.y - option.bg.height / 2, option.bg.width , option.bg.height);
+//              point.y += option.bg.height / 2;
+            }
+        }
+        if (option.unit < 1) {
+            value = FormatNumber(value, -Math.floor(Math.log(option.unit) / Math.LN10));
+        }
+    }
+    point.y += 5;
+    point.x += 12;
+    writeText(ctx, point, value, option.color, option.font);
+}
+//为了光标设置的样式
+function writeTextOptionFortoollist(ctx, point, value, option) {
+    ctx.strokeStyle = "#000";
+    //ctx.strokeRect(point.x, point.y - option.bg.height / 2, option.bg.width , option.bg.height);
+    //ctx.fillStyle = "#000";
+    ctx.lineWidth = 1; //设置线宽
+    var a = option.bg.width;
+    var b = option.bg.width / 2 * 0.3; //左小测
+    //ctx.strokeStyle=gradient;
+    //console.log(point.x);
+    //console.log(point.y);
+    ctx.strokeText(value, point.x + 3, point.y + 2.8, option.bg.width);
+    //ctx.translate(point.x+option.bg.width/2,point.y);
+    ctx.moveTo(point.x, point.y);
+    ctx.lineTo(point.x + b, point.y + option.bg.height / 2);
+    ctx.lineTo(point.x + a - b, point.y + option.bg.height / 2);
+    ctx.lineTo(point.x + a, point.y);
+    ctx.lineTo(point.x + a - b, point.y - option.bg.height / 2);
+    ctx.lineTo(point.x + b, point.y - option.bg.height / 2);
+    ctx.lineTo(point.x, point.y);
+    //  ctx.fillText(text, point.x, point.y);
+    ctx.closePath();
+    ctx.stroke();
+}
+
+
+//start 大, end 小的情况  二分法找寻value值位置
+function binsearch_r(arr, value, start, end) {
+    if (typeof start === "undefined") {
+        start = 0;
+    }
+    if (typeof end === "undefined") {
+        end = arr.length - 1;
+    }
+    var mid;
+    while (start <= end) {
+        mid = parseInt((start + end) / 2);
+        if (arr[mid] == value) {
+            return mid;
+        } else if (arr[mid] > value) {
+            start = mid + 1;
+        } else if (arr[mid] < value) {
+            end = mid - 1;
+        }
+    }
+    return -1;
+}
+//最后大于find最大的点的位置
+function find_last_little_r(x, find) {
+    index = find_first_big_r(x, find); //第一个最大值点位置
+    if (index == -1) //没有找到
+    {
+        if (x[0] <= find) {
+            return 0;
+        } else {
+            return -1;
+        }
+    } else {
+        if (x[index] == find) { //找寻到
+            return index;
+        } else {
+            index++;
+            if (index >= x.length) return -1;
+            return index;
+        }
+    }
+}
+//找到相邻的find位置
+function find_near(x, find) {
+    var index = find_first_big_r(x, find);
+    if (index == -1) return 0;
+    if (index < x.length - 1 && (x[index] - find > find - x[index + 1])) {
+        index++;
+    }
+    return index;
+}
+//旋转得到的新坐标
+//point是在原来坐标系内的坐标
+//cta 是新坐标系旋转的角度
+//ab 是新坐标系的远点,在原来坐标系中的坐标
+function axis_translate(point, cta, ab) {
+    var newpoint = {};
+    newpoint.x = (point.x - ab.x) * Math.cos(cta) + (point.y - ab.y) * Math.sin(cta);
+    newpoint.y = (ab.x - point.x) * Math.sin(cta) + (point.y - ab.y) * Math.cos(cta);
+    return newpoint;
+}
+//获取flash版本
+function get_flash_version() {
+    var UNDEF = "undefined",
+        OBJECT = "object",
+        SHOCKWAVE_FLASH = "Shockwave Flash",
+        SHOCKWAVE_FLASH_AX = "ShockwaveFlash.ShockwaveFlash",
+        FLASH_MIME_TYPE = "application/x-shockwave-flash",
+        EXPRESS_INSTALL_ID = "SWFObjectExprInst";
+    var playerVersion = [0, 0, 0];
+    var d = null;
+    if (typeof navigator.plugins != UNDEF && typeof navigator.plugins[SHOCKWAVE_FLASH] == OBJECT) {
+        d = navigator.plugins[SHOCKWAVE_FLASH].description;
+        if (d && !(typeof navigator.mimeTypes != UNDEF && navigator.mimeTypes[FLASH_MIME_TYPE] && !navigator.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) {
+            plugin = true;
+            d = d.replace(/^.*\s+(\S+\s+\S+$)/, "$1");
+            playerVersion[0] = parseInt(d.replace(/^(.*)\..*$/, "$1"), 10);
+            playerVersion[1] = parseInt(d.replace(/^.*\.(.*)\s.*$/, "$1"), 10);
+            playerVersion[2] = /[a-zA-Z]/.test(d) ? parseInt(d.replace(/^.*[a-zA-Z]+(.*)$/, "$1"), 10) : 0;
+        }
+    } else if (typeof window.ActiveXObject != UNDEF) {
+        try {
+            var a = new ActiveXObject(SHOCKWAVE_FLASH_AX);
+            if (a) { // a will return null when ActiveX is disabled
+                d = a.GetVariable("$version");
+                if (d) {
+                    ie = true; // cascaded feature detection for Internet Explorer
+                    d = d.split(" ")[1].split(",");
+                    playerVersion = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
+                }
+            }
+        } catch (e) {
+            return playerVersion;
+        }
+    }
+    return playerVersion;
+}
+//是否支持websocket
+function support_websocket() {
+    var version = get_flash_version();
+    if (version[0] >= 9) {
+        return true;
+    }
+    if (window.WebSocket) {
+        return true;
+    }
+    return false;
+}
+/*未使用
+function init_websocket()
+{
+    if (window.WebSocket) {
+        return true;
+    }
+    if (get_flash_version()[0] >= 9)
+    {
+        include(__baseurl__ + "js/swfobject.js");
+        include(__baseurl__ + "js/web_socket.js");
+        return true;
+    }
+    return false;
+}*/
+//设置宽度
+function set_width(obj, w) {
+    if (typeof obj.get == "function" && obj.get(0)) {
+        obj.get(0).width = w;
+        obj.width(w);
+    } else {
+        obj.width = w;
+    }
+}
+//设置高度
+function set_height(obj, h) {
+    // if(h>1){
+    //    if(obj.attr('id')=="plot_canvas_00"||obj.attr('id')=="plot_canvas_01"||obj.attr('id')=="plot_canvas_02"){
+    //         h=h-60;
+    //     } 
+    // }
+    
+    if (typeof obj.get == "function" && obj.get(0)) {
+        obj.get(0).height = h;
+        obj.height(h);
+    } else {
+        obj.height = h;
+    }
+}
+/*未使用
+function __indicator__name__change(obj)
+{
+    indicator.load(indicator.tab, $(obj).val());
+}*/
+//从search位置开始
+function start_with(search, obj) {
+    return obj.indexOf(search) == 0
+}
+//HTML5StockChartAPI函数
+function HTML5StockChartAPI(id) {
+    this.isinit = false;
+    this.id = id;
+    this.tplParams = {};
+    this.container = $("#" + this.id);
+    // this.container.html( __tpl__base__ + __tpl__indwin__);
+    this.config = Config.getInstance();
+
+    //console.log(DataReaderTrendLine.getYminmax()); 
+    this.option = {
+        debug: __debug__,
+        jsdebug: __javascript_debug__,
+        datasource: __datasource__,
+        datafile: __datafile__,
+        pair: __symbol__list__,
+        runtime_load: __runtime_load__,
+        staticChat: __static__,
+        startTime: __start_time__,
+        "toolbar.isenable": false,
+        plot_area: $("#plot_container"),
+        ind: [this.config.mainName]
+    };
+    if (!this.read('model')) this.write("model", "active");
+    var _this = this;
+    if (window["FlashCanvas"]) {
+        FlashCanvas.ready = function() {
+            FlashCanvas.init();
+            _this.init();
+        }
+    } else {
+        $(document).ready(function() {
+            _this.init();
+        });
+    }
+}
+
+HTML5StockChartAPI.prototype.setTPLParams = function(key, val) {
+    this.tplParams[key] = val;
+}
+
+HTML5StockChartAPI.prototype.init = function() {
+    if (this.isinit) {
+        return;
+    }
+    this.isinit = true;
+    
+    this.controller = new Controller(this);
+    if (!is_undefined(this.option["controller.staticChat"])) {
+        this.controller.staticChat = this.option["controller.staticChat"];
+    }
+    //为了兼容以前的版本,添加了这个全局变量
+    /*this.indicator = indicator = new WinAjax("indicator.add", "指标管理", 700, 500,this);
+    this.indicator.createWindow("__indicator__");
+
+    this.order = order = new WinAjax("order.order","订单",320,240,this);
+    this.order.createWindow("__order__");*/
+    //////////////////////////
+    if (this.c && this.p) {
+        this.setPair(this.c, this.p);
+    }
+
+}
+
+HTML5StockChartAPI.prototype.destroyed=function(){
+     this.isinit = false;
+      this.controller.deinit();
+      this.controller = null;
+}
+
+HTML5StockChartAPI.prototype.setStaticChart = function(isstatic) {
+    //alert(typeof isstatic === "undefined");
+    var p = (typeof isstatic === "undefined") ? true : isstatic;
+    if (this.isinit) {
+        this.controller.staticChat = p;
+    } else {
+        this.set("controller.staticChat", p);
+    }
+
+}
+
+HTML5StockChartAPI.prototype.setSymbolList = function(pair) {
+    return this.set("pair", pair);
+}
+
+HTML5StockChartAPI.prototype.setIndicatorConf = function(indicator) {
+    if (typeof indicator !== "string") {
+        indicator = indicator.join(":");
+    }
+    indicator = indicator.toLowerCase();
+    this.write("ind", indicator);
+    this.set("ind", indicator);
+    // this.isinit=false;
+    if (this.isinit) {
+        window.location.reload();
+        // this.isinit = false;
+        // this.controller.deinit();
+        // this.controller = null;
+        // this.isinit = false;
+        // this.init();
+    }
+}
+
+HTML5StockChartAPI.prototype.initSignal = function() {
+    var signal_id = this.read("signal");
+    //固定一个策略
+    if (signal_id < 4) {
+        signal_id = 5;
+    }
+    if (signal_id) {
+        this.config.Global.signal = signal_id;
+    } else {
+        signal_id = this.config.Global.signal;
+    }
+    return signal_id;
+}
+
+HTML5StockChartAPI.prototype.setModel = function(model) {
+    this.write("model", model);
+    this.config.Global.app_model = model;
+    if (this.isinit) {
+        window.location.href = "";
+    }
+}
+
+HTML5StockChartAPI.prototype.setSignal = function(signal_id) {
+    this.write("signal", signal_id);
+    this.config.Global.signal = signal_id;
+    if (this.isinit) {
+        window.location.href = "";
+    }
+}
+
+HTML5StockChartAPI.prototype.set = function(name, value) {
+    this.option[name] = value;
+    return this;
+}
+
+HTML5StockChartAPI.prototype.setPair = function(c, p) {
+    this.c = c;
+    this.p = p;
+    if (!this.isinit) {
+        return;
+    }
+    this.write("symbol", c);
+    $.cookie("symbol",c);
+    $.cookie("period",p)
+    // sessionStorage.setItem('period',p);
+    this.write("period", p);
+    
+    this.controller.set(this.c, this.p);
+    if (typeof this.option["paircb"] === "function") {
+        this.option["paircb"](this.c, this.p);
+    }
+    // console.log(DataReaderbdensity.prototype.getYminmax());
+}
+
+HTML5StockChartAPI.prototype.toolbarEnable = function() {
+    this.set("toolbar.isenable", true);
+    if (!this.isinit) {
+        return;
+    }
+    this.controller.toolbar.enable();
+
+}
+
+HTML5StockChartAPI.prototype.toolbarDisable = function() {
+    this.set("toolbar.isenable", false);
+    $("#toolbar").hide();
+    if (!this.isinit) {
+        return;
+    }
+    this.controller.toolbar.disable();
+}
+
+HTML5StockChartAPI.prototype.read = function(name) {
+    return FzmCookie.read(name);
+}
+
+HTML5StockChartAPI.prototype.write = function(name, data) {
+    if (typeof data === "string") {
+        return FzmCookie.write(name, data, 10000);
+    }
+    console.error("cookie write error");
+    return false;
+}
+
+HTML5StockChartAPI.prototype.initInd = function(def) {
+    var name = this.read("ind");
+    if (!name) {
+        name = def;
+    }
+    this.setInd(name);
+}
+
+HTML5StockChartAPI.prototype.setConfig = function(key, val) {
+    return this.config.set(key, val);
+}
+
+HTML5StockChartAPI.prototype.setInd = function(name) {
+    if (name == "tick_price" || name.indexOf("tick_source") === 0) {
+        this.p = "TICK";
+    } else {
+        if (this.p == "TICK") {
+            this.p = "H1";
+             $.cookie('period','H1');
+            // sessionStorage.setItem('period','H1');
+        }
+    }
+    this.setIndicatorConf(name);
+}
+
+HTML5StockChartAPI.prototype.clearCookie = function() {
+    this.write("period", "");
+    $.cookie('period','H1');
+    this.write("ind", "");
+}
+
+HTML5StockChartAPI.prototype.initPair = function(c, p, ignore) {
+    var symbol = this.read("symbol");
+    symbol = symbol ? symbol : c;
+    var period = this.read("period");
+    period = period ? period : p;
+    if (period == ignore) {
+        period = "H1";
+        $.cookie('period','H1');
+    }
+    this.setPair(symbol, period);
+}
+
+
+//坐标轴的设计按照通用配置的形式来设计。
+//
+//输入: 
+//
+//1. POINT(SCALE):  描点形式:需要,model读出的数据.
+//2. EXTEND(NOMAL): 扩展的方式,需要指定扩展对应的数据。
+//3. MIAN:  需要提供主图的数据
+//4. SCALE: 按照比例进行,这个需要提供的是最大值,最小值
+//
+//坐标值的密集阵值:一般指定多小像素内一个坐标,然后根据高度计算大概需要多少个坐标。
+//但是这个值不是精确的,而是有弹性的,为了计算一个最佳的坐标值。
+//
+//设计流程:
+//
+//首先是:[point 还是 scale]
+//
+//如果是scale 给出最大值,最小值 就可以进行计算了。调用 Axis_Scale
+//
+//如果是point: 那么闲判断主图有没有计算,如果没有计算,那么先计算主图。
+//
+//计算主图的过程是这样的:闲判断是否需要 扩展,如果需要扩展,那么
+//按照主图数据,进行扩展。这个时候,要知道主图是 p是多少。这样就可以扩展了。
+//
+//Axis_ExtendByMain
+//Axis_ExtendByTime
+//
+//主图扩展完成后(注意,这里要把Y的数据进行扩展,所以,要计算X的坐标,再计算Y的坐标),
+//那就计算扩展后主图的坐标。扩展完成后调用 Axis_Point, 进行描点处理。
+//
+//对于副图。
+//如果配置不是按照主图进行绘制的,那么直接报错。暂时不支持这样的情况。
+//
+//如果是按照主图进行扩展,那么
+//调用 Axis_ExtendByMain 扩展。
+//
+//最后调用 Axis_PointBYMain 获取坐标数据。
+//
+//
+//main 是主图坐标,因为附图可能和主图相关,所以要加这个值。
+//对于主图的坐标系,这个main值是null
+function Axis(main) {
+    this.main = main;
+    this.config = Config.getInstance();
+}
+
+Axis.POINT = 1;
+Axis.MAIN = 1 << 1;
+Axis.TIME = 1 << 2;
+Axis.BIG2SMALL = 1 << 3;
+Axis.BIG2BIG = 1 << 4;
+Axis.SCALE = 1 << 5;
+Axis.CUSTOM = 1 << 6;
+Axis.CUSTOM_DATA = 1 << 7;
+
+Axis.prototype.setViewConfig = function(viewconfig) {
+    if (viewconfig) this.viewconfig = viewconfig;
+}
+
+Axis.prototype.setData = function(data) {
+    if (data) {
+        this.data = data;
+        this.c = data.c;
+        this.p = data.p;
+        $.cookie('period',data.p);
+    }
+}
+
+Axis.prototype.clearData = function() {
+    this.data = null;
+    this.viewconfig = null;
+}
+
+Axis.prototype.getData = function() {
+    this.calc();
+    var ret = { data: this.data, axis: this.viewconfig };
+    return ret;
+}
+
+Axis.prototype.calc = function() {
+    //viewconfig 按canvas的ID进行组织,主图默认在序号为 0 的配置里面
+    //按照数据,现在刚刚传入的数据,每个图还是有关系的.我们要分离这样的关系。
+    //
+    //1. 读取每个 指标 计算坐标的标准配置
+    //2. 获取最大最小指。
+    //
+    //计算主图
+    var maxY = -Infinity;
+    var maxX = -Infinity;
+    var minX = Infinity;
+    var minY = Infinity;
+    for (var j = 0; j < this.viewconfig.plot.length; j++) {
+        var name = this.viewconfig.plot[j];
+        //判断是否参与计算
+        var vc = this.config.Global.View[name];
+        if (name != this.config.mainName && typeof vc["disable_axis_area"] !== 'undefined' && vc["disable_axis_area"]) {
+            continue;
+        }
+        if (this.data[name].maxX > maxX) maxX = this.data[name].maxX;
+        if (this.data[name].minX < minX) minX = this.data[name].minX;
+        if (this.data[name].maxY > maxY) maxY = this.data[name].maxY;
+        if (this.data[name].minY < minY) minY = this.data[name].minY;
+    }
+    this.viewconfig.x.max = maxX;
+    this.viewconfig.x.min = minX;
+    this.viewconfig.y.max = maxY;
+    this.viewconfig.y.min = minY;
+    if (this.main == null) {
+        this.calcMain();
+        this.main = this;
+    }
+    for (j = 0; j < this.viewconfig.plot.length; j++) {
+        name = this.viewconfig.plot[j];
+        if (name == this.config.mainName) continue;
+        this.calcOne(name);
+    }
+}
+
+Axis.prototype.calcOne = function(name) {
+    this.getAxis(name, "x");
+    this.getAxis(name, "y");
+}
+
+Axis.prototype.calcMain = function() {
+    //下面的数据时扩展过的数据,这样。
+    this.getAxisMainX();
+    this.getAxis(this.config.mainName, "y");
+}
+
+Axis.prototype.getAxis = function(name, tag) {
+    //tag 标记是 x 轴还是 y轴,取数据的时候用的到。
+    var data = this.data[name][tag];
+    if (!data || data.length == 0) return;
+    var plot = this.viewconfig[tag]; //在tag下面的配置
+    var axisconfig = this.config.Global.Axis[name][tag];
+    var unit = this.data[name][tag + "unit"];
+
+    if (axisconfig & Axis.POINT) {
+        if (plot.axis) debug("plot axis has set.");
+        var data = this.pointAxisValue(data, plot.beg, plot.end, this.viewconfig.one, plot.n, axisconfig);
+        plot.axis = data.axis;
+        plot.axis_option = {};
+        plot.axis_option.style = axisconfig;
+        plot.axis_option.unit = unit;
+
+        this.viewconfig[tag] = plot;
+        this.data[name][tag] = data.data;
+        //描点,计算坐标轴的值
+    } else if (axisconfig & Axis.MAIN) {
+        //通过主图计算
+        this.pointByMain(name); //这个不需要什么配置了
+        //不需要生成什么坐标的信息,坐标在主图中生成。
+    } else if (axisconfig & Axis.SCALE) {
+        //通过比例进行计算,每个都要生成坐标的信息。
+        if (!plot.axis) {
+            //计算坐标轴的值[比例计算的坐标轴]
+            var scalevalue = this.getScaleValue(plot.min, plot.max, unit, plot.n, axisconfig);
+            var data = this.scaleAxisValue(data, scalevalue, plot.beg, plot.end, axisconfig);
+            plot.axis = data.axis;
+            plot.axis_option = {};
+            plot.axis_option.style = axisconfig;
+            plot.axis_option.unit = unit;
+            this.viewconfig[tag] = plot;
+            this.data[name][tag] = data.data;
+        } else {
+            if (axisconfig & Axis.CUSTOM) {
+                this.data[name][tag] = this.customTranslate(name, data, plot.axis);
+            } else {
+                this.data[name][tag] = this.lineTranslate(data, plot.axis);
+            }
+        }
+    }
+    if (axisconfig & Axis.CUSTOM_DATA) {
+        if (this.viewconfig.x.axis && this.viewconfig.y.axis) {
+            for (var type in this.data[name].data) {
+                this.data[name].data[type].x = this.lineTranslate(this.data[name].data[type].x, this.viewconfig.x.axis);
+                this.data[name].data[type].y = this.lineTranslate(this.data[name].data[type].y, this.viewconfig.y.axis);
+            }
+        }
+    }
+}
+
+Axis.prototype.customTranslate = function(name, data, axis) {
+    var param = this.lineGetAxisParam(axis);
+    if (!param) {
+        return data;
+    }
+    var a = param[0];
+    var b = param[1];
+    if (name == "profit" || start_with("profit|", name)) {
+        for (var i = 0; i < data.length; i++) {
+            for (var j = 0; j < data[i].length; j++) {
+                data[i][j][1] = a * data[i][j][1] + b;
+            }
+        }
+        return data;
+    } else if (name == "kshapetest" || start_with("kshapetest|", name)) {
+        for (var i = 0; i < data.length; i++) {
+            data[i][0] = a * data[i][0] + b;
+        }
+        return data;
+    } else if (name == "fractals" || start_with("fractals|", name) || name == "advfractals" || start_with("advfractals|", name)) {
+        for (var i = 0; i < data.length; i++) {
+            data[i][1] = a * data[i][1] + b;
+        }
+        return data;
+    } else if (name == "bolling_desity") {
+        for (var i = 0; i < data.length; i++) {
+            for (var j = 0; j < data[i].length; j += 2) {
+                if (data[i][j] == -1) {
+                    continue;
+                }
+                data[i][j] = a * data[i][j] + b;
+            }
+        }
+        return data;
+    }
+    if (name == "wdesity") {
+        for (var i = 0; i < data.length; i++) {
+            for (var j = 0; j < data[i].length; j++) {
+                if (data[i][j] == 0) {
+                    data[i][j] = 0;
+                    continue;
+                }
+                data[i][j] = a * data[i][j] + b;
+            }
+        }
+        return data;
+    } else if (name == "trend_line") {
+        //计算曲线的斜率
+        var axis = this.viewconfig.y.axis;
+        dy = -(axis[0].key - axis[1].key) / (axis[0].value - axis[1].value);
+        dx = this.viewconfig.one;
+        var group = {};
+        for (i = 0; i < data.length; i++) {
+            var g = data[i][4];
+            if (g > 0) {
+                if (typeof group[g] === "undefined") {
+                    group[g] = 0;
+                } else {
+                    group[g] += 0;
+                }
+            } else {
+                group[g] = 0;
+            }
+            //斜率
+            data[i][1] = dy * (data[i][1] - data[i][0]) / dx
+                //位置
+            data[i][0] = a * data[i][0] + b + group[g];
+            data[i][7] = a * data[i][7] + b + group[g];
+            data[i][6] = this.main.axisMap[data[i][6]];
+        }
+        return data;
+    }
+}
+
+//beg 是坐标的开始值,这里的data必须是一维数组。
+Axis.prototype.pointAxisValue = function(data, beg, end, one, n, axisconfig) {
+    var index = 0;
+    var j = 0;
+
+    var data_axis = [];
+    var axis = [];
+
+    var total_pixel = beg - end;
+    var plot_number = Math.ceil(total_pixel / one);
+    if (n > plot_number) {
+        var mod = 1;
+    } else {
+        var mod = Math.round(plot_number / n);
+    }
+    //这里还有的一个问题是:大坐标表示小数据,还是大坐标,表示大数据,默认是大坐标表示大数据
+    if (axisconfig & Axis.BIG2SMALL) { //小的排在前面
+        if (data.length > 1 && data[data.length - 1] < data[0]) data = data.reverse();
+    }
+    for (var i = 0; i < data.length; i++) {
+        data_axis[i] = beg;
+        if (i % mod == 0) {
+            axis[j] = { key: beg, value: data[i] };
+            j++;
+        }
+        beg -= one;
+    }
+    var ret = { data: data_axis, axis: axis };
+    return ret;
+}
+
+Axis.prototype.scaleAxisValue = function(data, scalevalue, beg, end, axisconfig) {
+    var data_axis = [];
+    var axis = [];
+    if (!scalevalue) {
+        debug("error scalevalue.");
+        return { data: [], axis: [] };
+    }
+    var n = scalevalue.length;
+    //坐标大小问题,1. 大的坐标表示小的数字,2. 小的坐标表示大的数字
+    if (axisconfig & Axis.BIG2SMALL) { //小的排在前面
+        if (n > 1 && scalevalue[n - 1] < scalevalue[0]) {
+            scalevalue = scalevalue.reverse();
+        }
+    } else { //Axis.BIG2BIG
+        if (n > 1 && scalevalue[n - 1] > scalevalue[0]) {
+            scalevalue = scalevalue.reverse();
+        }
+    }
+    var one = Math.floor((beg - end) / (n - 1));
+    var index = 0;
+    while (beg >= end && index < n) {
+        axis.push({ key: beg, value: scalevalue[index++] });
+        beg -= one;
+    }
+    //下面开始转换数据,这里的data可以是一维,也可以是二维
+    data = this.lineTranslate(data, axis);
+    var ret = { data: data, axis: axis };
+    return ret;
+}
+
+Axis.prototype.getXValue = function(x, mode, axis) {
+    /*if (!axis) axis = this;
+    var _axis = axis.viewconfig.x.axis; //从小到大排列
+    
+    */
+    //查找x的值
+    var current = null;
+    var offset = null;
+    var min = Infinity;
+    for (var time in this.main.axisMap) {
+        var pos = this.main.axisMap[time];
+        if (typeof pos == "number") {
+            offset = Math.abs(pos - x);
+            if (offset < min) {
+                min = offset;
+                current = time;
+            }
+        }
+    }
+    return parseInt(current);
+    //return this.getValue(x, _axis, mode);
+}
+
+Axis.prototype.getValue = function(key, axis, mode) {
+    if (typeof axis === "undefined") return false;
+    var index = this.findNear(axis, key);
+    if (mode == PlotGrid.NEAR) {
+        return axis[index].value;
+    } else if (mode == PlotGrid.INTERPOLATION) {
+        return this.getInterpolation(key, index, axis);
+    }
+    return false;
+}
+
+Axis.prototype.getInterpolation = function(find, index, axis) {
+    //寻找两个差值点:
+    var newaxis = [];
+    var start, end;
+    if (axis.length <= 1) {
+        return axis[index].value;
+    }
+    if (index == 0) {
+        start = 0;
+        end = 1;
+    } else if (index == axis.length - 1) {
+        start = axis.length - 2;
+        end = axis.length - 1;
+    } else {
+        if (axis[index].key > find) {
+            start = index;
+            end = index + 1;
+        } else {
+            start = index - 1;
+            end = index;
+        }
+    }
+    newaxis.push({ key: axis[start].value, value: axis[start].key });
+    newaxis.push({ key: axis[end].value, value: axis[end].key });
+    return this.lineTranslate(find, newaxis, true);
+}
+
+Axis.prototype.findNear = function(axis, find) {
+    for (var i = 0; i < axis.length; i++) {
+        if (axis[i].key < find) { // find 在 i 和 i - 1 之间
+            if (i == 0) return 0;
+            if (find - axis[i].key < axis[i - 1].key - find) {
+                return i;
+            } else {
+                return i - 1;
+            }
+        }
+    }
+    return axis.length - 1;
+}
+
+Axis.prototype.getYValue = function(y, mode, axis) {
+    if (!axis) axis = this;
+    var _axis = axis.viewconfig.y.axis; //从小到大排列
+    return this.getValue(y, _axis, mode);
+}
+
+Axis.prototype.getX = function(data) {
+    return this.lineTranslate(data, this.viewconfig.x.axis);
+}
+
+Axis.prototype.getY = function(data) {
+    return this.lineTranslate(data, this.viewconfig.y.axis);
+}
+
+Axis.prototype.lineTranslate = function(data, axis, noround) {
+    if (axis.length == 0) return data;
+    if (axis.length == 1) {
+        var a = 0;
+        var b = axis[0].key;
+    } else {
+        var a = (axis[0].key - axis[axis.length - 1].key) / (axis[0].value - axis[axis.length - 1].value);
+        var b = axis[0].key - a * axis[0].value;
+    }
+    var is1d = is_array(data);
+    var is2d = is_array(data[0]);
+    if (is1d) {
+        for (var i = 0; i < data.length; i++) {
+            if (is2d) {
+                for (var j = 0; j < data[i].length; j++) {
+                    data[i][j] = Math.round(a * data[i][j] + b);
+                }
+            } else {
+                data[i] = Math.round(a * data[i] + b);
+            }
+        }
+    } else {
+        if (noround) {
+            data = a * data + b;
+        } else {
+            data = Math.round(a * data + b);
+        }
+    }
+    return data;
+}
+
+Axis.prototype.lineGetAxisParam = function(axis) {
+    if (axis.length == 0) return false;
+    if (axis.length == 1) {
+        var a = 0;
+        var b = axis[0].key;
+    } else {
+        var a = (axis[0].key - axis[axis.length - 1].key) / (axis[0].value - axis[axis.length - 1].value);
+        var b = axis[0].key - a * axis[0].value;
+    }
+    return [a, b];
+}
+
+Axis.prototype.getScaleValue = function(start, end, unit, n, axis_style) {
+
+    //浮动:这个n是建议的数目
+    var number = Math.ceil((end - start) / unit) / n;
+    if (number <= 0) {
+        if (start == end) {
+            var vals = [start];
+            return this.standarAxisValue(vals, start, end, axis_style);
+        }
+        return null;
+    }
+    var closest;
+    if (number <= 1) {
+        closest = unit;
+    } else {
+        var low = Math.pow(10, Math.floor(Math.log(number) / Math.LN10));
+        var high = low * 10;
+        var i = 0;
+        if (low >= 10) {
+            if (axis_style & Axis.TIME) {
+                var lookup = [1, 1.5, 2, 3.0, 4.5, 6.0, 10];
+            } else {
+                var lookup = [1, 1.5, 2, 2.5, 4, 5, 8, 10];
+            }
+            for (i = 0; i < lookup.length; i++) {
+                lookup[i] *= low;
+            }
+        } else {
+            if (axis_style & Axis.TIME) {
+                var lookup = [1, 2, 3, 4, 6, 10];
+            } else {
+                var lookup = [1, 2, 4, 5, 8, 10];
+            }
+        }
+        var min_value = Number.MAX_VALUE;
+        var min_index = 0;
+        for (i = 0; i < lookup.length; i++) {
+            var tmp = Math.abs(lookup[i] - number);
+            if (min_value > tmp) {
+                min_value = tmp;
+                min_index = i;
+            }
+        }
+        var closest = unit * lookup[min_index];
+    }
+    var minindex = Math.floor(start / closest);
+    var maxindex = Math.ceil(end / closest);
+    vals = [];
+    for (var j = minindex; j <= maxindex; j++) {
+        vals.push(j * closest);
+    }
+    return this.standarAxisValue(vals, start, end, axis_style);
+}
+
+Axis.prototype.standarAxisValue = function(axis, beg, end, axis_style) {
+    var abeg = axis[0];
+    var aend = axis[axis.length - 1];
+    var delta = 0;
+    if (axis_style & Axis.FIX_BEG) {
+        delta = abeg - beg;
+    } else if (axis_style & Axis.FIX_END) {
+        delta = aend - end;
+    }
+    for (var i = 0; i < axis.length; i++) {
+        axis[i] -= delta;
+    }
+    //下面开始计算坐标的值
+    return axis;
+}
+
+Axis.prototype.getAxisMainX = function() {
+    //计算之前复制一份:
+    var x = this.data[this.config.mainName].x;
+    this.getAxis(this.config.mainName, "x");
+    //这个是X轴坐标的映射,其他的坐标要靠这个来计算。
+    this.axisMap = {};
+    for (var i = 0; i < x.length; i++) {
+        this.axisMap[x[i]] = this.data[this.config.mainName].x[i];
+    }
+    //这样时间和坐标成了一一对应
+}
+
+Axis.prototype.pointByMain = function(name) {
+    //这里主要去除一些毛刺数据,所以统一又处理了一次。
+    //这个部分,以后如果要调节性能,还要进行修改。
+    var x = [];
+    var y = [];
+    var index = 0;
+    var data = this.data[name];
+    for (var i = 0; i < data.x.length; i++) {
+        var item = this.main.axisMap[data.x[i]];
+        if (item) {
+            //查找到坐标,那么就采用这个坐标
+            x[index] = item;
+            y[index] = data.y[i];
+            index++;
+        } else {
+            if (typeof item === "undefined") {
+                continue;
+            } else {
+                x[index] = item;
+                y[index] = data.y[i];
+                index++;
+            }
+        }
+    }
+    this.data[name].x = x;
+    this.data[name].y = y;
+}
+
+//配置画图的属性
+//1. 类映射
+//绘制图形的时候,是根据绘图的名称,来绘制的。
+//main 是主图,这个是固定的名字。
+//其他的是指标图,用各自的名字。每个画图对象通过两个方面来控制。
+
+//1. 是数据读取部分,我们把缓存在内存的数据看成是一个数据库,这个读取
+//虽然是千篇一律,但是还是有规律可循。
+//
+//2. 是数据的显示控制,我们会根据plotset的情况,最后转换成坐标的值。通过
+//这个坐标的值,来绘制不同的图形。
+//
+//3. 还有一个对象控制数据保存的过程。比如,数据下载怎么处理,
+//   下载后怎么保存,新数据怎么处理,新数据怎么保存等问题。
+//   处理读写数据的模块应该是要和 数据更新模块分离的。
+//
+//update by fangxiao from 2016/6/29 17:17
+function Config() {
+    //浏览器测试
+    this.getBrowserInfo();
+    this.name = "Config";
+    this.mainName = "main";
+    this.main = { reader: DataReaderCandle, writer: DataWriterCandle, plot: PlotCandle, data: DataReader.EXTEND, downdata: 1, newdata: 1 };
+    //扩展数据。必须有扩展的接口。否则会直接忽略这个选项。
+    //通过主图读取数据,主图会传入一个时间范围,然后通过函数读取数据,通过主图扩展数据
+    this.volumes = { reader: DataReadervolumes, writer: DataWriter, plot: Plotvolumes };
+    this.volumes2 = { reader: DataReadervolumes2, writer: DataWriter, plot: Plotvolumes2 };
+   // console.log(""+DataReadervolumes.getYminmax);
+    this.ma = { reader: DataReaderIndicatorsMa, writer: null, plot: PlotLine };
+    this.macd = { reader: DataReaderIndicatorsMacd, writer: null, plot: PlotMacd };
+    this.bolling = { reader: DataReaderIndicatorsBolling, writer: null, plot: PlotBolling };
+    this.kdj = { reader: DataReaderIndicatorsKDJ, writer: null, plot: PlotBolling };
+    //this.order = {reader:DataReaderIndicatorsOrder,write:null,plot:PlotOrder};
+    this.Global = {};
+    //这个DataWriter 的基类处理通用的读写。
+    this.Global.downloadCount = 600;
+    this.Global.maxStoreChunk = 20; // store max = 5 * this.Global.downloadCount 
+    this.Global.lowMark = 300;
+    this.Global.Interval = 20;
+    this.Global.newDisable = false;
+    this.Global.boxwidth = 1;
+    this.Global.trend_line_selected = [];
+    this.Global.xunit = {
+        //  YMD:1440,
+        //S5:1/12,
+        M1: 1,
+        M2: 2,
+        M3: 3,
+        M3: 4,
+        M5: 5,
+        M15: 15,
+        M30: 30,
+        H1: 60,
+        H2: 120,
+        H4: 240,
+        D1: 1440,
+        W1: 10080,
+        MN1: 4320
+    };
+    this.Global.styleName = { "hx": "中国经典", "mt": "MT4" };
+    //时间选择坐标的时间格式
+    this.Global.timeformat = {
+        YMD: "Y-m-d",
+        TICK: "i:s.u",
+        //S5:"m-d H:i:s",
+        M1: "m-d H:i",
+        M2: "m-d H:i",
+        M3: "m-d H:i",
+        M5: "m-d H:i",
+        M15: "m-d H:i",
+        M30: "m-d H:i",
+        H1: "m-d H:i",
+        H2: "m-d H:i",
+        H4: "m-d H:i",
+        D1: "m-d",
+        W1: "m-d",
+        MN1: "m-d"
+    };
+    this.Global.ajaxloadingID = "#loading";
+    this.Global.yunit = {};
+    this.Global.yunit.default_value = 0.00001;
+    this.Global.maxstep = 1 * 3600; //最大没有数据的时间
+    this.Global.maxCanvasCount = 8;
+    this.Global.forcePoll = true;
+    if (!this.Global.forcePoll && support_websocket()) {
+        this.Global.modelName = ModelShortWS;
+        this.Global.WSHost = __broadcast_server_active__;
+        this.Global.WSPort = "2003";
+        this.Global.pingTime = 5; //如果5s没有数据,就ping一下
+        this.Global.maxNOData = 10; //如果10s内都没有数据, 那么就close掉。//最好是ping time 的整数倍。也就是 10s 以上
+    } else {
+        this.Global.modelName = ModelShortPoll;
+    }
+    if (FzmCookie.read('model') == 'passive_mode') {
+        this.Global.modelName = ModelNode;
+    }
+    this.Global.viewName = View;
+    this.Global.canvasID = "#plot_area";
+    this.Global.canvasIDPerfix = "plot_canvas_";
+    this.Global.PollInterval = 3000; //30ms 判断一次
+    this.Global.maxConnectAliveTime = 12; //轮询的链接最多存活的时间
+    this.Global.DataAPIDB ="https://kdata.fxee.com/kdata?datafile=" + __datafile__;
+    if (__dbreset__) {
+        this.Global.DataAPIDB += "&dbreset=" + __dbreset__
+    }
+    this.Global.DataAPIUpload = "static.php?datafile=" + __datafile__;
+    if (__dbreset__) {
+        this.Global.DataAPIUpload += "&dbreset=" + __dbreset__
+    }
+    if (__datasource__ == "db") {
+        this.Global.DataAPI = this.Global.DataAPIDB; //一定要加上这个callbac=?否则json无法调用
+    } else if (__datasource__ == "upload") {
+        this.Global.DataAPI = this.Global.DataAPIUpload; //一定要加上这个callbac=?否则json无法调用
+    }
+    if (__refererhost__ != __apihost__) {
+        this.Global.PollMode = "jsonp";
+    } else {
+        this.Global.PollMode = "json";
+    }
+    if (this.Global.PollMode == "jsonp") {
+        /* $.ajaxSetup({ 
+           //'jsonp' : false,
+           'jsonpCallback': "_jsonp_"
+        });
+        */
+    }
+    //view 模块相关的配置
+    this.Global.View = {
+        main: { NXPixel: 100, NYPixel: 50, sep: 0 },
+        sin: { NXPixel: 100, NYPixel: 50, sep: 0 },
+        cos: { NXPixel: 100, NYPixel: 50, sep: 0 },
+        tick_source: { NXPixel: 100, NYPixel: 50, sep: 0 },
+        profit_line: { NXPixel: 100, NYPixel: 50, sep: 0 },
+        volumes: { sep: 1, height: 0.2 },
+        volumes2: { sep: 1, height: 0.2 },
+        ma: { sep: 0, height: 0.5 },
+        //order:{sep:0,height:0.5},
+        macd: { sep: 1, height: 0.2 },
+        bolling: { sep: 0, height: 0.5 },
+        kdj: { sep: 1, height: 0.2 },
+    };
+
+    this.Global.TPL = {
+        signal: 'main:profit',
+        mac2: 'main:volumes:volumes2:ma|main|10|color=red:ma|main|20|color=green:ma|main|50|color=yellow:ma|main|100|color=white:macd|main|12,26,9|color=white-lime:kdj|main|9|color=Red-blue-green:',
+        mac: "main:volumes",
+        bty: "main:volumes",
+        eth: "main:volumes",
+        ma: 'ma|main|10|color=red:ma|main|20|color=green:ma|main|50|color=yellow:ma|main|100|color=white:',
+        volumes:'volumes:',
+        macd: 'macd|main|12,26,9|color=white-lime:',
+        bolling: 'bolling|main|20,2|color=green-green-green:',
+        kdj: 'kdj|main|9|color=Red-blue-green:',
+        ssi: "main:easyforex:fxtrade:" +
+            "ma|main|10|color=red:" +
+            "ma|easyforex|10|color=red:" +
+            "ma|fxtrade|10|color=red:" +
+            "ma|main|50|color=yellow:" +
+            "ma|easyforex|50|color=yellow:" +
+            "ma|fxtrade|50|color=yellow:" +
+            "ma|main|100:" +
+            "ma|easyforex|100:" +
+            "ma|fxtrade|100:" +
+            "matrend|main|10,20,30,50|color=red:" +
+            "<matrend|main|50,80,120,180|color=yellow:" +
+            "matrend|easyforex|10,20,30,50|color=red:" +
+            "<matrend|easyforex|50,80,120,180|color=yellow:" +
+            "matrend|fxtrade|10,20,30,50|color=red:" +
+            "<matrend|fxtrade|50,80,120,180|color=yellow:" +
+            "rsi|easyforex,main|14:" +
+            "rsi|fxtrade,main|14",
+        bolling_desity: "main:bolling_desity:profit",
+        sin_cos: "sin||-10,10,1000|color=red:cos||-10,10,1000|color=green",
+        profit: "profit_line||{ajax_path}|color=red",
+        tick_price: "tick_source||bid-ask/20/1,fxdd,exness,fxcm|fxdd_color=green,fxpro_color=red,exness_color=blue,fxcm_color=yellow,fxdd_flag=true"
+    };
+
+    this.Global.arrow = {};
+    this.Global.arrow[DataWriterProfit.BUY_OPEN] = {
+        height: 15,
+        width: 1,
+        boder: "white",
+        fill: "red",
+        cta: (5 * Math.PI / 4),
+        incta: (5 * Math.PI / 4)
+    };
+    this.Global.arrow[DataWriterProfit.BUY_CLOSE] = {
+        height: 15,
+        width: 1,
+        boder: "pink",
+        fill: "pink",
+        cta: (Math.PI / 4),
+        incta: (Math.PI / 4)
+    };
+    this.Global.arrow[DataWriterProfit.SELL_OPEN] = {
+        height: 15,
+        width: 1,
+        boder: "aqua",
+        fill: "aqua",
+        cta: Math.PI * 7 / 4,
+        incta: Math.PI * 3 / 4
+    };
+    this.Global.arrow[DataWriterProfit.SELL_CLOSE] = {
+        height: 15,
+        width: 1,
+        boder: "yellow",
+        fill: "yellow",
+        cta: Math.PI * 3 / 4,
+        incta: Math.PI * 7 / 4
+    };
+    this.Global.autoScroll = false;
+    this.Global.signal = 3; //default signal id
+    this.Global.WinTplID = "#__wintplid__";
+    //this.Global.WinOrderTplID= "#__winordertplid__";
+    this.Global.WinAPI = "http://" + __apihost__ + "/window.php";
+    //this.Global.WinOrder = "http://" + __orderhost__+"/order";
+
+    //alert(__apihost__);
+    this.Global.Win = {};
+    this.Global.Win.__indicator__ = {
+        tab: {
+            add: "添加指标",
+            manage: "管理指标"
+        }
+    };
+
+    /*this.Global.Win.__order__ ={
+        tab:{
+            order:"下单"
+        }
+    };*/
+    this.Global.style = "hx";
+    this.Global.Model = {};
+    this.Global.timezone = 8;
+    this.Global.overPadding = 3;
+    this.Global.hoverTime = 400;
+    //坐标轴相关的配置
+    //对于坐标轴,有下面的配置模式:
+    //1. 按照比例显示绘制数据。比如Y轴上的数据,为了对比,一般采用这样的方式。
+    //2.
+    //按照点进行排列。从我们外汇的图表来说,还可以把数据扩充成线性连续的模式。
+    //K线图往往会缺乏数据。但是,有些时候,为了对比,或者绘制图形方便,扩充成连续的模式是非常的有必要的。
+    //但是,扩充的时候要非常的注意非交易日的判断。一般来说,非交易日的没有数据的时间一般大于12个小时,而这
+    //在交易日的情况下,基本不可能出现,所以,补充数据可以简单的判断没有数据的时间是否超过12个小时。
+    //
+    //3.
+    //主图可以按照连续的方式扩充。附图的扩充方式增加了一种新的方式,那就是按照主图进行扩充。
+    //
+    //这些主要在搜索坐标数据的时候非常有用。
+    //
+    //
+    this.Global.Axis = {
+        main: { x: Axis.POINT | Axis.TIME, y: Axis.SCALE | Axis.BIG2SMALL }, //扩展,也可以是 AXIS_NOMAL ,
+        sin: { x: Axis.SCALE, y: Axis.SCALE | Axis.BIG2SMALL },
+        cos: { x: Axis.SCALE, y: Axis.SCALE | Axis.BIG2SMALL },
+        tick_source: { x: Axis.SCALE | Axis.TIME, y: Axis.SCALE | Axis.BIG2SMALL | Axis.CUSTOM_DATA },
+        profit_line: { x: Axis.POINT | Axis.TIME, y: Axis.SCALE | Axis.BIG2SMALL },
+        ma: { x: Axis.MAIN | Axis.TIME, y: Axis.SCALE | Axis.BIG2SMALL },
+        macd: { x: Axis.MAIN | Axis.TIME, y: Axis.SCALE | Axis.BIG2SMALL },
+        bolling: { x: Axis.MAIN | Axis.TIME, y: Axis.SCALE | Axis.BIG2SMALL },
+        kdj: { x: Axis.MAIN | Axis.TIME, y: Axis.SCALE | Axis.BIG2SMALL },
+        volumes: { x: Axis.MAIN | Axis.TIME, y: Axis.SCALE | Axis.BIG2SMALL },
+        volumes2: { x: Axis.MAIN | Axis.TIME, y: Axis.SCALE | Axis.BIG2SMALL },
+        //并采用描点法。也就是不按照比例进行计算坐标
+        easyforex: { x: Axis.MAIN | Axis.TIME, y: Axis.SCALE | Axis.BIG2SMALL }, //扩展,以主图的形式。着就是说,
+        //主图没有的点,这个也进行扩展。
+        //order:{x:Axis.MAIN | Axis.TIME, y:Axis.SCALE | Axis.BIG2SMALL| Axis.CUSTOM},
+        profit: { x: Axis.MAIN | Axis.TIME, y: Axis.SCALE | Axis.BIG2SMALL | Axis.CUSTOM }
+    };
+
+    //default grid config
+    this.Global.Grid = {
+        //全局私有配置,这部分配置是每个对象私有的。暂时,我们只支持全局公共配置。
+        private: {
+
+        },
+        //全局公共配置
+        public: {
+            marginTop: [60, 80, 15, 1],
+            margin: [20, 65, 15, 1],
+            paddingX: 30, //绘制坐标的时候,要用到padding的值。
+            paddingY: 0,
+            NX: 10, //推荐的数目,但是按照现行算法可能会产生 50%左右的浮动(8-15)都有可能
+            NY: 10, //推荐的数目,但是按照现行算法可能会产生 50%左右的浮动
+            ledgeLen: 5,
+            crossXMode: PlotGrid.NEAR, //采用寻找最近的点的模式
+            crossYMode: PlotGrid.INTERPOLATION, //采用差值法
+            bgColor: "white",
+            axisColor: "rgb(225, 225, 225)",
+            gridColor: "rgb(128, 0, 0)",
+            fontColor: "rgba(225,225,225,0.4)",
+            font: '',
+            crossX: //光标画x轴线的颜色设置
+            {
+                bg: {
+                    color: "#999",
+                    width: 100,
+                    height: 14
+                },
+                font: "12px Arial",
+                color: "#999",
+                lineColor: "#999",
+                fillcolor:"#0a0a0a"
+            },
+            crossY: {
+                bg: //光标画Y轴线的颜色设置
+                {
+                    color: "#999",
+                    width: 80,
+                    height: 20
+                },
+                font: "12px Arial",
+                color: "#999",
+                lineColor: "#999",
+                fillcolor:"rgb(10,10,10)"
+            },
+            headText: {
+                font: "",
+                color: "rgb(200,0,0)"
+            }
+        },
+        hx: {
+            bgColor   : "#0a0a0a",
+            // background:url('../../../assets/img/Klogo.png') no-repeat,
+            // background-size: 100%,
+            axisColor : "#555",
+            gridColor : "#555",//水平刻度移动端
+            fontColor : "#555",
+            xstyle_axis : 0,
+            xstyle_grid : PlotGrid.NO_GRID,
+            ystyle_axis : 0,
+            ystyle_grid : PlotGrid.NO_GRID,
+            xname : 10,
+            yname : 10,
+            // fontColor : "rgb(110,110,110)",
+            font: "12px Arial"
+        },
+        mt: {
+            bgColor: "black",
+            axisColor: "rgb(225, 225, 225)",
+            gridColor: "LightSlateGray",
+            fontColor: "rgba(225,225,225,0.4)", //字体颜色
+            xstyle_axis: 0,
+            xstyle_grid: PlotGrid.NO_GRID,
+            ystyle_axis: 0,
+            ystyle_grid: 0,
+            xname: 10,
+            yname: 10,
+            fontColor: "rgba(225,225,225,0.4)",
+            font: "1.2em Arial"
+        }
+    };
+    this.Global.volumes = {//volumn颜色修改
+        public: {
+            //lineColor:["red","green"]
+             lineColor:["rgb(176,0,0)","rgb(24,179,75)"]//红涨绿卖
+        }
+    };
+    this.Global.volumes2 = {
+        public: {
+            lineColor: ["rgb(176,0,0)", "rgb(220,43,43)"]
+        }
+    };
+    this.Global.Line = {
+        public: {
+            lineColor: "pink"
+        }
+    };
+    /*this.Global.Order = {
+        public:{
+            fontcolor:["red","aqua" ],
+            linecolor:["red","aqua"],
+            font:"1px Georgia",
+            width : 1,
+            size:20,
+            tradersize:60,
+            midsize:30
+        }
+    };*/
+
+    this.Global.Candle = {
+        public: {
+            box_pixel: 4,
+            space_pixel: 4,
+            close: {
+                bg: {
+                    color: "#ff6600",
+                    fillcolor:"#0a0a0a",
+                    width: 55,
+                    height: 14
+                },
+                type:"price",
+                font: "",
+                color: "#ff6600",
+                lineColor: "rgb(225,225,225)"
+                
+            }
+        },
+
+        mt: {
+            open_big_color: "white",
+            open_small_color: "black",
+            ob_border_color: "rgb(220,43,43)",
+            os_border_color: "rgb(220,43,43)",
+            grid: "mt"
+        },
+        hx: {//红涨绿卖
+            open_big_color : "rgb(24,179,75)",/*红色"rgb(176,0,0)"*/
+            open_small_color : "rgb(10,10,10)",
+            ob_border_color : "rgb(24,179,75)",/*红色*/
+            os_border_color :"rgb(176,0,0)" ,/*绿色"rgb(24,179,75)"*/
+            grid: 'hx'
+        }
+    };
+}
+
+Config.obj = null;
+//单件模式
+Config.getInstance = function() {
+    if (Config.obj == null) {
+        Config.obj = new Config();
+        //以下进行测试
+    }
+    return Config.obj;
+}
+
+Config.prototype.get = function(key, _default) {
+    key = key.split(".");
+    var _tmp = this;
+    if (key.length == 0) return _default;
+    for (var i = 0; i < key.length; i++) {
+        if (typeof _tmp[key[i]] === "undefined") {
+            return _default;
+        } else {
+            _tmp = _tmp[key[i]]
+        }
+    }
+    return _tmp;
+}
+
+Config.prototype.getBrowserInfo = function() {
+    var ua = navigator.userAgent.toLowerCase();
+    var s;
+    if (s = ua.match(/msie\s+([\d.]+)/)) {
+        this.browser = "ie";
+        this.bversion = s[1].split(".");
+    } else if (s = ua.match(/firefox\/([\d.]+)/)) {
+        this.browser = "firefox";
+        this.bversion = s[1].split(".");
+    } else if (s = ua.match(/chrome\/([\d.]+)/)) {
+        this.browser = "chrome";
+        this.bversion = s[1].split(".");
+    } else if (s = ua.match(/opera.([\d.]+)/)) {
+        this.browser = "opera";
+        this.bversion = s[1].split(".");
+    } else if (s = ua.match(/version\/([\d.]+).*safari/)) {
+        this.browser = "safari";
+        this.bversion = s[1].split(".");
+    } else {
+        this.browser = "other";
+        this.bversion = [0, 0, 0];
+    }
+    if (!is_array(this.bversion) || this.bversion.length == 0) {
+        this.bversion = [0, 0, 0];
+    }
+    for (var i = 0; i < this.bversion.length; i++) {
+        this.bversion[i] = parseInt(this.bversion[i]);
+    }
+    //因为ie6的问题比较多,所以,添加一个专门的变量识别IE6
+    this.isIE6 = (this.browser == "ie" && this.bversion[0] <= 6) ? true : false;
+}
+
+Config.prototype.set = function(key, value) {
+    key = key.split(".");
+    _tmp = this;
+    if (key.length == 0) return this;
+    var last = key.pop();
+    for (var i = 0; i < key.length; i++) {
+        if (typeof _tmp[key[i]] === "undefined") {
+            _tmp[key[i]] = {};
+        }
+        _tmp = _tmp[key[i]];
+    }
+    _tmp[last] = value;
+    return this;
+}
+
+Config.prototype.merge = function(key1, key2) {
+    var dkey1 = this.get(key1);
+    var dkey2 = this.get(key2);
+    if (is_object(dkey1) && is_object(dkey2)) {
+        for (var key in dkey2) {
+            if (typeof key === "string" && typeof dkey2[key] !== "function") {
+                dkey1[key] = dkey2[key];
+            }
+        }
+    }
+    this.set(key1, dkey1);
+}
+
+//控制器主要的工作是初始化整个工作环境。
+//1. canvas : Config.Global.MaxCanvasCount = 10 每个页面图形个数应该是有限制的,canvas太多,往往也看不清楚。
+//2. 选择正确的model Config.Global.ModelName = "ModelShortPoll"
+//3. 兼容性判断
+//
+//增加indicator。减少indicator的接口。
+//绘图接口
+//绘图更新接口
+//
+var periods = {
+    // S5: 5,
+    M1: 60,
+    M2: 60 * 2,
+    M3: 60 * 3,
+    M4: 60 * 4,
+    M5: 60 * 5,
+    H1: 60 * 60,
+    H2: 60 * 60 * 2,
+    D1: 60 * 60 * 24,
+    W1: 60 * 60 * 24 * 7,
+    MN1: 60 * 60 * 24 * 30
+};
+
+function get_period_second(name) {
+    var name = name.toUpperCase();
+    var ratios = { S: 1, M: 60, H: 3600, D: 3600 * 24, W: 3600 * 24 * 7 };
+    if (name == "MN1") {
+        return periods[name];
+    }
+    var perfix = name.charAt(0);
+    if (ratios[perfix] && ratios[perfix] > 0) {
+        var base = parseInt(name.substr(1));
+        if (isNaN(base)) return 0;
+        return base * ratios[perfix];
+    }
+    return 0;
+}
+
+function Controller(api) {
+    this.config = Config.getInstance();
+    this.api = api;
+    // console.log("api"+this.api);
+    var opt = this.api.option;
+    var indicators;
+    this.plot_area = opt.plot_area;
+    this.staticChat = opt.staticChat;
+    this.startTime = opt.startTime;
+    this.pair = opt.pair;
+    this.toolbar = new ToolBar(this);
+    this.initInd(opt.ind);
+    this.runtime_load = opt.runtime_load;
+    this.isinit = false;
+
+    for (var key in this.pair) {
+        if (is_object(this.pair[key])) {
+            this.config.Global.yunit[key] = this.pair[key].yunit;
+        }
+    }
+    this.timerID = null;
+    this.intervalEvent = {};
+    this.recall = {};
+    if (this.api.option["toolbar.isenable"]) {
+        this.toolbar.enable();
+    } else {
+        this.toolbar.disable();
+    }
+
+    this.model = this.getModel();
+    this.view = this.getView();
+    if (!this.runtime_load) {
+
+        this.initChat();
+    }
+    this.isinit = false;
+    this.init();
+}
+
+Controller.prototype.deinit = function() {
+    this.model.deinit();
+    this.view.deinit();
+    this.toolbar.deinit();
+    this.model = null;
+    this.view = null;
+    this.toolbar = null;
+}
+
+Controller.prototype.initChat = function() {
+    this.indicators = this.api.indicators;
+    var prevlist = [];
+    var notseplist = [];
+    for (var key in this.ind) {
+
+        if (is_object(this.ind[key])) {
+            name = key;
+            if (this.ind[name].prev) {
+                prevlist.push(name);
+                continue;
+            }
+            if (!this.view.isSeperatePlot(name)) {
+                notseplist.push(name);
+                continue;
+            }
+            // if(name.split('"').length==2){
+            //     name=name.split('"')[1];
+            // }
+            this.registerChat(name, null, true);
+        }
+        //注册prev 形式的图
+    }
+    //对prevlist,首先它必须依赖一个 sep 的图。因为,每个not sep 都是,都是依赖某个sep放到某个sep上的。
+    for (var i = 0; i < prevlist.length; i++) {
+        var name = prevlist[i];
+        var index = this.view.plotindex[this.ind[name].prev];
+        if (typeof index === "undefined") {
+            continue;
+        }
+        this.registerChat(name, index);
+    }
+    //对于非seplist的图表,这个性质是固有的,依赖某个图。
+    for (var i = 0; i < notseplist.length; i++) {
+        var name = notseplist[i];
+        if (!this.ind[name].param) {
+            index = 0;
+        } else {
+            var index = this.view.plotindex[this.ind[name].param[0][0]];
+            if (typeof index === "undefined") {
+                index = 0;
+            }
+        }
+        this.registerChat(name, index);
+    }
+}
+
+Controller.prototype.getIndParam = function(name) {
+    if (this.ind[name] && this.ind[name].param) {
+        return this.ind[name].param;
+    }
+    return false;
+}
+
+Controller.prototype.getIndList = function() {
+    var ind = {};
+    for (var key in this.ind) {
+        ind[key] = 1;
+    }
+    return ind;
+}
+
+Controller.prototype.indTpl = function(indicator) {
+    //判断是不是tpl
+    //alert(disable_selected);
+    if (this.config.Global.TPL[indicator]) {
+        ToolBar.tplselect(indicator);
+        indicator = this.config.Global.TPL[indicator];
+        for (var key in HTML5StockChartAPI.API.tplParams) {
+            var data = HTML5StockChartAPI.API.tplParams[key];
+            if (typeof data === "string" || typeof data === "number") {
+                indicator = indicator.replace(key, data);
+            }
+        }
+    } else {
+        ToolBar.tplselect("none");
+    }
+
+    // indicator =JSON.stringify(indicator).split(":");
+    // console.log("indicator:"+indicator.split);
+    if(indicator.split==undefined){
+        return indicator
+    }
+    else{
+
+    }
+    if(indicator.split==undefined){
+        return indicator;
+    }
+    indicator =indicator.split(':');
+    return indicator;
+}
+
+Controller.prototype.initInd = function(indlist, disable_parse) {
+    //ind 的结构进行调整:
+    //区别对待下载数据,但是不显示的情况
+    var indlist = this.indTpl(indlist);
+    this.config.mainName = indlist[0];
+    // if(this.config.mainName.split('"').length==2){
+    //     this.config.mainName=this.config.mainName.split('"')[1];
+    // }
+    // this.config.mainName=indlist[0]+'"';
+    //alert(this.config.mainName);
+    if (disable_parse) {
+        var param_ind = indlist;
+    } else {
+        var param_ind = this.parseInd(indlist);
+    }
+    for (var i = 0; i < param_ind.length; i++) {
+        var ind = param_ind[i];
+        var name = param_ind[i].join("|");
+        var ind_name = ind[0];
+        //注册新的指标值,复制配置。
+        if (ind[1]) {
+            var depends = ind[1].split(",");
+            for (var j = 0; j < depends.length; j++) {
+                if (depends[j] == this.config.mainName || depends[j] == "null" || this.ind[depends[j]]) {
+                    //donothing
+                    continue;
+                }
+                if (this.config.Global.View[depends[j]]) {
+                    this.ind[depends[j]] = { name: depends[j], view: 0, prev: false };
+                }
+            }
+        }
+        ind.shift(); //shift 名称
+        ind.shift(); //shift depends
+        if (depends) {
+            ind.unshift(depends);
+        } else {
+            ind.unshift("none");
+        }
+        this.ind[name].param = ind;
+        this.config[name] = this.config[ind_name];
+        this.config.Global.View[name] = this.config.Global.View[ind_name];
+        this.config.Global.Axis[name] = this.config.Global.Axis[ind_name];
+    }
+}
+
+Controller.prototype.parseInd = function(indlist) {
+    var curperiod = get_period_second(this.api.p);
+    this.ind = {};
+    var param_ind = [];
+    for (var i = 0; i < indlist.length; i++) {
+        //判断是否是prev类型的
+        var prev = false;
+        var name = indlist[i];
+        if (indlist[i].charAt(0) == "<") //prev
+        {
+            prev = this.config.mainName;
+            if (i > 0) {
+                for (var j = i - 1; j >= 0; j--) {
+                    if (indlist[j][0] != "<") {
+                        prev = indlist[j];
+                        break;
+                    }
+                }
+            }
+            name = name.substr(1);
+        }
+        var ind = name.split("|");
+        var index = ind[0].indexOf(",");
+        var tper, tname;
+        if (index != -1) {
+            tname = ind[0].substring(0, index);
+            tper = ind[0].substring(index + 1);
+            name = tname + name.substring(ind[0].length);
+            ind[0] = tname;
+            if (tper != curperiod) {
+                continue;
+            }
+        }
+        if (ind.length > 1) {
+            param_ind.push(ind);
+        }
+        this.ind[name] = {
+            name: name,
+            view: 1,
+            prev: prev
+        };
+    }
+    return param_ind;
+}
+
+Controller.prototype.addIntervalEvent = function(name, obj, recall) {
+    this.intervalEvent[name] = obj;
+    if (recall) {
+        this.recall[name] = obj;
+    }
+}
+
+Controller.prototype.removeIntervalEvent = function(name) {
+    this.intervalEvent[name] = null;
+    if (this.recall[name]) {
+        this.recall[name] = null;
+    }
+}
+
+Controller.prototype.recallEvent = function() {
+    for (var key in this.recall) {
+        if (this.recall[key] && is_object(this.recall[key])) {
+            this.recall[key].recall(this);
+        }
+    }
+}
+
+Controller.prototype.init = function() {
+    if (this.isinit) {
+        return;
+    }
+    this.isinit = true;
+    this.toolbar.init();
+    this.view.init();
+    this.setGlobalInterval();
+    return true;
+}
+
+Controller.prototype.set = function(c, p) {
+    // console.log('p:'+p)
+    if (c && p) {
+        this.c = c.toUpperCase();
+        this.p = p.toUpperCase();
+        $.cookie('period',this.p);
+        this.init();
+        if (this.model) {
+
+            this.model.set(this.c, this.p);
+            this.model.init();
+        }
+    }
+}
+
+Controller.prototype.setGlobalInterval = function() {
+    var time = this.config.Global.Interval;
+    if (time < 20) {
+        time = 20;
+    } //以20ms为单位
+    //规则为:要实现一个功能,就分装一个函数在此处执行
+    if (this.timerID !== null) {
+        return;
+    }
+    var _this = this;
+    this.timerID = window.setInterval(function() {
+
+        var events = _this.intervalEvent;
+        for (var key in events) {
+            if (events[key] != null && is_object(events[key])) {
+                events[key].run(_this);
+            }
+        }
+    }, time);
+}
+
+Controller.prototype.flag = function(type) {
+    debug(type);
+    if (type == "new") {
+        this.draw();
+        this.recallEvent();
+        if (this.config.Global.autoScroll) {
+            triggerKeydown(Key.KEY_END);
+        }
+    } else if (type == "down") {
+        this.draw();
+        this.recallEvent();
+    }
+}
+
+Controller.prototype.getModel = function() {
+    var ModelClass = this.config.Global.modelName;
+    //以后要加入兼容性的判断,最后选择一个正确的model
+    return new ModelClass(this);
+}
+
+Controller.prototype.getView = function() {
+    var ViewClass = this.config.Global.viewName;
+    return new ViewClass(this);
+}
+
+Controller.prototype.registerChat = function(name, index, has_plot_area) {
+    var indinfo = this.ind[name];
+    if (indinfo.view) //如果没有view ,不会注册显示对象
+    {
+        this.view.registerPlot(name, index, has_plot_area, indinfo.param);
+    }
+    this.model.registerData(name);
+}
+
+Controller.prototype.unregisetChat = function(name) {
+    this.view.unregisetData(name);
+    this.view.unregisetPlot(name);
+}
+Controller.prototype.draw = function() {
+    if(this.model==undefined)return;
+    if (!this.model.ready) return;
+    var viewconfig = this.view.getAxisConfig(); //view 的图形分布情况
+    //然后。model要根据这个配置,生成相应的坐标数据。
+    //坐标配置:
+    // (绘图区域)
+    // canvas_id => [width, height, 对应的图形名称:main, ma, easyforex ...]
+    // 
+    // 返回的格式:图形名称 => 坐标数据
+    //
+    //主图要绘制的个数
+    if (viewconfig.length <= 0) return;
+    //清除原来的view数据
+    this.view.clearData();
+    this.model.clearData();
+    debug("draw_data_init");
+    var data = this.model.getData(viewconfig);
+    for (var i = 0; i < data.length; i++) {
+        //debug("get_data_beg");
+        //获取数据内部进行封装:我们只调整这一块。
+        //对画图来说,是自己计算的,还是服务器下载的是没有差别的。
+        //这样就不会让问题扩大化。
+        //debug("get_data_end");
+        this.view.updateData(data[i], i); //加入数据
+        //debug("calc_axis");
+    }
+    debug("draw_data_end");
+    this.view.draw();
+
+    //检查是否要下载数据
+    this.model.downloadData();
+    debug("draw_end");
+}
+
+Controller.prototype.startSet = function(name) {
+    var one = this.view.plot[this.config.mainName].getOneSize();
+    var area = this.view.grid[0].getPlotArea();
+    if (name == "Next") {
+        this.model.point(this.model.point() - Math.round(30 / one));
+    } else if (name == "Prev") {
+        this.model.point(this.model.point() + Math.round(30 / one));
+    } else if (name == "PageDown") {
+        this.model.point(this.model.point() + Math.round((area.x.beg - area.x.end) / one));
+    } else if (name == "PageUp") {
+        this.model.point(this.model.point() - Math.round((area.x.beg - area.x.end) / one));
+    } else if (name == "Home") {
+        this.model.point(this.model.endPos());
+        this.model.state = 'home';
+    } else if (name == "End") {
+        this.model.point(0);
+        this.model.state = 'end';
+    }
+    return this.model.point();
+}
+
+Controller.prototype.startOffset = function(offset) {
+    var start = this.model.point();
+    this.model.point(start + offset);
+}
+
+Controller.prototype.zoomIn = function() {
+    this.view.plot[this.config.mainName].zoomIn();
+    this.draw();
+}
+
+Controller.prototype.zoomOut = function() {
+    this.view.plot[this.config.mainName].zoomOut();
+    this.draw();
+}
+
+function Data() {
+
+}
+
+Data.OPEN = 0;
+Data.HIGH = 1;
+Data.LOW = 2;
+Data.CLOSE = 3;
+Data.VOLUMES = 4;
+//controller 中有一个接口会增加这个
+//事件,它提供一个接口给客户端
+//setVal()
+//getVal()
+//提供给controller 的接口是 
+//run
+function IntervalEvent(count, callback, zerocall) {
+    this.count = count;
+    if (this.count <= 0) {
+        this.count = 1;
+    }
+    this.current = 0;
+    this.callback = callback;
+    this.value = 0;
+    this.prev = null;
+    if (!zerocall) {
+        this.zerocall = 0;
+    } else {
+        this.zerocall = zerocall;
+    }
+}
+
+IntervalEvent.prototype.run = function(controller) {
+    this.current++;
+    if (this.count == this.current) {
+        this.current = 0;
+        if (this.zerocall) {
+            this.prev = this.value;
+            this.callback.call(this, controller);
+        } else {
+            if (this.value != 0) {
+                this.prev = this.value;
+                this.callback.call(this, controller);
+                this.value = 0;
+            }
+        }
+    }
+}
+
+IntervalEvent.prototype.getVal = function() {
+    return this.value;
+}
+
+IntervalEvent.prototype.recall = function(controller) {
+    this.value = this.prev;
+    if (this.zerocall) {
+        this.callback.call(this, controller, true);
+    } else {
+        if (this.value != 0) {
+            this.callback.call(this, controller, true);
+            this.value = 0;
+        }
+    }
+}
+
+IntervalEvent.prototype.setVal = function(val) {
+    this.value = val;
+    return this;
+}
+
+
+//数据更新部分:
+//广播服务器的设计是集中式的。我们要广播所有的数据,所以需要进行更新。
+//这个部分将会分为两个部分:下载K线,更新最新的数据
+//
+// 管理tick图:
+// 根据货币对k线,会注册一系列的K线,指标。
+// 更新或者下载的数据都有下面的属性:
+// 1. 货币对/时间/名称
+// 2. 绘图提供更新接口:
+// plot = plot_list[currency][time][name];
+// updateNew(data);
+// download(data);
+//
+//data.registerPlot(c, p, name, plot);
+//data.unregisetPlot(c, p, name, plot);
+//
+//采用广播协议的数据
+
+function Model(controller) {
+    this.data = {};
+    this.maindata = {};
+    this.dataObj = {};
+    this.realname = {};
+    this.flagset = {};
+    this.ready = false;
+    //保存数据指针。标志当前图形读取的位置。
+    this.datapoint = {};
+    this.config = Config.getInstance();
+    this.controller = controller;
+    this.registerData(this.config.mainName); // 注册主图
+    //alert(this.config.mainName);
+    this.main = this.dataObj[this.config.mainName];
+    this.downOptions = {};
+
+    //这个由数据层来更新
+    this.leftoffset = 0;
+    this.rightoffset = 0;
+    this.state = '';
+}
+
+Model.prototype.init = function() {
+    //初始化数据
+    if (this.c && this.p) {
+        //判断是否这个货币对的数据已经初始化过了
+        if (this.flag(Model.INITED)) {
+            hide_loading();
+            this.controller.draw();
+
+            if (this.config.Global.newDisable || this.config[this.config.mainName].newdata) {
+                this.newData();
+            }
+        } else if (this.flag(Model.INITING)) {
+            return;
+        } else {
+            this.flag(Model.FIRST_NEW, 1);
+            show_loading();
+            this.flag(Model.INITING, 1);
+            //alert(this.config.mainName);
+            if (this.config['main'].downdata) {
+                this.initData();
+            } else {
+                this.flag(Model.INITED, 1);
+                this.init();
+            }
+        }
+    }
+}
+
+Model.prototype.deinit = function() {
+    //释放socket 资源
+}
+
+Model.NEW = 1;
+Model.DOWN = 1 << 1;
+Model.NEW_DATA = 1 << 2;
+Model.DOWN_DATA = 1 << 3;
+Model.INITED = 1 << 4;
+Model.INITING = 1 << 5;
+Model.NEW_DISABLE = 1 << 6;
+Model.DOWN_END = 1 << 7;
+Model.FIRST_NEW = 1 << 8;
+Model.UPDATE = 1 << 9;
+
+Model.prototype.registerData = function(name) { 
+    // console.log("name:"+name);
+    if(this.config[name] && !this.dataObj[name]) {
+
+        var newname = name.split("|", 2);
+        if (newname.length == 2) {
+            this.realname[newname[0]] = name;
+        }
+        var Reader = this.config[name].reader;
+        var Writer = this.config[name].writer;
+        this.dataObj[name] = {};
+        if (Writer) {
+            this.dataObj[name].writer = new Writer(this, name);
+        }
+        if (Reader) {
+            this.dataObj[name].reader = new Reader(this, this.dataObj[name].writer, name);
+        }
+        //reader 要引用write
+    }
+
+}
+
+Model.prototype.clearData = function() {
+    for (var key in this.dataObj) {
+        if (is_object(this.dataObj[key])) {
+            this.dataObj[key].writer.clear();
+            this.dataObj[key].reader.clear();
+        }
+    }
+}
+
+Model.prototype.getDataReader = function(name) {
+    return this.dataObj[name].reader;
+}
+
+Model.prototype.unregisetData = function(name) {
+    this.dataObj[name] = null;
+}
+
+Model.prototype.set = function(c, p) {
+    if (this.c != c || this.p != p) {
+        if (this.newDataXHR) this.newDataXHR.abort();
+        //标记不在更新数据
+        this.isNewing = false;
+        if (this.subscribe) {
+            this.subscribe();
+        }
+        this.downOptions = {};
+    }
+    this.c = c;
+    this.p = p;
+    $.cookie('period',p);
+    //初始化标志位
+    this.flagset = init_obj(this.flagset, this.c, this.p, 0);
+    this.datapoint = init_obj(this.datapoint, this.c, this.p, 0);
+    //set 所有的reader对象
+    for (var key in this.dataObj) {
+        if (is_object(this.dataObj[key])) {
+            this.dataObj[key].reader.set();
+        }
+    }
+
+}
+
+Model.prototype.clearData = function() {
+    this.data = {};
+}
+
+Model.prototype.getShift = function(plot) {
+    var maxshift = -Infinity;
+    for (var i = 0; i < plot.length; i++) {
+        var name = plot[i];
+        var shift = this.dataObj[name].reader.getShift();
+        if (shift > maxshift) {
+            maxshift = shift;
+        }
+    }
+    return maxshift;
+}
+
+Model.prototype.getData = function(viewconfig) {
+    //all plot list.
+    var plot = [];
+    this.plotnum = viewconfig[0].plotnum;
+    for (var i = 0; i < viewconfig.length; i++) {
+        var arr = viewconfig[i].plot;
+        for (var j = 0; j < arr.length; j++) {
+            plot.push(arr[j]);
+        }
+    }
+    //初始化参数
+    for (var i = 0; i < plot.length; i++) {
+        var name = plot[i];
+        //if (name == this.config.mainName) continue;
+        var param = this.controller.getIndParam(name);
+        if (param) {
+            this.dataObj[name].reader.setParam(param);
+        }
+    }
+    var shift = this.getShift(plot);
+    //先计算普通的:
+    for (var i = 0; i < viewconfig.length; i++) {
+        this._getData(viewconfig[i].plot, viewconfig[i].plotnum + shift);
+    }
+    //再计算关联,但是不会在前台显示的数据
+    var nodatalist = [];
+    for (var i = 0; i < plot.length; i++) {
+        var param = this.controller.getIndParam(plot[i]);
+        if (param && param[0] != "none") {
+            for (var k = 0; k < param[0].length; k++) {
+
+                if (this.data[param[0][k]]) {
+                    continue;
+                } else {
+                    nodatalist.push(param[0][k]);
+                }
+            }
+        }
+    }
+    this._getData(nodatalist, viewconfig[0].plotnum + shift);
+    //再计算通过这些数据得到“计算的数据”
+    for (var j = 0; j < viewconfig.length; j++) {
+        for (var i = 0; i < viewconfig[j].plot.length; i++) {
+            var name = viewconfig[j].plot[i];
+            var param = this.controller.getIndParam(name);
+            if (param && param[2] != "__ignore__") {
+                if (name == this.config.mainName) {
+                    continue;
+                }
+                if (param[0] != "none") {
+                    for (var k = 0; k < param[0].length; k++) {
+                        this.dataObj[name].reader.setDependData(param[0][k], this.data[param[0][k]]);
+                    }
+                }
+                this.data[name] = this.dataObj[name].reader.getData(this.config[name].data);
+            }
+        }
+    }
+    //计算完成了,这些数据就没有用了,释放掉内存
+    for (var i = 0; i < nodatalist.length; i++) {
+        this.data[nodatalist[i]] = null;
+    }
+    return this.formatData(viewconfig, shift);
+}
+
+Model.prototype._getData = function(plotlist, num) {
+    if (!this.data[this.config.mainName]) {
+        this.data[this.config.mainName] = this.dataObj[this.config.mainName].reader.getData(this.plotnum, this.config[this.config.mainName].data, true);
+        this.maindata = this.dataObj[this.config.mainName].reader.getData(this.num, this.config[this.config.mainName].data, true);
+    }
+    //计算所有没有参数的情况
+    for (var i = 0; i < plotlist.length; i++) {
+        var name = plotlist[i];
+        if (name == this.config.mainName) continue;
+        var param = this.controller.getIndParam(name);
+        if (!param || param[2] === "__ignore__") {
+            this.data[name] = this.dataObj[name].reader.getDataByMain(this.config[name].data);
+        }
+    }
+}
+
+Model.prototype.shiftData = function(shift) {
+    //先shift main,main直接按照数字shift
+    //其他相关的shift按照时间进行shift。因为,不一定是对齐的。
+    var main = this.config.mainName;
+    if (shift > 0 && shift < this.data[main].x.length) {
+        //this.data[main].x =  this.data[main].x.slice(0, -shift);
+        //this.data[main].y =  this.data[main].y.slice(0, -shift);
+        //var minx =  this.data[main].x[this.data[main].x.length -1];
+        /*for (var key in this.data)
+        {
+           
+            if (key == main) continue;
+            if (this.data[key] && is_object(this.data[key]))
+            {
+                var shift = this.getShiftNumber(this.data[key].x, minx);
+                this.data[key].x =  this.data[key].x.slice(0, -shift);
+                this.data[key].y =  this.data[key].y.slice(0, -shift);
+            }
+        }*/
+    }
+
+    for (var key in this.data) {
+        if (this.data[key] && is_object(this.data[key])) {
+            this.data[key] = this.dataObj[key].reader.formatData(this.data[key].x, this.data[key].y);
+        }
+    }
+}
+
+Model.prototype.getShiftNumber = function(x, minx) {
+    var count = 0;
+    for (var i = x.length - 1; i >= 0; i--) {
+        if (x[i] >= minx) {
+            break;
+        } else {
+            count++;
+        }
+    }
+    return count;
+}
+
+//如果是主图的数据,因为要用于对齐,所以,复制一份
+//防止外界对其进行修改操作。
+Model.prototype.formatData = function(viewconfig, shift) {
+
+    this.shiftData(shift);
+    //再计算通过这些数据得到“计算的数据”
+    var data = [];
+    //var text;
+    for (var j = 0; j < viewconfig.length; j++) {
+        data[j] = {};
+        //text = ""; 
+        for (var i = 0; i < viewconfig[j].plot.length; i++) {
+            var name = viewconfig[j].plot[i];
+            if (name == this.config.mainName) {
+                data[j][name] = object_copy(this.data[this.config.mainName]);
+                data[j][name].x = array_copy1d(this.data[this.config.mainName].x);
+
+            } else {
+                data[j][name] = this.data[name];
+            }
+            //text += "[" + this.getShowName(name) + " " + this.lastData(this.data[name].y[0]) + "] ";
+        }
+        data[j].c = this.c;
+        data[j].p = this.p;
+        //data[j].text = text;
+    }
+    return data;
+}
+
+Model.prototype.update = function(data, type) {
+    if (!data) {
+        if (type == Model.DOWN) {
+            this.ready = true;
+            this.controller.flag("down");
+            this.flag(Model.DOWN_END, 1);
+        }
+        return;
+    }
+    if (data.code) {
+        if (data.code == "goto" && data.msg) {
+            window.location.href = data.msg;
+        }
+        return;
+    }
+    var is_new = false;
+    var is_down = false;
+    var is_update = false;
+    if (!data.c || !data.p) {
+        return;
+    }
+    var c = data.c.toUpperCase();
+    var p = data.p.toUpperCase();
+    //数据已经下载到末尾了
+    var end = data.end;
+    this.flag(Model.DOWN_END, end);
+    if (data.code) {
+        debug(data.code);
+        //发生了错误
+        return;
+    }
+    this.downOptions = data.options || {};
+    for (var key in data) {
+        //下载的数据
+        if (!is_object(data[key])) continue;
+        //这三个是保留的
+        if (key == "c" || key == "p" || key == "code" || key == "end") {
+            continue;
+        }
+        var keyreal = key;
+        if (typeof this.dataObj[key] === "undefined") {
+            key = this.realname[key];
+        }
+        if (typeof key === "undefined") {
+            continue;
+        }
+        if (this.dataObj[key]) {
+            if (type == Model.NEW) {
+                is_new = true;
+                if (this.dataObj[key].writer) this.dataObj[key].writer.setNewData(c, p, data[keyreal]);
+            } else if (type == Model.UPDATE) {
+                is_update = true;
+                if (this.dataObj[key].writer) this.dataObj[key].writer.setUpdateData(c, p, data[keyreal]);
+            } else if (this.downOptions.total_size) {
+                is_down = true;
+                if (this.dataObj[key].writer && this.dataObj[key].writer.setDownloadDataByOffset) {
+                    this.dataObj[key].writer.setDownloadDataByOffset(c, p, data[keyreal], this.downOptions);
+                } else {
+                    if (this.dataObj[key].writer) this.dataObj[key].writer.setDownloadData(c, p, data[keyreal]);
+                }
+            } else {
+                //判断是否存在数据对象,那么更新图形的数据。
+                is_down = true;
+                if (this.dataObj[key].writer) this.dataObj[key].writer.setDownloadData(c, p, data[keyreal]);
+            }
+        }
+    }
+    if (is_new) {
+        this.ready = true;
+        this.controller.flag("new");
+    }
+    if (is_down) {
+        this.ready = true;
+        this.controller.flag("down");
+    }
+    if (is_update) {
+        this.ready = true;
+        this.controller.flag("new");
+    }
+}
+
+Model.prototype.getIndicatorList = function() {
+    var list = [];
+    for (var key in this.dataObj) {
+        if (key == this.config.mainName) continue; //主图的数据,数据接口会默认更新
+        if (is_object(this.dataObj[key])) {
+            list.push(key);
+        }
+    }
+    return list;
+}
+
+//数据集合中,按照时间,或者某个x轴一路更新
+//肯定会有一个边界。这个数据边界就从这里取。
+Model.prototype.startXValue = function() {
+    var start = this.main.reader.startXValue();
+    if (start <= 0 && this.controller.startTime) {
+        return this.controller.startTime;
+    }
+    return start;
+}
+
+Model.prototype.endXValue = function() {
+    return this.main.reader.endXValue();
+}
+
+Model.prototype.leftDataCount = function() {
+    return this.endPos() - this.point() - this.plotnum;
+}
+
+Model.prototype.rightDataCount = function() {
+    return this.point();
+}
+
+Model.prototype.endPos = function() {
+    return this.main.reader.getEndPos();
+}
+
+Model.prototype.flag = function(key, value, c, p) {
+    if (!c) {
+        c = this.c;
+    }
+    if (!p) {
+        p = this.p;
+    }
+    if (!c || !p) {
+        return;
+    }
+    c = c.toUpperCase();
+    p = p.toUpperCase();
+    if (typeof value === "undefined") {
+        return (this.flagset[c][p] & key) == key; //判断标志位是否已经被设置了
+    } else if (value == 0) {
+        this.flagset[c][p] = this.flagset[c][p] & (~key); //清除标志位
+    } else {
+        this.flagset[c][p] = this.flagset[c][p] | key; //设置标志位
+    }
+}
+
+Model.prototype.point = function(value) {
+    if (typeof value === "undefined") {
+        return this.datapoint[this.c][this.p];
+    } else {
+        this.datapoint[this.c][this.p] = value;
+    }
+}
+
+Model.prototype.getLeftOffset = function() {
+    return this.leftoffset;
+}
+
+Model.prototype.getRightOffset = function() {
+    return this.rightoffset;
+}
+
+Model.prototype.getDownOffset = function(down_flag) {
+    this.count = this.config.Global.downloadCount;
+    if (down_flag == -1 && this.getRightOffset() == 0) {
+        return -1;
+    }
+    if (down_flag == 1 && this.getLeftOffset() >= this.downOptions.total_size) {
+        return -1;
+    }
+    if (down_flag == 1) {
+        var offset = this.getLeftOffset() + 1; //读取下一个数据
+        //超出范围
+        if (offset >= this.downOptions.total_size) offset = -1;
+    }
+    if (down_flag == -1) {
+        var offset = this.getRightOffset() - this.config.Global.downloadCount;
+        if (offset < 0) {
+            offset = 0;
+            this.count = this.getRightOffset() - offset;
+        }
+    }
+    return offset;
+}
+
+Model.prototype.getDataByTime = function(name, time, near) {
+    var x = this.dataObj[name].writer.getX(this.c, this.p);
+    var y = this.dataObj[name].writer.getY(this.c, this.p);
+    var index = binsearch_r(x, time);
+    var obj = {};
+    obj.time = timeToDate(time, this.config.Global.timeformat[this.p], this.config.Global.timezone);
+    if (index == -1 && near == "candle") {
+        index = find_last_little_r(x, time);
+        if (index == -1) return false;
+        var close = y[index][Data.CLOSE];
+        obj.data = [close, close, close, close, y[index][Data.VOLUMES]];
+    } else {
+        if (index == -1) return false;
+        obj.data = y[index];
+    }
+    return obj;
+}
+
+__javascript_debug__ = false;
+__datasource__ = "db";
+__datafile__ = "db";
+__debug__ = false;
+__static__ = false;
+__runtime_load__ = false;
+__start_time__ = false;
+__baseurl__ = "http:\/\/locaohost:9001\/";
+__broadcast_server_active__ = "115.236.165.18";
+__loadhost__ = "localhost:9001";
+__refererhost__ = "localhost:9001";
+__orderhost__ = "localhost:9001";
+__apihost__ = "rsi.33.cn";
+__dbreset__ = ""
+__musicselect__ = { "alert.wav": "alert", "alert2.wav": "alert2", "connect.wav": "connect", "disconnect.wav": "disconnect", "email.wav": "email", "expert.wav": "expert", "ok.wav": "ok", "request.wav": "request", "stops.wav": "stops", "tick.wav": "tick", "timeout.wav": "timeout", "wait.wav": "wait", "": "", "\u05a3\u0534 - ": "\u05a3\u0534 - " };
+
+//plot base function. process base plot function.
+function Key() {
+
+}
+
+
+Key.KEY_PREV = 37;
+Key.KEY_UP = 38;
+Key.KEY_NEXT = 39;
+Key.KEY_DOWN = 40;
+Key.KEY_HOME = 36;
+Key.KEY_END = 35;
+Key.KEY_PAGE_DOWN = 34;
+Key.KEY_PAGE_UP = 33;
+
+function Plot(view, grid, name) {
+    this.view = view;
+    this.name = name;
+    this.controller = this.view.controller;
+    this.grid = grid;
+    this.getPlotArea();
+
+    this.ctx = this.grid.ctx;
+    this.ctxBG = this.grid.ctxBG;
+    this.ctxFront = this.grid.ctxFront;
+
+    this.axis = this.grid.axis;
+    this.canvas = this.grid.canvas;
+    this.config = Config.getInstance();
+    this.param = {};
+    classname = getClassName(this);
+    classname = classname.substr(4);
+    if (this.config.Global[classname]) {
+        this.conf = this.config.Global[classname].public;
+    } else {
+        this.conf = {};
+    }
+    //对K线图的操作是全局性的。也就是说,这里的不会像grid里面一样复制一份全局配置。
+    //而是直接操作全局配置
+}
+
+//默认一个时间占据一个像素,这个是线条默认的占用值。
+Plot.prototype.getOneSize = function() {
+    return 1;
+}
+
+
+//默认一个时间占据一个像素,这个是线条默认的占用值。
+Plot.prototype.getPlotArea = function() {
+    var area = this.grid.getPlotArea();
+    this.top = area.y.end;
+    this.left = area.x.end;
+    this.bottom = area.y.beg;
+    this.right = area.x.beg + this.grid.conf.paddingX;
+}
+
+Plot.prototype.getShowName = function() {
+    var name = this.name.toUpperCase();
+    name = name.replace("MAIN", "OHLC").replace("FXTRADE", "OANDA").replace("||", " ");
+    if (name.indexOf("PROFIT_LINE") != -1) {
+        name = "PROFIT";
+    }
+    name = name.split("|");
+    if (name.length == 1) {
+        return name[0];
+    }
+    var pre = name.shift();
+    return pre + " (" + name.join(" , ") + ")";
+}
+
+Plot.prototype.lastData = function() {
+    var data = this.view.model.getDataReader(this.name).last();
+    if (typeof data === "undefined") {
+        return "";
+    }
+    try {
+        var yunit = this.axis.viewconfig.y.axis_option.unit;
+    } catch (e) {
+        return "";
+    }
+    var ret = [];
+    if (is_array(data)) {
+        for (var i = 0; i < data.length; i++) {
+            ret[i] = this.grid.getText(0, data[i], yunit);
+        }
+        return ret;
+    } else if (!isNaN(Number(data))) {
+        return this.grid.getText(0, data, yunit);
+    } else {
+        return data;
+    }
+}
+
+Plot.prototype.setParam = function(param) {
+    if (param.length >= 3) {
+        this.param = this.parseParam(param[2]);
+    }
+}
+
+Plot.prototype.parseParam = function(pstr) {
+    pstr = pstr.split(",");
+    var ret = {};
+    for (var i = 0; i < pstr.length; i++) {
+        var tmp = pstr[i].split("=", 2);
+        ret[tmp[0]] = tmp[1];
+    }
+    return ret;
+}
+
+Plot.prototype.lastDataShow = function() {
+        var data = this.lastData();
+        if (is_array(data)) {
+            return data.join(", ");
+        }
+        return data;
+    }
+    //价格标线
+Plot.prototype.priceFlag = function(close_price, conf) {
+    var close_y = this.axis.getY(close_price);
+    drawWithArrowheads(this.grid.xEnd.x-14,close_y,this.grid.xEnd.x+30,close_y,this.ctx);
+//  drawRow(this.ctx, new Point(this.grid.xEnd.x , close_y), 10, conf.lineColor, 1);
+    //能直接访问grid的内容
+    var height = conf.bg.height / 2;
+    if (close_y >= 0 && close_y - this.grid.O.y < height) {
+        close_y = this.grid.O.y + height;
+    }
+    if (close_y <= this.grid.xyEnd.y && this.grid.xyEnd.y - close_y < height) {
+        close_y = this.grid.xyEnd.y - height;
+    }
+    conf.unit = this.yunit;
+    writeTextOption(this.ctx, new Point(this.grid.xEnd.x-6, close_y), close_price, conf);
+}
+
+
+function Shape(ctx, width, height, opt) {
+    this.ctx = ctx;
+    this.width = width ? width : 0;
+    this.height = height ? height : 70;
+    if (!opt) {
+        opt = {};
+    }
+    this.boder = opt.boder ? opt.boder : "black";
+    this.fill = opt.fill ? opt.fill : "black";
+    this.cta = opt.cta ? opt.cta : 0;
+}
+
+__symbol__list__ = {
+    // "BTYBTC": { "time": ["M1", "M2", "M3", "M4", "M5", "M15", "M30", "H1", "H2", "H4", "D1", "W1", "MN1"], "yunit": 0.001 },
+    // "BTC": { "time": ["M1", "M2", "M3", "M4", "M5", "M15", "M30", "H1", "H2", "H4", "D1", "W1", "MN1"], "yunit": 0.01 },
+    "BCCBTC": { "time": ["M1", "M2", "M3", "M4", "M5", "M15", "M30", "H1", "H2", "H4", "D1", "W1", "MN1"], "yunit": 0.01 },
+    "ETHBTC": { "time": ["M1", "M2", "M3", "M4", "M5", "M15", "M30", "H1", "H2", "H4", "D1", "W1", "MN1"], "yunit": 0.01 },
+    "ETCBTC": { "time": ["M1", "M2", "M3", "M4", "M5", "M15", "M30", "H1", "H2", "H4", "D1", "W1", "MN1"], "yunit": 0.01 },
+    // "SC": { "time": ["M1", "M2", "M3", "M4", "M5", "M15", "M30", "H1", "H2", "H4", "D1", "W1", "MN1"], "yunit": 0.0001 },
+    // "WTC": { "time": ["M1", "M2", "M3", "M4", "M5", "M15", "M30", "H1", "H2", "H4", "D1", "W1", "MN1"], "yunit": 0.0001 },
+    // "NYCC": { "time": ["M1", "M2", "M3", "M4", "M5", "M15", "M30", "H1", "H2", "H4", "D1", "W1", "MN1"], "yunit": 0.001 },
+    // "BTS": { "time": ["M1", "M2", "M3", "M4", "M5", "M15", "M30", "H1", "H2", "H4", "D1", "W1", "MN1"], "yunit": 0.001 },
+    "LTCBTC": { "time": ["M1", "M2", "M3", "M4", "M5", "M15", "M30", "H1", "H2", "H4", "D1", "W1", "MN1"], "yunit": 0.01 },
+    "ZECBTC": { "time": ["M1", "M2", "M3", "M4", "M5", "M15", "M30", "H1", "H2", "H4", "D1", "W1", "MN1"], "yunit": 0.01 }
+}
+
+function ToolBar(controller) {
+    this.controller = controller;
+    this.pair = this.controller.pair;
+    // this.initPair();
+    // this.hideSymbol(); //隐藏没有数据的货币对
+    this.config = Config.getInstance();
+    this.api=this.controller.api;
+    this.isenable = true;
+}
+
+ToolBar.prototype.deinit = function() {
+
+}
+
+//显示出BTY 和ETH标签
+ToolBar.prototype.initPair = function() {
+   // $("#symbol").html('');
+    for (var c in this.pair) {
+        if (!is_object(this.pair[c])) {
+            continue;
+        }
+    }
+
+}
+
+ToolBar.prototype.enable = function() {
+    $("#toolbar").show();
+    this.isenable = true;
+}
+
+ToolBar.prototype.disable = function() {
+    $("#toolbar").hide();
+    this.isenable = false;
+}
+
+ToolBar.prototype.hideSymbol = function() {
+    var _this = this;
+    $("#symbol2").find("li").each(
+        function() {
+            var text = $(this).text();
+            text = $.trim(text);
+            $(this).show();
+            if (typeof _this.pair[text] !== "object") {
+                $(this).hide();
+            }
+        }
+    );
+}
+
+ToolBar.prototype.hidePeriod = function(c) {
+    var _this = this;
+    if (!c) return;
+    var _timeList = _this.pair[c];
+    if (!_timeList) return;
+    _timeList = _timeList.time;
+    _timeMap = {};
+    for (var i = 0; i < _timeList.length; i++) {
+        _timeMap[_timeList[i]] = 1;
+    }
+    $("#period").find("li").each(
+        function() {
+            var text = $(this).text();
+            text = $.trim(text);
+            $(this).show();
+            if (_timeMap[text] !== 1) {
+                $(this).hide();
+            }
+        }
+    );
+}
+
+ToolBar.prototype.init = function() {
+    this.InitIndicatorstatus();
+       //添加事件
+    var _this=this;
+    $("#Indicator_list label").click(function () {
+        var name=$(this).text();
+        _this.IndicatorStatusChange(this);
+    })
+    // $("#Indicator_list li").click(function () {
+    //     var name=$(this).attr('name');
+    //     if($(this).find('a').attr('class')=='active'){
+    //         $(this).find('a').removeClass('active');
+    //     }
+    //     else{
+    //        $(this).find('a').addClass('active'); 
+    //     }
+        
+    //     _this.IndicatorStatusChange(name);
+    // })
+    //bty,eth选择切换
+    $("#symbol2 a").click(function(){
+        $("#symbol2 a").removeClass("active");
+        var uid=$.cookie().id;
+        $(this).addClass("active");
+        _this.newsymbol(this);
+    });
+    $("#getsymbol").click(function(){
+        console.log($.cookie('symbol'));
+        if(sessionStorage.getItem('symbol')=='YCC'){
+            HTML5StockChartAPI.API.setPair('NYCC', sessionStorage.getItem('period'));
+        }else{
+             HTML5StockChartAPI.API.setPair($.cookie('symbol'), sessionStorage.getItem('period'));
+        }
+       
+    })
+     $("#ethsymbol").click(function(){
+        HTML5StockChartAPI.API.setPair("ETHBTC", $.cookie('period'));
+    })
+     $("#etcsymbol").click(function(){
+        HTML5StockChartAPI.API.setPair("ETCBTC", $.cookie('period'));
+    })
+     $("#bccsymbol").click(function(){
+        HTML5StockChartAPI.API.setPair("BCCBTC", $.cookie('period'));
+    })
+    /* $("#Indicator_list a").click(function(){
+        var name=$(this).text();
+        _this.IndicatorStatusChange(name);
+     });*/
+    $("#period li").click(function() {
+         $("#period a").removeClass("active");
+        _this.period(this);
+    });
+    $("#plot_area").bind('click', function() {
+        _this.toolList();
+    });
+    $('body').not($("#plot_area")).unbind('mouseover', function() {
+        // console.log($(this));
+        $('body').css("cursor", "hand");
+        _this.toolList();
+        //$("#dropzone").slideUp("normal");
+    });
+    // this.addSelectEvent($("#symbol2"), this.symbol);
+    this.addSelectEvent($("#period"), this.period);
+    //this.addSelectEvent($("#tool_list"), this.toolList);//加号功能,指标
+    this.addClickEvent($("#zoom"), this.zoom);
+    //选择:
+    ToolBar.selectItem($("#period"), $.cookie('period'));
+}
+
+ToolBar.prototype.InitIndicatorstatus = function() {
+    // console.log("this.api:"+this.api);
+
+    var inds = $.cookie('ind');
+    if (this.config.Global.TPL[inds]) {
+        inds = this.config.Global.TPL[inds];
+    }
+    if (inds.indexOf("ma|main|") != -1) {
+        this.SetIndicatorStatus("MA");
+    }
+    if (inds.indexOf("macd|main|") != -1) {
+        this.SetIndicatorStatus("MACD");
+    }
+    if (inds.indexOf("volumes") != -1) {
+        this.SetIndicatorStatus("VOLUMES");
+    }
+    if (inds.indexOf("bolling") != -1) {
+        this.SetIndicatorStatus("BOLLING");
+    }
+    if (inds.indexOf("kdj") != -1) {
+        this.SetIndicatorStatus("KDJ");
+    }
+}
+ToolBar.prototype.SetIndicatorStatus = function(indname) {
+    $("#Indicator_list label").each(function() {
+        if ($(this).text() == indname) {
+            $(this).addClass("active");
+
+        }
+    });
+}
+
+ToolBar.prototype.IndicatorStatusChange = function(obj) {
+    var name=$(obj).text();
+    if($(obj).attr("class")=='active'){
+        $(obj).removeClass('active');
+    }
+    else{
+         $(obj).addClass('active')
+    }
+    var indstr = "main:";
+    $("#Indicator_list label").each(function(){
+        if ($(this).attr("class")=='active') {
+           switch ($(this).text()) {
+                case "MA":
+                    indstr += Config.getInstance().Global.TPL["ma"];
+                    break;
+                case "VOLUMES":
+                    indstr += Config.getInstance().Global.TPL["volumes"];
+                    break;
+                case "MACD":
+                    indstr += Config.getInstance().Global.TPL["macd"];
+                    break;
+                case "BOLLING":
+                    indstr += Config.getInstance().Global.TPL["bolling"];
+                    break;
+                case "KDJ":
+                    indstr += Config.getInstance().Global.TPL["kdj"];
+                    break;
+            }
+        }
+    })
+    // var indstr = "main:";
+    // var indstr = this.api.read('ind');
+    // if(this.config.Global.TPL[indstr]) {
+    //     indstr = this.config.Global.TPL[indstr];
+    // }
+    // switch (obj) {
+    //     case "MA":
+    //         indstr += Config.getInstance().Global.TPL["ma"];
+    //         break;
+    //     case "VOLUMES":
+    //         indstr += Config.getInstance().Global.TPL["volumes"];
+    //         break;
+    //     case "MACD":
+    //         indstr += Config.getInstance().Global.TPL["macd"];
+    //         break;
+    //     case "BOLLING":
+    //         indstr += Config.getInstance().Global.TPL["bolling"];
+    //         break;
+    //     case "KDJ":
+    //         indstr += Config.getInstance().Global.TPL["kdj"];
+    //         break;
+    // }
+    // console.log("IndicatorStatusChange:"+name);
+    // var indstr = "main:";
+    // //  选中那个a 标签就执行什么
+    // $("input[name = Indicator]:checkbox").each(function() {
+    //     if ($(this).is(":checked")) {
+    //         switch ($(this).val()) {
+    //             case "MA":
+    //                 indstr += Config.getInstance().Global.TPL["ma"];
+    //                 break;
+    //             case "VOLUMES":
+    //                 indstr += Config.getInstance().Global.TPL["volumes"];
+    //                 break;
+    //             case "MACD":
+    //                 indstr += Config.getInstance().Global.TPL["macd"];
+    //                 break;
+    //             case "BOLLING":
+    //                 indstr += Config.getInstance().Global.TPL["bolling"];
+    //                 break;
+    //             case "KDJ":
+    //                 indstr += Config.getInstance().Global.TPL["kdj"];
+    //                 break;
+    //         }
+    //     }
+    // });
+    this.api.setInd(indstr);
+}
+   
+ToolBar.prototype.signal = function(obj) {
+    var signal_id = $.trim(obj.attr('name'));
+    //write cookie of signal
+    api.setSignal(signal_id);
+}
+
+ToolBar.prototype.model = function(obj) {
+    var model_id = $.trim(obj.attr('name'));
+    //write cookie of model
+    api.setModel(model_id);
+}
+
+ToolBar.prototype.tplswitch = function(obj) {
+    var tpl = $.trim(obj.attr('name'));
+    if (tpl == "none") return;
+    var api = HTML5StockChartAPI.API;
+    api.setIndicatorConf(tpl);
+}
+
+ToolBar.tplselect = function(name) {
+    ToolBar.selectItem($("#tpl_list"), name);
+    //alert(name);
+}
+
+ToolBar.prototype.clickFirst = function(obj) {
+    var obj = obj.find("li");
+    for (var i = 0; i < obj.length; i++) {
+        var item = $(obj.get(i));
+        if (item.css("display") == "none") {
+            continue;
+        }
+        item.click();
+        break;
+    }
+}
+
+ToolBar.prototype.clickByName = function(obj, name) {
+    var obj = obj.find("li");
+    for (var i = 0; i < obj.length; i++) {
+        var item = $(obj.get(i));
+        if ($.trim(item.text()) == name) {
+            item.click();
+            break;
+        }
+    }
+}
+
+ToolBar.prototype.clickByLiName = function(obj, name) {
+    var obj = obj.find("li");
+    for (var i = 0; i < obj.length; i++) {
+        var item = $(obj.get(i));
+        if (item.attr("name") == name) {
+            item.click();
+            break;
+        }
+    }
+}
+
+ToolBar.prototype.symbol = function(obj) {
+    var c = $.trim(obj.text());
+    //c="MAC";
+    var c = this.findSelected($("#symbol2"));
+    //if(c = "ETH") window.location.href="http://33.cn/ethcny";
+    //if(c = "BTY") window.location.href="http://33.cn/";
+    this.hidePeriod(c); //隐藏没有数据的时间周期
+    var p = this.findSelected($("#period"));
+    $.cookie('period',p);
+    // console.log("p=", p);
+    if (!p) {
+        //this.clickFirst($("#period"));
+        HTML5StockChartAPI.API.setPair(c, this.controller.p);
+    } else {
+        HTML5StockChartAPI.API.setPair(c, p);
+    }
+}
+
+ToolBar.prototype.newsymbol = function(obj) {
+
+    var c = $(obj).attr("name");
+    if ($.cookie('symbol') != c) {
+        $.cookie("symbol", null);
+        $.cookie("symbol", c);
+    }
+    //$("#period").children().first();
+    // $("#period").children().first().text(c);
+
+    //c="MAC";
+    //var c = this.findSelected($("#symbol")); 
+    //if(c = "ETH") window.location.href="http://33.cn/ethcny";
+    //if(c = "BTY") window.location.href="http://33.cn/";
+   // this.hidePeriod(c); //隐藏没有数据的时间周期
+    var p = this.findSelected($("#period"));
+    $.cookie('period',p);
+    // console.log("p=", p);
+    if (!p) {
+        //this.clickFirst($("#period"));
+        HTML5StockChartAPI.API.setPair(c, this.controller.p);
+    } else {
+        HTML5StockChartAPI.API.setPair(c, p);
+    }
+}
+
+ToolBar.prototype.toolList = function(obj) {
+    var name = obj.attr("name");
+    var _this = this;
+    if (name == "cross") //cross情况
+    {
+        $("#plot_area").css("cursor", "crosshair");
+        var view = this.controller.view;
+        if (window["FlashCanvas"]) {
+            var count = 5;
+        } else {
+            var count = 2;
+        }
+        var crossMoveInterval = new IntervalEvent(
+            count,
+            function(controller, recall) //可以重新被call
+            {
+                var _this = controller.view;
+                if (typeof recall == "undefined") {
+                    _this.draw();
+                }
+                if (!this.value || this.value.length != 3) {
+                    return;
+                }
+                var x = this.value[0];
+                var y = this.value[1];
+                var index = this.value[2];
+                for (var i = 0; i < _this.canvasActiveCount; i++) {
+                    _this.grid[i].drawCrossX(x, _this.axis[0]);
+                }
+                _this.grid[index].drawCrossY(y);
+            }
+        );
+        for (var i = 0; i < view.canvasActiveCount; i++) {
+            view.canvas[i].bind("mousemove", crossMoveInterval, this.crossMove);
+        }
+
+        //if the page is redraw, call it by controller.recall(). now, only new tick
+        //redraw need to recall.
+        this.controller.addIntervalEvent("crossMove", crossMoveInterval, true);
+        $(document).bind("mouseover", function(e) {
+            // console.log(e.target);
+            $("body").css("cursor", "default");
+            for (var i = 0; i < view.canvasActiveCount; i++) {
+                view.canvas[i].unbind("mousemove", _this.crossMove);
+            }
+            view.draw();
+            _this.controller.removeIntervalEvent("crossMove");
+            _this.clickByLiName($("#tool_list"), "none");
+            $(document).unbind("mouseover");
+        });
+    } else if (name == "kline_first") { //
+        var view = this.config.Global.View;
+        for (var key in view) {
+            if (is_object(view[key]) && typeof view[key].disable_axis_area !== "undefined") {
+                view[key].disable_axis_area = 1;
+            }
+        }
+        this.controller.draw();
+    } else if (name == "ind_first") {
+        var view = this.config.Global.View;
+        for (var key in view) {
+            if (is_object(view[key]) && typeof view[key].disable_axis_area !== "undefined") {
+                view[key].disable_axis_area = 0;
+            }
+        }
+        this.controller.draw();
+    } else if (name == "indicator") {
+        $("#tool_list").find("li[name='indicator']").css('cursor', 'pointer');
+        indicator.show();
+    } else if (name == "tick_price") {
+
+    }
+}
+ToolBar.prototype.toolList = function() {
+    var _this = this;
+    $("#plot_area").css("cursor", "crosshair");
+     this.controller=this.api.controller;
+    var view = this.controller.view;
+    if (window["FlashCanvas"]) {
+        var count = 5;
+    } else {
+        var count = 2;
+    }
+    var crossMoveInterval = new IntervalEvent(
+        count,
+        function(controller, recall) //可以重新被call
+        {
+            var _this = controller.view;
+            if (typeof recall == "undefined") {
+                _this.draw();
+            }
+            if (!this.value || this.value.length != 3) {
+                return;
+            }
+            var x = this.value[0];
+            var y = this.value[1];
+            var index = this.value[2];
+            for (var i = 0; i < _this.canvasActiveCount; i++) {
+                _this.grid[i].drawCrossX(x, _this.axis[0]);
+            }
+            _this.grid[index].drawCrossY(y);
+        }
+    );
+    for (var i = 0; i < view.canvasActiveCount; i++) {
+        view.canvas[i].bind("mousemove", crossMoveInterval, this.crossMove);
+    }
+
+    //if the page is redraw, call it by controller.recall(). now, only new tick
+    //redraw need to recall.
+    this.controller.addIntervalEvent("crossMove", crossMoveInterval, true);
+    $(document).bind("mouseover", function(e) {
+        $("#plot_area").css("cursor", "default");
+        if(e.target.id.indexOf("plot")==-1){
+            for (var i = 0; i < view.canvasActiveCount; i++) {
+                view.canvas[i].unbind("mousemove", _this.crossMove);
+            }
+            view.draw();
+            _this.controller.removeIntervalEvent("crossMove");
+            _this.clickByLiName($("#tool_list"), "none");
+            $(document).unbind("mouseover");
+        }
+       
+    });
+}
+
+
+
+ToolBar.prototype.crossMove = function(event) {
+    var crossMoveInterval = event.data;
+    var id = $(this).attr("id");
+    var index = id.split("_").pop();
+    index = index.substr(0, index.length - 1);
+    index = parseInt(index);
+    var x = event.pageX - $(this).offset().left;
+    var y = event.pageY - $(this).offset().top;
+    crossMoveInterval.setVal([x, y, index]);
+}
+
+ToolBar.prototype.period = function(obj) {
+    var c =$.cookie('symbol');
+    if ($(obj).find("a").length ==1) {
+        var p = $.trim($(obj).text());
+       $.cookie('period',p);
+    } else {
+        // $(obj).find("a").setAttribute('class','active');
+        var elemt = obj.firstChild; 
+        elemt.setAttribute('class', 'active');// obj拿到的是类似<li name="M1" class="period"><a href="#">M1</a></li>,所以需要拿到M1也就是a标签下的text
+        var p = $.trim($(elemt).text());
+        $.cookie('period',p);
+         $.cookie('period',p);
+    }
+    // console.log("period:"+p)
+    HTML5StockChartAPI.API.setPair(c, p);
+    /* if (!c) {
+         return; //没有意义,直接忽略
+     } else {
+         HTML5StockChartAPI.API.setPair("MAC", p);
+     }*/
+}
+ToolBar.prototype.zoom = function(obj) {
+    var name = obj.attr("name");
+    if (name == "in") {
+        this.controller.zoomIn();
+    } else if (name == "out") {
+        this.controller.zoomOut();
+    }
+}
+
+ToolBar.prototype.style = function(obj) {
+    var name = obj.attr("name");
+    set_style(name);
+    this.controller.draw();
+}
+ToolBar.prototype.findSymbolSelected = function(obj) {
+    var text = "";
+
+    $(obj).find("a").each(function() {
+        if ($(this).attr("class") == "active") {
+            text = $(this).attr("name");
+        }
+
+    })
+    // console.log("findSymbolSelected:"+$.trim(text));
+    return $.trim(text);
+}
+
+ToolBar.prototype.findSelected = function(obj) {
+    var text = obj.find("li > strong").text();
+    return $.trim(text);
+}
+
+ToolBar.prototype.addSelectEvent = function(obj, callback) {
+    //获取li
+    var _this = this;
+    var _obj = obj.find("li");
+    _obj.each(
+        function() {
+            var __callback = callback;
+            var __obj = _obj;
+            $(this).bind("click", _this,
+                function(event) {
+                    var _this = event.data;
+                    __obj.each(
+                        function() {
+                            var text = $(this).text();
+                            text = $.trim(text);
+                            // $(this).html("<a href=\"javascript:void(0)\">" + text + "</a>");
+                        }
+                    );
+                    $(this).html('<a class="active" >' + $.trim($(this).text()) + '</a>');
+                    if (__callback) __callback.call(_this, $(this));
+                }
+            );
+        }
+    );
+}
+
+ToolBar.prototype.addClickEvent = function(obj, callback) {
+    var _this = this;
+    var _obj = obj.find("li");
+    _obj.each(
+        function() {
+            var __callback = callback;
+            $(this).bind("click", _this,
+                function(event) {
+                    var _this = event.data;
+                    if (__callback) __callback.call(_this, $(this))
+                }
+            );
+        }
+    );
+}
+
+//select item , not trigger event.
+ToolBar.selectItem = function(obj, name) {
+    var __obj = obj.find("li");
+    var _this = obj.find("li[name='" + name + "']");
+    __obj.each(
+        function() {
+            var text = $(this).text();
+            text = $.trim(text);
+            $(this).html("<a href=\"javascript:void(0)\">" + text + "</a>");
+        }
+    );
+    //alert(_this.length);
+    $(_this).html('<a class="active">' + $.trim($(_this).text()) + '</a>');
+}
+
+//view 视图,负责绘制图形。
+//控制器把从model 读取数据后,做处理完成。然后更新到view里面。
+//view 再利用这些数据,绘制出图形,view 不能直接读取model 的数据。
+//而是读取control 的数据,这样有一个中间的层次,便于扩展。
+//view 没有c . p 的概念。每个图形的model都会有一个getData接口。
+//每个图形的 view 都有一个setData 的接口。
+//关于图形的显示格式。我想任何选项,包括view 包括 model的都通过
+//更改config的形式来实现。对象本身只是读取配置,不提供更改接口。
+//比如:view 的样式的修改。每次在之前会读取配置。
+//比如:model改成静态图形了,也是类似的修改配置,就可以自动完成。
+//在不同对象之间传递配置信息过于繁琐。我想直接读取配置是最好的方式。
+//
+function View(controller) {
+    //当前的图像
+    this.controller = controller;
+    this.model = this.controller.model;
+    this.config = Config.getInstance();
+    this.plot_area = this.controller.plot_area;
+    this.setPlotArea();
+    this.canvas = [];
+    this.canvasBG = [];
+    this.canvasFront = [];
+    this.canvasContainer = [];
+    this.resize = [];
+    this.grid = [];
+    this.axis = [];
+
+    //给每个canvas分配一个grid对象
+
+    var main_axis = new Axis(null);
+
+    for (var i = 0; i < this.config.Global.maxCanvasCount; i++) {
+        var prefix = "#" + this.config.Global.canvasIDPerfix + i;
+        var id = prefix + "2";
+        var bg = prefix + "1";
+        var front = prefix + "0";
+
+        var id_div = "#" + this.config.Global.canvasIDPerfix + "div" + "_" + i;
+        //canvas
+        var tmp = $(id);
+        if (!tmp) {
+            continue;
+        }
+        if (!this.config.isIE6) {
+            tmp.hide();
+        }
+
+        this.canvas.push(tmp);
+        this.canvasBG.push($(bg).hide());
+        this.canvasFront.push($(front).hide());
+        this.canvasContainer.push($(prefix).hide());
+
+        //resize
+        var resize = $(id_div);
+        resize.hide();
+        this.resize.push(resize);
+
+        if (i == 0) { //主图
+            var axis_obj = main_axis;
+        } else {
+            var axis_obj = new Axis(main_axis);
+        }
+        this.axis.push(axis_obj);
+        this.grid.push(new PlotGrid(this, i));
+    }
+
+    //设置宽度
+    this.setWidth();
+    this.setHeight();
+
+    set_style();
+    //主图被注册了
+    this.canvasActiveCount = 1;
+    //判断兼容性
+    if (!check_textRender(this.canvas[0])) {
+        //console.log('loading stroke text' + __baseurl__ + "js/strokeText.js");
+        //include(__baseurl__ + "js/strokeText.js");
+    }
+    this.plot = {};
+    this.plotindex = {};
+    this.plotArea = {};
+    this.plotArea[this.config.mainName] = true;
+    this.viewconfig = [];
+
+    //注册主图
+    this.registerPlot(this.config.mainName, null, true, this.controller.ind[this.config.mainName].param);
+}
+
+View.prototype.deinit = function() {
+
+}
+
+View.prototype.setPlotArea = function(fixd) {
+    if (this.plot_area != window) {
+        var pa = $(this.plot_area);
+        this.plotWidth = pa.attr("fw") ? pa.attr("fw") : pa.width();
+        this.plotHeight = pa.attr("fh") ? pa.attr("fh") : pa.height();
+        $("#plot_area").height(this.plotHeight);
+        $("#plot_area").width(this.plotWidth);
+        $("#plot_content").show();
+        return;
+    }
+    if (!fixd) {
+        fixd = {};
+        fixd.x = 10;
+        fixd.y = 3;
+        if (this.config.browser == "ie" && this.config.bversion[0] >= 8) {
+            fixd.y = 8;
+        }
+    }
+    $("#plot_content").hide();
+    this.plotWidth = $(this.plot_area).width() - fixd.x;
+    this.offsetHeight = $("#plot_area").offset().top;
+    this.plotHeight = $(this.plot_area).height() - this.offsetHeight - fixd.y;
+    $("#plot_area").height(this.plotHeight + 1);
+    $("#plot_area").width($(this.plot_area).width());
+    if (this.plotWidth < 200) this.plotWidth = 200;
+    if (this.plotHeight < 100) this.plotHeight = 100;
+    $("#plot_content").show();
+}
+
+View.prototype.setWidth = function(w) {
+    if (!w) {
+        w = this.plotWidth;
+    }
+    for (var i = 0; i < this.config.Global.maxCanvasCount; i++) {
+        set_width(this.canvas[i], w);
+        set_width(this.canvasBG[i], w);
+        set_width(this.canvasFront[i], w);
+        set_width(this.resize[i], w);
+        this.grid[i].setWidth(w);
+    }
+}
+
+View.prototype.setHeight = function() {
+    // console.log()
+    for (var i = 0; i < this.config.Global.maxCanvasCount; i++) {
+        set_height(this.canvas[i], 1);
+    }
+}
+
+View.prototype.init = function() {
+    //注册全局事件
+    //resize 和 canvas 的事件放在grid中
+    this.lastW = $(this.plot_area).width();
+    this.lastH = $(this.plot_area).height();
+    $(document).bind("keydown", this, this.keydown);
+    $(document).bind("keyup", this, this.keyup);
+    $(this.plot_area).bind("resize", this, this.resizeWindow);
+    var _this = this;
+    _this.wheelEvent = new IntervalEvent(3,
+        function(controller) {
+            var mainName = controller.config.mainName;
+            var one = controller.view.plot[mainName].getOneSize();
+            var offset = Math.round(-this.value * 40 / one);
+            controller.startOffset(offset);
+            controller.draw();
+        }
+    );
+    this.controller.addIntervalEvent("wheelEvent", _this.wheelEvent);
+    var wheelobj;
+    if (this.plot_area == window) {
+        wheelobj = document;
+    } else {
+        wheelobj = this.plot_area;
+    }
+    $(wheelobj).mousewheel(
+        function(event, delta)
+        {
+            var e =  window.event||event;
+            console.log("滚轮事件:"+e)
+            if (e.wheelDelta == 120) {
+                _this.controller.zoomIn();
+                return true;
+            } else if (e.wheelDelta == -120) {
+                _this.controller.zoomOut();
+                return true;
+            }
+            if (e.detail == -3) {
+                _this.controller.zoomIn();
+                return true;
+            } else if (e.detail == 3) {
+                _this.controller.zoomOut();
+                return true;
+            }
+             if (e.originalEvent.deltaY == -3) {
+                _this.controller.zoomIn();
+                return true;
+            } else if (e.originalEvent.deltaY == 3) {
+                _this.controller.zoomOut();
+                return true;
+            }
+
+            //return false;
+        }
+    );
+    //注册十字光标事件
+
+}
+
+View.prototype.registerPlot = function(name, index, has_plot_area, param) {
+    if (this.config[name] && !this.plot[name]) {
+        var Plot = this.config[name].plot;
+        var index = this.getCanvas(name, index);
+        this.plot[name] = new Plot(this, this.grid[index], name);
+        if (param) this.plot[name].setParam(param);
+        if(index==0){
+            this.canvas[index].css('display', 'block');
+            this.canvasBG[index].css('display', 'block');
+            this.canvasFront[index].css('display', 'block');
+            // this.canvas[index].css('padding-top', '60px');
+            // this.canvasBG[index].css('padding-top', '60px');
+            // this.canvasFront[index].css('padding-top', '60px');
+            
+        }
+        else{
+            this.canvas[index].css('display', 'block');
+            this.canvasBG[index].css('display', 'block');
+            this.canvasFront[index].css('display', 'block');
+            //  this.canvas[index].css('padding-top', '10px');
+            // this.canvasBG[index].css('padding-top', '10px');
+            // this.canvasFront[index].css('padding-top', '10px');
+        }
+        
+        this.canvasContainer[index].css('display', 'block');
+        this.resize[index].show();
+        this.plotindex[name] = index;
+        if (has_plot_area) {
+            this.plotArea[name] = has_plot_area;
+        }
+        this.grid[index].addPlot(name, this.plot[name]);
+        this.setLast();
+    }
+}
+
+View.prototype.isSeperatePlot = function(name) {
+    if (!this.config.Global.View[name]) {
+        return null;
+    }
+    return this.config.Global.View[name].sep;
+}
+
+View.prototype.setLast = function() {
+    for (var i = 0; i < this.canvasActiveCount; i++) {
+        this.grid[i].clearLast();
+    }
+    this.grid[this.canvasActiveCount - 1].setLast();
+}
+
+View.prototype.unregisetPlot = function(name) {
+    this.plot[name] = null;
+    this.plotindex[name] = null;
+    this.setLast();
+    var index = this.plotindex[name];
+    this.grid[index].removePlot(name);
+}
+
+View.prototype.draw = function() {
+    //draw grid
+    //绘制Y轴
+    for (var i = 0; i < this.canvasActiveCount; i++) {
+        if (is_object(this.grid[i])) {
+            if (this.data[i].axis.y.axis) {
+                this.grid[i].drawBg();
+                this.grid[i].drawY();
+                this.grid[i].drawX(this.axis[0]);
+                //画canvas分割折线
+                var ctx = this.grid[i].ctx;
+                if(i != this.canvasActiveCount - 1){
+                drawLever(ctx,this.grid[i].xEnd.x-20,this.grid[i].yEnd.y-2,'#999',10,10);
+                drawLever(ctx,this.grid[i].xEnd.x-20,this.grid[i].yEnd.y+2,'#999',10,-10); 
+                }
+                
+                //绘制底部线条
+                // this.grid[i].drawLine(this.ctx, data.x, data.y, color);
+                //this.grid[i].drawBoder(this.axis[0]);
+            } else {
+                this.grid[i].drawBg();
+                this.grid[i].drawX(this.axis[0]);
+                 // drawLever(ctx,this.grid[i].xEnd.x,this.grid[i].yEnd.y,'#999',10,10);
+                //绘制底部线条
+                //this.grid[i].drawBoder(this.axis[0]);
+            }
+        }
+        if (i == this.canvasActiveCount - 1) {
+            //画线
+            //绘制底线没有其他图层了画线
+            var ctx = this.grid[i].ctx;
+            ctx.beginPath();
+            ctx.moveTo(this.grid[i].O.x, this.grid[i].yEnd.y+20 - this.grid[i].O.y);
+            ctx.lineTo(this.grid[i].xEnd.x, this.grid[i].yEnd.y+20 - this.grid[i].O.y);
+            ctx.closePath();
+            ctx.lineWidth = 0.3;
+            ctx.strokeStyle = "#fff";
+            ctx.stroke();
+
+        }
+    }
+
+
+    //绘制x。目前,x只需要绘制最后一个图形x轴部分
+    //开始绘制每个图形
+    for (i = 0; i < this.data.length; i++) {
+        var plot = this.data[i].data;
+        var text = "";
+        for (var key in plot) {
+            if (is_object(plot[key])) {
+                //坐标轴的选项对绘图中的 转换是有用的。在通过数字 转换
+                //成固定格式的数据的时候非常有用。比如时间转换,4舍五入等。
+                if (plot[key].x && plot[key].x.length > 0) {
+                    this.plot[key].draw(plot[key]);
+                    //顶部内容 update by fangxiao from 2016/6/29/17:47
+                    //  text += "[" + this.plot[key].getShowName() + " " + this.plot[key].lastDataShow() + "] ";
+                }
+            }
+        }
+        if (text.length > 0) {
+            //  console.log(text);
+            this.grid[i].writeHeadText(text);
+        }
+    }
+}
+
+//获取坐标轴的配置:
+//
+//1.附图,那么要和主图对应,这样时间应该是通过查询产生的。所以,不需要提供配置。
+//2.计算x轴,完全是利用主图的配置,这样计算主图的配置就可以了。
+//
+View.prototype.getAxisConfig = function() {
+    var one = this.plot[this.config.mainName].getOneSize(); //获取一个点占用的点数
+    var nx = this.config.Global.View[this.config.mainName].NXPixel; //x轴的数目推荐坐标的数目
+    var ny = this.config.Global.View[this.config.mainName].NYPixel; //x轴的数目推荐坐标的数目
+    var viewconfig = [];
+    for (var i = 0; i < this.canvasActiveCount; i++) {
+        if (is_object(this.grid[i])) {
+            viewconfig[i] = {};
+            var area = this.grid[i].getPlotArea();
+            var plotnum = Math.ceil((area.x.beg - area.x.end) / one);
+            viewconfig[i].plotnum = plotnum;
+            viewconfig[i].one = one;
+            viewconfig[i].x = {};
+            viewconfig[i].x.n = Math.round((area.x.beg - area.x.end) / nx);
+            viewconfig[i].x.beg = area.x.beg;
+            viewconfig[i].x.end = area.x.end;
+            viewconfig[i].y = {};
+            viewconfig[i].y.n = Math.round((area.y.beg - area.y.end) / ny);
+            viewconfig[i].y.beg = area.y.beg;
+            viewconfig[i].y.end = area.y.end;
+        }
+    }
+    for (var key in this.plotindex) {
+        var index = this.plotindex[key];
+        if (index === null) continue;
+        if (!viewconfig[index]) continue;
+        if (typeof viewconfig[index].plot === "undefined") viewconfig[index].plot = [];
+        viewconfig[index].plot.push(key);
+    }
+    this.viewconfig = viewconfig;
+    return viewconfig;
+}
+
+View.prototype.getAxis = function(name) {
+    var index = this.plotindex[name];
+    return this.axis[index];
+}
+
+View.prototype.getCanvas = function(name, index) {
+
+    //为指标和主函数分配canvas.
+    var plotconfig = this.config.Global.View;
+    //判断是否要增加canvas
+    if (name == this.config.mainName) {
+        this.grid[0].setHeight(this.plotHeight);
+    }
+    if ((typeof index !== "undefined") && index !== null && index < this.canvasActiveCount) {
+        return index;
+    }
+
+    if (!plotconfig[name] || !plotconfig[name].sep) {
+        return 0;
+    }
+    var h = this.getUnitHeight(name);
+    // console.log("getUnitHeight:"+h);
+    var index = this.setExistPlotHeight(h);
+    // console.log("getUnitHeight:"+h * plotconfig[name].height);
+    this.grid[index++].setHeight(h * plotconfig[name].height);
+    this.canvasActiveCount = index;
+    return index - 1;
+}
+
+//设置已经存在的图像的高度
+View.prototype.setExistPlotHeight = function(unit_h) {
+        //设置所有的canvas 的高度为0
+        var plotconfig = this.config.Global.View;
+        for (i = 0; i < this.grid.length; i++) {
+            this.grid[i].setHeight(1);
+        }
+        this.grid[0].setHeight(unit_h);
+        var index = 1;
+        //返回新加入名称的canvas
+        for (var key in this.plot) {
+            if (is_object(this.plot[key])) {
+                if (key == this.config.mainName) continue; //主图, 直接pass
+                if (!plotconfig[key]) continue; //没有配置,直接pass
+                if (plotconfig[key].sep) { //分离
+                    // console.log("unit_h * plotconfig[key].height:"+unit_h * plotconfig[key].height)
+                    this.grid[index++].setHeight(unit_h * plotconfig[key].height);
+                }
+            }
+        }
+        return index;
+        //新图加在末尾
+    }
+    //新家图像
+View.prototype.getUnitHeight = function(newname) {
+    var x = 1;
+    var plotconfig = this.config.Global.View;
+    for (var key in this.plot) {
+        if (is_object(this.plot[key])) {
+            if (key == this.config.mainName) continue; //主图, 直接pass
+            if (!plotconfig[key]) continue; //没有配置,直接pass
+            if (!this.plotArea[key]) {
+                continue;
+            }
+            if (plotconfig[key].sep) { //分离
+                x += plotconfig[key].height;
+            }
+        }
+    }
+    if (newname) {
+        x += plotconfig[newname].height;
+    }
+    var h = this.plotHeight * (1 / x);
+    return h;
+}
+
+View.prototype.clearData = function() {
+    this.data = [];
+    //清除原来的main值
+    this.axis[0].main = null;
+    for (var i = 0; i < this.canvasActiveCount; i++) {
+        this.axis[i].clearData();
+    }
+}
+
+View.prototype.updateData = function(data, index) {
+    var axis = this.axis[index];
+    axis.setViewConfig(this.viewconfig[index]);
+    axis.setData(data);
+    this.data[index] = axis.getData();
+}
+
+//这里的PlotGrid 的名字是暂时使用的,具体什么名字还没有取好
+//因为事件主要是在plotgrid中处理,所以,我用了这个名字
+View.prototype.keydown = function(event) {
+    var _this = event.data;
+    PlotGrid.setMoveInterval("key", _this.grid[0]);
+    debug("keydown");
+    if (event.keyCode == Key.KEY_NEXT) {
+        var offset = _this.controller.startSet("Next");
+        PlotGrid.moveQueue.push(offset);
+        return false;
+    } else if (event.keyCode == Key.KEY_PREV) {
+        var offset = _this.controller.startSet("Prev");
+        PlotGrid.moveQueue.push(offset);
+        return false;
+    } else if (event.keyCode == Key.KEY_PAGE_DOWN) {
+        var offset = _this.controller.startSet("PageDown");
+        PlotGrid.moveQueue.push(offset);
+        return false;
+    } else if (event.keyCode == Key.KEY_PAGE_UP) {
+        var offset = _this.controller.startSet("PageUp");
+        PlotGrid.moveQueue.push(offset);
+        return false;
+    } else if (event.keyCode == Key.KEY_HOME) {
+        var offset = _this.controller.startSet("Home");
+        PlotGrid.moveQueue.push(offset);
+        return false;
+    } else if (event.keyCode == Key.KEY_END) {
+        var offset = _this.controller.startSet("End");
+        PlotGrid.moveQueue.push(offset);
+        return false;
+    } else if (event.keyCode == Key.KEY_UP) {
+        _this.controller.zoomIn();
+        return false;
+    } else if (event.keyCode == Key.KEY_DOWN) {
+        _this.controller.zoomOut();
+        return false;
+    }
+}
+
+View.prototype.keyup = function(event) {
+    debug("keyup");
+    var _this = event.data;
+    PlotGrid.clearMoveInterval(_this.grid[0]);
+}
+
+View.prototype.resizeGrid = function(offset, index) {
+    debug("set resize offset " + offset);
+    if (offset == 0) return;
+    var grid1 = this.grid[index];
+    var grid2 = this.grid[index + 1];
+    // if(index==0){
+    //    var margin1 = grid1.marginTop[grid1.TOP] + grid1.marginTop[grid1.BOTTOM];
+    //    var margin2 = grid2.marginTop[grid2.TOP] + grid2.marginTop[grid2.BOTTOM]; 
+    // }else{
+    //     var margin1 = grid1.margin[grid1.TOP] + grid1.margin[grid1.BOTTOM];
+    //     var margin2 = grid2.margin[grid2.TOP] + grid2.margin[grid2.BOTTOM];
+    // }
+    var margin1 = grid1.margin[grid1.TOP] + grid1.margin[grid1.BOTTOM];
+        var margin2 = grid2.margin[grid2.TOP] + grid2.margin[grid2.BOTTOM];
+    if (!grid1 || !grid2) return;
+    if (offset > 0 && grid2.height - margin2 - offset <= 5) {
+        offset = grid2.height - 5 - margin2;
+    }
+    if (offset < 0 && grid1.height - margin1 + offset <= 5) {
+        offset = -(grid1.height - 5 - margin1);
+    }
+    grid1.setHeight(grid1.height + offset);
+    grid2.setHeight(grid2.height - offset);
+}
+
+View.prototype.resizeWindow = function(e) {
+    var _this = e.data;
+    if (!_this.lastW) {
+        return;
+    }
+    if (_this.lastW == $(window).width() && _this.lastH == $(window).height()) {
+        return;
+    }
+    //debugx("resize0: " + _this.lastW + "," +  _this.lastH);
+    //debugx("resize1: " + $(window).width() + "," + $(window).height());
+    _this.setPlotArea();
+    _this.setWidth();
+    //_this.setExistPlotHeight(_this.getUnitHeight());
+    //debugx("resize2: " + $(window).width() + "," + $(window).height());
+    //保存最新的window值
+    _this.lastW = $(window).width();
+    _this.lastH = $(window).height();
+    _this.controller.draw();
+}
+
+function Win(title, width, height, opt) {
+    this.title = title;
+    this.width = width ? width : 400;
+    this.height = height ? height : 300;
+    if (!opt) opt = {};
+    this.autoclose = opt.autoclose ? opt.autoclose : 0;
+    this.left = opt.left ? opt.left : -1; //-1表示默认向左,其实就是窗口居中
+    this.top = opt.top ? opt.top : -1; //top 的意义和 left相同
+    this.config = Config.getInstance();
+    this.tpl = $(this.config.Global.WinTplID);
+    this.cache = {};
+}
+Win.zindex = 1000;
+
+Win.prototype.getHtml = function() {
+    var html = this.tpl.html();
+    html = html.replace("{|$title|}", this.title);
+    html = html.replace("{|$autoclose|}", this.autoclose);
+    return html;
+}
+
+Win.prototype.createWindow = function(targetID) {
+    if ($("#" + targetID).length) {
+        return;
+    }
+    this.conf = this.config.Global.Win[targetID];
+    var html
+    var newhtml
+    if (targetID == "__order__") {
+        this.win = $("<div id='" + targetID + "'> </div><input type=\"hidden\" id=\"ordershow\" value=\"0\" />");
+        html = this.getHtml();
+        newhtml = html.replace("class=\"content\">", "id='popwin' class=\"content\">");
+    } else {
+        this.win = $("<div id='" + targetID + "'> </div>");
+        newhtml = this.getHtml();
+    }
+    this.targetID = targetID;
+    $("body").append(this.win);
+
+    this.win.html(newhtml);
+    this.dragArea = this.getClassQuery("popTop");
+    this.win.dragdrop(this.dragArea);
+    this.setWidth(this.width).setHeight(this.height);
+    this.win.css("position", "absolute");
+    this.win.css("z-index", Win.zindex);
+    this.setPotion();
+    Win.zindex++;
+    this.addTab();
+    this.addEvent();
+    this.clickFirst(this.getClassQuery("cc"));
+    this.win.hide();
+}
+
+Win.prototype.addTab = function() {
+    var query = this.getClassQuery("cc");
+    query = $(query);
+    for (var key in this.conf.tab) {
+        if (typeof this.conf.tab[key] == "string") {
+            query.append('<li name="' + key + '"><a href="javascript:;">' + this.conf.tab[key] + '</a></li>');
+        }
+    }
+}
+
+Win.prototype.clickFirst = function(query) {
+    query = $(query);
+    query.children().first().click();
+}
+
+Win.prototype.setPotion = function() {
+    if (this.top == -1) {
+        var top = Math.max(0, ($(window).height() - this.height) / 2);
+    }
+    if (this.left == -1) {
+        var left = Math.max(0, ($(window).width() - this.width) / 2);
+    }
+    this.win.css("top", top + "px");
+    this.win.css("left", left + "px");
+}
+
+Win.prototype.setWidth = function(w) {
+    var mainContainer = this.getClassQuery("windowBody");
+    $(mainContainer).width(w);
+    return this;
+}
+
+Win.prototype.setHeight = function(h) {
+    var mainContainer = this.getClassQuery("windowBody");
+    $(mainContainer).height(h);
+    return this;
+}
+
+Win.prototype.getClassQuery = function(classname) {
+    var targetID = this.targetID;
+    if (targetID.charAt(0) != "#") {
+        targetID = "#" + this.targetID
+    }
+    if (classname.charAt(0) != ".") {
+        classname = " ." + classname;
+    }
+    var query = targetID + classname;
+    return query
+}
+
+Win.prototype.show = function() {
+    this.win.show();
+    this.win.css("z-index", Win.zindex++);
+}
+
+Win.prototype.addEvent = function() {
+    //close
+    var query = this.getClassQuery("adel");
+    var _this = this;
+    $(query).click(
+        function() {
+            $("#tool_dl").find("li[name=none]").click();
+            _this.win.hide();
+        }
+    );
+
+    //tab
+    var query = this.getClassQuery("cc");
+    var _this = this;
+    $(query).children().click(function(e) {
+        $(query).children().removeClass("current");
+        $(this).addClass("current");
+        if (_this.load) {
+            _this.load($(this).attr("name"));
+        }
+    });
+}
+
+function WinAjax(name, title, width, height, opt) {
+    sup(this, title, width, height, opt);
+}
+
+ClassExtend(WinAjax, Win);
+
+WinAjax.prototype.load = function(name, flag) {
+    //这里可以根据name 做一些特殊的处理。
+    //但是,目前,我们采用的是 ajax 从服务器下载相关的配置
+    this.tab = name;
+    this.flag = flag;
+    var query = this.getClassQuery("content");
+    if (this.cache[name + flag]) {
+        $(query).html(this.cache[name + flag]);
+        return;
+    }
+    var api
+    if (name == "order") {
+        api = this.config.Global.WinOrder;
+    } else {
+        api = this.config.Global.WinAPI;
+    }
+
+
+    var _this = this;
+    if (this.ajax) {
+        this.ajax.abort();
+    }
+    var param = { win: this.targetID, tab: name, __tmp: Math.random() };
+    if (this.flag) {
+        param.flag = this.flag;
+    }
+    if (name == "order") {
+        this.ajax = $.get(api, function(data) {
+            //_this.cache[data.tab + data.flag] = data.data;
+            $(query).html(data);
+
+        }, "html");
+    } else {
+        this.ajax = $.get(api, param, function(data) {
+            _this.cache[data.tab + data.flag] = data.data;
+            $(query).html(data.data);
+        }, "jsonp");
+
+    }
+}
+
+function ShapeArrow(ctx, width, height, opt) {
+    sup(this, ctx, width, height, opt);
+}
+
+ClassExtend(ShapeArrow, Shape);
+
+ShapeArrow.prototype.arrowhalf = function(ctx, width, height) {
+    var pi = Math.PI;
+    ctx.save();
+    ctx.translate(0, -height);
+    ctx.beginPath();
+    ctx.moveTo(0, 0);
+    ctx.lineTo(width, 0);
+    var head = (0.618) * height;
+    ctx.lineTo(width, head);
+    if (width <= 3) {
+        var add = 3;
+    } else {
+        var add = width / 0.618;
+    }
+    ctx.lineTo(width + add, head - width * Math.tan(pi / 3));
+    ctx.lineTo(0, height);
+    ctx.closePath();
+    ctx.stroke();
+    ctx.fill();
+    ctx.restore();
+}
+
+ShapeArrow.prototype.basic_arrow = function(ctx, width, height) {
+    ctx.save();
+    this.arrowhalf(ctx, width, height);
+    ctx.transform(-1, 0, 0, 1, 0, 0);
+    this.arrowhalf(ctx, width, height);
+    ctx.restore();
+}
+
+//箭头的定位在于两个方面。一个方面是旋转的角度,一个是箭头指向的位置
+ShapeArrow.prototype.draw = function(point) {
+    var ctx = this.ctx;
+    var cta = this.cta;
+    ctx.save();
+    ctx.translate(point.x, point.y);
+    ctx.rotate(cta);
+    ctx.strokeStyle = this.boder;
+    ctx.fillStyle = this.fill;
+    this.basic_arrow(ctx, this.width, this.height);
+    ctx.restore();
+}
+
+function PlotAdvFractals(view, grid, name) {
+    sup(this, view, grid, name);
+}
+ClassExtend(PlotAdvFractals, Plot);
+
+PlotAdvFractals.prototype.draw = function(data) {
+    var color;
+    if (this.param.lineColor) {
+        color = this.param.lineColor;
+    } else {
+        color = this.conf.lineColor;
+    }
+    /* for(var i = 0 ;i<data.x.length ;i++){
+       if(data.y[i][0] ==-1){
+           writeText(this.ctx, new Point(data.x[i] , data.y[i][1]+12), "d", color[0], this.param.font);
+        }else if(data.y[i][0] == 1){
+           writeText(this.ctx, new Point(data.x[i] , data.y[i][1]-12), "u", color[1], this.param.font);
+        } 
+    }*/
+    var y1 = []
+    for (var i = 0; i < data.y.length; i++) {
+        y1[i] = data.y[i][1];
+    }
+    drawLine(this.ctx, data.x, y1, color[0]);
+}
+
+function Plotadx(view, grid, name) {
+    sup(this, view, grid, name);
+}
+ClassExtend(Plotadx, Plot);
+
+Plotadx.prototype.draw = function(data) {
+    var color;
+    if (this.param.lineColor) {
+        color = this.param.lineColor;
+    } else {
+        color = this.conf.lineColor;
+    }
+    var y1 = []
+    var y2 = []
+    var y3 = []
+    for (var i = 0; i < data.y.length; i++) {
+        y1[i] = data.y[i][0];
+        y2[i] = data.y[i][1];
+        y3[i] = data.y[i][2];
+    }
+    drawLine(this.ctx, data.x, y1, color[0]);
+    drawLine(this.ctx, data.x, y2, color[1]);
+    drawLine(this.ctx, data.x, y3, color[2]);
+}
+
+
+
+
+function Plotatr(view, grid, name) {
+    sup(this, view, grid, name);
+}
+ClassExtend(Plotatr, Plot);
+
+Plotatr.prototype.draw = function(data) {
+    //建立点
+    var color;
+    if (this.param.color) {
+        color = this.param.color;
+    } else {
+        color = this.conf.lineColor;
+    }
+    var y1 = []
+    var y2 = []
+    for (var i = 0; i < data.y.length; i++) {
+        y1[i] = data.y[i][0];
+        y2[i] = data.y[i][1];
+    }
+    drawLine(this.ctx, data.x, y1, color[0]);
+    drawLine(this.ctx, data.x, y2, color[1]);
+}
+
+
+function Plotbdensity(view, grid, name) {
+    sup(this, view, grid, name);
+}
+ClassExtend(Plotbdensity, Plot);
+
+Plotbdensity.prototype.draw = function(data) {
+    //建立点
+    var color;
+    if (this.param.lineColor) {
+        color = this.param.lineColor;
+    } else {
+        color = this.conf.lineColor;
+    }
+
+    for (var i = 0; i < data.y.length; i++) {
+        if (data.y[i][2] != 0) {
+            writeText(this.ctx, new Point(data.x[i], data.y[i][0]), "~", color[0], this.param.font)
+            writeText(this.ctx, new Point(data.x[i], data.y[i][1]), "*", color[0], this.param.font)
+        }
+        if (data.y[i][6] != 0) {
+            writeText(this.ctx, new Point(data.x[i], data.y[i][4]), "~", color[1], this.param.font)
+            writeText(this.ctx, new Point(data.x[i], data.y[i][5]), "*", color[1], this.param.font)
+        }
+        if (data.y[i][10] != 0) {
+            writeText(this.ctx, new Point(data.x[i], data.y[i][8]), "~", color[2], this.param.font)
+            writeText(this.ctx, new Point(data.x[i], data.y[i][9]), "*", color[2], this.param.font)
+        }
+    }
+}
+
+function PlotBolling(view, grid, name) {
+    sup(this, view, grid, name);
+}
+ClassExtend(PlotBolling, Plot);
+
+PlotBolling.prototype.draw = function(data) {
+    //建立点
+    var color;
+    if (this.param.color) {
+        color = this.param.color.split("-");
+    } else {
+        color = this.conf.lineColor;
+    }
+    var y1 = []
+    var y2 = []
+    var y3 = []
+    for (var i = 0; i < data.y.length; i++) {
+        y1[i] = data.y[i][0];
+        y2[i] = data.y[i][1];
+        y3[i] = data.y[i][2];
+    }
+    drawLine(this.ctx, data.x, y1, color[0]);
+    drawLine(this.ctx, data.x, y2, color[1]);
+    drawLine(this.ctx, data.x, y3, color[2]);
+}
+
+
+function PlotBollingDesity(view, grid, name) {
+    sup(this, view, grid, name);
+    this.color = ["red", "rgb(255, 128, 128)", "red", "rgb(255, 128, 128)",
+        "green", "rgb(128, 255, 128)", "green", "rgb(128, 255, 128)",
+        "yellow", "rgb(128, 255, 128)", "yellow", "rgb(128, 255, 128)",
+        "Cyan", "Cyan",
+        "Blue", "Blue",
+        "Fuchsia", "Fuchsia",
+    ];
+}
+
+ClassExtend(PlotBollingDesity, Plot);
+
+PlotBollingDesity.prototype.draw = function(data) {
+    this.X = data.x;
+    this.Y = data.y;
+    this.setMaxMinDesity();
+    this.getPlotArea();
+    this.box = this.view.plot[this.config.mainName].getBoxSize();
+    this.left = this.view.plot[this.config.mainName].getBoxLeft();
+    for (var i = 0; i < this.X.length; i++) {
+        this.drawOne(this.X[i], this.Y[i]);
+    }
+}
+
+PlotBollingDesity.prototype.setMaxMinDesity = function() {
+    var min = Infinity
+    var max = -Infinity;
+    var y = this.Y;
+    for (var i = 0; i < y.length; i++) {
+        for (var j = 1; j < y.length; j += 2) {
+            if (y[i][j] == -1) {
+                continue;
+            }
+            if (max < y[i][j]) {
+                max = y[i][j];
+            }
+
+            if (min > y[i][j]) {
+                min = y[i][j]
+            }
+        }
+    }
+    this.maxD = max;
+    this.minD = min;
+}
+
+PlotBollingDesity.prototype.drawOne = function(time, data) {
+    var price, desity, color, left, top;
+    try {
+        for (var i = 0; i < 16; i += 2) {
+            price = data[i];
+            if (price == -1 || data[i + 1] == -1) {
+                continue;
+            }
+            desity = this.getDesity(data[i + 1]);
+            color = this.color[i / 2];
+            this.ctx.fillStyle = color;
+            left = time - this.left;
+            top = price - desity;
+            if (top < this.top || top > this.bottom) {
+                continue;
+            }
+            this.ctx.fillRect(left, top, this.box, desity);
+        }
+    } catch (e) {}
+}
+
+PlotBollingDesity.prototype.getDesity = function(d) {
+    return (Math.floor(((d - this.minD) / (this.maxD - this.minD)) * 6) + 1);
+}
+
+PlotBollingDesity.prototype.lastDataShow = function() {
+    var data = this.lastData();
+    var newdata = [];
+    for (var i = 0; i < data.length; i += 2) {
+        newdata[i / 2] = data[i];
+    }
+    return newdata;
+}
+
+function PlotCandle(view, grid, name) {
+    sup(this, view, grid, name);
+    //放大缩小尺寸控制更加灵活。采用配置数组的形式
+     this.box = [1, 2, 3, 5, 7, 9, 11, 13];
+    this.space = [0, 1, 1, 2, 2, 3, 4, 5];
+    this.left = [0, 1, 1, 2, 3, 4, 5, 6]
+    // this.box = [ 7, 9, 11, 13,15,18,21,23];
+    // this.space = [ 2, 3, 4, 5,6,8,9,10];
+    // this.left = [ 3, 4, 5, 6,7,9,10,11]
+    // this.box   = [3, 5, 9, 13, 17, 19, 23, 25];
+    // this.space = [1, 2, 3, 5, 7, 8, 10, 11];
+    // this.left  = [1, 2, 4, 6, 8, 9, 11, 12]
+}
+
+ClassExtend(PlotCandle, Plot);
+
+PlotCandle.prototype.zoomIn = function() {
+    if (this.conf.box_pixel >= 7 && this.conf.space_pixel >= 7) {
+        return;
+    }
+    if (this.conf.box_pixel < this.conf.space_pixel) {
+        this.conf.box_pixel++;
+    } else if (this.conf.box_pixel > this.conf.space_pixel) {
+        this.spaceOffset(1);
+    } else {
+        this.conf.box_pixel++;
+    }
+}
+
+PlotCandle.prototype.spaceOffset = function(offset) {
+    var prev = this.space[this.conf.space_pixel];
+    this.conf.space_pixel = this.conf.space_pixel + offset;
+    var current = this.space[this.conf.space_pixel];
+    if (prev == current) {
+        this.conf.box_pixel = this.conf.box_pixel + offset;
+    }
+}
+
+PlotCandle.prototype.zoomOut = function() {
+    if (this.conf.box_pixel <= 0 && this.conf.space_pixel <= 0) {
+        return;
+    }
+    if (this.conf.box_pixel < this.conf.space_pixel) {
+        this.spaceOffset(-1);
+    } else if (this.conf.box_pixel > this.conf.space_pixel) {
+        this.conf.box_pixel--;
+    } else {
+        this.spaceOffset(-1);
+    }
+    this.conf.box_pixel = this.conf.box_pixel < 0 ? 0 : this.conf.box_pixel;
+}
+
+PlotCandle.prototype.getOneSize = function() {
+    return this.box[this.conf.box_pixel] + 2*this.space[this.conf.space_pixel];
+}
+
+PlotCandle.prototype.getBoxLeft = function() {
+    return this.left[this.conf.box_pixel];
+}
+
+PlotCandle.prototype.getBoxSize = function() {
+    return this.box[this.conf.box_pixel];
+}
+
+PlotCandle.prototype.draw = function(data) {
+    this.data = data;
+    this.X = data.x;
+    this.Y = data.y;
+    this.xunit = this.data.xunit;
+    this.yunit = this.data.yunit;
+    this.closePriceFlag();
+    var width = this.box[this.conf.box_pixel];
+    var left = this.left[this.conf.box_pixel];
+    if (width > 2) {
+        width--;
+    }
+    this.config.Global.boxwidth = width;
+    //最高最低点标签
+    var maxy=this.Y[this.data.maxIndex][1]-5;
+    var miny=this.Y[this.data.minIndex][2]+15;
+    writeText(this.ctx,new Point(this.X[this.data.maxIndex],maxy),parseFloat(this.data.maxY).toFixed(3), "#ff6600", "#fff");
+    writeText(this.ctx,new Point(this.X[this.data.minIndex],miny),parseFloat(this.data.minY).toFixed(3), "#ff6600", "#fff");
+    //画个分界线
+
+    for (var i = 0; i < this.X.length; i++) {
+
+        this.drawOne(this.X[i], this.Y[i], width, left);
+        // var ohlc=this.Y[i];
+        // var maxy=parseFloat(GetText(ohlc[1],this.yunit)).toFixed(3);
+        // var miny=parseFloat(GetText(ohlc[2],this.yunit)).toFixed(3); 
+        // if(maxy==this.data.maxY){
+        //      writeText(this.ctx, new Point(this.X[i] + this.conf.ledgeLen + 2, this.Y[i]), this.data.maxY, this.conf.fontColor, this.conf.font);
+        // }
+        // if(miny==this.data.minY){
+        //     writeText(this.ctx, new Point(this.X[i] + this.conf.ledgeLen + 2, this.Y[i]), this.data.maxY, this.conf.fontColor, this.conf.font);
+        // }
+    }
+    //console.log(data.text);
+}
+
+//按照道理,这些数据都应该是计算好了之后,
+//会送给客户端的。这个部分,还是要对数据层进行改进
+//才能比较好的封装。现在暂时这样处理。
+PlotCandle.prototype.closePriceFlag = function() {
+    //view 一般不调用model的数据。因为,这样使得view 和 model层直接联系起来。
+    //但是,我们知道,我们的Controller 是一般性的分发。
+    //而且这样的一般性的分发在大多数情况下面是够用的。
+    //出于这样的考虑,我们允许在view里面调用model,因为,的确很多时候需要这样的调用。
+    //每个图都有对应的 model plot
+
+    var close_price = this.view.model.getDataReader(this.name).close(0);
+    this.priceFlag(close_price, this.conf.close);
+}
+
+PlotCandle.prototype.over = function(x, y) {
+    //查找最接近的
+   // console.log("1");
+    if (!this.X || !this.Y) return;
+    var index = find_near(this.X, x);
+    if (index == -1) return false;
+    if (Math.abs(this.X[index] - x) > this.getOneSize()) {
+        return false;
+    }
+    var ohlc = this.Y[index];
+
+    // console.log("text PlotCandle");
+    //找到此金额的y轴坐标
+    //if (ohlc[Data.HIGH] - this.config.Global.overPadding <= y && ohlc[Data.LOW] + this.config.Global.overPadding >= y) {
+        var findTime = this.axis.getXValue(x, PlotGrid.NEAR);
+        if (findTime === false) return;
+        var cdata = this.view.model.getDataByTime(this.name, findTime, "candle");
+        if (!cdata) return false;
+        var time = cdata.time;
+        var ohlc = cdata.data;
+        var yunit = this.axis.viewconfig.y.axis_option.unit;
+        var fallOrDegrees = parseFloat(GetText(ohlc[Data.CLOSE], yunit) - GetText(ohlc[Data.OPEN], yunit)) / parseFloat(GetText(ohlc[Data.OPEN], yunit));
+        var fallOrDegrees = fallOrDegrees.toFixed(3);
+        
+        $(".freetimebox li:first-child").text("时间:"+time);
+        $(".freetimebox li:nth(1)").text("开:"+GetText(ohlc[Data.OPEN], yunit));
+        $(".freetimebox li:nth(2)").text("高:"+GetText(ohlc[Data.HIGH], yunit));
+        $(".freetimebox li:nth(3)").text("低:"+GetText(ohlc[Data.LOW], yunit));
+        $(".freetimebox li:nth(4)").text("收:"+GetText(ohlc[Data.LOW], yunit));
+        $(".freetimebox li:nth(4)").text("收:"+GetText(ohlc[Data.CLOSE], yunit));
+        $(".freetimebox li:nth(5)").text("涨幅:"+fallOrDegrees);
+        $(".freetimebox li:nth(6)").text("振幅:"+fallOrDegrees);
+        $(".freetimebox li:nth(7)").text("量:"+GetText(ohlc[Data.VOLUMES], yunit));
+         $('.freetimebox').show();
+        //timeLine Data
+        // timelineData(time, GetText(ohlc[Data.OPEN], yunit), GetText(ohlc[Data.HIGH], yunit), GetText(ohlc[Data.LOW], yunit), GetText(ohlc[Data.CLOSE], yunit), GetText(ohlc[Data.VOLUMES], yunit));
+      //  console.log("text PlotCandle");
+       // return time + "<br/>" + "O: " + GetText(ohlc[Data.OPEN], yunit) + "<br />" + "H: " + GetText(ohlc[Data.HIGH], yunit) + "<br />" + "L : " + GetText(ohlc[Data.LOW], yunit) + "<br />" + "C: " + GetText(ohlc[Data.CLOSE], yunit) + "<br />" + "V: " + GetText(ohlc[Data.VOLUMES], yunit) + "<br />";
+   // } else {
+   //     return false;
+   // }
+}
+
+PlotCandle.prototype.drawOne = function(time, ohlc, width, left) {
+    var ctx = this.ctx;
+    var open = ohlc[Data.OPEN];
+    var high = ohlc[Data.HIGH];
+    var low = ohlc[Data.LOW];
+    var close = ohlc[Data.CLOSE];
+    time += 0.5;
+    open += 0.5;
+    high += 0.5;
+    low += 0.5;
+    close += 0.5;
+    if (high == low) {
+        //画个横线就可以了
+        ctx.strokeStyle = this.conf.os_border_color;
+        ctx.beginPath();
+        ctx.moveTo(time - left, open);
+        ctx.lineTo(time + width, open);
+        ctx.stroke();
+        return;
+    }
+    if (open < close) {
+        var up = open;
+        var down = close;
+        var fill = this.conf.open_big_color;
+        var border = this.conf.ob_border_color;
+    } else {
+        var up = close;
+        var down = open;
+        var fill = this.conf.open_small_color;
+        var border = this.conf.os_border_color;
+    }
+    ctx.strokeStyle = border;
+    ctx.beginPath();
+    ctx.moveTo(time, high);
+    ctx.lineTo(time, low);
+    ctx.stroke();
+    if (this.conf.space_pixel > 0) {
+        ctx.fillStyle = fill;
+        ctx.fillRect(time - left, up, width, down - up);
+        ctx.strokeRect(time - left, up, width, down - up);
+    }
+}
+
+
+function PlotFractals(view, grid, name) {
+    sup(this, view, grid, name);
+}
+ClassExtend(PlotFractals, Plot);
+
+PlotFractals.prototype.draw = function(data) {
+    var color;
+    if (this.param.lineColor) {
+        color = this.param.lineColor;
+    } else {
+        color = this.conf.lineColor;
+    }
+    /* for(var i = 0 ;i<data.x.length ;i++){
+       if(data.y[i][0] ==-1){
+           writeText(this.ctx, new Point(data.x[i] , data.y[i][1]+12), "d", color[0], this.param.font);
+        }else if(data.y[i][0] == 1){
+           writeText(this.ctx, new Point(data.x[i] , data.y[i][1]-12), "u", color[1], this.param.font);
+        } 
+    }*/
+    var y1 = []
+    for (var i = 0; i < data.y.length; i++) {
+        y1[i] = data.y[i][1];
+    }
+    drawLine(this.ctx, data.x, y1, color[0]);
+}
+
+//grid 是一个令人纠结的类,他是图形的一部分,各种图形都在grid上进行绘制
+function PlotGrid(view, index) {
+    this.TOP = 0;
+    this.RIGHT = 1;
+    this.BOTTOM = 2;
+    this.LEFT = 3;
+
+    this.index = index;
+    this.view = view;
+    this.axis = this.view.axis[index];
+    this.canvas = $(this.view.canvas[index]);
+    this.canvasBG = $(this.view.canvasBG[index]);
+    this.canvasFront = $(this.view.canvasFront[index]);
+    this.canvasContainer = $(this.view.canvasContainer[index]);
+
+    this.resize = this.view.resize[index];
+    this.controller = this.view.controller;
+    this.plot = [];
+
+    if (!this.canvas.get(0).getContext) {
+        //debug(Alert(this.canvas.get(0)));
+        $("#flash_notify").show();
+        alert("not support flash or html5");
+    }
+    this.ctx = this.canvas.get(0).getContext('2d');
+   
+    this.ctxBG = this.canvasBG.get(0).getContext('2d');
+    this.ctxFront = this.canvasFront.get(0).getContext('2d');
+   // if(index==0){
+   //  this.height = this.canvas.get(0).height-60;
+   // }
+   // else{
+   //  this.height = this.canvas.get(0).height-10;
+   // }
+    this.width = this.canvas.get(0).width;
+    this.height = this.canvas.get(0).height;
+    
+    // var img=document.getElementById("myCanvas");
+    // this.ctx.drawImage(pic,0,0,this.width, this.height);  
+    this.config = Config.getInstance();
+    this.conf = this.config.Global.Grid.public; //这个是全局公共配置,更改会引起全局对象的改变。
+    //私有变量导出
+    this.margin = array_copy(this.conf.margin);
+    this.xstyle_axis = this.conf.xstyle_axis;
+    this.ystyle_axis = this.conf.ystyle_axis;
+    this.setConfig();
+    this.addEvent();
+    PlotGrid._this = this;
+}
+
+PlotGrid.FIX_BEG = 1; //开始值固定 (小值)
+PlotGrid.FIX_END = 1 << 1; //结束值固定 (大值)
+PlotGrid.FLOAT = 1 << 2; //浮动计算,可以得到更好的坐标值(浮动20%,得到一些更好的值)
+PlotGrid.GT_ZERO = 1 << 3;
+PlotGrid.TIME = 1 << 4;
+PlotGrid.FIX_PIXEL = 1 << 5;
+PlotGrid.NO_GRID = 1 << 6;
+PlotGrid.NO_AXIS = 1 << 7;
+PlotGrid.NEAR = 1 << 8; //采用寻找最近的点的模式
+PlotGrid.INTERPOLATION = 1 << 9; //采用差值法
+PlotGrid.ADD_YEAR = 1 << 10; //采用差值法
+
+PlotGrid.prototype.setConfig = function() {
+    this.O = new Point(this.margin[this.LEFT], this.margin[this.TOP]);
+    this.xEnd = new Point(this.width - this.margin[this.RIGHT], this.margin[this.TOP]);
+    this.yEnd = new Point(this.margin[this.LEFT], this.height - this.margin[this.BOTTOM]);
+    this.xyEnd = new Point(this.width - this.margin[this.RIGHT], this.height - this.margin[this.BOTTOM]);
+}
+
+PlotGrid.prototype.setLast = function() {
+    this.clearLast();
+    if (this.margin[this.BOTTOM] < 20) {
+        this.margin[this.BOTTOM] = 20; //又足够的地方写字
+    }
+    this.resize.hide();
+    this.xstyle_axis = this.xstyle_axis & ~PlotGrid.NO_AXIS;
+    this.setConfig();
+}
+
+PlotGrid.prototype.clearLast = function() {
+    this.margin = array_copy(this.conf.margin);
+    if (!this.xstyle_axis) {
+        this.xstyle_axis = 0;
+    }
+    this.resize.show();
+    this.xstyle_axis |= PlotGrid.NO_AXIS;
+    this.setConfig();
+}
+
+PlotGrid.prototype.setHeight = function(h) {
+    h = Math.round(h);
+ // console.log(h);
+    this.height = h;
+    // if(this.canvasContainer.attr('id')=="plot_canvas_0"){
+    //     h=h-60;
+    // }
+    // else{
+    //     h=h;
+    // }
+    // console.log("PlotGrid.prototype.setHeight:"+this.height)
+    set_height(this.canvas, h);
+    set_height(this.canvasBG, h);
+    set_height(this.canvasFront, h);
+    set_height(this.canvasContainer, h);
+    this.resize.css("top", $(this.canvas).offset().top + h - 4);
+    this.setConfig();
+}
+
+PlotGrid.prototype.setWidth = function(w) {
+    this.width = w;
+    this.setConfig();
+}
+
+PlotGrid.prototype.getPlotArea = function() {
+        //获取绘图的区域
+        var area = { x: {}, y: {} };
+        area.y.beg = Math.round(this.xyEnd.y - this.conf.paddingY);
+        area.y.end = Math.round(this.xEnd.y);
+        area.x.beg = Math.round(this.xyEnd.x - this.conf.paddingX);
+        area.x.end = Math.round(this.yEnd.x);
+        return area;
+    }
+    //绘制行,要考虑padding的值 update by fangxiao from 2016/6/29 17:16
+PlotGrid.prototype.drawY = function(axis) {
+    if (!axis) axis = this.axis;
+    axis_option = axis.viewconfig.y.axis_option;
+    var points = axis.viewconfig.y.axis;
+    for (var i = 0; i < points.length; i++) {
+        var point = new Point(this.O.x, points[i].key);
+        var len = this.xEnd.x - this.O.x;
+        if (this.conf.ystyle_grid & PlotGrid.NO_GRID) {
+            //do noting
+        } else {
+            drawRow(this.ctx, point, len, this.conf.gridColor, 1);
+        }
+        
+        if (this.ystyle_axis & PlotGrid.NO_AXIS) {
+            //do nothing
+        } else {
+            var point = new Point(this.xEnd.x, points[i].key);
+            //drawRow(this.ctx, point, this.conf.ledgeLen, this.conf.axisColor, 1); 去除y轴右侧字旁边的横杆
+            var text = this.getText(axis_option.style, points[i].value, axis_option.unit);
+            if (i == points.length - 1) //最后一个点,往内缩
+            {
+//              var ypoint = points[i].key + 12;
+
+                var ypoint = points[i].key;
+            } else {
+                var ypoint = points[i].key;
+            }
+            if(i!=0){
+               drawDashLine(this.ctx,this.O.x,ypoint,this.xEnd.x,ypoint,2); 
+            }
+            
+            writeText(this.ctx, new Point(this.xEnd.x + this.conf.ledgeLen + 2, ypoint), text, this.conf.fontColor, this.conf.font);
+
+        }
+    }
+}
+
+PlotGrid.prototype.drawCrossX = function(x, axis) {
+    var len = this.yEnd.y - this.O.y;
+    drawCol(this.ctx, new Point(x, this.O.y-15), len+20, this.conf.crossX.lineColor, 0.6);
+    if (this.xstyle_axis & PlotGrid.NO_AXIS) {
+        //do nothing;
+    } else {
+        this.writeXLable(x, axis);
+    }
+}
+
+//开始绘制
+PlotGrid.prototype.writeXLable = function(x, axis) {
+    if (typeof axis === "undefined") {
+        axis = this.axis;
+    }
+    var value = this.axis.getXValue(x, this.conf.crossXMode, axis);
+    if (value === false) return;
+    var opt = axis.viewconfig.x.axis_option;
+    value = this.getText(opt.style, value, opt.unit);
+    writeTextOption(this.ctx, new Point(x - this.conf.crossX.bg.width / 2, this.yEnd.y + this.conf.crossX.bg.height / 2), value, this.conf.crossX);
+}
+
+//开始绘制
+PlotGrid.prototype.writeYLable = function(y, axis) {
+    if (typeof axis === "undefined") {
+        axis = this.axis;
+    }
+    var value = this.axis.getYValue(y, this.conf.crossYMode, axis);
+    if (value === false) return;
+    var opt = axis.viewconfig.y.axis_option;
+    value = this.getText(opt.style, value, opt.unit);
+    writeTextOption(this.ctx, new Point(this.xEnd.x, y), value, this.conf.crossY);
+}
+
+PlotGrid.prototype.writeHeadText = function(text) {
+    writeText(this.ctx, new Point(this.O.x + 10, this.O.y + 20), text, this.conf.headText.color, this.conf.headText.font);
+}
+
+PlotGrid.prototype.drawCrossY = function(y) {
+    var len = this.xEnd.x - this.O.x;
+    drawRow(this.ctx, new Point(this.O.x, y), len, this.conf.crossY.lineColor, 0.3);
+    if (this.ystyle_axis & PlotGrid.NO_AXIS) {
+        //do nothing
+    } else {
+        this.writeYLable(y);
+    }
+}
+
+PlotGrid.prototype.drawX = function(axis) {
+    if (!axis) axis = this.axis;
+    axis_option = axis.viewconfig.x.axis_option;
+    var points = axis.viewconfig.x.axis;
+    if (typeof points === "undefined") {
+        return;
+    }
+
+
+    for (var i = 0; i < points.length; i++) {
+        var point = new Point(points[i].key, this.O.y);
+        var len = this.yEnd.y - this.O.y;
+        if (this.conf.xstyle_grid & PlotGrid.NO_GRID) {
+            //do noting
+        } else {
+            drawCol(this.ctx, point, len, this.conf.gridColor, 1);
+        }
+        if (this.xstyle_axis & PlotGrid.NO_AXIS) {
+            //do nothing
+        } else {
+            var point = new Point(points[i].key, this.yEnd.y);
+            //画线
+
+            drawCol(this.ctx, point, this.conf.ledgeLen, this.conf.axisColor, 1);
+            var offset = 0;
+            if (i == points.length - 1) {
+                var text = this.getText(axis_option.style | PlotGrid.ADD_YEAR, points[i].value, axis_option.unit);
+                offset = -20;
+            } else {
+                var text = this.getText(axis_option.style, points[i].value, axis_option.unit);
+            }
+            writeText(this.ctx, new Point(points[i].key + offset,
+                this.yEnd.y + this.conf.ledgeLen + 12), text, this.conf.fontColor, this.conf.font);
+        }
+    }
+}
+
+//如果是固定像素的形式的,xstart 是开始index xend 是结束的 index xunit 是数据
+//设计默认是xend 是画在最右边,如果屏幕像素不够,自动会舍弃xstart 这边的。
+PlotGrid.prototype.drawBg = function() {
+        this.ctx.fillStyle = this.conf.bgColor;
+        this.ctx.fillRect(0, 0, this.width, this.height);
+    }
+    //update by fangxiao from 2016、6/29 17:24
+PlotGrid.prototype.drawBoder = function(axis) {
+    /*
+    if (!axis) axis = this.axis;
+    axis_option = axis.viewconfig.x.axis_option;
+    var points  = axis.viewconfig.x.axis;
+    if (typeof points === "undefined")
+    {
+        return;
+    }*/
+    //绘制底部线条
+    this.ctx.lineWidth = 0.85;
+    this.ctx.strokeStyle = this.conf.axisColor;
+    //this.ctx.moveTo(this.O.x + 0.5,this.0.y+this.O.y-this.yend.y+0.5);
+    //this.ctx.lineTo(this.xEnd.x+0.5,this.0.y+this.O.y-this.yend.y+0.5);
+    //this.ctx.stroke();
+    //this.ctx.moveTo(this.O.x + 0.5,this.yEnd.y - this.O.y);
+    //this.ctx.lineTo(this.xEnd.x - this.O.x, this.yEnd.y - this.O.y);
+    //this.ctx.fill();
+    //  this.ctx.stroke();
+    this.ctx.strokeRect(this.O.x + 0.5, this.O.y + 0.5, this.xEnd.x - this.O.x, this.yEnd.y - this.O.y);
+}
+
+
+PlotGrid.prototype.getText = function(style, value, unit) {
+    if (style & Axis.TIME) {
+        var format = this.config.Global.timeformat[this.axis.p];
+        if (style & PlotGrid.ADD_YEAR) {
+            format = "Y-" + format;
+        }
+        var text = timeToDate(value, format, this.config.Global.timezone);
+    } else {
+        var text = GetText(value, unit);
+    }
+    return text;
+}
+
+PlotGrid.minwidth = 1; //每个图形点的最小值,至少是一个像素
+PlotGrid.moveQueue = [];
+PlotGrid.moveTimeid = null;
+PlotGrid.xleft = 0;
+PlotGrid.ytop = 0;
+//1. 情况1: 指标 和 
+//加载第一次数据被绑定
+//2. 情况2:在加载数据的时候,这在初始化。【这个时候,加一个任务,初始化未初始化的指标】
+//3. 情况3:数据已经初始化完成了,指标被加入。这个时候,马上初始化指标。然后,新下载的数据,先让指标自己缓存起来。
+//4. 暂时只考虑被绑定的情况
+
+PlotGrid.setMoveInterval = function(mode, _this) {
+    if (PlotGrid.moveTimeid !== null) return;
+    debug(mode);
+    if (typeof mode === "undefined") {
+        mode = "mouse";
+    }
+    if (mode == "mouse") {
+        PlotGrid.mode = mode;
+        //var _time = 30;
+        var _time = 10;
+        PlotGrid.minwidth = _this.view.plot[_this.view.config.mainName].getOneSize();
+    } else if (mode == "key") {
+        PlotGrid.mode = mode;
+        //var _time = 100;
+        var _time = 100;
+    } else {
+        //do nothing
+        PlotGrid.mode = mode;
+    }
+    if (window["FlashCanvas"]) {
+        //_time = 60;
+        _time = 60;
+    }
+    this.moveTimeid = window.setInterval(function() {
+        if (PlotGrid.moveQueue.length > 0) {
+            debug("setInterval draw beg");
+            PlotGrid.moveTo(PlotGrid.moveQueue.pop(), _this);
+            debug("setInterval draw end");
+            PlotGrid.moveQueue = [];
+        }
+    }, _time);
+    debug(this.moveTimeid);
+}
+
+PlotGrid.clearMoveInterval = function(_this) {
+    if (PlotGrid.moveQueue.length > 0) {
+        PlotGrid.moveTo(PlotGrid.moveQueue.pop(), _this);
+        PlotGrid.moveQueue = [];
+    }
+    if (PlotGrid.moveTimeid !== null) window.clearInterval(PlotGrid.moveTimeid);
+    debug("clearMoveInterval");
+    PlotGrid.moveTimeid = null;
+}
+
+
+PlotGrid.prototype.getYValue = function(y, axis) {
+    if (typeof axis === "undefined") {
+        axis = this.axis;
+    }
+    var value = this.axis.getYValue(y, this.conf.crossYMode, axis);
+    if (value === false) return;
+    var opt = axis.viewconfig.y.axis_option;
+    value = this.getText(opt.style, value, opt.unit);
+    return value;
+}
+PlotGrid.prototype.addEvent = function() {
+        this.active = true;
+        //这两个事件在主图中注册就可以了
+        $(this.canvasContainer).bind('mousedown touchstart', this, function(e) {
+
+            debug('mousedown');
+            var _this = e.data;
+            //PlotGrid.xleft = e.pageX;
+            PlotGrid.xleft = isPC() ? e.pageX - $(this).offset().left : e.originalEvent.targetTouches[0].pageX - $(this).offset().left;
+            PlotGrid.setMoveInterval('mouse', _this);
+            var canvas_mousemove = function(e) {
+                //console.log("move");
+                var _this = e.data;
+                //var newxleft = e.pageX - $(this).offset().left;
+                var newxleft = isPC() ? e.pageX - $(this).offset().left : e.originalEvent.targetTouches[0].pageX - $(this).offset().left;
+                PlotGrid.moveQueue.push(newxleft);
+                debug("move to " + newxleft);
+                return false;
+            };
+            $(_this.canvasContainer).bind('mousemove touchmove', _this, canvas_mousemove);
+
+            var _canvas = _this.canvas;
+            if (_canvas.selector == "#plot_canvas_02") {
+                /*var x = e.pageX - $(_canvas).offset().left;*/
+                var x = isPC() ? e.pageX - $(_canvas).offset().left : e.originalEvent.targetTouches[0].pageX - $(_canvas).offset().left;
+                /*var y = e.pageY - $(_canvas).offset().top;*/
+                var y = isPC() ? e.pageY - $(_canvas).offset().top : e.originalEvent.targetTouches[0].pageY - $(_canvas).offset().top;
+                /*
+                if(_this.xEnd.x >x && (_this.xEnd.x-x)<40){
+                    $("#tool_list").find("li[name='order']").css('cursor', 'pointer');
+                    $("#ordershow").val(_this.getYValue(y));
+                    $("#orderprice").val( $("#ordershow").val());
+                    $("#orderdirection").html("买");
+
+                    order.show();
+                }else if(_this.xEnd.x <x){
+                    $("#tool_list").find("li[name='order']").css('cursor', 'pointer');
+                    $("#ordershow").val(_this.getYValue(y));
+                    $("#orderprice").val( $("#ordershow").val());
+                    $("#orderdirection").html("卖");
+                    order.show();
+                }*/
+            }
+
+            $(document).bind('mouseup touchend', _this, function(e) {
+                var _this = e.data;
+
+
+                $(_this.canvasContainer).unbind('mousemove', canvas_mousemove);
+                $(this).unbind('mouseup');
+                PlotGrid.clearMoveInterval(_this);
+                return false;
+            });
+            return false;
+        });
+        $(this.resize).bind("mousedown touchstart", this, function(e) {
+            debug("resize mouse down");
+            var _this = e.data;
+            //PlotGrid.ytop = e.pageY;
+            PlotGrid.ytop = isPC() ? e.pageY : e.originalEvent.targetTouches[0].pageY;
+            PlotGrid.setMoveInterval('resize', _this);
+            $("body").css("cursor", "n-resize");
+            var document_mousemove = function(e) {
+                var _this = e.data;
+                //var newxtop = e.pageY;
+                var newxtop = isPC() ? e.pageY : e.originalEvent.targetTouches[0].pageY;
+                PlotGrid.moveQueue.push(newxtop);
+                debug("move to new top " + newxtop);
+                return false;
+            };
+            $(document).bind('mousemove tonchmove', _this, document_mousemove);
+            $(document).bind('mouseup touchend', _this, function(e) {
+                $(document).unbind('mousemove tonchmove', document_mousemove);
+                $("body").css("cursor", "default");
+                $(document).unbind('mouseup');
+                PlotGrid.clearMoveInterval(_this);
+                return false;
+            });
+            return false;
+        });
+        this.bindHover();
+    }
+    //鼠标经过的位置hover出框框
+PlotGrid.prototype.bindHover = function() {
+    var _this = this;
+    var mouseMoveInterval = new IntervalEvent(
+        3,
+        function(controller) //可以重新被call
+        {
+            if (!this.value || this.value.length != 4) {
+                return;
+            }
+            var x = this.value[0];
+            var y = this.value[1];
+            var time = this.value[2];
+            if (time < 0) //已经显示过了,不用再显示了。
+            {
+                return;
+            }
+            var newtime = (new Date()).getTime();
+            if (newtime - time >= PlotGrid._this.config.Global.hoverTime) {
+                var show = 1;
+                this.value[2] = -1;
+            } else {
+                var show = 0;
+            }
+            //  console.log("time:"+time+",newtime:"+newtime+",show:"+show+",x:"+x+",y:"+y);//头部标题内容
+            if (this.X && this.Y) {
+                var index = find_near(this.X, x);
+                if ((index != -1) && (Math.abs(this.X[index] - x) <= this.getOneSize())) {
+                    var ohlc = this.Y[index];
+                    if (ohlc[Data.HIGH] - this.config.Global.overPadding <= y && ohlc[Data.LOW] + this.config.Global.overPadding >= y) {
+                        var findTime = this.axis.getXValue(x, PlotGrid.NEAR);
+                        if (findTime === false) return;
+                        var cdata = this.view.model.getDataByTime(this.name, findTime, "candle");
+                        if (!cdata) return false;
+                        var time = cdata.time;
+                        var ohlc = cdata.data;
+                        var yunit = this.axis.viewconfig.y.axis_option.unit;
+                        var fallOrDegrees = parseFloat(GetText(ohlc[Data.CLOSE], yunit) - GetText(ohlc[Data.OPEN], yunit)) / parseFloat(GetText(ohlc[Data.OPEN], yunit));
+                        var fallOrDegrees = fallOrDegrees.toFixed(3);
+                        //timeLine Data
+                       // timelineData(time, GetText(ohlc[Data.OPEN], yunit), GetText(ohlc[Data.HIGH], yunit), GetText(ohlc[Data.LOW], yunit), GetText(ohlc[Data.CLOSE], yunit), fallOrDegrees, GetText(ohlc[Data.VOLUMES], yunit));
+                        // console.log("text PlotCandle");
+                    }
+                }
+            }
+
+
+
+            PlotGrid.doHover(x, y, this.value[3], show);
+        }, true
+    );
+    $(this.canvas).bind("mousemove touchmove", this, this.mouseMove);
+    this.controller.addIntervalEvent("mouseMoveInterval", mouseMoveInterval);
+    $(this.canvas).bind("mouseout touchend", this, function(e) {
+        $("#msgbox").hide();
+    });
+}
+
+PlotGrid.prototype.mouseMove = function(e) {
+        var _this = e.data;
+        PlotGrid._this = _this;
+        var _canvas = _this.canvas;
+        //var x = e.pageX - $(_canvas).offset().left;
+        var x = isPC() ? e.pageX - $(_canvas).offset().left : e.originalEvent.targetTouches[0].pageX - $(_canvas).offset().left;
+        //var y = e.pageY - $(_canvas).offset().top;
+        var y = isPC() ? e.pageY - $(_canvas).offset().top : e.originalEvent.targetTouches[0].pageY - $(_canvas).offset().top;
+
+        var time = (new Date()).getTime();
+        var interval = _this.controller.intervalEvent.mouseMoveInterval;
+        //位置没有变化,不进行处理
+        if (interval.value && interval.value[0] == x && interval.value[1] == y) {
+            return;
+        }
+        interval.setVal([x, y, time, e]);
+
+    }
+    //十字光标经过操作
+PlotGrid.doHover = function(x, y, e, showhover) {
+    var _this = PlotGrid._this;
+    if (!showhover) {
+        if ($("#msgbox").css('display') != "none") {
+            $("#msgbox").css("top", -1000).css("left", -1000);
+            $("#msgbox").hide();
+            //debugx("hide1: " + x + "," + y);
+        }
+        return false;
+    }
+    //_this.controller.intervalEvent.mouseMoveInterval.setVal(null);
+    var overstr = '';
+    for (var i = _this.plot.length - 1; i >= 0; i--) {
+        if (_this.plot[i].obj.over) { //将内容加入头部
+
+            overstr = _this.plot[i].obj.over(x, y);
+            if (overstr) break;
+        }
+    }
+    if (overstr) {
+        $("#msgbox").html(overstr);
+        //debugx("show: " + x + "," + y);
+        var top = e.pageY + 10;
+        var left = e.pageX + 10;
+        var w = $("#msgbox").width();
+        var h = $("#msgbox").height();
+        if (top + h + 10 > $(window).height()) {
+            top = $(window).height() - h - 12;
+        }
+        if (left + w + 10 > $(window).width()) {
+            left = $(window).width() - w - 12;
+        }
+        $("#msgbox").css("top", top).css("left", left);
+        $("#msgbox").show();
+    } else {
+        $("#msgbox").css("top", -1000).css("left", -1000);
+        $("#msgbox").hide();
+        //debugx("hide2: " + x + "," + y);
+    }
+}
+
+PlotGrid.prototype.removeEvent = function() {
+    this.active = false;
+    $(document).unbind("keydown");
+    $(this.canvas).unbind('mousedown uchstartto');
+    $(this.canvas).unbind('mousemove touchmove');
+    $(document).unbind('mouseup touchend');
+}
+
+PlotGrid.moveTo = function(newxleft, _this) {
+    if (PlotGrid.mode == "mouse") {
+        if (newxleft - PlotGrid.xleft > PlotGrid.minwidth) //move to left
+        {
+            _this.controller.startOffset(Math.round((newxleft - PlotGrid.xleft) / PlotGrid.minwidth));
+            _this.controller.draw();
+            PlotGrid.xleft = newxleft;
+        } else if (PlotGrid.xleft - newxleft > PlotGrid.minwidth) {
+            _this.controller.startOffset(-Math.round((PlotGrid.xleft - newxleft) / PlotGrid.minwidth));
+            _this.controller.draw();
+            PlotGrid.xleft = newxleft;
+        }
+    } else if (PlotGrid.mode == "key") {
+        _this.controller.draw();
+    } else if (PlotGrid.mode == "resize") {
+        _this.view.resizeGrid(newxleft - PlotGrid.ytop, _this.index);
+        _this.controller.draw();
+        PlotGrid.ytop = newxleft;
+    }
+}
+
+PlotGrid.prototype.addPlot = function(name, plot) {
+    var obj = { name: name, obj: plot };
+    this.plot.push(obj);
+}
+
+PlotGrid.prototype.removePlot = function(name) {
+    var plot = [];
+    for (var i = 0; i < plot.length; i++) {
+        var item = plot[i];
+        if (item.name != name) {
+            plot.push(item);
+        }
+    }
+    this.plot = plot;
+}
+
+function isPC() {
+    var userAgentInfo = navigator.userAgent;
+    //alert(userAgentInfo)
+    var Agents = ["Android", "iPhone",
+        "SymbianOS", "Windows Phone",
+        "iPad", "iPod"
+    ];
+    var flag = true;
+    for (var v = 0; v < Agents.length; v++) {
+        if (userAgentInfo.indexOf(Agents[v]) > 0) {
+            flag = false;
+            break;
+        }
+    }
+    return flag;
+}
+
+function PlotKshape(view, grid, name) {
+    sup(this, view, grid, name);
+}
+ClassExtend(PlotKshape, Plot);
+
+PlotKshape.tagMap = {
+    1: "A",
+    2: "a",
+    3: "B",
+    4: "b",
+    5: "C",
+    6: "c",
+    7: "D",
+    8: "d",
+    9: "E",
+    10: "e",
+    11: "N",
+    12: "n",
+    13: "W",
+    14: "w",
+    15: "X",
+    16: "x",
+    17: "F",
+    18: "f",
+    19: "L",
+    20: "l",
+    21: "T",
+    22: "t",
+    23: "G",
+    24: "g",
+    25: "Z",
+    26: "z",
+    27: "V",
+    28: "v",
+    29: "J",
+    30: "j",
+    31: "Y",
+    32: "y"
+};
+PlotKshape.prototype.draw = function(data) {
+    //建立点
+    var color;
+    if (this.param.lineColor) {
+        color = this.param.lineColor;
+    } else {
+        color = this.conf.lineColor;
+    }
+    for (var i = 0; i < data.x.length; i++) {
+        if (data.y[i][1] != -1) {
+            writeText(this.ctx, new Point(data.x[i], data.y[i][0]), PlotKshape.tagMap[data.y[i][1]], color[0], this.param.font);
+        }
+        if (data.y[i][2] != -1) {
+            writeText(this.ctx, new Point(data.x[i], data.y[i][0] + 12), PlotKshape.tagMap[data.y[i][2]], color[1], this.param.font);
+        }
+    }
+}
+
+function PlotLine(view, grid, name) {
+    sup(this, view, grid, name);
+}
+ClassExtend(PlotLine, Plot);
+
+PlotLine.prototype.draw = function(data) {
+    //建立点
+    var color;
+    if (this.param.color) {
+        color = this.param.color;
+    } else {
+        color = this.conf.lineColor;
+    }
+    drawLine(this.ctx, data.x, data.y, color);
+}
+
+function PlotMacd(view, grid, name) {
+    sup(this, view, grid, name);
+}
+ClassExtend(PlotMacd, Plot);
+
+PlotMacd.prototype.draw = function(data) {
+    //建立点
+    var color;
+    if (this.param.color) {
+        color = this.param.color.split("-");
+    } else {
+        color = this.conf.lineColor;
+    }
+    var y1 = []
+    var y2 = []
+    for (var i = 0; i < data.y.length; i++) {
+        y1[i] = data.y[i][0];
+        y2[i] = data.y[i][1];
+    }
+    //color[1] = "rgb(112,207,88)";
+    drawLine(this.ctx, data.x, y2, color[0],1.5);
+    this.plotBar(data.x, y1, color[1]);
+}
+PlotMacd.prototype.getShowName = function() {
+    var name = this.name.toUpperCase();
+    name = name.replace("MAIN", "").replace("||", " ");
+    name = name.split("|");
+    if (name.length == 1) {
+        return name[0];
+    }
+    var pre = name.shift();
+    return pre + " (" + name.join(" , ") + ")";
+}
+
+PlotMacd.prototype.plotBar = function(x, H, colorbar) {
+    var zero_y = this.axis.getY(0);
+    drawRow(this.ctx, { x: this.left, y: zero_y }, this.right - this.left, this.conf.lineColorZero);
+    this.ctx.beginPath();
+    this.ctx.strokeStyle = colorbar;
+    for (var i = 0; i < x.length; i++) {
+        try {
+            if (isNaN(H[i])) continue;
+            this.ctx.moveTo(x[i] + 0.5, zero_y);
+            this.ctx.lineTo(x[i] + 0.5, H[i]);
+        } catch (e) {
+            // console.log(e);
+            // console.log(x[i]);
+            // console.log(H[i]);
+        }
+    }
+    this.ctx.stroke();
+}
+
+function Plotmatrend(view, grid, name) {
+    sup(this, view, grid, name);
+}
+ClassExtend(Plotmatrend, Plot);
+
+Plotmatrend.prototype.draw = function(data) {
+    //建立点
+    var color;
+    if (this.param.color) {
+        color = this.param.color;
+    } else {
+        color = this.conf.lineColor;
+    }
+    var y1 = []
+    var y2 = []
+    var y3 = []
+    var y4 = []
+    var y5 = []
+    var y6 = []
+    for (var i = 0; i < data.y.length; i++) {
+        y1[i] = data.y[i][0];
+        y2[i] = data.y[i][1];
+        y3[i] = data.y[i][2];
+        y4[i] = data.y[i][3];
+        y5[i] = data.y[i][4];
+        y6[i] = data.y[i][5]
+    }
+    drawLine(this.ctx, data.x, y1, color[0]);
+    drawLine(this.ctx, data.x, y2, color[1]);
+    drawLine(this.ctx, data.x, y3, color[2]);
+    drawLine(this.ctx, data.x, y4, color[3]);
+    drawLine(this.ctx, data.x, y5, color[4]);
+    drawLine(this.ctx, data.x, y6, color[5]);
+}
+
+function PlotMLine(view, grid, name) {
+    sup(this, view, grid, name);
+    this.laststatus = "";
+    this.lastquick = "";
+}
+ClassExtend(PlotMLine, Plot);
+
+PlotMLine.prototype.draw = function(data) {
+    //建立点,mline的格式
+    //
+    var color, width;
+    this.data = data;
+    var last = this.lastData();
+    for (var key in data.data) {
+        if (this.param[key.toLowerCase() + "_color"]) {
+            color = this.param[key.toLowerCase() + "_color"];
+        } else {
+            color = this.conf.lineColor;
+        }
+        if (data.width && data.width[key]) {
+            width = data.width[key];
+            //console.log(width);
+        }
+        if (data.data[key].x.length > 0) {
+            drawLine(this.ctx, data.data[key].x, data.data[key].y, color, width);
+        }
+        if (this.param[key.toLowerCase() + "_flag"]) {
+            this.priceFlag(last[key].bidask[0], this.config.Global.Candle["public"].close);
+        }
+    }
+}
+
+PlotMLine.prototype.lastDataShow = function() {
+    var text = [];
+    text.push("Local-QuickT = " + this.data.offset.local);
+    text.push("QuickT-SlowT = " + this.data.offset.delt);
+    if (1) {
+        var last = this.lastData();
+        var laststatus = "BID(";
+        for (var key in last) {
+            laststatus += key + "=" + this.grid.getText(0, last[key].bidask[0], this.data.yunit) + " ";
+        }
+        this.laststatus = laststatus + ")";
+    }
+    if (!this.data.quick.inquick) {
+        var quick = this.data.quick;
+        if (quick.start && quick.end) {
+            this.lastquick = " ([" + quick.start + ", " + quick.end + "] Point: " + quick.point / 10 + " Time: " + quick.delt + ") "
+        }
+    }
+    return this.lastquick + this.laststatus + text.join(" , ");
+}
+
+PlotMLine.prototype.getShowName = function() {
+    var text = "";
+    var keyarr;
+    var name = this.name.split("|", 2)[0];
+    for (var key in this.param) {
+        if (key.indexOf("_color") !== -1) {
+            keyarr = key.split("_");
+            text += keyarr[0] + "(" + this.param[key] + ") ";
+        }
+    }
+    var ret = name + " " + text;
+    ret = ret.toUpperCase();
+    return ret;
+}
+
+function PlotOrder(view, grid, name) {
+    sup(this, view, grid, name);
+
+    this.arrow = {};
+    var conf = this.config.Global.arrow[DataWriterProfit.BUY_OPEN];
+    this.arrow[DataWriterProfit.BUY_OPEN] = new ShapeArrow(this.ctx, conf.width, conf.height, conf);
+
+    var conf = this.config.Global.arrow[DataWriterProfit.BUY_CLOSE];
+    this.arrow[DataWriterProfit.BUY_CLOSE] = new ShapeArrow(this.ctx, conf.width, conf.height, conf);
+
+    var conf = this.config.Global.arrow[DataWriterProfit.SELL_OPEN];
+    this.arrow[DataWriterProfit.SELL_OPEN] = new ShapeArrow(this.ctx, conf.width, conf.height, conf);
+
+    var conf = this.config.Global.arrow[DataWriterProfit.SELL_CLOSE];
+    this.arrow[DataWriterProfit.SELL_CLOSE] = new ShapeArrow(this.ctx, conf.width, conf.height, conf);
+}
+ClassExtend(PlotProfit, Plot);
+
+PlotProfit.prototype.draw = function(data) {
+    var x, y, type;
+    this.X = data.x;
+    this.Y = data.y;
+    for (var i = 0; i < data.x.length; i++) {
+        for (var j = 0; j < data.y[i].length; j++) {
+            y = data.y[i][j];
+            type = y[0];
+            y = y[1];
+            x = this.fixedX(data.x[i], type);
+            this.arrow[type].draw(new Point(x, y));
+        }
+    }
+}
+
+PlotProfit.prototype.getShowName = function() {
+    return this.controller.c + " " + this.controller.p;
+}
+
+PlotProfit.prototype.lastDataShow = function() {
+    return "";
+}
+
+PlotProfit.prototype.fixedX = function(x, type) {
+    x += 0.5;
+    var box = this.view.plot[this.config.mainName].getBoxSize();
+    var left = this.view.plot[this.config.mainName].getBoxLeft();
+    if (type == DataWriterProfit.BUY_OPEN || type == DataWriterProfit.SELL_OPEN) {
+        x -= left;
+    } else {
+        x += box - left;
+    }
+    return x;
+}
+
+PlotProfit.prototype.over = function(x1, y1) {
+    if (!this.X) {
+        return false;
+    }
+    var x, y, type, bk = false;
+    x1 += 0.5;
+    for (var i = 0; i < this.X.length; i++) {
+        for (var j = 0; j < this.Y[i].length; j++) {
+            y = this.Y[i][j][1];
+            type = this.Y[i][j][0];
+            x = this.fixedX(this.X[i], type);
+            if (this.inarrow(new Point(x, y), type, x1, y1)) {
+                bk = true;
+                break;
+            }
+        }
+        if (bk) {
+            break;
+        }
+    }
+    if (!bk) {
+        return false;
+    }
+    var findTime = this.axis.getXValue(this.X[i], PlotGrid.NEAR);
+    if (findTime === false) return;
+    var cdata = this.view.model.getDataByTime(this.name, findTime);
+    if (!cdata) {
+        return false;
+    }
+    cdata.data = cdata.data[j];
+    /*
+    var data = cdata.data[2];
+    var open_time  = timeToDate(data[1], null, this.config.Global.timezone);
+    var close_time = timeToDate(data[8], null, this.config.Global.timezone);
+    return "Ticket:     " + data[0] + "<br />" +
+           "Open Time:  " + open_time + "<br />" +
+           "Close Time: " + close_time + "<br />" +
+           "Open Price: " + data[5] + "<br />" +
+           "Close Price:" + data[9] + "<br />" +
+           "Size:       " + data[3] + "<br />" + 
+           "Profit:     " + data[13] + "<br />";
+    */
+
+    return "<b>Type</b>: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" + (DataWriterProfit.nameMap[cdata.data[0]]) + "<br/>" +
+        "<b>Price</b>: &nbsp;&nbsp;&nbsp;&nbsp;" + cdata.data[1] + "<br/>" +
+        "<b>OrderID</b>: " + cdata.data[2] + "<br/>";
+}
+
+//某个坐标是否在某个点内部
+PlotProfit.prototype.inarrow = function(point, type, x, y) {
+    var conf = this.config.Global.arrow[type];
+    var cta = conf.incta;
+    var len = conf.height;
+    var width = conf.width + 5;
+    point.y = -point.y;
+    y = -y;
+    var newpoint = axis_translate(new Point(x, y), cta, point);
+    if (newpoint.x >= 0 && newpoint.x <= len && Math.abs(newpoint.y) <= width) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+function Plotcombinparam1001(view, grid, name) {
+    sup(this, view, grid, name);
+}
+ClassExtend(Plotcombinparam1001, Plot);
+
+Plotcombinparam1001.prototype.draw = function(data) {
+    //建立点
+    var color;
+    if (this.param.color) {
+        color = this.param.color;
+    } else {
+        color = this.conf.lineColor;
+    }
+    var y1 = []
+    var y2 = []
+    var y3 = []
+    var y4 = []
+    var y5 = []
+    var y6 = []
+    for (var i = 0; i < data.y.length; i++) {
+        y1[i] = data.y[i][0];
+        y2[i] = data.y[i][1];
+        y3[i] = data.y[i][2];
+        y4[i] = data.y[i][3];
+        y5[i] = data.y[i][4];
+        y6[i] = data.y[i][5];
+    }
+    drawLine(this.ctx, data.x, y1, color[0]);
+    drawLine(this.ctx, data.x, y2, color[1]);
+    drawLine(this.ctx, data.x, y3, color[2]);
+    drawLine(this.ctx, data.x, y4, color[3]);
+    drawLine(this.ctx, data.x, y5, color[4]);
+    drawLine(this.ctx, data.x, y6, color[5]);
+}
+
+function PlotProfit(view, grid, name) {
+    sup(this, view, grid, name);
+
+    this.arrow = {};
+    var conf = this.config.Global.arrow[DataWriterProfit.BUY_OPEN];
+    this.arrow[DataWriterProfit.BUY_OPEN] = new ShapeArrow(this.ctx, conf.width, conf.height, conf);
+
+    var conf = this.config.Global.arrow[DataWriterProfit.BUY_CLOSE];
+    this.arrow[DataWriterProfit.BUY_CLOSE] = new ShapeArrow(this.ctx, conf.width, conf.height, conf);
+
+    var conf = this.config.Global.arrow[DataWriterProfit.SELL_OPEN];
+    this.arrow[DataWriterProfit.SELL_OPEN] = new ShapeArrow(this.ctx, conf.width, conf.height, conf);
+
+    var conf = this.config.Global.arrow[DataWriterProfit.SELL_CLOSE];
+    this.arrow[DataWriterProfit.SELL_CLOSE] = new ShapeArrow(this.ctx, conf.width, conf.height, conf);
+}
+ClassExtend(PlotProfit, Plot);
+
+PlotProfit.prototype.draw = function(data) {
+    var x, y, type;
+    this.X = data.x;
+    this.Y = data.y;
+    for (var i = 0; i < data.x.length; i++) {
+        for (var j = 0; j < data.y[i].length; j++) {
+            y = data.y[i][j];
+            type = y[0];
+            y = y[1];
+            x = this.fixedX(data.x[i], type);
+            this.arrow[type].draw(new Point(x, y));
+        }
+    }
+}
+
+PlotProfit.prototype.getShowName = function() {
+    return this.controller.c + " " + this.controller.p;
+}
+
+PlotProfit.prototype.lastDataShow = function() {
+    return "";
+}
+
+PlotProfit.prototype.fixedX = function(x, type) {
+    x += 0.5;
+    var box = this.view.plot[this.config.mainName].getBoxSize();
+    var left = this.view.plot[this.config.mainName].getBoxLeft();
+    if (type == DataWriterProfit.BUY_OPEN || type == DataWriterProfit.SELL_OPEN) {
+        x -= left;
+    } else {
+        x += box - left;
+    }
+    return x;
+}
+
+PlotProfit.prototype.over = function(x1, y1) {
+    if (!this.X) {
+        return false;
+    }
+    var x, y, type, bk = false;
+    x1 += 0.5;
+    for (var i = 0; i < this.X.length; i++) {
+        for (var j = 0; j < this.Y[i].length; j++) {
+            y = this.Y[i][j][1];
+            type = this.Y[i][j][0];
+            x = this.fixedX(this.X[i], type);
+            if (this.inarrow(new Point(x, y), type, x1, y1)) {
+                bk = true;
+                break;
+            }
+        }
+        if (bk) {
+            break;
+        }
+    }
+    if (!bk) {
+        return false;
+    }
+    var findTime = this.axis.getXValue(this.X[i], PlotGrid.NEAR);
+    if (findTime === false) return;
+    var cdata = this.view.model.getDataByTime(this.name, findTime);
+    if (!cdata) {
+        return false;
+    }
+    cdata.data = cdata.data[j];
+    /*
+    var data = cdata.data[2];
+    var open_time  = timeToDate(data[1], null, this.config.Global.timezone);
+    var close_time = timeToDate(data[8], null, this.config.Global.timezone);
+    return "Ticket:     " + data[0] + "<br />" +
+           "Open Time:  " + open_time + "<br />" +
+           "Close Time: " + close_time + "<br />" +
+           "Open Price: " + data[5] + "<br />" +
+           "Close Price:" + data[9] + "<br />" +
+           "Size:       " + data[3] + "<br />" + 
+           "Profit:     " + data[13] + "<br />";
+    */
+
+    return "<b>Type</b>: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" + (DataWriterProfit.nameMap[cdata.data[0]]) + "<br/>" +
+        "<b>Price</b>: &nbsp;&nbsp;&nbsp;&nbsp;" + cdata.data[1] + "<br/>" +
+        "<b>OrderID</b>: " + cdata.data[2] + "<br/>";
+}
+
+//某个坐标是否在某个点内部
+PlotProfit.prototype.inarrow = function(point, type, x, y) {
+    var conf = this.config.Global.arrow[type];
+    var cta = conf.incta;
+    var len = conf.height;
+    var width = conf.width + 5;
+    point.y = -point.y;
+    y = -y;
+    var newpoint = axis_translate(new Point(x, y), cta, point);
+    if (newpoint.x >= 0 && newpoint.x <= len && Math.abs(newpoint.y) <= width) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+function Plotrsi(view, grid, name) {
+    sup(this, view, grid, name);
+}
+
+ClassExtend(Plotrsi, Plot);
+
+Plotrsi.prototype.draw = function(data) {
+    this.plotBar(data.x, data.y);
+}
+
+Plotrsi.prototype.lastDataShow = function() {
+    var data = this.lastData();
+    return data;
+}
+
+Plotrsi.prototype.plotBar = function(x, H) {
+    var zero_y = this.axis.getY(50);
+    drawRow(this.ctx, { x: this.left, y: zero_y }, this.right - this.left, this.conf.lineColorZero);
+    this.ctx.beginPath();
+    this.ctx.strokeStyle = this.conf.lineColorH;
+    for (var i = 0; i < x.length; i++) {
+        try {
+            if (isNaN(H[i])) continue;
+            this.ctx.moveTo(x[i] + 0.5, zero_y);
+            this.ctx.lineTo(x[i] + 0.5, H[i]);
+        } catch (e) {
+            // console.log(e);
+            // console.log(x[i]);
+            // console.log(H[i]);
+        }
+    }
+    this.ctx.stroke();
+}
+
+function Plotrsisma(view, grid, name) {
+    sup(this, view, grid, name);
+    //放大缩小尺寸控制更加灵活。采用配置数组的形式
+    this.box = [1, 2, 3, 5, 7, 9, 11, 13];
+    this.space = [0, 1, 1, 2, 2, 3, 4, 5];
+    this.left = [0, 1, 1, 2, 3, 4, 5, 6]
+}
+
+ClassExtend(Plotrsisma, Plot);
+
+Plotrsisma.prototype.zoomIn = function() {
+    if (this.conf.box_pixel >= 7 && this.conf.space_pixel >= 7) {
+        return;
+    }
+    if (this.conf.box_pixel < this.conf.space_pixel) {
+        this.conf.box_pixel++;
+    } else if (this.conf.box_pixel > this.conf.space_pixel) {
+        this.spaceOffset(1);
+    } else {
+        this.conf.box_pixel++;
+    }
+}
+
+Plotrsisma.prototype.spaceOffset = function(offset) {
+    var prev = this.space[this.conf.space_pixel];
+    this.conf.space_pixel = this.conf.space_pixel + offset;
+    var current = this.space[this.conf.space_pixel];
+    if (prev == current) {
+        this.conf.box_pixel = this.conf.box_pixel + offset;
+    }
+}
+
+Plotrsisma.prototype.zoomOut = function() {
+    if (this.conf.box_pixel <= 0 && this.conf.space_pixel <= 0) {
+        return;
+    }
+    if (this.conf.box_pixel < this.conf.space_pixel) {
+        this.spaceOffset(-1);
+    } else if (this.conf.box_pixel > this.conf.space_pixel) {
+        this.conf.box_pixel--;
+    } else {
+        this.spaceOffset(-1);
+    }
+    this.conf.box_pixel = this.conf.box_pixel < 0 ? 0 : this.conf.box_pixel;
+}
+
+Plotrsisma.prototype.getOneSize = function() {
+    return this.box[this.conf.box_pixel] + 2 * this.space[this.conf.space_pixel];
+}
+
+Plotrsisma.prototype.getBoxLeft = function() {
+    return this.left[this.conf.box_pixel];
+}
+
+Plotrsisma.prototype.getBoxSize = function() {
+    return this.box[this.conf.box_pixel];
+}
+Plotrsisma.prototype.draw = function(data) {
+        this.data = data;
+        this.X = data.x;
+        this.Y = data.y;
+        this.xunit = this.data.xunit;
+        this.yunit = this.data.yunit;
+        var width = this.box[this.conf.box_pixel];
+        var left = this.left[this.conf.box_pixel];
+        if (width > 2) {
+            width--;
+        }
+        for (var i = 0; i < this.X.length; i++) {
+            this.drawOne(this.X[i], this.Y[i], width, left);
+        }
+
+        var ySma = []
+        for (var i = 0; i < data.y.length; i++) {
+            ySma[i] = data.y[i][7];
+        }
+        drawLine(this.ctx, data.x, ySma, this.conf.SmaColor);
+    }
+    //鼠标经过十字光标显示的内容框
+Plotrsisma.prototype.over = function(x, y) {
+    //查找最接近的
+   // console.log("1");
+    if (!this.X || !this.Y) return;
+    var index = find_near(this.X, x);
+    if (index == -1) return false;
+    if (Math.abs(this.X[index] - x) > this.getOneSize()) {
+        return false;
+    }
+    var ohlc = this.Y[index];
+    if (ohlc[Data.HIGH] - this.config.Global.overPadding <= y && ohlc[Data.LOW] + this.config.Global.overPadding >= y) {
+        // console.log("Plotrsisma");
+        var findTime = this.axis.getXValue(x, PlotGrid.NEAR);
+        if (findTime === false) return;
+        var cdata = this.view.model.getDataByTime(this.name, findTime, "candle");
+        if (!cdata) return false;
+        var time = cdata.time;
+        var ohlc = cdata.data;
+        var yunit = this.axis.viewconfig.y.axis_option.unit;
+         var fallOrDegrees=parseFloat(GetText(ohlc[Data.CLOSE], yunit)-GetText(ohlc[Data.OPEN], yunit))/parseFloat(GetText(ohlc[Data.OPEN], yunit)) ;
+         var fallOrDegrees=fallOrDegrees.toFixed(3);
+        //timeLine Data
+       // timelineData(time,GetText(ohlc[Data.OPEN], yunit),GetText(ohlc[Data.HIGH], yunit),GetText(ohlc[Data.LOW], yunit),GetText(ohlc[Data.CLOSE], yunit),fallOrDegrees,GetText(ohlc[Data.VOLUMES], yunit));
+
+        // return time + "<br/>" + "O: " + GetText(ohlc[Data.OPEN], yunit) + "<br />" + "H: " + GetText(ohlc[Data.HIGH], yunit) + "<br />" + "L : " + GetText(ohlc[Data.LOW], yunit) + "<br />" + "C: " + GetText(ohlc[Data.CLOSE], yunit) + "<br />" +
+        //     +"V: " + GetText(ohlc[Data.VOLUMES], yunit) + "<br />";
+
+    } else {
+        return false;
+    }
+}
+
+Plotrsisma.prototype.drawOne = function(time, ohlc, width, left) {
+    var ctx = this.ctx;
+    var open = ohlc[Data.OPEN];
+    var high = ohlc[Data.HIGH];
+    var low = ohlc[Data.LOW];
+    var close = ohlc[Data.CLOSE];
+    time += 0.5;
+    open += 0.5;
+    high += 0.5;
+    low += 0.5;
+    close += 0.5;
+
+    if (high == low) {
+        //画个横线就可以了
+        ctx.strokeStyle = this.conf.hx.os_border_color;
+        ctx.beginPath();
+        ctx.moveTo(time - left, open);
+        ctx.lineTo(time + width, open);
+        ctx.stroke();
+        return;
+    }
+    if (open < close) {
+        var up = open;
+        var down = close;
+        var fill = this.conf.hx.open_big_color;
+        var border = this.conf.hx.ob_border_color;
+    } else {
+        var up = close;
+        var down = open;
+        var fill = this.conf.hx.open_small_color;
+        var border = this.conf.hx.os_border_color;
+    }
+    ctx.strokeStyle = border;
+    ctx.beginPath();
+    ctx.moveTo(time, high);
+    ctx.lineTo(time, low);
+    ctx.stroke();
+    if (this.conf.space_pixel > 0) {
+        ctx.fillStyle = fill;
+        ctx.fillRect(time - left, up, width, down - up);
+        ctx.strokeRect(time - left, up, width, down - up);
+    }
+}
+
+
+function PlotTrendLine(view, grid, name) {
+    sup(this, view, grid, name);
+}
+
+ClassExtend(PlotTrendLine, Plot);
+
+PlotTrendLine.prototype.draw = function(data) {
+    this.X = data.x;
+    this.Y = data.y;
+    var plot_list = this.config.Global.trend_line_selected;
+    if (plot_list == null) {
+        return;
+    }
+    for (var i = 0; i < data.x.length; i++) {
+        if (plot_list.indexOf("" + data.y[i][2]) == -1) {
+            continue;
+        }
+        this.drawTrendLine(data.x[i], data.y[i][0], data.y[i][1], data.y[i][2], data.y[i]);
+    }
+}
+
+PlotTrendLine.prototype.drawTrendLine = function(x, y, tan, type, data) {
+    //曲线方程 y = ax + b
+    var a = -tan;
+    var b = y + tan * x;
+    var p = [];
+    p[0] = {};
+    p[1] = {};
+    var i = 0;
+    var o = this.grid.O;
+    var xy = this.grid.xyEnd;
+    var plot_point = {};
+    if (data[5] == 0 && typeof data[6] !== "undefined") {
+        plot_point.x = data[6];
+        plot_point.y = data[7];
+    } else {
+        if (tan != 0) {
+            //和坐标轴的交点的计算
+            //o 点 , 和o点的对角点
+
+
+            //计算曲线与坐标轴的绘图区域的焦点
+            //top
+            ytop = o.y;
+            xtop = (ytop - b) / a;
+            if (i < 2 && xtop >= o.x && xtop <= xy.x) {
+                p[i].x = xtop;
+                p[i].y = ytop;
+                i++;
+            }
+            //bottom
+            ybot = xy.y;
+            xbot = (ybot - b) / a;
+            if (i < 2 && xbot >= o.x && xbot <= xy.x) {
+                p[i].x = xbot;
+                p[i].y = ybot;
+                i++;
+            }
+            //left
+            xleft = o.x;
+            yleft = xleft * a + b;
+            if (i < 2 && yleft >= o.y && yleft <= xy.y) {
+                p[i].x = xleft;
+                p[i].y = yleft;
+                i++;
+            }
+            //right
+            xright = xy.x;
+            yright = xright * a + b;
+            if (i < 2 && yright >= o.y && yright <= xy.y) {
+                p[i].x = xright;
+                p[i].y = yright;
+                i++;
+            }
+        } else {
+            p[0].x = o.x;
+            p[0].y = y;
+            p[1].x = xy.x;
+            p[1].y = y;
+        }
+        //从 x ,y 开始,然后绘制到边界上。
+        if (p[0].x > x) {
+            plot_point = p[0];
+        } else {
+            plot_point = p[1];
+        }
+    }
+    plotLine(this.ctx, { x: x, y: y }, plot_point, this.conf.lineColor[type]);
+}
+
+PlotTrendLine.prototype.over = function(x1, y1) {
+    //console.log(this.X);
+    //console.log(this.Y);
+    mind = Infinity;
+    mini = 0;
+    if (typeof this.X === "undefined") {
+        return;
+    }
+    for (var i = 0; i < this.X.length; i++) {
+        var d = this.distance(x1, y1, this.X[i], this.Y[i]);
+        if (d < mind) {
+            mind = d;
+            mini = i;
+        }
+    }
+    //i 是最短距离了
+    if (mind <= 3) {
+        return "<b>index:</b>" + this.Y[mini][3] + "<br/>";
+    }
+}
+
+PlotTrendLine.prototype.distance = function(x1, y1, x, y) {
+    //曲线方程
+    A = -y[1];
+    B = -1;
+    C = y[0] + y[1] * x;
+    d = Math.abs(A * x1 + B * y1 + C) / Math.sqrt(A * A + B * B);
+    return d;
+}
+
+function Plotvolumes(view, grid, name) {
+    sup(this, view, grid, name);
+}
+ClassExtend(Plotvolumes, Plot);
+
+Plotvolumes.prototype.draw = function(data) {
+    //偏移量配置  根据function Plotrsisma(view, grid, name)函数的配置
+    var left = [0, 1, 1, 2, 3, 4, 5, 6];
+    // var left = [ 3, 4, 5, 6,7,9,10,11]
+    //建立点
+    var color;
+    if (this.param.color) {
+        color = this.param.color;
+    } else {
+        color = this.conf.lineColor;
+    }
+    var zero_y = this.axis.getY(0);
+    for (var i = 0; i < data.y.length - 1; i++) {
+        if (isNaN(data.y[i][0])) {
+            data.y[i][0] = 1;
+        }
+        /*if (data.y[i][0]>data.y[i+1][0]){
+        this.ctx.strokeStyle = color[1]; //green
+      }else if (data.y[i][0]<data.y[i+1][0]){
+        this.ctx.strokeStyle = color[0]; //red
+      }*/
+        if (data.y[i].length == 2) {
+            if(zero_y>data.y[i][0]){
+                var height=zero_y-data.y[i][0];
+            }
+            else{
+                var height=data.y[i][0]-zero_y;
+            }
+            this.ctx.strokeStyle = color[1]; //green
+            //绘制矩形 参考Plotrsisma.prototype.drawOne函数
+            this.ctx.closePath();
+            this.ctx.beginPath();
+            this.ctx.lineWidth = 1;
+            this.ctx.fillStyle = color[1];
+            this.ctx.fillRect(data.x[i]+0.5-left[this.config.Global.Candle.public.box_pixel],zero_y-height,this.config.Global.boxwidth,height);
+            this.ctx.strokeRect(data.x[i]+0.5-left[this.config.Global.Candle.public.box_pixel],zero_y-height,this.config.Global.boxwidth,height);
+            this.ctx.closePath();
+            // this.ctx.moveTo(data.x[i] + 0.5, zero_y);
+            // this.ctx.lineTo(data.x[i] + 0.5, data.y[i][0]);
+            // this.ctx.closePath();
+            // this.ctx.lineWidth = this.config.Global.boxwidth;
+            // this.ctx.stroke();
+            // this.ctx.closePath();
+            
+        } else {
+            this.ctx.strokeStyle = color[0]; //red
+             
+            this.ctx.closePath();
+            this.ctx.beginPath();
+            if(zero_y>data.y[i][0]){
+                var height=zero_y-data.y[i][0];
+            }
+            else{
+                var height=data.y[i][0]-zero_y;
+            }
+            this.ctx.lineWidth = 1;
+            this.ctx.fillStyle = "#0a0a0a";
+            this.ctx.fillRect(data.x[i]+0.5-left[this.config.Global.Candle.public.box_pixel],zero_y-height,this.config.Global.boxwidth,height);
+            this.ctx.strokeRect(data.x[i]+0.5-left[this.config.Global.Candle.public.box_pixel],zero_y-height,this.config.Global.boxwidth,height);
+            this.ctx.closePath();
+//          if(zero_y>data.y[i][0])
+//          {
+//              var height=zero_y-data.y[i][0];
+//              this.ctx.strokeRect(data.x[i] + 0.5-this.config.Global.boxwidth,data.y[i][0],this.config.Global.boxwidth,height)
+//              this.ctx.closePath();
+//          }
+//          else{
+//              var height=data.y[i][0]-zero_y;
+//              this.ctx.lineWidth=5;
+//              if(height!=0){
+//                  this.ctx.strokeRect(data.x[i] + 0.5-this.config.Global.boxwidth,data.y[i][0],this.config.Global.boxwidth,height);
+//                  this.ctx.closePath();
+//              }
+//              
+//          }
+//          this.ctx.closePath();
+           
+        }
+//      this.ctx.beginPath();
+//      this.ctx.moveTo(data.x[i] + 0.5, zero_y);
+//      this.ctx.lineTo(data.x[i] + 0.5, data.y[i][0]);
+//      this.ctx.closePath();
+//      this.ctx.lineWidth = this.config.Global.boxwidth;
+//      this.ctx.stroke();
+//      this.ctx.closePath();
+       
+    }
+    this.ctx.beginPath();
+    this.ctx.moveTo(data.x[data.y.length - 1] + 0.5, zero_y);
+    this.ctx.lineTo(data.x[data.y.length - 1] + 0.5, data.y[data.y.length - 1][0]);
+    this.ctx.closePath();
+    //this.ctx.lineWidth = this.config.Global.boxwidth;
+    this.ctx.stroke();
+}
+
+function Plotvolumes2(view, grid, name) {
+    sup(this, view, grid, name);
+}
+ClassExtend(Plotvolumes2, Plot);
+
+Plotvolumes2.prototype.draw = function(data) {
+    //建立点
+    var color;
+    if (this.param.color) {
+        color = this.param.color;
+    } else {
+        color = this.conf.lineColor;
+    }
+    var zero_y = this.axis.getY(0);
+    for (var i = 0; i < data.x.length; i++) {
+        if (isNaN(data.y[i][0])) continue;
+        this.ctx.beginPath();
+        this.ctx.moveTo(data.x[i] + 0.5, zero_y);
+        if (data.y[i][0] > zero_y) {
+            this.ctx.strokeStyle = color[1];
+            this.ctx.lineTo(data.x[i] + 0.5, 2 * zero_y - data.y[i][0]);
+        } else {
+            this.ctx.strokeStyle = color[0];
+            this.ctx.lineTo(data.x[i] + 0.5, data.y[i][0]);
+        }
+        this.ctx.closePath();
+        this.ctx.stroke();
+    }
+
+}
+
+function PlotWave(view, grid, name) {
+    sup(this, view, grid, name);
+}
+ClassExtend(PlotWave, Plot);
+
+PlotWave.prototype.draw = function(data) {
+    //建立点
+    var color;
+    if (this.param.color) {
+        color = this.param.color;
+    } else {
+        color = this.conf.lineColor;
+    }
+    var y1 = []
+    for (var i = 0; i < data.y.length; i++) {
+        y1[i] = data.y[i][0];
+    }
+    drawLine(this.ctx, data.x, y1, color[0]);
+}
+
+function Plotwdensity(view, grid, name) {
+    sup(this, view, grid, name);
+}
+ClassExtend(Plotwdensity, Plot);
+
+Plotwdensity.prototype.draw = function(data) {
+    //建立点
+    var color;
+    if (this.param.lineColor) {
+        color = this.param.lineColor;
+    } else {
+        color = this.conf.lineColor;
+    }
+
+    for (var i = 0; i < data.y.length; i++) {
+        for (var j = 0; j < data.y[i].length / 2; j++) {
+            if (data.y[i][2 * j] != 0 && data.y[i][j * 2 + 1] != 0) {
+                writeText(this.ctx, new Point(data.x[i], data.y[i][2 * j]), "~", color[j], this.param.font)
+            }
+        }
+    }
+}
+
+//Node 版本的数据接收
+//这里主要针对本地传送数据。[直接一次性加载的策略]
+
+function ModelNode(controller) {
+    sup(this, controller);
+    this.host = this.config.Global.NodeHost;
+    this.port = this.config.Global.NodePort;
+    this.isinit = false;
+}
+
+ClassExtend(ModelNode, Model);
+
+ModelNode.prototype.initData = function() {
+    if (this.isinit) return;
+    this.isinit = true;
+    var socket = io.connect('http://' + document.domain);
+    this.socket = socket;
+    var _this = this;
+    socket.on("error", function(data) {
+        // console.log("error");
+    });
+    socket.on("init", function(data) {
+        // console.log("init");
+        _this.updateData(data, "init");
+    });
+    socket.on("data", function(data) {
+        if (data.main && data.main.options.prev_calculated == 0) console.log("data");
+        _this.updateData(data, "new");
+    });
+    var _this = this;
+    _this.isconnect = false;
+    socket.on("connect", function() {
+        _this.isconnect = true;
+        _this.subscribe();
+    });
+    this.socket = socket;
+}
+ModelNode.prototype.subscribe = function() {
+    if (this.isconnect) {
+        this.socket.emit("subscribe", { c: this.controller.c, p: this.controller.p });
+    }
+}
+ModelNode.prototype.downloadData = function() {
+
+}
+
+ModelNode.prototype.newData = function() {
+
+}
+
+ModelNode.prototype.updateData = function(data, action_name) {
+    // console.log("data.p:"+data.p);
+    if (data && data.c && data.p) {
+        if (data.c != this.c || data.p != this.p) {
+            //$("#symbol li[name="+data.c+"]").click();
+            $("#period li[name=" + data.p + "]").click();
+            action_name = "init";
+        }
+    }
+    if (action_name == "init") {
+        if (data && data.c && data.p) {
+            this.flag(Model.INITED, 1, data.c, data.p);
+        } else {
+            this.flag(Model.INITED, 1);
+        }
+        hide_loading();
+    } else {
+        debug("update");
+    }
+    this.update(data, Model.UPDATE);
+}
+
+//采用短连接下载数据的接口,有两个子类,一个子类是poll 采用轮询的方式更新数据。
+//还有一个 WS采用websocket 的方式更新数据,
+//如果在配置中,指定采用poll,那么我们就采用poll
+//如果在配置中 指定采用websokect,但是发现,有些浏览器不支持,我们还是要退回轮询的方式。
+//而服务器端 会有两套服务器。
+//为了便于扩展。我们没有直接重写 data.set 类。
+
+function ModelShort(controller) {
+    sup(this, controller);
+    this.controller=controller;
+    this.api = this.config.Global.DataAPI;
+    this.prevPoint = 0;
+}
+
+ClassExtend(ModelShort, Model);
+ModelShort.prototype.getAPI = function() {
+    console.log($.cookie('symbol'));
+    if($.cookie('symbol')=="YCC"){
+
+     return "https://kdata.fxee.com/kdata?datafile=db" + "&c=NYCC&p="+ this.p;
+    }
+    else{
+        return "https://kdata.fxee.com/kdata?datafile=db" + "&c=" + $.cookie('symbol') + "&p=" + this.p;
+    }
+    // if(this.p==null){
+    //     return "https://tick.33.cn:4062/kdata?datafile=db" + "&c=" + $.cookie('symbol') + "&p=H1" ;
+    // }
+    // else{
+    //     return "https://tick.33.cn:4062/kdata?datafile=db" + "&c=" + $.cookie('symbol') + "&p=" + this.p;
+    // }
+    
+//  if(this.c=="ETC"){
+//     return etcUrl + "&c=" + this.c + "&p=" + this.p;
+//  }
+//  else{
+//      if (this.api.indexOf("?") == -1) {
+//          return this.api + "?" + "c=" + this.c + "&p=" + this.p;
+//      } else {
+//          return this.api + "&c=" + this.c + "&p=" + this.p;
+//      }
+//  }
+   
+}
+
+ModelShort.prototype.download = function(action_name) {
+    this.count = this.config.Global.downloadCount;
+    if (action_name == "down") {
+        if (this.flag(Model.DOWN_END)) return;
+        //判断左边是否需要下载(左边的优先下载)
+        var down_flag = 0;
+        if (this.leftDataCount() < this.config.Global.lowMark) {
+            if (this.downOptions.total_size) {
+                if (this.getLeftOffset() < this.downOptions.total_size - 1) down_flag = 1;
+            } else {
+                down_flag = 1; //left
+            }
+        }
+        //判断右边是否需要下载。对于以时间下载的模式,不会消去数据。所以,右边的永远不需要下载。
+        if (down_flag == 0 && this.rightDataCount() < this.config.Global.lowMark) {
+            if (this.downOptions.total_size) {
+                if (this.getRightOffset() > 0) down_flag = -1;
+            }
+        }
+        if (!down_flag) return;
+    }
+    if (this.config[this.config.mainName].downdata == 0) return;
+    var api = this.getAPI();
+    if (!api) return;
+
+    var _this = this;
+    var ind = this.getIndicatorList();
+    //用一个数字,来标记这些状态. init_beg 和 init_end
+    //是一对,设置了一个,就会清除另外的一个
+    if (this.flag(Model.DOWN) == 1) return; //如果数据正在下载中,那么忽略新的下载任务
+    if (this.downOptions.total_size) {
+        //以位置分页
+        if (this.state.length == '' && action_name == 'down') {
+            var offset = this.getDownOffset(down_flag);
+            if (offset < 0) return;
+        } else if (this.state == 'home') {
+            offset = this.downOptions.total_size - this.count;
+        } else if (this.state == "end") {
+            offset = 0;
+        }
+        if (this.getRightOffset() <= offset && offset <= this.getLeftOffset()) {
+            this.state = '';
+            return;
+        }
+        var baseparam = { action: action_name, offset: offset, count: this.count, 'ind': ind.join(":") }
+    } else {
+        //以时间分页
+        var baseparam = { action: action_name, ts: this.startXValue(), count: this.count, 'ind': ind.join(":") }
+    }
+    var pollmode = this.config.Global.PollMode;
+    baseparam.out = pollmode;
+    this.flag(Model.DOWN, 1);
+    $.ajax({
+        type: "post",
+        url: api,
+        data: baseparam,
+        success: function(data) {
+            // console.log("ajax data:"+data);
+            if (data) {
+
+                _this.processDown(data, data.action);
+            }
+        },
+        error : function() {    
+           // view("异常!");    
+           alert("异常!");   
+           //光标移至输入用户名框
+           $("#loginusername").focus();
+           return -1; 
+        },  
+        complete: function(xhr) {
+            _this.flag(Model.DOWN, 0);
+            _this.state = '';
+        },
+        dataType: baseparam.out
+    });
+}
+
+ModelShort.prototype.processDown = function(data, action_name) {
+    if (action_name == "init") {
+        if (data && data.c && data.p) {
+            this.flag(Model.INITED, 1, data.c, data.p);
+        } else {
+            this.flag(Model.INITED, 1);
+        }
+        hide_loading();
+    } else {
+        debug("down ok");
+    }
+    this.update(data, Model.DOWN);
+    this.flag(Model.DOWN_DATA, 1); //标记下载的数据可用了
+    if (action_name == "init") {
+        //this.newData();
+    }
+}
+
+ModelShort.prototype.initData = function() {
+    return this.download("init");
+}
+
+ModelShort.prototype.downloadData = function() {
+    this.download("down");
+}
+
+
+//通过广播的方式得到tick数据。在本地计算出K线的数据。(方案1)
+//但是本地计算有些麻烦,比较简单的解决方案是:支持一个new 命令
+//把相关的数据下载下来。并注册广播该数据。这个广播服务器需要复杂一点。
+//暂时采用第二种方案,个人认为这个方案在不需要tick报价的情况下,客户端
+//逻辑最少,数据最不容易出错。
+//
+//tick广播服务器,只要缓存24小时内的数据,一般就不会有出现断层。【如果new
+//命令在的时间是在24小时以外的。可以提醒客户端,刷新。但是不考虑这样的异常。】
+//
+//下载数据:会收集所有注册指标的名称,一起下载。下载的数据,按照主K线图对齐。
+//没有对齐的填上NULL,如果某个点为NULL,那么这个点就直接跳过,不会进行绘制
+//function 继承
+function ModelShortPoll(controller) {
+    sup(this, controller);
+    this.interval = new IntervalEvent(Math.round(this.config.Global.PollInterval / this.config.Global.Interval), function(controller) {
+        if(controller.model==undefined)return;
+        controller.model.newData();
+    }, true);
+    controller.addIntervalEvent("poll", this.interval);
+}
+
+ClassExtend(ModelShortPoll, ModelShort);
+ModelShortPoll.prototype.newData = function() {
+    var api = this.getAPI();
+    if (!api) return;
+    //如果是静态图形
+    if (this.controller.staticChat) return true;
+    var _this = this;
+    if (this.isNewing) {
+        if (getTime() - this.lastSend > 1000 * this.config.Global.maxConnectAliveTime) {
+            //reconnect. may be the connect is error
+        } else {
+            return false;
+        }
+    }
+    //如果没有初始化,那么返回
+    if (!this.flag(Model.INITED)) {
+        return;
+    }
+    this.isNewing = true;
+    this.lastSend = getTime();
+    var ind = this.getIndicatorList();
+    //更新时间按照主图:的最新数据
+    var first = this.flag(Model.FIRST_NEW) ? 1 : 0;
+    this.c = this.c;
+    console.log(this);
+    var baseparam = { action: 'new', "ind": ind.join(":"), te: this.endXValue(), first: first, __tmp: Math.random() };
+    var pollmode = this.config.Global.PollMode;
+    baseparam.out = pollmode;
+    this.newDataXHR = $.ajax({
+        type: "post",
+        url: api,
+        data: baseparam,
+        success: function(data) {
+            _this.processNew(data);
+            _this.isNewing = false;
+        },
+        complete: function(xhr) {
+            _this.isNewing = false;
+        },
+        dataType: baseparam.out
+    });
+    return true;
+}
+
+ModelShortPoll.prototype.processNew = function(data) {
+    if (data != null) {
+        this.update(data, Model.NEW);
+        this.flag(Model.FIRST_NEW, 0, data.c, data.p);
+    }
+}
+
+//通过广播的方式得到tick数据。在本地计算出K线的数据。(方案1)
+//但是本地计算有些麻烦,比较简单的解决方案是:支持一个new 命令
+//把相关的数据下载下来。并注册广播该数据。这个广播服务器需要复杂一点。
+//暂时采用第二种方案,个人认为这个方案在不需要tick报价的情况下,客户端
+//逻辑最少,数据最不容易出错。
+//
+//tick广播服务器,只要缓存24小时内的数据,一般就不会有出现断层。【如果new
+//命令在的时间是在24小时以外的。可以提醒客户端,刷新。但是不考虑这样的异常。】
+//
+//下载数据:会收集所有注册指标的名称,一起下载。下载的数据,按照主K线图对齐。
+//没有对齐的填上NULL,如果某个点为NULL,那么这个点就直接跳过,不会进行绘制
+//function 继承
+
+//这个是通过 websocket 广播进行数据更新的模式。数据下载部分不变,只是更新了数据更新的部分。
+function ModelShortWS(controller) {
+    sup(this, controller);
+    this.wsinit = false;
+    if (!this.config.Global.WSHost) {
+        return;
+    }
+    this.url = "ws://" + this.config.Global.WSHost + ":" + this.config.Global.WSPort + "/";
+    this.interval = new IntervalEvent(Math.round(1000 / this.config.Global.Interval), function(controller) {
+        var model = controller.model;
+        if (getTime() - model.lastRead > model.config.Global.maxNOData * 1000) {
+            model.lastRead = getTime();
+            if (model.wsinit) {
+                if (model.ws) {
+                    model.ws.close();
+                }
+                model.ws = null;
+                model.wsinit = false;
+                model.newData();
+            } else {
+                model.ws = null;
+                model.wsinit = false;
+                model.newData();
+            }
+            return;
+        }
+        if (getTime() - model.lastRead > model.config.Global.pingTime * 1000) {
+            if (model.ws) {
+                try {
+                    model.ws.send("ping");
+                } catch (e) {}
+            }
+        }
+    }, true);
+    if (!this.config.Global.newDisable) {
+        controller.addIntervalEvent("ws", this.interval);
+    }
+    this.ws = null;
+}
+
+ClassExtend(ModelShortWS, ModelShort);
+
+ModelShortWS.prototype.initWS = function() {
+    var _this = this;
+    if (this.ws) return;
+    if (this.url) {
+        this.ws = new WebSocket(this.url);
+        this.ws.onopen = function() {
+            _this.open();
+        };
+        this.ws.onmessage = function(e) {
+            _this.message(e);
+        };
+        this.ws.onclose = function(e) {
+            _this.message(e);
+        };
+    }
+}
+
+ModelShortWS.prototype.newData = function() {
+    //如果是静态图形
+    if (this.controller.staticChat || this.config.Global.newDisable) return true;
+    if (!this.flag(Model.INITED)) {
+        return;
+    }
+    //货币对+指标列表
+    var ind = this.getIndicatorList();
+    this.cmd = [];
+    var hasmain = false;
+    var super_ind = [];
+    for (var i = 0; i < ind.length; i++) {
+        if (ind[i] == this.config.mainName) {
+            hasmain = true;
+            break;
+        }
+    }
+    if (!hasmain) ind.push(this.config.mainName);
+    for (var i = 0; i < ind.length; i++) {
+        var mycmd = this.dataObj[ind[i]].reader.getWSCmd();
+        if (mycmd) {
+            this.cmd.push(mycmd);
+        } else {
+            super_ind.push(ind[i]);
+        }
+    }
+    if (super_ind.length != 0) {
+        super_ind = super_ind.join(',');
+        this.cmd.push("super_sub:" + this.c + "_" + this.p + ";" + super_ind + ":" + this.endXValue());
+    }
+    this.initWS();
+    if (this.wsinit) {
+        this.sendcmd();
+        this.cmd = null;
+    }
+}
+
+ModelShortWS.prototype.sendcmd = function() {
+    if (this.cmd) {
+        try {
+            for (var i = 0; i < this.cmd.length; i++) {
+                this.ws.send(this.cmd[i]);
+            }
+        } catch (e) {}
+    }
+}
+
+ModelShortWS.prototype.open = function() {
+    this.wsinit = true;
+    this.sendcmd();
+}
+
+ModelShortWS.prototype.message = function(e) {
+    this.lastRead = getTime();
+    if (e.data == "here") {
+        return;
+    }
+    var data = eval("(" + e.data + ")");
+    this.update(data, Model.NEW);
+}
+
+ModelShortWS.prototype.close = function(e) {
+    this.ws = null;
+    this.wsinit = false;
+    this.initWS();
+}
+
+//一般任务reader是一个很简单的东西,但是它实际上也不是非常简单,它涉及预处理。定位等。
+//现在我们考虑一般的情况,那就是main 图 和 这个指标图并不是时间对齐的。
+//我们需要通过time查找。这里,我们采用二分查找。
+//
+//基本的reader会提供两个函数,一个是通过一个start值和number 读取数据
+//一个是通过一个时间范围。读取这个时间范围内的数据。
+//
+//通过精心的组织代码,我们发现这个代码还是可以控制的。虽然,你很难想像用Javascript
+//写这样大型的绘图程序到底能否成功。
+//
+function DataReader(model, writer, name) {
+    //每个datreader 对象建立的时候。有一个data write 对象
+    this.model = model;
+    this.controller = this.model.controller;
+    /*if (name!="volumes"){
+     this.setParam(this.controller.ind[name].param);
+    }*/
+    this.writer = writer;
+    this.name = name;
+    this.config = Config.getInstance();
+    this.shift = 0;
+}
+
+DataReader.EXTEND = 1;
+DataReader.MAIN = 1 << 1;
+
+DataReader.prototype.setWriter = function(writer) {
+    this.writer = writer;
+}
+
+DataReader.prototype.setParam = function(param) {
+    this.param = param;
+}
+
+DataReader.prototype.getShift = function() {
+    //为了计算精确,  从图表中多读取这样多的数据。同时,兼容K线这一端对齐的 和 非对齐的情况,这样,指标的计算只和图表数据相关 和原始数据无关。
+    //为了不影响画图,最好不要影响画图
+    //时间刻度一般以主图为准。
+    return this.shift;
+}
+
+DataReader.prototype.getStart = function(number) {
+    //数据指针
+    var start = this.model.point();
+    var endpos = this.getEndPos();
+    if (endpos < 0) {
+        return -1;
+    }
+    //alert(start);
+    if (start < 0) {
+        start = 0;
+    }
+    if (start > endpos) {
+        start = endpos;
+    }
+    if (!number) return start;
+
+    if (endpos - start < number) {
+        start = endpos - number + 1;
+    }
+    if (start < 0) {
+        start = 0;
+    }
+    if (start > endpos) {
+        start = endpos - number + 1;
+    }
+    //修正
+    this.model.point(start);
+    return start;
+}
+
+DataReader.prototype.getEndPos = function() {
+    var x = this.main.getX(this.c, this.p);
+    return x.length - 1;
+}
+
+DataReader.prototype.startXValue = function() {
+    var x = this.main.getX(this.c, this.p);
+    return x[x.length - 1];
+}
+
+DataReader.prototype.endXValue = function() {
+    var x = this.main.getX(this.c, this.p);
+    return x[0];
+}
+
+DataReader.prototype.set = function() {
+    this.c = this.model.c;
+    // console.log("this.model.p:"+this.model.p);
+    this.p = this.model.p;
+    this.xunit = this.config.Global.xunit[this.p] * 60; //这个是根据时间决定其单位
+
+    if (this.config[this.name] && this.config[this.name].yunit) {
+        this.yunit = this.config[this.name].yunit;
+    } else {
+        this.yunit = this.config.get("Global.yunit." + this.c, this.config.Global.yunit.default_value); //这个是根据货币对决定其单位
+    }
+    if (this.writer) {
+        this.store = this.writer.getStore(this.c, this.p);
+    }
+    this.config = Config.getInstance();
+    // this.config.mainName="main";
+    this.main = this.model.dataObj[this.config.mainName].writer; //这个对main是引用关系,所以只要c,p 没有切换
+    this.mainData = this.model.data[this.config.mainName]; //main刚刚读取的数据
+
+
+    this.step = this.xunit;
+    this.maxstep = this.config.Global.maxstep; //(5个小时没有数据,那么不进行补充)
+    //这个数据,依然是引用了main的最新的数据。
+}
+
+DataReader.prototype.getMainData = function() {
+    this.mainData = this.model.data[this.config.mainName];
+    return this.mainData;
+}
+
+DataReader.prototype.getYminmax = function(y) {
+    return minmax(y);
+}
+
+DataReader.prototype.getWSCmd = function() {
+    return false;
+}
+
+//抽象函数,不提供任何的功能。//主图数据
+DataReader.prototype.getDataByMain = function(readconfig) {
+    this.mainData = this.getMainData();
+    var nLen = this.mainData.x.length;
+    if (nLen > this.model.plotnum) {
+        nLen = this.model.plotnum
+    }
+    var start = this.mainData.x[nLen - 1];
+    var end = this.mainData.x[0];
+    var x = new Array();
+    var y = new Array();
+    var xdata = this.writer.getX(this.c, this.p);
+    var ydata = this.writer.getY(this.c, this.p);
+    //这个部分是数据,首先查找xdata,当然还要判断是否扩展。
+    //这里的扩展方式是扩展K线图。其他的扩展,在其他的图里面表示。
+    //先获取数据:
+
+    var count = 0;
+    var index = find_first_big_r(xdata, end); //查找到第一个点
+    if (index == -1) {
+        index = 0;
+    }
+    if (xdata[index] > end) index++; //去掉第一个大于的点
+    for (var i = index; i < xdata.length; i++) {
+        if (xdata[i] >= start) {
+            x[count] = xdata[i];
+            y[count] = ydata[i];
+            count++;
+        } else {
+            break;
+        }
+    }
+    if (readconfig & DataReader.EXTEND) {
+        //多添加一个最后时间的数据,这个数据如果不存在,那么就复制前一个数据的 open 值,这个时间值肯定小于 start
+        if (xdata[i]) {
+            x.push(xdata[i]);
+            y.push(ydata[i]);
+        } else if (x[x.length - 1] > start) {
+            x.push(start);
+            var ylast = y[y.length - 1][Data.OPEN];
+            y.push([ylast, ylast, ylast, ylast, y[y.length - 1][Data.VOLUMES]]);
+        }
+        return this.extendByMain(x, y);
+    }
+    //深度拷贝
+    y = array_copy(y);
+    // }
+    return { x: x, y: y };
+}
+
+DataReader.prototype._formatData = function(x, y) {
+
+    var data = {};
+    data.x = x;
+    data.y = y;
+    data.xunit = this.xunit;
+    data.yunit = this.yunit;
+    data.maxX = x[0];
+    data.minX = x[x.length - 1];
+    data.maxIndex=0;
+    data.minIndex=0;
+
+    var _minmax = this.getYminmax(y);
+    data.maxY = _minmax[1];
+    data.minY = _minmax[0];
+    data.maxIndex=_minmax[3];
+    data.minIndex=_minmax[2];
+    return data;
+}
+
+DataReader.prototype.formatData = function(x, y) {
+    return this._formatData(x, y);
+}
+
+DataReader.prototype.last = function(index) {
+    if (!index || index < 0) index = 0;
+    var y = this.writer.getY(this.c, this.p);
+    return y[index];
+}
+
+function DataWriter(model, name) {
+    this.model = model;
+    this.name = name;
+    this.config = this.model.config;
+    this.storeSet = {};
+}
+
+DataWriter.prototype.getStore = function(c, p) {
+    this.storeSet = init_obj(this.storeSet, c, p, { x: [], y: [] });
+    return this.storeSet[c][p];
+}
+
+DataWriter.prototype.clear = function() {
+    this.storeSet = {};
+}
+
+DataWriter.prototype.setNewData = function(c, p, data) {
+    //do nothing.
+}
+
+DataWriter.prototype.setDownloadData = function(c, p, data) {
+    //do nothing.
+}
+
+DataWriter.prototype.getX = function(c, p) {
+    var store = this.getStore(c, p);
+    return store.x;
+}
+
+DataWriter.prototype.getY = function(c, p) {
+    var store = this.getStore(c, p);
+    return store.y;
+}
+
+function DataWriterbdensity(model, name) {
+    sup(this, model, name);
+}
+ClassExtend(DataWriterbdensity, DataWriter);
+
+
+DataWriterbdensity.prototype.setNewData = function(c, p, data) {
+    if (!is_array(data) || data.length == 0) {
+        return;
+    }
+    var store = this.getStore(c, p);
+}
+
+DataWriterbdensity.prototype.notify = function(items) {
+    if (items && items.length) {
+        /*var typename = DataWriterProfit.nameMap[items[items.length - 1][0]];
+        typename = typename.replace("/", "_").toLowerCase();
+        var url = $("#music_list select[name="+typename+"]").val();
+        playmusic(url);
+        */
+    }
+}
+
+DataWriterbdensity.prototype.parseItem = function(items) {
+    var newarr = [];
+    var type = null;
+    for (var i = 0; i < items.length; i++) {
+        var item = items[i];
+        if (item[0] == "buy" && item[1] == "open") {
+            type = DataWriterProfit.BUY_OPEN;
+        } else if (item[0] == "buy" && item[1] == "close") {
+            type = DataWriterProfit.BUY_CLOSE;
+        } else if (item[0] == "sell" && item[1] == "open") {
+            type = DataWriterProfit.SELL_OPEN;
+        } else if (item[0] == "sell" && item[1] == "close") {
+            type = DataWriterProfit.SELL_CLOSE;
+        }
+        if (type) {
+            newarr[i] = [type, parseFloat(item[2]), item[3]];
+        }
+    }
+
+    if (newarr.length == 0) {
+        return false;
+    }
+    newarr = this.formatItem(newarr);
+    return newarr;
+}
+
+DataWriterbdensity.prototype.formatItem = function(arr) {
+    for (var i = 0; i < arr.length; i++) {}
+    return arr;
+}
+
+DataWriterbdensity.prototype.setDownloadData = function(c, p, data) {
+    //数据按照时间倒序序进行排列
+    var beg, end;
+    //处理指标
+    if (!is_array(data.x)) {
+        return;
+    }
+    var store = this.getStore(c, p);
+    var item;
+    for (var i = 0; i < data.x.length; i++) {
+        //format time
+        var time = formatTime(data.x[i], p);
+        store.x.push(time);
+        item = data.y[i]; //this.parseItem(data[i][1]);
+        if (item) store.y.push(item);
+    }
+
+}
+
+function DataWriterCandle(model, name) {
+    sup(this, model, name);
+    this.chunks = []; //数据在服务器端的[开始,结束,total,在本地数组中的,开始位置,长度,方便删除]
+}
+
+ClassExtend(DataWriterCandle, DataWriter);
+//重写父类.
+//写类不能像读类一样,直接读取model.c 个 model.p 
+//因为,数据属于什么类,由服务器端返回的值决定
+//
+DataWriterCandle.prototype.getStore = function(c, p) {
+    this.storeSet = init_obj(this.storeSet, c, p, { time: [], ohlc: [], v: [] });
+    return this.storeSet[c][p];
+}
+
+DataWriterCandle.prototype.setDownloadDataByOffset = function(c, p, data, options) {
+    //数据按照时间倒序序进行排列
+    var beg, end;
+    //处理指标
+    if (!is_array(data.x)) {
+        return;
+    }
+    this.c = c;
+    this.p = p;
+    var store = this.getStore(c, p);
+    data.x = data.x.reverse();
+    data.y = data.y.reverse();
+    //判断offset 是否衔接,如果不衔接,那么重置所有的数据。
+    //如果衔接。要判断一下左衔接 还是 右衔接。
+    //如果是左衔接,并且缓存数目超过一个配置的值,那么删除一部分数据
+    //每个数据用一个chunks来表示
+    options.astart = 0;
+    options.alen = data.x.length;
+    if (this.chunks.length && options.end + 1 == this.chunks[0].start) { //右衔接[在头部加入数据]
+        var len = data.x.length;
+        store.time = data.x.concat(store.time);
+        store.ohlc = data.y.concat(store.ohlc);
+        this.shiftLeftChunk(store, options); //把chunk往左移
+    } else if (this.chunks.length && this.chunks[this.chunks.length - 1].end + 1 == options.start) { //左衔接
+        var len = data.x.length;
+        store.time = store.time.concat(data.x);
+        store.ohlc = store.ohlc.concat(data.y);
+        this.shiftRightChunk(store, options);
+    } else { //不衔接
+        store.time = data.x;
+        store.ohlc = data.y;
+        this.chunks = [];
+        this.chunks[0] = options;
+    }
+    //更新数据offset 的范围
+    this.model.leftoffset = this.chunks[this.chunks.length - 1].end;
+    this.model.rightoffset = this.chunks[0].start;
+}
+
+DataWriterCandle.prototype.shiftLeftChunk = function(store, options) {
+    //update chunk data
+    for (var i = 0; i < this.chunks.length; i++) {
+        this.chunks[i].astart += options.alen;
+    }
+    this.chunks.unshift(options);
+    //更新数据指针,头部数据被加入
+    this.model.point(this.model.point() + options.alen);
+    if (store.time.length > this.config.Global.maxStoreChunk * this.config.Global.downloadCount) {
+        var chunk = this.chunks.pop();
+        store.time.splice(chunk.astart);
+        store.ohlc.splice(chunk.astart);
+    }
+}
+
+DataWriterCandle.prototype.shiftRightChunk = function(store, options) {
+    //处理chunk
+    var lastchunk = this.chunks[this.chunks.length - 1];
+    options.astart += lastchunk.astart + lastchunk.alen;
+    this.chunks.push(options);
+
+    if (store.time.length > this.config.Global.maxStoreChunk * this.config.Global.downloadCount) {
+        var chunk = this.chunks.shift();
+        for (var i = 0; i < this.chunks.length; i++) {
+            this.chunks[i].astart -= chunk.alen;
+        }
+        //头部数据被删除
+        store.time.splice(0, chunk.alen);
+        store.ohlc.splice(0, chunk.alen);
+        //更新数据指针
+        var point = this.model.point();
+        point -= chunk.alen;
+        this.model.point(point);
+    }
+}
+
+DataWriterCandle.prototype.setUpdateData = function(c, p, data) {
+        //更新第一个数据
+        if (!is_array(data.x) || data.x.length == 0) {
+            return;
+        }
+        var store = this.getStore(c, p);
+        var mintime = data.x[0];
+        data.x = data.x.reverse();
+        data.y = data.y.reverse();
+
+        if (store.time.length == 0 || parseInt(data.options.prev_calculated) == 0) {
+            store.time = data.x;
+            store.ohlc = data.y;
+            //console.log(store.time);
+            return;
+        }
+        var i = 0;
+        while (i < store.time.length && store.time[i] >= mintime) {
+            i++;
+        }
+        if (i == store.time.length) {
+            store.time = data.x;
+            store.ohlc = data.y;
+        } else {
+            store.time.splice(0, i);
+            store.ohlc.splice(0, i);
+            store.time = data.x.concat(store.time);
+            store.ohlc = data.y.concat(store.ohlc);
+        }
+    }
+    /*
+    DataWriterCandle.prototype.setNewData = function(c, p, data)
+    {
+       console.log("newdata=",data,is_array(data),data.length);
+        //更新第一个数据
+        if (!is_array(data) || data.length == 0)
+        {
+            return;
+        }
+        data = data.reverse();
+        var store = this.getStore(c, p);
+        var time = parseInt(data[0][0]);
+        while (data.length && time < store.time[0])
+        {
+            data.shift();
+            time = parseInt(data[0][0]);
+        }
+        if (data.length == 0)
+        {
+            return;
+        }
+        //
+        for (var i = 1; i < data[0].length; i++)
+        {
+            data[0][i] = parseFloat(data[0][i]);
+        }
+        var first = data[0].slice(1);
+        if (time == store.time[0])
+        {
+            store.time[0] = time;
+            store.ohlc[0] = first;
+        } else {
+            store.time.unshift(time);
+            store.ohlc.unshift(first);
+        }
+        if (isNaN(store.ohlc[0][0]))
+        {
+            alert("update new NaN");
+        }
+        //store.v[0]  = parseFloat(data[0][5]);
+        for (var i =  1; i < data.length; i++)
+        {
+            if (!is_array(data[i]))
+            {
+                continue;
+            }
+            for (var j = 1; j < data[i].length; j++)
+            {
+                data[i][j] = parseFloat(data[i][j]);
+            }
+            store.time.unshift(parseInt(data[i][0]));
+            var newdata = data[i].slice(1);
+            store.ohlc.unshift(newdata);
+        }
+    }*/
+DataWriterCandle.prototype.setNewData = function(c, p, data) {
+    //更新第一个数据
+    if (!is_array(data.x) || data.x.length == 0) {
+        return;
+    }
+    var store = this.getStore(c, p);
+    var time = parseInt(data.x[0]);
+    while (data.x.length && time < store.time[0]) {
+        data.x.shift();
+        data.y.shift();
+        time = parseInt(data.x[0]);
+    }
+    if (data.x.length == 0) {
+        return;
+    }
+    var first = data.y[0];
+    if (time == store.time[0]) {
+        store.time[0] = time;
+        store.ohlc[0] = data.y[0]
+    } else {
+        store.time.unshift(time);
+        store.ohlc.unshift(data.y[0]);
+    }
+    if (isNaN(store.ohlc[0][0])) {
+        alert("update new NaN");
+    }
+    for (var i = 1; i < data.x.length; i++) {
+        store.time.unshift(data.x[i]);
+        store.ohlc.unshift(data.y[i]);
+    }
+}
+
+
+DataWriterCandle.prototype.getX = function(c, p) {
+    var store = this.getStore(c, p);
+    return store.time;
+}
+
+DataWriterCandle.prototype.getY = function(c, p) {
+    var store = this.getStore(c, p);
+    return store.ohlc;
+}
+
+DataWriterCandle.prototype.setDownloadData = function(c, p, data) {
+    //数据按照时间倒序序进行排列
+    var beg, end;
+    //处理指标
+    if (!is_array(data)) {
+    if (is_array(data.x) && is_array(data.y)) {
+        var newdata = [];
+            for (var i = data.x.length -1; i >= 0; i--) {
+                var item = [];
+                item.push(data.x[i]);
+                item = item.concat(data.y[i]);
+        newdata.push(item);
+        }
+            data = newdata;
+    } else {
+        return;
+    }
+    }
+    var store = this.getStore(c, p);
+    for (var i = 0; i < data.length; i++) {
+        if (!is_array(data[i])) {
+            continue;
+        }
+        for (var j = 1; j < data[i].length; j++) {
+            data[i][j] = parseFloat(data[i][j]);
+        }
+        store.time.push(parseInt(data[i][0]));
+        store.ohlc.push(data[i].slice(1));
+    }
+}
+
+function DataWriterFractals(model, name) {
+    sup(this, model, name);
+}
+ClassExtend(DataWriterFractals, DataWriter);
+
+
+DataWriterFractals.prototype.setNewData = function(c, p, data) {
+    if (!is_array(data) || data.length == 0) {
+        return;
+    }
+    //data = data.reverse();
+    var store = this.getStore(c, p);
+    /*
+    for (var i =  0; i < data.length; i++)
+    {
+        if (!is_array(data[i]))
+        {
+            continue;
+        }
+        var item = this.parseItem(data[i][1]);
+        var newitem;
+        if (item) {} else {continue;}
+        var time = formatTime(data[i][0], p);
+        if (store.x[0] == time) {
+            //可能会有新的买卖点
+            newitem = array_diff(item, store.y[0]);
+            store.y[0] = item;
+        } else {
+            store.x.unshift(time);
+            store.y.unshift(item);
+            newitem = item;
+        }
+        this.notify(newitem);
+    }
+    */
+}
+
+DataWriterFractals.prototype.notify = function(items) {
+    if (items && items.length) {
+        /*var typename = DataWriterProfit.nameMap[items[items.length - 1][0]];
+        typename = typename.replace("/", "_").toLowerCase();
+        var url = $("#music_list select[name="+typename+"]").val();
+        playmusic(url);
+        */
+    }
+}
+
+DataWriterFractals.prototype.parseItem = function(items) {
+    var newarr = [];
+    var type = null;
+    for (var i = 0; i < items.length; i++) {
+        var item = items[i];
+        if (item[0] == "buy" && item[1] == "open") {
+            type = DataWriterProfit.BUY_OPEN;
+        } else if (item[0] == "buy" && item[1] == "close") {
+            type = DataWriterProfit.BUY_CLOSE;
+        } else if (item[0] == "sell" && item[1] == "open") {
+            type = DataWriterProfit.SELL_OPEN;
+        } else if (item[0] == "sell" && item[1] == "close") {
+            type = DataWriterProfit.SELL_CLOSE;
+        }
+        if (type) {
+            newarr[i] = [type, parseFloat(item[2]), item[3]];
+        }
+    }
+
+    if (newarr.length == 0) {
+        return false;
+    }
+    newarr = this.formatItem(newarr);
+    return newarr;
+}
+
+DataWriterFractals.prototype.formatItem = function(arr) {
+    for (var i = 0; i < arr.length; i++) {}
+    return arr;
+}
+
+DataWriterFractals.prototype.setDownloadData = function(c, p, data) {
+    //数据按照时间倒序序进行排列
+    var beg, end;
+    //处理指标
+    if (!is_array(data.x)) {
+        return;
+    }
+    var store = this.getStore(c, p);
+    var item;
+    for (var i = 0; i < data.x.length; i++) {
+        //format time
+        var time = formatTime(data.x[i], p);
+        store.x.push(time);
+        item = data.y[i]; //this.parseItem(data[i][1]);
+        if (item) store.y.push(item);
+    }
+}
+
+
+function DataWriterKshape(model, name) {
+    sup(this, model, name);
+}
+ClassExtend(DataWriterKshape, DataWriter);
+
+
+DataWriterKshape.prototype.setNewData = function(c, p, data) {
+    if (!is_array(data) || data.length == 0) {
+        return;
+    }
+    //data = data.reverse();
+    var store = this.getStore(c, p);
+    /*
+    for (var i =  0; i < data.length; i++)
+    {
+        if (!is_array(data[i]))
+        {
+            continue;
+        }
+        var item = this.parseItem(data[i][1]);
+        var newitem;
+        if (item) {} else {continue;}
+        var time = formatTime(data[i][0], p);
+        if (store.x[0] == time) {
+            //可能会有新的买卖点
+            newitem = array_diff(item, store.y[0]);
+            store.y[0] = item;
+        } else {
+            store.x.unshift(time);
+            store.y.unshift(item);
+            newitem = item;
+        }
+        this.notify(newitem);
+    }
+    */
+}
+
+DataWriterKshape.prototype.notify = function(items) {
+    if (items && items.length) {
+        /*var typename = DataWriterProfit.nameMap[items[items.length - 1][0]];
+        typename = typename.replace("/", "_").toLowerCase();
+        var url = $("#music_list select[name="+typename+"]").val();
+        playmusic(url);
+        */
+    }
+}
+
+DataWriterKshape.prototype.parseItem = function(items) {
+    var newarr = [];
+    var type = null;
+    for (var i = 0; i < items.length; i++) {
+        var item = items[i];
+        if (item[0] == "buy" && item[1] == "open") {
+            type = DataWriterProfit.BUY_OPEN;
+        } else if (item[0] == "buy" && item[1] == "close") {
+            type = DataWriterProfit.BUY_CLOSE;
+        } else if (item[0] == "sell" && item[1] == "open") {
+            type = DataWriterProfit.SELL_OPEN;
+        } else if (item[0] == "sell" && item[1] == "close") {
+            type = DataWriterProfit.SELL_CLOSE;
+        }
+        if (type) {
+            newarr[i] = [type, parseFloat(item[2]), item[3]];
+        }
+    }
+
+    if (newarr.length == 0) {
+        return false;
+    }
+    newarr = this.formatItem(newarr);
+    return newarr;
+}
+
+DataWriterKshape.prototype.formatItem = function(arr) {
+    for (var i = 0; i < arr.length; i++) {}
+    return arr;
+}
+
+DataWriterKshape.prototype.setDownloadData = function(c, p, data) {
+    //数据按照时间倒序序进行排列
+    var beg, end;
+    //处理指标
+    if (!is_array(data.x)) {
+        return;
+    }
+    var store = this.getStore(c, p);
+    var item;
+    for (var i = 0; i < data.x.length; i++) {
+        //format time
+        var time = formatTime(data.x[i], p);
+        store.x.push(time);
+        item = data.y[i]; //this.parseItem(data[i][1]);
+        if (item) store.y.push(item);
+    }
+}
+
+
+function DataWriterMath(model, name) {
+    sup(this, model, name);
+}
+ClassExtend(DataWriterMath, DataWriter);
+
+function DataWriterProfit(model, name) {
+    sup(this, model, name);
+}
+ClassExtend(DataWriterProfit, DataWriter);
+
+DataWriterProfit.BUY_OPEN = 1;
+DataWriterProfit.BUY_CLOSE = 2;
+DataWriterProfit.SELL_OPEN = 3;
+DataWriterProfit.SELL_CLOSE = 4;
+
+DataWriterProfit.nameMap = {
+    1: "Open/Buy",
+    2: "Close/Buy",
+    3: "Open/Sell",
+    4: "Close/Sell"
+};
+
+DataWriterProfit.prototype.setNewData = function(c, p, data) {
+    if (!is_array(data) || data.length == 0) {
+        return;
+    }
+    data = data.reverse();
+    var store = this.getStore(c, p);
+    for (var i = 0; i < data.length; i++) {
+        if (!is_array(data[i])) {
+            continue;
+        }
+        var item = this.parseItem(data[i][1]);
+        var newitem;
+        if (item) {} else {
+            continue;
+        }
+        var time = formatTime(data[i][0], p);
+        if (store.x[0] == time) {
+            //可能会有新的买卖点
+            newitem = array_diff(item, store.y[0]);
+            store.y[0] = item;
+        } else {
+            store.x.unshift(time);
+            store.y.unshift(item);
+            newitem = item;
+        }
+        this.notify(newitem);
+    }
+}
+
+DataWriterProfit.prototype.notify = function(items) {
+    if (items && items.length) {
+        var typename = DataWriterProfit.nameMap[items[items.length - 1][0]];
+        typename = typename.replace("/", "_").toLowerCase();
+        var url = $("#music_list select[name=" + typename + "]").val();
+        // playmusic(url);
+    }
+}
+
+DataWriterProfit.prototype.parseItem = function(items) {
+
+    var newarr = [];
+    var type = null;
+    for (var i = 0; i < items.length; i++) {
+        var item = items[i];
+        if (item[0] == "buy" && item[1] == "open") {
+            type = DataWriterProfit.BUY_OPEN;
+        } else if (item[0] == "buy" && item[1] == "close") {
+            type = DataWriterProfit.BUY_CLOSE;
+        } else if (item[0] == "sell" && item[1] == "open") {
+            type = DataWriterProfit.SELL_OPEN;
+        } else if (item[0] == "sell" && item[1] == "close") {
+            type = DataWriterProfit.SELL_CLOSE;
+        }
+        if (type) {
+            newarr[i] = [type, parseFloat(item[2]), item[3]];
+        }
+    }
+
+    if (newarr.length == 0) {
+        return false;
+    }
+    newarr = this.formatItem(newarr);
+    return newarr;
+}
+
+DataWriterProfit.prototype.formatItem = function(arr) {
+    for (var i = 0; i < arr.length; i++) {}
+    return arr;
+}
+
+DataWriterProfit.prototype.setDownloadData = function(c, p, data) {
+    //数据按照时间倒序序进行排列
+    var beg, end;
+    //处理指标
+    if (!is_array(data)) {
+        return;
+    }
+    var store = this.getStore(c, p);
+    var item;
+    for (var i = 0; i < data.length; i++) {
+        if (!is_array(data[i])) {
+            continue;
+        }
+        //format time
+        var time = formatTime(data[i][0], p);
+        store.x.push(time);
+        item = this.parseItem(data[i][1]);
+        if (item) store.y.push(item);
+    }
+}
+
+function DataWriterTickSource(model, name) {
+    sup(this, model, name);
+    this.lastSource = null;
+}
+ClassExtend(DataWriterTickSource, DataWriter);
+
+DataWriterTickSource.prototype.setNewData = function(c, type, data) {
+    if (!is_array(data) || !is_array(data[0])) return;
+    this.lastSource = type;
+    var store = this.getStore(c, type);
+    for (var i = 0; i < data.length; i++) {
+        store.x.push(parseInt(data[i][0]) * 1000 + parseInt(data[i][1]));
+        store.y.push([parseFloat(data[i][2]), parseFloat(data[i][3])]);
+    }
+
+    if (store.x.length > this.maxdata) {
+        store.x = store.x.slice(this.maxdata / 2);
+        store.y = store.y.slice(this.maxdata / 2);
+    }
+}
+
+
+function DataReaderadx(model, writer, name) {
+    sup(this, model, writer, name);
+}
+ClassExtend(DataReaderadx, DataReader);
+
+
+function DataReaderAjax(model, writer, name) {
+    this.isinit = false;
+    sup(this, model, writer, name);
+    this.data = {};
+    this.lastdata = {};
+
+
+}
+
+ClassExtend(DataReaderAjax, DataReader);
+
+DataReaderAjax.prototype.setParam = function(param) {
+    if (this.isinit) return;
+    this.isinit = true;
+    var url = param[1];
+    var _this = this;
+    $.get(url, function(data) {
+        _this.setAjaxData(data);
+    }, "json");
+}
+
+DataReaderAjax.prototype.setAjaxData = function(data) {
+    this.data = data;
+    this.model.ready = true;
+    this.model.controller.flag("down");
+    //this.model.ready = false; //不更新图表了
+    this.main = this;
+    return this;
+}
+
+DataReaderAjax.prototype.getX = function() {
+    return this.data.x;
+}
+
+DataReaderAjax.prototype.getY = function() {
+    return this.data.y;
+}
+
+
+DataReaderAjax.prototype.getData = function(number, readconfig) {
+    var start = this.getStart(number);
+    this.lastdata = this.data.y[0];
+    start = this.getStart(number);
+    index = 0;
+    var x = [];
+    var y = [];
+    for (var i = start; i < this.data.x.length; i++) {
+        x[index] = this.data.x[i];
+        y[index] = this.data.y[i];
+        index++;
+        if (index >= number) {
+            break;
+        }
+    }
+    var data = {};
+    data.x = x;
+    data.y = array_copy2d(y);
+    return data;
+}
+
+DataReaderAjax.prototype.last = function() {
+    return this.lastdata;
+}
+
+DataReaderAjax.prototype.close = function(index) {
+    if (!index || index < 0) index = 0;
+    return this.data.y[index][Data.CLOSE];
+}
+
+
+DataReaderAjax.prototype.getEndPos = function() {
+    var x = this.data.x;
+    return x.length - 1;
+}
+
+DataReaderAjax.prototype.startXValue = function() {
+    var x = this.data.x;
+    return x[x.length - 1];
+}
+
+DataReaderAjax.prototype.endXValue = function() {
+    var x = this.data.x;
+    return x[0];
+}
+
+//现在,这样处理,一旦指标被注册了,
+//就会首先在已知K线上进行初始化操作。这个初始化操作是已有K线时间范围的数据
+//后面的数据,就会绑定在K线的下载结果里面
+//在指标初始化未结束的时候,如果这个时候,指标绑定下载了数据,那么就会保存在一个缓冲区里面。
+//指标初始化过程类似K线的初始化过程如下:先下载第一个1000个K线的指标。显示出来,
+//然后下载后面的指标,下载结束以后,合并缓冲区里面的指标,最后,初始化结束。
+
+function DataReaderatr(model, writer, name) {
+    sup(this, model, writer, name);
+}
+
+ClassExtend(DataReaderatr, DataReader);
+
+
+//���ڣ�����������һ��ָ�걻ע���ˣ�
+//�ͻ���������֪K���Ͻ��г�ʼ��������������ʼ������������K��ʱ�䷶Χ������
+//���������ݣ��ͻ�������K�ߵ����ؽ�������
+//��ָ����ʼ��δ������ʱ������������ʱ����ָ���������������ݣ���ô�ͻᱣ����һ�����������档
+//ָ����ʼ����������K�ߵij�ʼ���������£������ص�һ��1000��K�ߵ�ָ�ꡣ��ʾ������
+//Ȼ�����غ�����ָ��,���ؽ����Ժ󣬺ϲ�������������ָ�꣬���󣬳�ʼ��������
+
+//
+//��ȡ����ͼ������
+//
+function DataReaderbdensity(model, writer, name) {
+    sup(this, model, writer, name);
+}
+
+ClassExtend(DataReaderbdensity, DataReader);
+
+DataReaderbdensity.prototype.getYminmax = function(y) {
+    var ymax = -Infinity;
+    var ymin = Infinity;
+    var maxIndex=0;
+    var minIndex=0;
+    if (!y) {
+        return [ymin, ymax,minIndex,maxIndex];
+    }
+    var nIndex = 0;
+    for (var i = 0; i < y.length; i++) {
+        for (var j = 0; j < y[i].length; j++) {
+            nIndex = (j / 4) * 4 + 2
+            if (j % 4 <= 1 && y[i][nIndex] != 0) {
+                var value = y[i][j];
+                if (value > ymax) {
+                    ymax = value;
+                    maxIndex=i;
+                }
+                if (value < ymin) {
+                    ymin = value;
+                    minIndex=i;
+                }
+            }
+        }
+    }
+   console.log("ymin:"+ymin+",ymax:"+ymax);
+    return [ymin, ymax,minIndex,maxIndex];
+}
+
+//现在,这样处理,一旦指标被注册了,
+//就会首先在已知K线上进行初始化操作。这个初始化操作是已有K线时间范围的数据
+//后面的数据,就会绑定在K线的下载结果里面
+//在指标初始化未结束的时候,如果这个时候,指标绑定下载了数据,那么就会保存在一个缓冲区里面。
+//指标初始化过程类似K线的初始化过程如下:先下载第一个1000个K线的指标。显示出来,
+//然后下载后面的指标,下载结束以后,合并缓冲区里面的指标,最后,初始化结束。
+
+function DataReaderBolling(model, writer, name) {
+    sup(this, model, writer, name);
+}
+
+ClassExtend(DataReaderBolling, DataReader);
+
+
+//现在,这样处理,一旦指标被注册了,
+//就会首先在已知K线上进行初始化操作。这个初始化操作是已有K线时间范围的数据
+//后面的数据,就会绑定在K线的下载结果里面
+//在指标初始化未结束的时候,如果这个时候,指标绑定下载了数据,那么就会保存在一个缓冲区里面。
+//指标初始化过程类似K线的初始化过程如下:先下载第一个1000个K线的指标。显示出来,
+//然后下载后面的指标,下载结束以后,合并缓冲区里面的指标,最后,初始化结束。
+
+function DataReaderBollingDesity(model, writer, name) {
+    sup(this, model, writer, name);
+    this.sourcedata = null;
+}
+
+ClassExtend(DataReaderBollingDesity, DataReader);
+
+DataReaderBollingDesity.prototype.formatData = function(x, y) {
+    var data = {};
+    data.x = x;
+    data.y = y;
+    data.xunit = this.xunit;
+    data.yunit = this.yunit;
+    data.maxX = x[0];
+    data.minX = x[x.length - 1];
+    data.maxIndex=0;
+    data.minIndex=0;
+
+    var min = Infinity
+    var max = -Infinity;
+    for (var i = 0; i < y.length; i++) {
+        for (var j = 0; j < y.length; j += 2) {
+            if (y[i][j] == -1) {
+                continue;
+            }
+            if (max < y[i][j]) {
+                max = y[i][j];
+                data.maxIndex=i;
+            }
+
+            if (min > y[i][j]) {
+                min = y[i][j];
+                data.minIndex=i;
+            }
+        }
+    }
+    data.maxY = max;
+    data.minY = min;
+    return data;
+}
+
+//
+//读取蜡烛图的数据
+//
+
+function DataReaderCandle(model, writer, name) {
+    sup(this, model, writer, name);
+}
+
+ClassExtend(DataReaderCandle, DataReader);
+//抽象函数,不提供任何的功能。
+DataReaderCandle.prototype.getDataByNumber = function(number, readconfig) {
+    if (readconfig & DataReader.EXTEND) {
+        //以扩展的方式读取
+        return this.getDataByNumberExtend(number, readconfig);
+    }
+    //普通的读取方式
+    //这里,如果读取到末尾了,要修正start
+    var x = new Array(number);
+    var y = new Array(number);;
+    var index = 0;
+    start = this.getStart(number);
+    for (var i = start; i < this.store.time.length; i++) {
+        x[index] = this.store.time[i];
+        y[index] = this.store.ohlc[i];
+        index++;
+        if (index >= number) {
+            break;
+        }
+    }
+    if (index < number) {
+        x = x.slice(0, index - 1);
+        y = y.slice(0, index - 1);
+    }
+    //深度复制
+    y = array_copy2d(y);
+    return { x: x, y: y };
+}
+
+DataReaderCandle.prototype.getData = function(number, readconfig) {
+    return this.getDataByNumber(number, readconfig);
+}
+
+DataReaderCandle.prototype.getDataByNumberExtend = function(number, readconfig) {
+    // console.log("number:"+number);
+    var x = new Array(number);
+    var y = new Array(number);
+    var index = 0;
+    //普通的读取方式
+    //这里,如果读取到末尾了,要修正start
+    var start = this.getStart(number);
+    var xdata = this.writer.getX(this.c, this.p);
+    var ydata = this.writer.getY(this.c, this.p);
+    var length = xdata.length;
+    if (length == 0) {
+        return { x: [], y: [] };
+    }
+    x[index] = xdata[start];
+    y[index] = ydata[start];
+    for (var i = start; i < length - 1; i++) {
+        var ctime = xdata[i]; //当前时间
+        var ptime = xdata[i + 1]; //前一个时间
+        //1. 
+        if (ctime - ptime == this.step || ctime - ptime > this.maxstep) { //连续,或者相差太大。加入
+            index++;
+            x[index] = xdata[i + 1];
+            y[index] = ydata[i + 1];
+        } else { //需要补全,x值每次 加step y用 ptime对应的值
+            var close = ydata[i + 1][Data.CLOSE];
+            var candle = [close, close, close, close, ydata[i + 1][Data.VOLUMES]];
+            for (var newtime = xdata[i] - this.step; newtime > xdata[i + 1]; newtime -= this.step) {
+                index++;
+                x[index] = newtime;
+                y[index] = candle;
+            }
+            index++;
+            x[index] = xdata[i + 1];
+            y[index] = ydata[i + 1];
+        }
+        if (index + 1 >= number) {
+            break;
+        }
+    }
+    index++;
+    if (index < number) {
+        x = x.slice(0, index);
+        y = y.slice(0, index);
+    }
+    y = array_copy2d(y);
+    return { x: x, y: y };
+}
+
+//和main的时间进行对齐,对于稀疏的数据,这个非常重要
+DataReaderCandle.prototype.extendByMain = function(xdata, ydata) {
+    var mainX = this.getMainData().x;
+    var x = new Array();
+    var y = new Array();
+    var j = 0;
+    //1. 如果时间值超过了Main[0],那么直接忽略
+    //2. 如果某个值开始小于main[0],那么,main 开始加。直到main[i] < 这个值。
+    //3. 我们的索引加
+    if (xdata.length == 0 || xdata[xdata.length - 1] > mainX[mainX.length - 1]) {
+        //无效,这样的情况无法进行补全。
+        return { x: [], y: [] };
+    }
+    //计算第一个数据
+    var current = 0,
+        count = 0;
+    var close = ydata[current][Data.CLOSE];
+    candle = [close, close, close, close, ydata[current][Data.VOLUMES]];
+    for (var i = 0; i < mainX.length; i++) {
+        if (xdata[current] > mainX[i]) //这样的情况是无效的,从程序的条件可以看出,current 不会越界。
+        {
+            while (xdata[current] > mainX[i]) {
+                current++;
+            }
+            if (!ydata[current]) {
+                alert(current); //debug 的信息
+            }
+            close = ydata[current][Data.CLOSE];
+            candle = [close, close, close, close, ydata[current][Data.VOLUMES]];
+        }
+        if (mainX[i] > xdata[current]) {
+            y[count++] = candle;
+        } else if (mainX[i] == xdata[current]) {
+            y[count++] = ydata[current];
+        }
+    }
+    x = array_copy1d(mainX);
+    y = array_copy2d(y);
+    return { x: x, y: y };
+}
+
+DataReaderCandle.prototype.close = function(index) {
+    if (!index || index < 0) index = 0;
+    return this.store.ohlc[index][Data.CLOSE];
+}
+
+DataReaderCandle.prototype.formatData = function(x, y) {
+    var data = {};
+    data.x = x;
+    data.y = y;
+    data.xunit = this.xunit;
+    data.yunit = this.yunit;
+    data.maxX = x[0];
+    var nLen = y.length;
+    if (nLen > this.model.plotnum) {
+        nLen = this.model.plotnum;
+    }
+    data.minX = x[nLen - 1];
+    data.maxIndex=0;
+    data.minIndex=0;
+
+    var min = Infinity
+    var max = -Infinity;
+    //console.log("model=",this.model.plotnum,x);
+    for (var i = 0; i < y.length && i < this.model.plotnum; i++)
+    //for(var i=y.length-1;i>=0&& (y.length-i)<=this.model.plotnum;i--)
+    {
+        if (y[i][Data.HIGH] > max) {
+            max = y[i][Data.HIGH];
+            data.maxIndex=i;
+        }
+        if (y[i][Data.LOW] < min) {
+            min = y[i][Data.LOW];
+            data.minIndex=i;
+        }
+    }
+    data.maxY = max;
+    data.minY = min;
+    return data;
+}
+
+DataReaderCandle.prototype.getYminmax = function(y) {
+    var ymax = -Infinity;
+    var ymin = Infinity;
+    var minIndex=0;
+    var maxIndex=0;
+    if (!y) {
+        return [ymin, ymax,minIndex,maxIndex];
+    }
+    //for(var i=y.length-1;i>=0&& (y.length-i)<=this.model.plotnum;i--)
+    for (var i = 0; i < y.length && i < this.model.plotnum; i++) {
+        for (var j = 0; j < 4; j++) {
+            var value = y[i][j];
+            if (value > ymax) {
+                ymax = value;
+                maxIndex=i;
+            }
+            if (value < ymin) {
+                ymin = value;
+                minIndex=i;
+            }
+        }
+    }
+     return [ymin, ymax,minIndex,maxIndex];
+}
+
+function PlotEasyforex(plot, canvas) {
+    this.plot = plot;
+    this.canvas = canvas;
+    this.last = last;
+    this.initMyPlot();
+}
+
+//X Y 轴都要根据数据,绘制图形。
+//分离 主绘图区域 的数据 和 candle的 绘制。
+//使得数据 和 绘图分离,提高复用能力。
+// 
+PlotEasyforex.prototype.initMyPlot = function() {
+
+}
+
+
+//���ڣ�����������һ��ָ�걻ע���ˣ�
+//�ͻ���������֪K���Ͻ��г�ʼ��������������ʼ������������K��ʱ�䷶Χ������
+//���������ݣ��ͻ�������K�ߵ����ؽ�������
+//��ָ����ʼ��δ������ʱ������������ʱ����ָ���������������ݣ���ô�ͻᱣ����һ�����������档
+//ָ����ʼ����������K�ߵij�ʼ���������£������ص�һ��1000��K�ߵ�ָ�ꡣ��ʾ������
+//Ȼ�����غ�����ָ��,���ؽ����Ժ󣬺ϲ�������������ָ�꣬���󣬳�ʼ��������
+
+//
+//��ȡ����ͼ������
+//
+function DataReaderFractals(model, writer, name) {
+    sup(this, model, writer, name);
+}
+
+ClassExtend(DataReaderFractals, DataReader);
+
+DataReaderFractals.prototype.getYminmax = function(y) {
+    var ymax = -Infinity;
+    var ymin = Infinity;
+    var minIndex=0;
+    var maxIndex=0;
+    if (!y) {
+        return [ymin, ymax,minIndex,maxIndex];
+    }
+    for (var i = 0; i < y.length; i++) {
+        var value = y[i][1];
+        if (value > ymax) {
+            ymax = value;
+            maxIndex=i;
+        }
+        if (value < ymin) {
+            ymin = value;
+            minmax=i;
+        }
+    }
+     return [ymin, ymax,minIndex,maxIndex];
+}
+
+function DataReaderIndicators(model, writer, name) {
+    sup(this, model, writer, name);
+    this.data = {};
+    this.lastdata = {};
+}
+
+ClassExtend(DataReaderIndicators, DataReader);
+
+DataReaderIndicators.prototype.minmax = function(start, n) {
+    var high = -Infinity;
+    var low = Infinity;
+    for (var i = start; i < start + n && i < this.y.length; i++) {
+        if (this.y[i][Data.HIGH] > high) {
+            high = this.y[i][Data.HIGH];
+        }
+
+        if (this.y[i][Data.LOW] < low) {
+            low = this.y[i][Data.LOW];
+        }
+    }
+    // console.log(this.name, high, low);
+    return [high, low];
+}
+
+DataReaderIndicators.prototype.sum = function(start, length) {
+    if (this.y.length < start + length) {
+        return false;
+    }
+    var sum = 0;
+    for (var i = start; i < start + length; i++) {
+        sum += this.y[i][Data.CLOSE];
+    }
+    return sum;
+}
+
+DataReaderIndicators.prototype.setParam = function(param) {
+    this.param = param;
+}
+
+DataReaderIndicators.prototype.setDependData = function(name, data) {
+    this.data[name] = data;
+}
+
+//大多数指标可以这样初始化。如果子类初始化不一样,可以做处理
+DataReaderIndicators.prototype.dataInit = function(name) {
+    //init 先计算前n个值
+    //y是一个二维数组
+    if (!name) {
+        name = this.param[0][0];
+    }
+    if (this.data[name] && this.data[name].y) {
+        //[read only] 如果需要修改,请先复制。否则会改动原始数据。
+        this.y = this.data[name].y;
+        this.x = this.data[name].x;
+    } else {
+        return false;
+    }
+    //默认数据源是倒序排列的
+    if (this.n > this.y.length) {
+        return false;
+    }
+    if (!this.y) {
+        return false;
+    }
+    if (this.y && this.y.length == 0) {
+        return false;
+    }
+    return true;
+}
+
+//常用指标的实现
+DataReaderIndicators.prototype.wpr = function(n) {
+    var data = [];
+    var minmax = this.minmax(0, n);
+    var low = minmax[1];
+    var high = minmax[0];
+    var wr;
+    if (low == high) {
+        wr = 0;
+    } else {
+        wr = 100 * (this.y[0][Data.CLOSE] - high) / (high - low);
+    }
+    data.push(wr);
+    var index = 0;
+    for (var i = 1; i < this.y.length - n; i++) {
+        index = i + n - 1; //from i to index, total n number data.
+        if (this.y[index][Data.LOW] > low && this.y[index][Data.HIGH] < high && this.y[i][Data.LOW] > low && this.y[i][Data.HIGH] < high) {
+            //do nothing, high and low 不会变化
+        } else {
+            minmax = this.minmax(i, n);
+            low = minmax[1];
+            high = minmax[0];
+        }
+        if (low == high) {
+            wr = 0;
+        } else {
+            wr = 100 * (this.y[i][Data.CLOSE] - high) / (high - low);
+        }
+        data.push(wr);
+    }
+    //后面为空的补零,这样和时间才能对齐。
+    for (var i = 0; i < n; i++) {
+        data.push(0);
+    }
+    return data;
+}
+
+DataReaderIndicators.prototype.ma = function(n) {
+    var avg = [];
+    var sum = this.sum(0, n);
+    avg.push(sum / n);
+    for (var i = 1; i < this.y.length - n; i++) {
+        sum -= this.y[i - 1][Data.CLOSE];
+        sum += this.y[i + n - 1][Data.CLOSE];
+        avg.push(sum / n);
+    }
+    for (var i = 0; i < n; i++) {
+        avg.push(0);
+    }
+    return avg;
+}
+
+DataReaderIndicators.prototype.strength = function(n) {
+    var data = [];
+    var high = -Infinity;
+    var low = Infinity;
+    var index, item;
+    for (var i = 0; i < this.y.length - n; i++) {
+        index = i + n - 1;
+        item = this.y[i][Data.CLOSE] - this.y[index][Data.CLOSE];
+        if (high < item) {
+            high = item;
+        }
+        if (low > item) {
+            low = item;
+        }
+        data.push(item);
+    }
+    for (var i = 0; i < data.length; i++) {
+        data[i] = (data[i] / (high - low)) * 100;
+    }
+    //后面为空的补零,这样和时间才能对齐。
+    for (var i = 0; i < n; i++) {
+        data.push(0);
+    }
+    return data;
+}
+
+DataReaderIndicators.prototype.last = function() {
+    return this.lastdata;
+}
+
+//���ڣ�����������һ��ָ�걻ע���ˣ�
+//�ͻ���������֪K���Ͻ��г�ʼ��������������ʼ������������K��ʱ�䷶Χ������
+//���������ݣ��ͻ�������K�ߵ����ؽ�������
+//��ָ����ʼ��δ������ʱ������������ʱ����ָ���������������ݣ���ô�ͻᱣ����һ�����������档
+//ָ����ʼ����������K�ߵij�ʼ���������£������ص�һ��1000��K�ߵ�ָ�ꡣ��ʾ������
+//Ȼ�����غ�����ָ��,���ؽ����Ժ󣬺ϲ�������������ָ�꣬���󣬳�ʼ��������
+
+//
+//��ȡ����ͼ������
+//
+function DataReaderKshape(model, writer, name) {
+    sup(this, model, writer, name);
+}
+
+ClassExtend(DataReaderKshape, DataReader);
+
+DataReaderKshape.prototype.getYminmax = function(y) {
+    var ymax = -Infinity;
+    var ymin = Infinity;
+    var maxIndex=0;
+    var minIndex=0;
+    if (!y) {
+        return [ymin, ymax,minIndex,maxIndex];
+    }
+    for (var i = 0; i < y.length; i++) {
+        var value = y[i][0];
+        if (value > ymax) {
+            ymax = value;
+            maxIndex=i;
+        }
+        if (value < ymin) {
+            ymin = value;
+            minIndex=i;
+        }
+
+    }
+    //console.log(ymax)
+    //console.log(ymin)
+    return [ymin, ymax,minIndex,maxIndex];
+}
+
+function DataReaderMa(data, period, shift) {
+    if (!period) {
+        period = 14;
+    }
+
+    if (!shift) {
+        shift = 0;
+    }
+    this.data = data;
+    this.period = period;
+     $.cookie('period',period);
+    this.shift = shift;
+    this.X = [];
+    this.Y = [];
+}
+ClassExtend(DataReaderMa, DataReader);
+DataReaderMa.prototype.calc = function(start, count, time, data) {
+    //计算移动平均线
+    //start:
+    var sum = 0;
+    var i, j;
+    for (i = start, j = 0; j < count; i++, j++) {
+        this.X[j] = time[i];
+    }
+}
+
+//现在,这样处理,一旦指标被注册了,
+//就会首先在已知K线上进行初始化操作。这个初始化操作是已有K线时间范围的数据
+//后面的数据,就会绑定在K线的下载结果里面
+//在指标初始化未结束的时候,如果这个时候,指标绑定下载了数据,那么就会保存在一个缓冲区里面。
+//指标初始化过程类似K线的初始化过程如下:先下载第一个1000个K线的指标。显示出来,
+//然后下载后面的指标,下载结束以后,合并缓冲区里面的指标,最后,初始化结束。
+
+function DataReaderMacd(model, writer, name) {
+    sup(this, model, writer, name);
+}
+
+ClassExtend(DataReaderMacd, DataReader);
+
+
+
+function DataReaderMaex(model, writer, name) {
+    sup(this, model, writer, name);
+}
+
+ClassExtend(DataReaderMaex, DataReader);
+
+function DataReaderMath(model, writer, name) {
+
+    this.data = {};
+    this.lastdata = {};
+    sup(this, model, writer, name);
+    this.start = 0;
+    this.end = 0;
+    this.number = 0;
+    this.xunit = 0;
+    this.yunit = 0;
+}
+
+ClassExtend(DataReaderMath, DataReader);
+
+//对数学公式来说,只要设置一个 x轴的区间 和 要划分的 数目就可以了
+
+DataReaderMath.prototype.setXArea = function(start, end, number) {
+    this.start = start;
+    this.end = end;
+    this.number = number;
+    if (number <= 0) {
+        return;
+    }
+    var x = [];
+    var step = (this.end - this.start) / this.number;
+    var i = this.start;
+    while (i <= this.end) {
+        x.push(i);
+        i += step;
+    }
+    this.data.x = x.reverse();
+}
+
+DataReaderMath.prototype.setParam = function(param) {
+    if (param.length >= 2) {
+        param = param[1].split(",");
+        for (var i = 0; i < param.length; i++) {
+            param[i] = parseInt(param[i]);
+        }
+        this.setXArea(param[0], param[1], param[2]);
+    }
+}
+
+DataReaderMath.prototype.last = function() {
+    return this.lastdata;
+}
+
+DataReaderMath.prototype.getEndPos = function() {
+    var x = this.data.x;
+    return x.length - 1;
+}
+
+DataReaderMath.prototype.startXValue = function() {
+    var x = this.data.x;
+    return x[x.length - 1];
+}
+
+DataReaderMath.prototype.endXValue = function() {
+    var x = this.data.x;
+    return x[0];
+}
+
+
+DataReaderMath.prototype.formatData = function(x, y) {
+    var data = {};
+    data.x = x;
+    data.y = y;
+    data.maxX = x[0];
+    data.minX = x[x.length - 1];
+    data.maxIndex=0;
+    data.minIndex=0;
+
+    var _minmax = minmax(y);
+    data.maxY = _minmax[1];
+    data.minY = _minmax[0];
+    data.maxIndex=_minmax[3];
+    data.minIndex=_minmax[2];
+
+    data.xunit = this.getUnit(data.minX, data.maxX);
+    data.yunit = this.getUnit(data.minY, data.maxY);
+    return data;
+}
+
+DataReaderMath.prototype.getUnit = function(min, max) {
+        var step = (max - min) / this.number;
+        return Math.pow(10, Math.floor(Math.log(step) / Math.LN10));
+    }
+    //现在,这样处理,一旦指标被注册了,
+    //就会首先在已知K线上进行初始化操作。这个初始化操作是已有K线时间范围的数据
+    //后面的数据,就会绑定在K线的下载结果里面
+    //在指标初始化未结束的时候,如果这个时候,指标绑定下载了数据,那么就会保存在一个缓冲区里面。
+    //指标初始化过程类似K线的初始化过程如下:先下载第一个1000个K线的指标。显示出来,
+    //然后下载后面的指标,下载结束以后,合并缓冲区里面的指标,最后,初始化结束。
+
+function DataReaderOrder(model, writer, name) {
+    sup(this, model, writer, name);
+}
+
+ClassExtend(DataReaderOrder, DataReader);
+
+
+//
+//读取蜡烛图的数据
+//
+function DataReaderProfit(model, writer, name) {
+    sup(this, model, writer, name);
+}
+
+ClassExtend(DataReaderProfit, DataReader);
+
+DataReaderProfit.prototype.getYminmax = function(y) {
+    var ymax = -Infinity;
+    var ymin = Infinity;
+    var maxIndex=0;
+    var minIndex=0;
+    if (!y) {
+        return [ymin, ymax,minIndex,maxIndex];
+    }
+    for (var i = 0; i < y.length; i++) {
+        for (var j = 0; j < y[i].length; j++) {
+            var value = y[i][j][1];
+            if (value > ymax) {
+                ymax = value;
+                maxIndex=i;
+            }
+            if (value < ymin) {
+                ymin = value;
+                minIndex=i;
+            }
+        }
+    }
+    return [ymin, ymax,minIndex,maxIndex];
+}
+
+function DataReaderTickSource(model, writer, name) {
+    sup(this, model, writer, name);
+    this.maxdata = this.config[name].maxdata;
+    this.data = {};
+    this.cmd = "";
+    this.number = 60;
+    this.nameToId = { 'FXDD': 0, 'FXPRO': 1, 'EXNESS': 2, 'IRONFX': 3, "FXCM": 4 };
+    this.idToName = ['FXDD', 'FXPRO', 'EXNESS', 'IRONFX', "FXCM"];
+    this.microsecond = 0;
+    this.lastStatus = { width: {}, offset: {}, time: {}, quick: { queue: {}, inquick: false } };
+    this.lastdata;
+}
+
+ClassExtend(DataReaderTickSource, DataReader);
+
+DataReaderTickSource.prototype.setParam = function(param) {
+    this.param = param;
+    var cmd = this.param[1].split(",");
+    var tmp = cmd.shift();
+    tmp = tmp.split("/");
+    this.bidask = tmp[0];
+    this.number = parseInt(tmp[1]);
+    this.microsecond = parseInt(tmp[2]);
+    if (!this.c) {
+        return;
+    }
+    var r = [];
+    for (var i = 0; i < cmd.length; i++) {
+        r.push(this.c + "_" + cmd[i]);
+    }
+    this.cmd = "tick_source:" + r.join(",");
+}
+
+DataReaderTickSource.prototype.getWSCmd = function() {
+    this.setParam(this.param);
+    return this.cmd;
+}
+
+DataReaderTickSource.prototype.getData = function() {
+    var type, id;
+    var store, len;
+    var x, y, bidask;
+    var data = { x: [], y: {} };
+    this.lastdata = {};
+    this.lastStatus.time[this.writer.lastSource] = now();
+    for (var i = 0; i < this.idToName.length; i++) {
+        x = [];
+        y = [];
+        type = this.idToName[i];
+        id = this.nameToId[type];
+        store = this.writer.getStore(this.c, type);
+        len = store.x.length;
+        if (len == 0) {
+            continue;
+        }
+        if (this.bidask == "bid") {
+            bidask = 0;
+        } else if (this.bidask == "bid-ask") {
+            bidask = -1;
+        } else {
+            bidask = 1;
+        }
+        this.lastdata[type] = {};
+        this.lastdata[type].bidask = store.y[len - 1];
+        for (var j = 0; j < this.number && j < len; j++) {
+            var second = store.x[len - 1 - j];
+            if (this.microsecond) {
+                x[j] = second;
+            } else {
+                x[j] = parseInt(second / 1000) * 1000;
+            }
+            if (bidask < 0) {
+                y[j] = (store.y[len - 1 - j][0] + store.y[len - 1 - j][1]) / 2;
+            } else {
+                y[j] = store.y[len - 1 - j][bidask];
+            }
+        }
+        this.lastdata[type].x = x[0];
+        this.lastdata[type].y = y[0];
+        data.y[type] = { x: x, y: y };
+    }
+    return data;
+}
+
+DataReaderTickSource.prototype.formatData = function(x, y) {
+    var minX = Infinity;
+    var minY = Infinity;
+    var maxX = -Infinity;
+    var maxY = -Infinity;
+    var hasdata = false;
+    var len = 0;
+    for (var type in y) {
+        if (!is_object(y[type])) continue;
+        len = y[type].x.length;
+        if (len == 0) {
+            continue;
+        }
+        hasdata = true;
+        var data = this._formatData(y[type].x, y[type].y);
+        if (minX > data.minX) minX = data.minX;
+        if (minY > data.minY) minY = data.minY;
+        if (maxX < data.maxX) maxX = data.maxX;
+        if (maxY < data.maxY) maxY = data.maxY;
+    }
+    if (!hasdata) {
+        return { x: [], y: [] };
+    }
+    var data = this.lastInfo();
+    data.x = [minX, maxX];
+    data.xunit = 1;
+    data.yunit = this.yunit;
+    data.minX = minX;
+    data.minY = minY;
+    data.maxY = maxY;
+    data.maxX = maxX;
+    data.y = [minY, maxY]
+    data.data = y;
+    return data;
+}
+
+DataReaderTickSource.prototype.last = function() {
+    return this.lastdata;
+}
+
+DataReaderTickSource.prototype.lastInfo = function() {
+    //计算平均值
+    var avg = 0;
+    var num = 0;
+    var timemax = -Infinity;
+    var timemin = Infinity;
+
+    var tick_timemax = -Infinity;
+    var tick_timemin = Infinity;
+    var maxname, minname;
+    var tick_maxname, tick_minname;
+    var last = this.lastdata;
+    for (var key in last) {
+        if (!is_object(last[key])) {
+            continue;
+        }
+        if (this.lastStatus.time[key] > timemax) {
+            timemax = this.lastStatus.time[key];
+            maxname = key;
+        }
+        if (this.lastStatus.time[key] < timemin) {
+            timemin = this.lastStatus.time[key];
+            minname = key;
+        }
+        if (last[key].x > tick_timemax) {
+            tick_timemax = last[key].x;
+            tick_maxname = key;
+        }
+        if (last[key].x < tick_timemin) {
+            tick_timemin = last[key].x;
+            tick_minname = key;
+        }
+        if (typeof this.lastStatus.width[key] === "undefined") {
+            this.lastStatus.width[key] = 3;
+        }
+        num++;
+        avg += last[key].y;
+    }
+    avg = avg / num;
+    this.lastStatus.offset.local = now() - tick_timemax;
+    this.lastStatus.offset.delt = timemax - timemin;
+    //存在突破,要显示最后的bid ask 时间
+    if (this.lastStatus.quick.inquick == true) {
+        var quick = this.lastStatus.quick;
+        quick.queue[this.writer.lastSource] = 1;
+        qnumber = 0;
+        for (var key in quick.queue) {
+            if (quick.queue[key] === 1) {
+                qnumber++;
+            }
+        }
+        if (qnumber == num) {
+            quick.end = maxname;
+            quick.inquick = false;
+            quick.delt = this.lastStatus.time[quick.end] - this.lastStatus.time[quick.start];
+        }
+    }
+    var show = false;
+    var point = Math.abs(Math.floor(last[maxname].y / this.yunit) - Math.floor(avg / this.yunit));
+    if (this.lastStatus.quick.inquick == false && point >= 4) {
+        show = true;
+        this.lastStatus.quick = {};
+        this.lastStatus.quick.bidask = {};
+        this.lastStatus.quick.start = maxname;
+        this.lastStatus.quick.inquick = true;
+        this.lastStatus.quick.queue = {};
+        this.lastStatus.quick.point = point;
+        this.lastStatus.quick.queue[maxname] = 1;
+        for (var key in this.lastStatus.width) {
+            if (this.lastStatus.width[key] === 6) this.lastStatus.width[key] = 3;
+            this.lastStatus.quick.bidask[key] = this.lastdata[key] ? this.lastdata[key].bidask : [];
+        }
+        this.lastStatus.width[maxname] = 6;
+    }
+    if (Math.abs(Math.floor(last[minname].y / this.yunit) - Math.floor(avg / this.yunit)) >= 4) {
+        show = true;
+        for (var key in this.lastStatus.width) {
+            if (this.lastStatus.width[key] === 0.5) this.lastStatus.width[key] = 3;
+        }
+        this.lastStatus.width[minname] = 0.5;
+    }
+    this.lastStatus.show = show;
+    return this.lastStatus;
+    //计算最快值和最慢值
+}
+
+function PlotCandleBollingDesity(plot, canvas) {
+    this.name = "BollingDesity";
+    this.plot = plot;
+    this.grid = this.plot.grid;
+    this.api = plot.api;
+    this.time = [];
+    this.data = []; //所有的数据
+    this.cdata = new Point([], []); //当前要绘制的点
+
+    this.config = {
+        Long: { Up: 0, Low: 2, Color: "Yellow" },
+        Mid1: { Up: 4, Low: 6, Color: "Red" },
+        Mid2: { Up: 8, Low: 10, Color: "Purple" },
+        Short1: { Up: 12, Low: 14, Color: "Green" },
+        Short2: { Up: 16, Low: 18, Color: "LightSeaGreen" }
+    };
+
+    this.init = false;
+    this.databuf = [];
+}
+
+//PlotCandle 有一个指标列表,在相应的处理上,加上这个这些接口
+//提供下面的接口,用于下载数据,更新数据: 先更新time_start 和 mid_time 
+//再更新剩下来的部分
+
+PlotCandleBollingDesity.prototype.init = function(time_start, mid_time, time_end) {
+
+    if (time_start == mid_time) {
+        this.initComplete();
+        return;
+    }
+    var _this = this;
+    $.get(this.api, { action: 'indicator', name: this.name, 'ts': time_start, 'te': mid_time }, function(data) {
+        _this.processHistoryData(data);
+        if (mid_time == time_end) {
+            this.initComplete();
+        }
+    }, 'json');
+
+    if (mid_time < time_end) {
+        $.get(this.api, { action: 'indicator', name: this.name, 'ts': mid_time + 1, 'te': time_end }, function(data) {
+            _this.processHistoryData(data);
+            //处理原来下载的数据
+            this.initComplete();
+        }, 'json');
+    }
+}
+
+PlotCandleBollingDesity.prototype.initComplete = function() {
+    for (var i = 0; i < this.databuf.length; i++) {
+        this.processHistoryData(this.databuf[i]);
+    }
+    this.databuf = [];
+    this.init = true;
+}
+
+PlotCandleBollingDesity.prototype.draw = function() {
+    var X = array_copy(this.cdata.x);
+    var Y = array_copy(this.cdata.y);
+    //分成5种线来绘制
+    var yset = {};
+    for (var i = 0; i < X.length; i++) {
+        for (var key in this.config) {
+            if (typeof key == "string" && key != "undefined") {
+                var max_index = this.config[key].Up;
+                var min_index = this.config[key].Low;
+                var color = this.config[key].Color;
+                if (yset[key] === undefined) {
+                    yset[key] = {};
+                }
+                if (Y[i][max_index] != 0) {
+                    if (yset[key].Up === undefined) {
+                        yset[key].Up = new Point([], [], []);
+                    }
+                    yset[key].Up.x.push(X[i]);
+                    yset[key].Up.y.push(Y[i][max_index]);
+                    yset[key].Up.z.push(Y[i][max_index + 1]);
+                }
+                if (Y[i][min_index] != 0) {
+                    if (yset[key].Low === undefined) {
+                        yset[key].Low = new Point([], [], []);
+                    }
+                    yset[key].Low.x.push(X[i]);
+                    yset[key].Low.y.push(Y[i][min_index]);
+                    yset[key].Low.z.push(Y[i][min_index + 1]);
+                }
+            }
+        }
+    }
+    var minmax = this.getMinMaxDensity();
+    for (var key in yset) {
+        if (typeof key == "string" && key != "undefined") {
+            if (yset[key].Up) {
+                this.drawOne(yset[key].Up, this.config[key].Color, minmax);
+            }
+            if (yset[key].Low) {
+                this.drawOne(yset[key].Low, this.config[key].Color, minmax);
+            }
+        }
+    }
+}
+
+PlotCandleBollingDesity.prototype.getLineHeight = function(min, max, data) {
+    for (var i = 0; i < data.length; i++) {
+        data[i] = Math.floor(((data[i] - min) / (max - min)) * 5) + 1;
+    }
+    return data;
+}
+
+PlotCandleBollingDesity.prototype.drawOne = function(data, color, minmax) {
+    data.y = this.grid.getY(data.y);
+    data.z = this.getLineHeight(minmax[0], minmax[1], data.z);
+
+    var ctx = this.grid.ctx;
+    ctx.fillStyle = color;
+    for (var i = 0; i < data.x.length; i++) {
+        ctx.fillRect(data.x[i] - this.plot.box_pixel, data.y[i] - data.z[i], 2 * this.plot.box_pixel + 1, data.z[i]);
+    }
+}
+
+PlotCandleBollingDesity.prototype.updateNew = function(time) {
+    //do nothing
+}
+
+PlotCandleBollingDesity.prototype.down = function(time_start, time_end) {
+    var _this = this;
+    $.get(this.api, { action: 'indicator', name: this.name, 'ts': time_start, 'te': time_end }, function(data) {
+        if (this.init) {
+            _this.processHistoryData(data);
+        } else {
+            _this.databuf.push(data);
+        }
+    }, 'json');
+}
+
+PlotCandleBollingDesity.prototype.processHistoryData = function(data) {
+    var newdata = data[this.name];
+    if (!is_array(newdata) || newdata.length == 0) {
+        return;
+    }
+    for (var i = 0; i < newdata.length; i++) {
+        var item = newdata[i];
+        this.time.push(parseInt(item.pop()));
+        var flag = item.shift();
+        if (flag == null) {
+            item = null;
+        } else {
+            for (var j = 0; j < item.length; j++) {
+                item[j] = parseFloat(item[j]);
+            }
+        }
+        this.data.push(item);
+    }
+}
+
+PlotCandleBollingDesity.prototype.getDrawData = function(start_index, end_index) {
+    var y = this.data.slice(start_index, end_index + 1);
+    this.cdata.y = [];
+    this.cdata.x = [];
+    for (var i = 0; i < y.length - 1; i++) {
+        if (y[i] != null) {
+            this.cdata.y.push(y[i]);
+            this.cdata.x.push(this.plot.X[i]);
+        }
+    }
+    return this.cdata;
+}
+
+PlotCandleBollingDesity.prototype.getMinMax = function() {
+    var data = this.cdata.y;
+    var max = -Infinity;
+    var min = Infinity;
+    for (var i = 0; i < data.length; i++) {
+        for (var key in this.config) {
+            if (typeof key == "string" && key != "undefined") {
+                var max_index = this.config[key].Up;
+                var min_index = this.config[key].Low;
+
+                if (data[i][max_index] > 0 && max < data[i][max_index]) {
+                    max = data[i][max_index]
+                }
+                if (data[i][min_index] > 0 && min > data[i][min_index]) {
+                    min = data[i][min_index];
+                }
+            }
+        }
+    }
+    return [min, max];
+}
+
+PlotCandleBollingDesity.prototype.getMinMaxDensity = function() {
+        var data = this.cdata.y;
+        var max = -Infinity;
+        var min = Infinity;
+        for (var i = 0; i < data.length; i++) {
+            for (var key in this.config) {
+                if (typeof key == "string" && key != "undefined") {
+                    var max_index = this.config[key].Up;
+                    var min_index = this.config[key].Low;
+                    max = Math.max(max, data[i][max_index + 1], data[i][min_index + 1]);
+                    min = Math.min(min, data[i][max_index + 1], data[i][min_index + 1]);
+                }
+            }
+        }
+        return [min, max];
+    }
+    //arr 从小到大
+    //reverse = true arr 从大到小
+function bsearch(arr, match, reverse) {
+    var start = 0;
+    var end = arr.length - 1;
+    if (!reverse) {
+        reverse = false;
+    }
+    while (start <= end) {
+        mid = Math.floor((end - start) / 2) + start;
+        if (arr[mid] > match) {
+            if (reverse) {
+                start = mid + 1;
+            } else {
+                end = mid - 1;
+            }
+        } else if (arr[mid] < match) {
+            if (reverse) {
+                end = mid - 1;
+            } else {
+                start = mid + 1;
+            }
+        } else { //macth
+            return mid;
+        }
+    }
+    return -1;
+}
+
+//
+//读取蜡烛图的数据
+//
+function DataReaderTrendLine(model, writer, name) {
+    sup(this, model, writer, name);
+}
+
+ClassExtend(DataReaderTrendLine, DataReader);
+
+DataReaderTrendLine.prototype.getYminmax = function(y) {
+    var ymax = -Infinity;
+    var ymin = Infinity;
+    var maxIndex=0;
+    var minIndex=0;
+    //console.log("DataReaderTrendLine.prototype.getYminmax");
+    if (!y) {
+        return [ymin, ymax,minIndex,maxIndex];
+    }
+    for (var i = 0; i < y.length; i++) {
+        var value = y[i][0];
+        if (value > ymax) {
+            ymax = value;
+            maxIndex=i;
+        }
+        if (value < ymin) {
+            ymin = value;
+            minIndex=i;
+        }
+    }
+    return [ymin, ymax,minIndex,maxIndex];
+}
+
+//���ڣ�����������һ��ָ�걻ע���ˣ�
+//�ͻ���������֪K���Ͻ��г�ʼ��������������ʼ������������K��ʱ�䷶Χ������
+//���������ݣ��ͻ�������K�ߵ����ؽ�������
+//��ָ����ʼ��δ������ʱ������������ʱ����ָ���������������ݣ���ô�ͻᱣ����һ�����������档
+//ָ����ʼ����������K�ߵij�ʼ���������£������ص�һ��1000��K�ߵ�ָ�ꡣ��ʾ������
+//Ȼ�����غ�����ָ��,���ؽ����Ժ󣬺ϲ�������������ָ�꣬���󣬳�ʼ��������
+
+//
+//��ȡ����ͼ������
+//
+function DataReadervolumes(model, writer, name) {
+    sup(this, model, writer, name);
+}
+
+ClassExtend(DataReadervolumes, DataReader);
+
+DataReadervolumes.prototype.getDataByMain = function(readconfig) {
+    this.mainData = this.getMainData();
+    //var start = this.mainData.x[this.mainData.x.length - 1];
+    //var end   = this.mainData.x[0];
+    var x = new Array();
+    var y = new Array();
+    for (var i = 0; i < this.mainData.x.length && i < this.model.plotnum; i++) {
+        x.push(this.mainData.x[i]);
+        if (this.mainData.y[i][Data.OPEN] <= this.mainData.y[i][Data.CLOSE]) {
+            y.push([this.mainData.y[i][4]]);
+        } else {
+            y.push([this.mainData.y[i][4], 0]);
+        }
+    }
+    y = array_copy(y);
+    return { x: x, y: y };
+}
+
+DataReadervolumes.prototype.getYminmax = function(y) {
+    var ymax = -Infinity;
+    var ymin = 0;
+    var minIndex=0;
+    var maxIndex=0;
+    if (!y) {
+        return [ymin, ymax,minIndex,maxIndex];
+    }
+    for (var i = 0; i < y.length && i < this.model.plotnum; i++)
+    //for(var i=y.length-1;i>=0&& (y.length-i)<=this.model.plotnum;i--)
+    {
+        var value = y[i][0];
+        if (value > ymax) {
+            ymax = value;
+            maxIndex=i;
+        }
+    }
+    return [0, ymax,minIndex,maxIndex];
+}
+
+//���ڣ�����������һ��ָ�걻ע���ˣ�
+//�ͻ���������֪K���Ͻ��г�ʼ��������������ʼ������������K��ʱ�䷶Χ������
+//���������ݣ��ͻ�������K�ߵ����ؽ�������
+//��ָ����ʼ��δ������ʱ������������ʱ����ָ���������������ݣ���ô�ͻᱣ����һ�����������档
+//ָ����ʼ����������K�ߵij�ʼ���������£������ص�һ��1000��K�ߵ�ָ�ꡣ��ʾ������
+//Ȼ�����غ�����ָ��,���ؽ����Ժ󣬺ϲ�������������ָ�꣬���󣬳�ʼ��������
+
+//
+//��ȡ����ͼ������
+//
+function DataReadervolumes2(model, writer, name) {
+    sup(this, model, writer, name);
+}
+
+ClassExtend(DataReadervolumes2, DataReader);
+
+DataReadervolumes2.prototype.getDataByMain = function(readconfig) {
+    this.mainData = this.getMainData();
+    var x = new Array();
+    var y = new Array();
+    for (var i = 0; i < this.mainData.x.length && i < this.model.plotnum; i++) {
+        x.push(this.mainData.x[i]);
+        y.push([this.mainData.y[i][5]]);
+    }
+    y = array_copy(y);
+    return { x: x, y: y };
+}
+
+DataReadervolumes2.prototype.getYminmax = function(y) {
+    var ymax = -Infinity;
+    var ymin = Infinity;
+    var minIndex=0;
+    var maxIndex=0;
+    if (!y) {
+        return [ymin, ymax,minIndex,maxIndex];
+    }
+    //for(var i=y.length-1;i>=0&& (y.length-i)<=this.model.plotnum;i--)
+    for (var i = 0; i < y.length && i < this.model.plotnum; i++) {
+        var value = y[i][0];
+        if (value > ymax) {
+            ymax = value;
+            maxIndex=i;
+        }
+        if (value < ymin) {
+            ymin = value;
+            minIndex=i;
+        }
+    }
+    return [0, ymax,minIndex,maxIndex];
+}
+
+
+function DataReaderWave(model, writer, name) {
+    sup(this, model, writer, name);
+}
+
+ClassExtend(DataReaderWave, DataReader);
+//���ڣ�����������һ��ָ�걻ע���ˣ�
+//�ͻ���������֪K���Ͻ��г�ʼ��������������ʼ������������K��ʱ�䷶Χ������
+//���������ݣ��ͻ�������K�ߵ����ؽ�������
+//��ָ����ʼ��δ������ʱ������������ʱ����ָ���������������ݣ���ô�ͻᱣ����һ�����������档
+//ָ����ʼ����������K�ߵij�ʼ���������£������ص�һ��1000��K�ߵ�ָ�ꡣ��ʾ������
+//Ȼ�����غ�����ָ��,���ؽ����Ժ󣬺ϲ�������������ָ�꣬���󣬳�ʼ��������
+
+//
+//��ȡ����ͼ������
+//
+function DataReaderwdensity(model, writer, name) {
+    sup(this, model, writer, name);
+}
+
+ClassExtend(DataReaderwdensity, DataReader);
+
+DataReaderwdensity.prototype.getYminmax = function(y) {
+    var ymax = -Infinity;
+    var ymin = Infinity;
+    var minIndex=0;
+    var maxIndex=0;
+    if (!y) {
+        return [ymin, ymax,minIndex,maxIndex];
+    }
+    for (var i = 0; i < y.length; i++) {
+        for (var j = 0; j < y[i].length / 2; j++) {
+            if (y[i][j * 2] != 0 && y[i][j * 2 + 1] != 0) {
+                var value = y[i][j * 2];
+                if (value > ymax) {
+                    ymax = value;
+                    maxIndex=i;
+                }
+                if (value < ymin) {
+                    ymin = value;
+                    minIndex=i;
+                }
+            }
+        }
+    }
+    return [ymin, ymax,minIndex,maxIndex];
+}
+
+//现在,这样处理,一旦指标被注册了,
+//就会首先在已知K线上进行初始化操作。这个初始化操作是已有K线时间范围的数据
+//后面的数据,就会绑定在K线的下载结果里面
+//在指标初始化未结束的时候,如果这个时候,指标绑定下载了数据,那么就会保存在一个缓冲区里面。
+//指标初始化过程类似K线的初始化过程如下:先下载第一个1000个K线的指标。显示出来,
+//然后下载后面的指标,下载结束以后,合并缓冲区里面的指标,最后,初始化结束。
+
+function DataReaderWpr(model, writer, name) {
+    sup(this, model, writer, name);
+}
+
+ClassExtend(DataReaderWpr, DataReader);
+
+function DataReaderMathCos(model, writer, name) {
+    sup(this, model, writer, name);
+    this.setXArea(-10, 10, 100);
+}
+
+ClassExtend(DataReaderMathCos, DataReaderMath);
+
+DataReaderMathCos.prototype.getData = function() {
+    if (this.number <= 0 || this.start == this.end) {
+        return { x: [], y: [] };
+    }
+    var y = [];
+    var x = this.data.x;
+    for (var i = 0; i < x.length; i++) {
+        y.push(Math.cos(x[i]));
+    }
+    this.lastdata = y[0];
+    this.data.y = y;
+    return this.data;
+}
+
+function DataReaderMathSin(model, writer, name) {
+    sup(this, model, writer, name);
+    this.setXArea(-10, 10, 100);
+}
+
+ClassExtend(DataReaderMathSin, DataReaderMath);
+
+
+DataReaderMathSin.prototype.getData = function() {
+    if (this.number <= 0 || this.start == this.end) {
+        return { x: [], y: [] };
+    }
+    var x = this.data.x;
+    var y = [];
+    for (var i = 0; i < x.length; i++) {
+        y.push(Math.sin(x[i]));
+    }
+    this.lastdata = y[0];
+    this.data.y = y;
+    return this.data;
+}
+
+function DataReaderIndicatorsBolling(model, writer, name) {
+    sup(this, model, writer, name);
+    this.nPeriod = 12;
+    this.nDev = 2;
+    this.vlast = [0, 0, 0];
+}
+
+ClassExtend(DataReaderIndicatorsBolling, DataReaderIndicators);
+
+DataReaderIndicatorsBolling.prototype.setParam = function(param) {
+    //这个函数里面做一定的初始化工作。特别是shift
+    this.param = param;
+    n = param[1].split(",");
+    this.nPeriod = parseInt(n[0]);
+    this.nDev = parseInt(n[1]);
+    this.shift = this.nPeriod;
+}
+
+DataReaderIndicatorsBolling.prototype.getData = function() {
+    var mx = this.model.maindata.x;
+    var my = this.model.maindata.y
+    if (mx.length < this.nPeriod) {
+        return { x: [], y: [] };
+    }
+    var sum = 0;
+    for (var i = 0; i < this.nPeriod; i++) {
+        sum += my[i][Data.CLOSE];
+    }
+    var avg = [];
+    var matime = [];
+    var sma = 0.0,
+        dev = 0.0;
+    sma = sum / this.nPeriod;
+    for (var i = 0; i < this.nPeriod; i++) {
+        dev += Math.pow((my[i][Data.CLOSE] - sma), 2);
+    }
+    dev = Math.sqrt(dev / this.nPeriod);
+    avg.push([sma, (sma + this.nDev * dev), (sma - this.nDev * dev)]);
+    matime.push(mx[0]);
+    for (var i = 1; i <= (mx.length - this.nPeriod) && i < this.model.plotnum; i++) {
+        sum -= my[i - 1][Data.CLOSE];
+        sum += my[i + this.nPeriod - 1][Data.CLOSE];
+        sma = sum / this.nPeriod;
+        dev = 0;
+        for (var j = 0; j < this.nPeriod; j++) {
+            dev += Math.pow((my[i + j][Data.CLOSE] - sma), 2);
+        }
+        dev = Math.sqrt(dev / this.nPeriod);
+        avg.push([sma, (sma + this.nDev * dev), (sma - this.nDev * dev)]);
+        matime.push(mx[i]);
+    }
+    this.vlast = [sma, (sma + this.nDev * dev), (sma - this.nDev * dev)];
+    return { x: matime, y: avg };
+}
+
+DataReaderIndicatorsBolling.prototype.last = function() {
+    return this.vlast;
+}
+
+function DataReaderIndicatorsDWPR(model, writer, name) {
+    sup(this, model, writer, name);
+}
+
+ClassExtend(DataReaderIndicatorsDWPR, DataReaderIndicators);
+
+//对指标,数据部分由
+DataReaderIndicatorsDWPR.prototype.setN = function(n) {
+    this.n = parseInt(n);
+    this.shift = parseInt(n);
+}
+
+DataReaderIndicatorsDWPR.prototype.setParam = function(param) {
+    //这个函数里面做一定的初始化工作。特别是shift
+    this.param = param;
+    this.n = param[1].split(",");
+    this.n[0] = parseInt(this.n[0]);
+    this.n[1] = parseInt(this.n[1]);
+    this.reffer = this.param[0];
+    this.shift = Math.max(this.n[0], this.n[1]);
+}
+
+DataReaderIndicatorsDWPR.prototype.getData = function() {
+    //
+    if (!this.dataInit(this.reffer[0])) {
+        return { x: [], y: [] };
+    }
+    var data1 = this.wpr(this.n[0]);
+    if (!this.dataInit(this.reffer[1])) {
+        return { x: [], y: [] };
+    }
+    var data2 = this.wpr(this.n[1]);
+
+    if (data1.length != data2.length) {
+        return { x: [], y: [] };
+    }
+    var data = [];
+    for (var i = 0; i < data1.length; i++) {
+        data[i] = data1[i] - data2[i];
+    }
+    this.lastdata = data[0];
+    return { x: this.x, y: data };
+}
+
+function DataReaderIndicatorsKDJ(model, writer, name) {
+    sup(this, model, writer, name);
+    this.nPeriod = 9;
+    this.factor_1 = 2.0 / 3.0;
+    this.factor_2 = 1.0 / 3.0;
+    this.vlast = [0, 0, 0];
+}
+
+ClassExtend(DataReaderIndicatorsKDJ, DataReaderIndicators);
+
+
+DataReaderIndicatorsKDJ.prototype.setParam = function(param) {
+    //这个函数里面做一定的初始化工作。特别是shift
+    this.param = param;
+    n = param[1].split(",");
+    this.nPeriod = parseInt(n[0]);
+    this.shift = this.nPeriod;
+}
+
+DataReaderIndicatorsKDJ.prototype.getData = function() {
+    var mx = this.model.maindata.x.reverse();
+    var my = this.model.maindata.y.reverse();
+    if (mx.length < this.nPeriod) {
+        return { x: [], y: [] };
+    }
+    var k, d, j, rsv;
+    var yvalue = [];
+    var matime = [];
+    var cn, ln, hn;
+    var kpre = 50;
+    var dpre = 50;
+    for (i = this.nPeriod - 1; i < mx.length; i++) {
+        ln = Infinity;
+        hn = -Infinity;
+        cn = my[i][Data.CLOSE];
+        for (j = 0; j < this.nPeriod; j++) {
+            if (ln > my[i - j][Data.LOW]) {
+                ln = my[i - j][Data.LOW];
+            }
+            if (hn < my[i - j][Data.HIGH]) {
+                hn = my[i - j][Data.HIGH];
+            }
+        }
+        if ((hn - ln) == 0) {
+            rsv = 50;
+        } else {
+            rsv = (cn - ln) / (hn - ln) * 100;
+        }
+        k = this.factor_1 * kpre + this.factor_2 * rsv;
+        d = this.factor_1 * dpre + this.factor_2 * k;
+        j = 3 * d - 2 * k;
+        kpre = k;
+        dpre = d;
+        yvalue.push([k, d, j]);
+        matime.push(mx[i]);
+    }
+    matime = matime.reverse();
+    yvalue = yvalue.reverse();
+    this.vlast = [k, d, j];
+    return { x: matime, y: yvalue };
+}
+
+DataReaderIndicatorsKDJ.prototype.last = function() {
+    return this.vlast;
+}
+
+function DataReaderIndicatorsMa(model, writer, name) {
+    sup(this, model, writer, name);
+}
+
+ClassExtend(DataReaderIndicatorsMa, DataReaderIndicators);
+
+//对指标,数据部分由
+DataReaderIndicatorsMa.prototype.setN = function(n) {
+    this.n = parseInt(n);
+    this.shift = parseInt(n);
+}
+
+DataReaderIndicatorsMa.prototype.setParam = function(param) {
+    //这个函数里面做一定的初始化工作。特别是shift
+    this.param = param;
+    this.setN(this.param[1]);
+}
+
+DataReaderIndicatorsMa.prototype.getData = function() {
+    var mx = this.model.maindata.x;
+    var my = this.model.maindata.y
+    if (mx.length < this.n) {
+        return { x: [], y: [] };
+    }
+    var sum = 0;
+    //---- initial accumulation
+    //移动平均线的做法:前n个平均数目,那可以从 0 遍历到 length - this.n
+    //和一般求解指标不同,我这里采用倒过来求解的办法
+    //先初始化平均值
+    for (var i = 0; i < this.n; i++) {
+        sum += my[i][Data.CLOSE];
+    }
+    var avg = [];
+    var matime = [];
+    avg.push(sum / this.n);
+    matime.push(mx[0]);
+    for (var i = 1; i <= (mx.length - this.n) && i < this.model.plotnum; i++) {
+        sum -= my[i - 1][Data.CLOSE];
+        sum += my[i + this.n - 1][Data.CLOSE];
+        avg.push(sum / this.n);
+        matime.push(mx[i]);
+    }
+    //后面为空的补零,这样和时间才能对齐。
+    /*for (var i = 0; i < this.n; i++)
+    {
+        avg.push(0);
+    }*/
+    this.lastdata = avg[0];
+    return { x: matime, y: avg };
+}
+
+function DataReaderIndicatorsMacd(model, writer, name) {
+    sup(this, model, writer, name);
+    this.nFastPeriod = 12;
+    this.nSlowPeriod = 26;
+    this.nSignalPeriod = 9;
+    this.vlast = [0, 0];
+}
+
+ClassExtend(DataReaderIndicatorsMacd, DataReaderIndicators);
+
+DataReaderIndicatorsMacd.prototype.setParam = function(param) {
+    //这个函数里面做一定的初始化工作。特别是shift
+    this.param = param;
+    n = param[1].split(",");
+    this.nFastPeriod = parseInt(n[0]);
+    this.nSlowPeriod = parseInt(n[1]);
+    if (this.nFastPeriod > this.nSlowPeriod) {
+        nTmp = this.nFastPeriod;
+        this.nFastPeriod = this.nSlowPeriod;
+        this.nSlowPeriod = nTmp;
+    }
+    this.nSignalPeriod = parseInt(n[2]);
+    this.shift = this.nSlowPeriod + this.nSignalPeriod;
+}
+
+DataReaderIndicatorsMacd.prototype.getData = function() {
+    var mx = this.model.maindata.x;
+    var my = this.model.maindata.y
+    if (mx.length < this.shift) {
+        return { x: [], y: [] };
+    }
+    var sumfast = 0.0;
+    for (var i = 1; i <= this.nFastPeriod; i++) {
+        sumfast += my[mx.length - i][Data.CLOSE];
+    }
+    var sumslow = sumfast;
+    var vfast = sumfast / this.nFastPeriod;
+    var prfast = 2.0 / (this.nFastPeriod + 1.0);
+    for (var i = this.nFastPeriod + 1; i <= this.nSlowPeriod; i++) {
+        sumslow += my[mx.length - i][Data.CLOSE];
+        vfast = vfast * (1 - prfast) + prfast * my[mx.length - i][Data.CLOSE];
+    }
+    var vslow = sumslow / this.nSlowPeriod;
+    var prslow = 2.0 / (this.nSlowPeriod + 1.0);
+
+    var matime = [];
+    var macdy = [];
+    matime.push(mx[mx.length - this.nSlowPeriod]);
+    macdy.push([vfast - vslow, NaN]);
+    var summacd = vfast - vslow;
+    for (var i = this.nSlowPeriod + 1; i < this.nSlowPeriod + this.nSignalPeriod; i++) {
+        vfast = vfast * (1 - prfast) + prfast * my[mx.length - i][Data.CLOSE];
+        vslow = vslow * (1 - prslow) + prslow * my[mx.length - i][Data.CLOSE];
+        summacd += vfast - vslow;
+        matime.push(mx[mx.length - i]);
+        if (i < (this.nSlowPeriod + this.nSignalPeriod - 1)) {
+            macdy.push([vfast - vslow, NaN]);
+        } else {
+            macdy.push([vfast - vslow, summacd / this.nSignalPeriod]);
+        }
+    }
+
+    for (var i = this.nSlowPeriod + this.nSignalPeriod; i <= mx.length; i++) {
+        vfast = vfast * (1 - prfast) + prfast * my[mx.length - i][Data.CLOSE];
+        vslow = vslow * (1 - prslow) + prslow * my[mx.length - i][Data.CLOSE];
+        summacd += vfast - vslow;
+        summacd -= macdy[macdy.length - this.nSignalPeriod][0];
+        matime.push(mx[mx.length - i]);
+        macdy.push([vfast - vslow, summacd / this.nSignalPeriod]);
+    }
+    this.vlast = [vfast - vslow, summacd / this.nSignalPeriod]
+    return { x: matime, y: macdy };
+}
+
+DataReaderIndicatorsMacd.prototype.last = function() {
+    return this.vlast;
+}
+
+// DataReaderIndicatorsMacd.prototype.getYminmax = function(y) {
+
+//     var ymax = -Infinity;
+//     var ymin = Infinity;
+//     if (!y) {
+//         return [ymin, ymax];
+//     }
+//     for (var i = 1; i <= y.length && i <= this.model.plotnum; i++) {
+//         for (var j = 0; j < y[y.length - i].length; j++) {
+//             var value = y[y.length - i][j];
+//             if (!isNaN(value)) {
+//                 if (value > ymax) {
+//                     ymax = value;
+//                 }
+//                 if (value < ymin) {
+//                     ymin = value;
+//                 }
+//             }
+//         }
+//     }
+//     return [ymin, ymax];
+// }
+DataReaderIndicatorsMacd.prototype.getYminmax = function(y) {
+
+    var ymax = -Infinity;
+    var maxIndex=0;
+    var minIndex=0;
+    var ymin = Infinity;
+    if (!y) {
+        return [ymin, ymax,minIndex,maxIndex];
+    }
+    for (var i = 1; i <= y.length && i <= this.model.plotnum; i++) {
+        for (var j = 0; j < y[y.length - i].length; j++) {
+            var value = y[y.length - i][j];
+            if (!isNaN(value)) {
+                if (value > ymax) {
+                    maxIndex=i;
+                    ymax = value;
+                }
+                if (value < ymin) {
+                    minIndex=i;
+                    ymin = value;
+                }
+            }
+        }
+    }
+    return [ymin, ymax,minIndex,maxIndex];
+}
+
+function DataReaderIndicatorsMaTrend(model, writer, name) {
+    sup(this, model, writer, name);
+}
+
+ClassExtend(DataReaderIndicatorsMaTrend, DataReaderIndicators);
+
+DataReaderIndicatorsMaTrend.prototype.setParam = function(param) {
+    //这个函数里面做一定的初始化工作。特别是shift
+    this.param = param;
+    this.n = param[1].split(",");
+    for (var i = 0; i < this.n.length; i++) {
+        this.n[i] = parseInt(this.n[i]);
+    }
+    this.n = this.n.sort(function(a, b) {
+        return a - b
+    });
+    this.reffer = this.param[0];
+    this.shift = Math.max.apply(this, this.n);
+}
+
+DataReaderIndicatorsMaTrend.prototype.getData = function() {
+    var ma = [];
+    var trend = [];
+    if (!this.dataInit()) {
+        return { x: [], y: [] };
+    }
+    for (var i = 0; i < this.n.length; i++) {
+        // alert(this.n[i]);
+        ma[i] = this.ma(this.n[i]);
+    }
+    var num, delt;
+    for (var i = 0; i < this.y.length - 1; i++) {
+        num = 0;
+        delt = 0;
+        for (var j = 0; j < this.n.length; j++) {
+            if (ma[j][i] > ma[j][i + 1]) {
+                num++;
+            } else if (ma[j][i] < ma[j][i + 1]) {
+                num--;
+            }
+            delt++;
+            for (var k = j + 1; k < this.n.length; k++) {
+                if (ma[j][i] > ma[k][i]) {
+                    num++;
+                } else if (ma[j][i] < ma[k][i]) {
+                    num--;
+                }
+                delt++;
+            }
+        }
+        num = num / delt;
+        trend[i] = num;
+    }
+    trend[this.y.length - 1] = 0;
+    this.lastdata = trend[0];
+    return { x: this.x, y: trend };
+}
+
+function DataReaderIndicatorsRSI(model, writer, name) {
+    sup(this, model, writer, name);
+}
+
+ClassExtend(DataReaderIndicatorsRSI, DataReaderIndicators);
+
+//对指标,数据部分由
+DataReaderIndicatorsRSI.prototype.setN = function(n) {
+    this.n = parseInt(n);
+    this.shift = parseInt(n);
+}
+
+DataReaderIndicatorsRSI.prototype.setParam = function(param) {
+    //这个函数里面做一定的初始化工作。特别是shift
+    this.param = param;
+    this.reffer = this.param[0];
+    this.setN(param[1]);
+}
+
+DataReaderIndicatorsRSI.prototype.empty = function() {
+    return {
+        x: [],
+        y: []
+    };
+}
+
+DataReaderIndicatorsRSI.prototype.getData = function() {
+    if (!this.dataInit(this.reffer[1])) {
+        return this.empty();
+    }
+    var K = this.strength(this.n);
+    if (!this.dataInit(this.reffer[0])) {
+        return this.empty();
+    }
+    var E = this.strength(this.n);
+    if (K.length != E.length) {
+        return this.empty();
+    }
+    var H = [];
+    for (var i = 0; i < K.length; i++) {
+        H[i] = (K[i] - E[i] + 200) / 4;
+    }
+    this.lastdata = H[0];
+    return { x: this.x, y: H };
+}
+
+function DataReaderIndicatorsWPR(model, writer, name) {
+    sup(this, model, writer, name);
+}
+
+ClassExtend(DataReaderIndicatorsWPR, DataReaderIndicators);
+
+//对指标,数据部分由
+
+DataReaderIndicatorsWPR.prototype.setN = function(n) {
+    this.n = parseInt(n);
+    this.shift = parseInt(n);
+}
+
+DataReaderIndicatorsWPR.prototype.setParam = function(param) {
+    //这个函数里面做一定的初始化工作。特别是shift
+    this.param = param;
+    this.setN(this.param[1]);
+}
+
+DataReaderIndicatorsWPR.prototype.getData = function() {
+    if (!this.dataInit()) {
+        return { x: [], y: [] };
+    }
+    var data = this.wpr(this.n);
+    this.lastdata = data[0];
+    return { x: this.x, y: data };
+}
+
+function html5chart(api,type,period) {
+    if (type&&period) {
+        $('#'+type.toLowerCase()).addClass('active');
+        //$.clearCookie();
+        api.initPair(type, period);
+        $.cookie('symbol', type);
+        $.cookie('period',period);
+         // $.cookie('period',period);
+        // var indstr="main:ma|main|5|color=black:ma|main|10|color=yellow:ma|main|20|color=red:ma|main|30|color=green:";
+        // api.setInd(indstr);
+        api.initInd('MAC');
+        // console.log($('li[name="ETH"]'));
+    } else {
+        $.cookie('symbol', 'BCCBTC');
+        $.cookie('period', 'H1');
+        // sessionStorage.setItem('period','H1');
+        api.initPair('BCCBTC', "H1");
+        api.initInd('MAC');
+    }
+    return;
+}

+ 31 - 0
static/css/inputemail.css

@@ -0,0 +1,31 @@
+@charset "utf-8";
+
+* {
+	margin:0;
+	padding:0;
+}
+ul, li {
+	list-style:none;
+}
+.inputElem {
+	width:260px;
+	height:34px;
+	line-height:22px;
+	border:1px solid #ccc;
+}
+.parentCls {
+	width:260px!important;
+	height:268px; margin:0 auto;
+
+}
+.parentCls ul{ padding-right: 10px; background:#fff;}
+.auto-tip li { width: 100%; height: 30px; line-height: 30px; font-size: 14px; color: #000;}
+.auto-tip li.hoverBg {
+	background:#ddd;
+	cursor:pointer;
+	width: 216px;
+}
+
+.hidden {
+	display:none;
+}

+ 149 - 0
static/emailAutoComplete.js

@@ -0,0 +1,149 @@
+function EmailAutoComplete(options) { 
+    this.config = { 
+        targetCls: '.inputElem', 
+        parentCls: '.parentCls',
+        hiddenCls: '.hiddenCls',
+        searchForm: '.jqtransformdone', 
+        hoverBg: 'hoverBg', 
+        inputValColor: 'black', 
+        mailArr: ["","@qq.com","@163.com","@126.com","@sina.com","@gmail.com","@foxmail.com","@sohu.com","@vip.qq.com","@hotmail.com","@163.net","@sina.com.cn","@139.com","@189.cn","@33.cn"], 
+        isSelectHide: true, 
+        callback: null 
+    };
+    this.cache = { onlyFlag: true, currentIndex: -1, oldIndex: -1 };
+    this.init(options) 
+}
+EmailAutoComplete.prototype = { constructor: EmailAutoComplete, init: function(options) { this.config = $.extend(this.config, options || {});
+    var self = this,
+    _config = self.config,
+    _cache = self.cache;
+    $(_config.targetCls).each(function(index, item) { $(item).keyup(function(e) {
+        var target = e.target,
+        targetVal = $.trim($(this).val()),
+        keycode = e.keyCode,
+        elemHeight = $(this).outerHeight(),
+        elemWidth = $(this).outerWidth(),
+        parentNode = $(this).closest(_config.parentCls);
+        console.log(targetVal);
+        if(targetVal.indexOf('script')>-1){
+            targetVal='';
+            $(this).val("");
+            return false;
+        }
+        $(parentNode).css({ 'position': 'relative' });
+        if (targetVal == '') { $(item).attr({ 'data-html': '' });
+        $(_config.hiddenCls, parentNode).val('');
+        _cache.currentIndex = -1;
+        _cache.oldIndex = -1;
+        $(".auto-tip", parentNode) && !$(".auto-tip", parentNode).hasClass('hidden') && $(".auto-tip", parentNode).addClass('hidden');
+        self._removeBg(parentNode) } else { $(item).attr({ 'data-html': targetVal });
+        $(_config.hiddenCls, parentNode).val(targetVal);
+        $(".auto-tip", parentNode) && $(".auto-tip", parentNode).hasClass('hidden') && $(".auto-tip", parentNode).removeClass('hidden');
+        self._renderHTML({ keycode: keycode, e: e, target: target, targetVal: targetVal, height: elemHeight, width: elemWidth, parentNode: parentNode }) } }) });
+        $(_config.searchForm).each(function(index, item) { $(item).keydown(function(e) {
+            var keyCode = e.keyCode;
+            if (keyCode == 13) {
+                return false 
+            }
+        }) 
+    });
+    $(document).click(function(e) { e.stopPropagation();
+        var target = e.target,
+        tagCls = _config.targetCls.replace(/^\./, '');
+        if (!$(target).hasClass(tagCls)) { $('.auto-tip') && $('.auto-tip').each(function(index, item) {!$(item).hasClass('hidden') && $(item).addClass('hidden') }) } }); }, _renderHTML: function(cfg) {
+        var self = this,
+            _config = self.config,
+            _cache = self.cache,
+            curVal;
+        var curIndex = self._keyCode(cfg.keycode);
+        $('.auto-tip', cfg.parentNode).hasClass('hidden') && $('.auto-tip', cfg.parentNode).removeClass('hidden');
+        if (curIndex > -1) { self._keyUpAndDown(cfg.targetVal, cfg.e, cfg.parentNode) } else {
+            if (/@/.test(cfg.targetVal)) { curVal = cfg.targetVal.replace(/@.*/, '') } else { curVal = cfg.targetVal }
+            if (_cache.onlyFlag) { $(cfg.parentNode).append('<input type="hidden" class="hiddenCls"/>');
+                var wrap = '<ul class="auto-tip">';
+                for (var i = 0; i < _config.mailArr.length; i++) { wrap += '<li class="p-index' + i + '">' + '<span class="output-num"></span><em class="em" data-html="' + _config.mailArr[i] + '">' + _config.mailArr[i] + '</em></li>' }
+                wrap += '</ul>';
+                _cache.onlyFlag = false;
+                $(cfg.parentNode).append(wrap);
+                $('.auto-tip', cfg.parentNode).css({ 'position': 'absolute', 'top': cfg.height, 'width': cfg.width - 2 + 'px', 'left': 0, 'border': '1px solid #ccc', 'z-index': 10000 }) }
+            $('.auto-tip li', cfg.parentNode).each(function(index, item) { $('.output-num', item).html(curVal);!$('.output-num', item).hasClass(_config.inputValColor) && $('.output-num', item).addClass(_config.inputValColor);
+                var emVal = $.trim($('.em', item).attr('data-html'));
+                $(item).attr({ 'data-html': curVal + '' + emVal }) });
+            self._accurateMate({ target: cfg.target, parentNode: cfg.parentNode });
+            self._itemHover(cfg.parentNode);
+            self._executeClick(cfg.parentNode) } }, _accurateMate: function(cfg) {
+        var self = this,
+            _config = self.config,
+            _cache = self.cache;
+        var curVal = $.trim($(cfg.target, cfg.parentNode).attr('data-html')),
+            newArrs = [];
+        if (/@/.test(curVal)) {
+            var prefix = curVal.replace(/@.*/, ""),
+                suffix = curVal.replace(/.*@/, "");
+            $.map(_config.mailArr, function(n) {
+                var reg = new RegExp(suffix);
+                if (reg.test(n)) { newArrs.push(n) } });
+            if (newArrs.length > 0) { $('.auto-tip', cfg.parentNode).html('');
+                $(".auto-tip", cfg.parentNode) && $(".auto-tip", cfg.parentNode).hasClass('hidden') && $(".auto-tip", cfg.parentNode).removeClass('hidden');
+                var html = '';
+                for (var j = 0, jlen = newArrs.length; j < jlen; j++) { html += '<li class="p-index' + j + '">' + '<span class="output-num"></span><em class="em" data-html="' + newArrs[j] + '">' + newArrs[j] + '</em></li>' }
+                $('.auto-tip', cfg.parentNode).html(html);
+                $('.auto-tip li', cfg.parentNode).each(function(index, item) { $('.output-num', item).html(prefix);!$('.output-num', item).hasClass(_config.inputValColor) && $('.output-num', item).addClass(_config.inputValColor);
+                    var emVal = $.trim($('.em', item).attr('data-html'));
+                    $(item).attr('data-html', '');
+                    $(item).attr({ 'data-html': prefix + '' + emVal }) });
+                _cache.currentIndex = -1;
+                _cache.oldIndex = -1;
+                $('.auto-tip .output-num', cfg.parentNode).html(prefix);
+                self._itemHover(cfg.parentNode);
+                self._executeClick(cfg.parentNode) } else { $(".auto-tip", cfg.parentNode) && !$(".auto-tip", cfg.parentNode).hasClass('hidden') && $(".auto-tip", cfg.parentNode).addClass('hidden');
+                $('.auto-tip', cfg.parentNode).html('') } } }, _itemHover: function(parentNode) {
+        var self = this,
+            _config = self.config,
+            _cache = self.cache;
+        $('.auto-tip li', parentNode).hover(function(index, item) {!$(this).hasClass(_config.hoverBg) && $(this).addClass(_config.hoverBg) }, function() { $(this).hasClass(_config.hoverBg) && $(this).removeClass(_config.hoverBg) }) }, _removeBg: function(parentNode) {
+        var self = this,
+            _config = self.config;
+        $(".auto-tip li", parentNode).each(function(index, item) { $(item).hasClass(_config.hoverBg) && $(item).removeClass(_config.hoverBg) }) }, _keyUpAndDown: function(targetVal, e, parentNode) {
+        var self = this,
+            _cache = self.cache,
+            _config = self.config;
+        if ($('.auto-tip' + ' li', parentNode) && $('.auto-tip' + ' li').length > 0) {
+            var plen = $('.auto-tip' + ' li', parentNode).length,
+                keyCode = e.keyCode;
+            _cache.oldIndex = _cache.currentIndex;
+            if (keyCode == 38) {
+                if (_cache.currentIndex == -1) { _cache.currentIndex = plen - 1 } else { _cache.currentIndex = _cache.currentIndex - 1;
+                    if (_cache.currentIndex < 0) { _cache.currentIndex = plen - 1 } }
+                if (_cache.currentIndex !== -1) {!$('.auto-tip .p-index' + _cache.currentIndex, parentNode).hasClass(_config.hoverBg) && $('.auto-tip .p-index' + _cache.currentIndex, parentNode).addClass(_config.hoverBg).siblings().removeClass(_config.hoverBg);
+                    var curAttr = $('.auto-tip' + ' .p-index' + _cache.currentIndex, parentNode).attr('data-html');
+                    $(_config.targetCls, parentNode).val(curAttr);
+                    $(_config.hiddenCls, parentNode).val(curAttr) } } else if (keyCode == 40) {
+                if (_cache.currentIndex == plen - 1) { _cache.currentIndex = 0 } else { _cache.currentIndex++;
+                    if (_cache.currentIndex > plen - 1) { _cache.currentIndex = 0 } }
+                if (_cache.currentIndex !== -1) {!$('.auto-tip .p-index' + _cache.currentIndex, parentNode).hasClass(_config.hoverBg) && $('.auto-tip .p-index' + _cache.currentIndex, parentNode).addClass(_config.hoverBg).siblings().removeClass(_config.hoverBg);
+                    var curAttr = $('.auto-tip' + ' .p-index' + _cache.currentIndex, parentNode).attr('data-html');
+                    $(_config.targetCls, parentNode).val(curAttr);
+                    $(_config.hiddenCls, parentNode).val(curAttr) } } else if (keyCode == 13) {
+                var curVal = $('.auto-tip' + ' .p-index' + _cache.oldIndex, parentNode).attr('data-html');
+                $(_config.targetCls, parentNode).val(curVal);
+                $(_config.hiddenCls, parentNode).val(curVal);
+                if (_config.isSelectHide) {!$(".auto-tip", parentNode).hasClass('hidden') && $(".auto-tip", parentNode).addClass('hidden') }
+                _config.callback && $.isFunction(_config.callback) && _config.callback();
+                _cache.currentIndex = -1;
+                _cache.oldIndex = -1 } } }, _keyCode: function(code) {
+        var arrs = ['17', '18', '38', '40', '37', '39', '33', '34', '35', '46', '36', '13', '45', '44', '145', '19', '20', '9'];
+        for (var i = 0, ilen = arrs.length; i < ilen; i++) {
+            if (code == arrs[i]) {
+                return i } }
+        return -1 }, _executeClick: function(parentNode) {
+        var _self = this,
+            _config = _self.config;
+        $('.auto-tip' + ' li', parentNode).unbind('click');
+        $('.auto-tip' + ' li', parentNode).bind('click', function(e) {
+            var dataAttr = $(this).attr('data-html');
+            $(_config.targetCls, parentNode).val(dataAttr);
+            if (_config.isSelectHide) {!$(".auto-tip", parentNode).hasClass('hidden') && $(".auto-tip", parentNode).addClass('hidden') }
+            $(_config.hiddenCls, parentNode).val(dataAttr);
+            _config.callback && $.isFunction(_config.callback) && _config.callback() }) } };
+$(function() { new EmailAutoComplete({}) });

BIN
static/img/Klogo.png


BIN
static/img/apply/phone.png


BIN
static/img/apply/phoneHover.png


BIN
static/img/apply/qq.png


BIN
static/img/apply/qqHover.png


BIN
static/img/apply/wx.png


BIN
static/img/apply/wxHover.png


BIN
static/img/loading.gif


File diff suppressed because it is too large
+ 1 - 0
static/jquery-3.2.1.min.js


+ 117 - 0
static/jquery.cookie.js

@@ -0,0 +1,117 @@
+/*!
+ * jQuery Cookie Plugin v1.4.1
+ * https://github.com/carhartl/jquery-cookie
+ *
+ * Copyright 2013 Klaus Hartl
+ * Released under the MIT license
+ */
+(function (factory) {
+  if (typeof define === 'function' && define.amd) {
+    // AMD
+    define(['jquery'], factory);
+  } else if (typeof exports === 'object') {
+    // CommonJS
+    factory(require('jquery'));
+  } else {
+    // Browser globals
+    factory(jQuery);
+  }
+}(function ($) {
+
+  var pluses = /\+/g;
+
+  function encode(s) {
+    return config.raw ? s : encodeURIComponent(s);
+  }
+
+  function decode(s) {
+    return config.raw ? s : decodeURIComponent(s);
+  }
+
+  function stringifyCookieValue(value) {
+    return encode(config.json ? JSON.stringify(value) : String(value));
+  }
+
+  function parseCookieValue(s) {
+    if (s.indexOf('"') === 0) {
+      // This is a quoted cookie as according to RFC2068, unescape...
+      s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
+    }
+
+    try {
+      // Replace server-side written pluses with spaces.
+      // If we can't decode the cookie, ignore it, it's unusable.
+      // If we can't parse the cookie, ignore it, it's unusable.
+      s = decodeURIComponent(s.replace(pluses, ' '));
+      return config.json ? JSON.parse(s) : s;
+    } catch(e) {}
+  }
+
+  function read(s, converter) {
+    var value = config.raw ? s : parseCookieValue(s);
+    return $.isFunction(converter) ? converter(value) : value;
+  }
+
+  var config = $.cookie = function (key, value, options) {
+
+    // Write
+
+    if (value !== undefined && !$.isFunction(value)) {
+      options = $.extend({}, config.defaults, options);
+
+      if (typeof options.expires === 'number') {
+        var days = options.expires, t = options.expires = new Date();
+        t.setTime(+t + days * 864e+5);
+      }
+
+      return (document.cookie = [
+        encode(key), '=', stringifyCookieValue(value),
+        options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
+        options.path    ? '; path=' + options.path : '',
+        options.domain  ? '; domain=' + options.domain : '',
+        options.secure  ? '; secure' : ''
+      ].join(''));
+    }
+
+    // Read
+
+    var result = key ? undefined : {};
+
+    // To prevent the for loop in the first place assign an empty array
+    // in case there are no cookies at all. Also prevents odd result when
+    // calling $.cookie().
+    var cookies = document.cookie ? document.cookie.split('; ') : [];
+
+    for (var i = 0, l = cookies.length; i < l; i++) {
+      var parts = cookies[i].split('=');
+      var name = decode(parts.shift());
+      var cookie = parts.join('=');
+
+      if (key && key === name) {
+        // If second argument (value) is a function it's a converter...
+        result = read(cookie, value);
+        break;
+      }
+
+      // Prevent storing a cookie that we couldn't decode.
+      if (!key && (cookie = read(cookie)) !== undefined) {
+        result[name] = cookie;
+      }
+    }
+
+    return result;
+  };
+
+  config.defaults = {};
+
+  $.removeCookie = function (key, options) {
+    if ($.cookie(key) === undefined) {
+      return false;
+    }
+
+    // Must not alter options, thus extending a fresh object...
+    $.cookie(key, '', $.extend({}, options, { expires: -1 }));
+    return !$.cookie(key);
+  };
+
+}));

+ 93 - 0
static/jquery.extension.js

@@ -0,0 +1,93 @@
+//dragdrop
+(function($) {
+	$.fn.dragdrop = function(eventobj)
+	{
+		var moveobj  = this;
+		var mouseup = function (e) 
+		{
+			$(document).unbind("mousemove", mousemove);
+			$(document).unbind("mouseup", mouseup);
+			return false;
+		}
+	    var mousemove = function (e) 
+		{
+			var position = e.data;
+			e.pageX = Math.max(0, Math.min(e.pageX, $(window).width()));
+			e.pageY = Math.max(0, Math.min(e.pageY, $(window).height()));
+			var newleft  = e.pageX - position.left;
+			var newtop   = e.pageY - position.top;
+			$(moveobj).css("left", newleft + "px");
+			$(moveobj).css("top",  newtop + "px");
+		}
+        var mousedown = function (e) {
+			var left = e.pageX - $(this).offset().left;
+			var top  = e.pageY - $(this).offset().top;
+			$(document).bind('mousemove', {left: left, top: top} , mousemove);
+			$(document).bind('mouseup', mouseup);
+			return false;
+		}
+		$(eventobj).bind('mousedown', mousedown);
+	};
+})(jQuery);
+
+
+/*! Copyright (c) 2009 Brandon Aaron (http://brandonaaron.net)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
+ * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
+ *
+ * Version: 3.0.2
+ * 
+ * Requires: 1.2.2+
+ */
+
+(function($) {
+
+var types = ['DOMMouseScroll', 'mousewheel'];
+
+$.event.special.mousewheel = {
+	setup: function() {
+		if ( this.addEventListener )
+			for ( var i=types.length; i; )
+				this.addEventListener( types[--i], handler, false );
+		else
+			this.onmousewheel = handler;
+	},
+
+	teardown: function() {
+		if ( this.removeEventListener )
+			for ( var i=types.length; i; )
+				this.removeEventListener( types[--i], handler, false );
+		else
+			this.onmousewheel = null;
+	}
+};
+
+$.fn.extend({
+	mousewheel: function(fn) {
+		return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
+	},
+	
+	unmousewheel: function(fn) {
+		return this.unbind("mousewheel", fn);
+	}
+});
+
+
+function handler(event) {
+	var args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true;
+	
+	event = $.event.fix(event || window.event);
+	event.type = "mousewheel";
+	
+	if ( event.wheelDelta ) delta = event.wheelDelta/120;
+	if ( event.detail     ) delta = -event.detail/3;
+	
+	// Add events and delta to the front of the arguments
+	args.unshift(event, delta);
+
+	return $.event.handle.apply(this, args);
+}
+
+})(jQuery);

+ 559 - 0
static/jquery.mCustomScrollbar.css

@@ -0,0 +1,559 @@
+/* basic scrollbar styling */
+/* vertical scrollbar */
+.mCSB_container{
+	width:auto;
+	margin-right:30px;
+	overflow:hidden;
+}
+.mCSB_container.mCS_no_scrollbar{
+	margin-right:0;
+}
+.mCS_disabled>.mCustomScrollBox>.mCSB_container.mCS_no_scrollbar,
+.mCS_destroyed>.mCustomScrollBox>.mCSB_container.mCS_no_scrollbar{
+	margin-right:30px;
+}
+.mCustomScrollBox>.mCSB_scrollTools{
+	width:16px;
+	height:100%;
+	top:0;
+	right:0;
+}
+.mCSB_scrollTools .mCSB_draggerContainer{
+	position:absolute;
+	top:0;
+	left:0;
+	bottom:0;
+	right:0; 
+	height:auto;
+}
+.mCSB_scrollTools a+.mCSB_draggerContainer{
+	margin:20px 0;
+}
+.mCSB_scrollTools .mCSB_draggerRail{
+	width:2px;
+	height:100%;
+	margin:0 auto;
+	-webkit-border-radius:10px;
+	-moz-border-radius:10px;
+	border-radius:10px;
+}
+.mCSB_scrollTools .mCSB_dragger{
+	cursor:pointer;
+	width:100%;
+	height:30px;
+}
+.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
+	width:4px;
+	height:100%;
+	margin:0 auto;
+	-webkit-border-radius:10px;
+	-moz-border-radius:10px;
+	border-radius:10px;
+	text-align:center;
+}
+.mCSB_scrollTools .mCSB_buttonUp,
+.mCSB_scrollTools .mCSB_buttonDown{
+	display:block;
+	position:relative;
+	height:20px;
+	overflow:hidden;
+	margin:0 auto;
+	cursor:pointer;
+}
+.mCSB_scrollTools .mCSB_buttonDown{
+	top:100%;
+	margin-top:-40px;
+}
+/* horizontal scrollbar */
+.mCSB_horizontal>.mCSB_container{
+	height:auto;
+	margin-right:0;
+	margin-bottom:30px;
+	overflow:hidden;
+}
+.mCSB_horizontal>.mCSB_container.mCS_no_scrollbar{
+	margin-bottom:0;
+}
+.mCS_disabled>.mCSB_horizontal>.mCSB_container.mCS_no_scrollbar,
+.mCS_destroyed>.mCSB_horizontal>.mCSB_container.mCS_no_scrollbar{
+	margin-right:0;
+	margin-bottom:30px;
+}
+.mCSB_horizontal.mCustomScrollBox>.mCSB_scrollTools{
+	width:100%;
+	height:16px;
+	top:auto;
+	right:auto;
+	bottom:0;
+	left:0;
+	overflow:hidden;
+}
+.mCSB_horizontal>.mCSB_scrollTools a+.mCSB_draggerContainer{
+	margin:0 20px;
+}
+.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
+	width:100%;
+	height:2px;
+	margin:7px 0;
+	-webkit-border-radius:10px;
+	-moz-border-radius:10px;
+	border-radius:10px;
+}
+.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger{
+	width:30px;
+	height:100%;
+}
+.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
+	width:100%;
+	height:4px;
+	margin:6px auto;
+	-webkit-border-radius:10px;
+	-moz-border-radius:10px;
+	border-radius:10px;
+}
+.mCSB_horizontal>.mCSB_scrollTools .mCSB_buttonLeft,
+.mCSB_horizontal>.mCSB_scrollTools .mCSB_buttonRight{
+	display:block;
+	position:relative;
+	width:20px;
+	height:100%;
+	overflow:hidden;
+	margin:0 auto;
+	cursor:pointer;
+	float:left;
+}
+.mCSB_horizontal>.mCSB_scrollTools .mCSB_buttonRight{
+	margin-left:-40px;
+	float:right;
+}
+.mCustomScrollBox{
+	-ms-touch-action:none; /*MSPointer events - direct all pointer events to js*/
+}
+
+/* default scrollbar colors and backgrounds (default theme) */
+.mCustomScrollBox>.mCSB_scrollTools{
+	opacity:0.75;
+	filter:"alpha(opacity=75)"; -ms-filter:"alpha(opacity=75)"; /* old ie */
+}
+.mCustomScrollBox:hover>.mCSB_scrollTools{
+	opacity:1;
+	filter:"alpha(opacity=100)"; -ms-filter:"alpha(opacity=100)"; /* old ie */
+}
+.mCSB_scrollTools .mCSB_draggerRail{
+	background:#000; /* rgba fallback */
+	background:rgba(0,0,0,0.4);
+	filter:"alpha(opacity=40)"; -ms-filter:"alpha(opacity=40)"; /* old ie */
+}
+.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
+	background:#fff; /* rgba fallback */
+	background:rgba(255,255,255,0.75);
+	filter:"alpha(opacity=75)"; -ms-filter:"alpha(opacity=75)"; /* old ie */
+}
+.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
+	background:rgba(255,255,255,0.85);
+	filter:"alpha(opacity=85)"; -ms-filter:"alpha(opacity=85)"; /* old ie */
+}
+.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{
+	background:rgba(255,255,255,0.9);
+	filter:"alpha(opacity=90)"; -ms-filter:"alpha(opacity=90)"; /* old ie */
+}
+.mCSB_scrollTools .mCSB_buttonUp,
+.mCSB_scrollTools .mCSB_buttonDown,
+.mCSB_scrollTools .mCSB_buttonLeft,
+.mCSB_scrollTools .mCSB_buttonRight{
+	/*background-image:url(../mCSB_buttons.png);*/
+	background-repeat:no-repeat;
+	opacity:0.4;
+	filter:"alpha(opacity=40)"; -ms-filter:"alpha(opacity=40)"; /* old ie */
+}
+.mCSB_scrollTools .mCSB_buttonUp{
+	background-position:0 0;
+	/* 
+	sprites locations are 0 0/-16px 0/-32px 0/-48px 0 (light) and -80px 0/-96px 0/-112px 0/-128px 0 (dark) 
+	*/
+}
+.mCSB_scrollTools .mCSB_buttonDown{
+	background-position:0 -20px;
+	/* 
+	sprites locations are 0 -20px/-16px -20px/-32px -20px/-48px -20px (light) and -80px -20px/-96px -20px/-112px -20px/-128px -20px (dark) 
+	*/
+}
+.mCSB_scrollTools .mCSB_buttonLeft{
+	background-position:0 -40px;
+	/* 
+	sprites locations are 0 -40px/-20px -40px/-40px -40px/-60px -40px (light) and -80px -40px/-100px -40px/-120px -40px/-140px -40px (dark) 
+	*/
+}
+.mCSB_scrollTools .mCSB_buttonRight{
+	background-position:0 -56px;
+	/* 
+	sprites locations are 0 -56px/-20px -56px/-40px -56px/-60px -56px (light) and -80px -56px/-100px -56px/-120px -56px/-140px -56px (dark) 
+	*/
+}
+.mCSB_scrollTools .mCSB_buttonUp:hover,
+.mCSB_scrollTools .mCSB_buttonDown:hover,
+.mCSB_scrollTools .mCSB_buttonLeft:hover,
+.mCSB_scrollTools .mCSB_buttonRight:hover{
+	opacity:0.75;
+	filter:"alpha(opacity=75)"; -ms-filter:"alpha(opacity=75)"; /* old ie */
+}
+.mCSB_scrollTools .mCSB_buttonUp:active,
+.mCSB_scrollTools .mCSB_buttonDown:active,
+.mCSB_scrollTools .mCSB_buttonLeft:active,
+.mCSB_scrollTools .mCSB_buttonRight:active{
+	opacity:0.9;
+	filter:"alpha(opacity=90)"; -ms-filter:"alpha(opacity=90)"; /* old ie */
+}
+
+/*scrollbar themes*/
+/*dark (dark colored scrollbar)*/
+.mCS-dark>.mCSB_scrollTools .mCSB_draggerRail{
+	background:#000; /* rgba fallback */
+	background:rgba(0,0,0,0.15);
+}
+.mCS-dark>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
+	background:#000; /* rgba fallback */
+	background:rgba(0,0,0,0.75);
+}
+.mCS-dark>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
+	background:rgba(0,0,0,0.85);
+}
+.mCS-dark>.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-dark>.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{
+	background:rgba(0,0,0,0.9);
+}
+.mCS-dark>.mCSB_scrollTools .mCSB_buttonUp{
+	background-position:-80px 0;
+}
+.mCS-dark>.mCSB_scrollTools .mCSB_buttonDown{
+	background-position:-80px -20px;
+}
+.mCS-dark>.mCSB_scrollTools .mCSB_buttonLeft{
+	background-position:-80px -40px;
+}
+.mCS-dark>.mCSB_scrollTools .mCSB_buttonRight{
+	background-position:-80px -56px;
+}
+/*light-2*/
+.mCS-light-2>.mCSB_scrollTools .mCSB_draggerRail{
+	width:4px;
+	background:#fff; /* rgba fallback */
+	background:rgba(255,255,255,0.1);
+	-webkit-border-radius:1px;
+	-moz-border-radius:1px;
+	border-radius:1px;
+}
+.mCS-light-2>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
+	width:4px;
+	background:#fff; /* rgba fallback */
+	background:rgba(255,255,255,0.75);
+	-webkit-border-radius:1px;
+	-moz-border-radius:1px;
+	border-radius:1px;
+}
+.mCS-light-2.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
+	width:100%;
+	height:4px;
+	margin:6px 0;
+}
+.mCS-light-2.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
+	width:100%;
+	height:4px;
+	margin:6px auto;
+}
+.mCS-light-2>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
+	background:rgba(255,255,255,0.85);
+}
+.mCS-light-2>.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-light-2>.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{
+	background:rgba(255,255,255,0.9);
+}
+.mCS-light-2>.mCSB_scrollTools .mCSB_buttonUp{
+	background-position:-32px 0;
+}
+.mCS-light-2>.mCSB_scrollTools .mCSB_buttonDown{
+	background-position:-32px -20px;
+}
+.mCS-light-2>.mCSB_scrollTools .mCSB_buttonLeft{
+	background-position:-40px -40px;
+}
+.mCS-light-2>.mCSB_scrollTools .mCSB_buttonRight{
+	background-position:-40px -56px;
+}
+/*dark-2*/
+.mCS-dark-2>.mCSB_scrollTools .mCSB_draggerRail{
+	width:4px;
+	background:#000; /* rgba fallback */
+	background:rgba(0,0,0,0.1);
+	-webkit-border-radius:1px;
+	-moz-border-radius:1px;
+	border-radius:1px;
+}
+.mCS-dark-2>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
+	width:4px;
+	background:#000; /* rgba fallback */
+	background:rgba(0,0,0,0.75);
+	-webkit-border-radius:1px;
+	-moz-border-radius:1px;
+	border-radius:1px;
+}
+.mCS-dark-2.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
+	width:100%;
+	height:4px;
+	margin:6px 0;
+}
+.mCS-dark-2.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
+	width:100%;
+	height:4px;
+	margin:6px auto;
+}
+.mCS-dark-2>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
+	background:rgba(0,0,0,0.85);
+}
+.mCS-dark-2>.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-dark-2>.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{
+	background:rgba(0,0,0,0.9);
+}
+.mCS-dark-2>.mCSB_scrollTools .mCSB_buttonUp{
+	background-position:-112px 0;
+}
+.mCS-dark-2>.mCSB_scrollTools .mCSB_buttonDown{
+	background-position:-112px -20px;
+}
+.mCS-dark-2>.mCSB_scrollTools .mCSB_buttonLeft{
+	background-position:-120px -40px;
+}
+.mCS-dark-2>.mCSB_scrollTools .mCSB_buttonRight{
+	background-position:-120px -56px;
+}
+/*light-thick*/
+.mCS-light-thick>.mCSB_scrollTools .mCSB_draggerRail{
+	width:4px;
+	background:#fff; /* rgba fallback */
+	background:rgba(255,255,255,0.1);
+	-webkit-border-radius:2px;
+	-moz-border-radius:2px;
+	border-radius:2px;
+}
+.mCS-light-thick>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
+	width:6px;
+	background:#fff; /* rgba fallback */
+	background:rgba(255,255,255,0.75);
+	-webkit-border-radius:2px;
+	-moz-border-radius:2px;
+	border-radius:2px;
+}
+.mCS-light-thick.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
+	width:100%;
+	height:4px;
+	margin:6px 0;
+}
+.mCS-light-thick.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
+	width:100%;
+	height:6px;
+	margin:5px auto;
+}
+.mCS-light-thick>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
+	background:rgba(255,255,255,0.85);
+}
+.mCS-light-thick>.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-light-thick>.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{
+	background:rgba(255,255,255,0.9);
+}
+.mCS-light-thick>.mCSB_scrollTools .mCSB_buttonUp{
+	background-position:-16px 0;
+}
+.mCS-light-thick>.mCSB_scrollTools .mCSB_buttonDown{
+	background-position:-16px -20px;
+}
+.mCS-light-thick>.mCSB_scrollTools .mCSB_buttonLeft{
+	background-position:-20px -40px;
+}
+.mCS-light-thick>.mCSB_scrollTools .mCSB_buttonRight{
+	background-position:-20px -56px;
+}
+/*dark-thick*/
+.mCS-dark-thick>.mCSB_scrollTools .mCSB_draggerRail{
+	width:4px;
+	background:#000; /* rgba fallback */
+	background:rgba(0,0,0,0.1);
+	-webkit-border-radius:2px;
+	-moz-border-radius:2px;
+	border-radius:2px;
+}
+.mCS-dark-thick>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
+	width:6px;
+	background:#000; /* rgba fallback */
+	background:rgba(0,0,0,0.75);
+	-webkit-border-radius:2px;
+	-moz-border-radius:2px;
+	border-radius:2px;
+}
+.mCS-dark-thick.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
+	width:100%;
+	height:4px;
+	margin:6px 0;
+}
+.mCS-dark-thick.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
+	width:100%;
+	height:6px;
+	margin:5px auto;
+}
+.mCS-dark-thick>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
+	background:rgba(0,0,0,0.85);
+}
+.mCS-dark-thick>.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-dark-thick>.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{
+	background:rgba(0,0,0,0.9);
+}
+.mCS-dark-thick>.mCSB_scrollTools .mCSB_buttonUp{
+	background-position:-96px 0;
+}
+.mCS-dark-thick>.mCSB_scrollTools .mCSB_buttonDown{
+	background-position:-96px -20px;
+}
+.mCS-dark-thick>.mCSB_scrollTools .mCSB_buttonLeft{
+	background-position:-100px -40px;
+}
+.mCS-dark-thick>.mCSB_scrollTools .mCSB_buttonRight{
+	background-position:-100px -56px;
+}
+/*light-thin*/
+.mCS-light-thin>.mCSB_scrollTools .mCSB_draggerRail{
+	background:#fff; /* rgba fallback */
+	background:rgba(255,255,255,0.1);
+}
+.mCS-light-thin>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
+	width:2px;
+}
+.mCS-light-thin.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
+	width:100%;
+}
+.mCS-light-thin.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
+	width:100%;
+	height:2px;
+	margin:7px auto;
+}
+/*dark-thin*/
+.mCS-dark-thin>.mCSB_scrollTools .mCSB_draggerRail{
+	background:#000; /* rgba fallback */
+	background:rgba(0,0,0,0.15);
+}
+.mCS-dark-thin>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
+	width:2px;
+	background:#000; /* rgba fallback */
+	background:rgba(0,0,0,0.75);
+}
+.mCS-dark-thin.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
+	width:100%;
+}
+.mCS-dark-thin.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
+	width:100%;
+	height:2px;
+	margin:7px auto;
+}
+.mCS-dark-thin>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
+	background:rgba(0,0,0,0.85);
+}
+.mCS-dark-thin>.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-dark-thin>.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{
+	background:rgba(0,0,0,0.9);
+}
+.mCS-dark-thin>.mCSB_scrollTools .mCSB_buttonUp{
+	background-position:-80px 0;
+}
+.mCS-dark-thin>.mCSB_scrollTools .mCSB_buttonDown{
+	background-position:-80px -20px;
+}
+.mCS-dark-thin>.mCSB_scrollTools .mCSB_buttonLeft{
+	background-position:-80px -40px;
+}
+.mCS-dark-thin>.mCSB_scrollTools .mCSB_buttonRight{
+	background-position:-80px -56px;
+}
+
+/* custom styling */
+/* content_1 scrollbar */
+.content_1>.mCustomScrollBox>.mCSB_scrollTools{
+	height:96%;
+	top:2%;
+}
+/* content_2 scrollbar */
+.content_2 .mCSB_scrollTools .mCSB_draggerRail{
+	width:6px;
+	box-shadow:1px 1px 1px rgba(255,255,255,0.1);
+}
+.content_2 .mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
+	background:rgba(255,255,255,0.4);
+	filter:"alpha(opacity=40)"; -ms-filter:"alpha(opacity=40)"; /* old ie */
+}
+.content_2 .mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
+	background:rgba(255,255,255,0.5);
+	filter:"alpha(opacity=50)"; -ms-filter:"alpha(opacity=50)"; /* old ie */
+}
+.content_2 .mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.content_2 .mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{
+	background:rgba(255,255,255,0.6);
+	filter:"alpha(opacity=60)"; -ms-filter:"alpha(opacity=60)"; /* old ie */
+}
+/* content_3 scrollbar */
+.content_3>.mCustomScrollBox>.mCSB_scrollTools{
+	height:94%;
+	top:3%;
+}
+.content_3 .mCSB_scrollTools .mCSB_draggerRail{
+	width:0;
+	border-right:1px dashed #09C;
+}
+.content_3 .mCSB_scrollTools .mCSB_dragger{
+	height:11px;
+}
+.content_3 .mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
+	width:11px;
+	-webkit-border-radius:11px;
+	-moz-border-radius:11px;
+	border-radius:11px;
+	background:#09C;
+}
+/* content_4 scrollbar */
+.content_4>.mCustomScrollBox>.mCSB_scrollTools{
+	height:94%;
+	top:3%;
+}
+.content_4 .mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
+	width:8px;
+	-webkit-border-radius:2px;
+	-moz-border-radius:2px;
+	border-radius:2px;
+	background:#d0b9a0;
+	-webkit-box-shadow:1px 1px 5px rgba(0,0,0,0.5);
+	-moz-box-shadow:1px 1px 5px rgba(0,0,0,0.5);
+	box-shadow:1px 1px 5px rgba(0,0,0,0.5);
+}
+.content_4 .mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar,
+.content_4 .mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{
+	background:#dfcdb9;
+}
+.content_4 .mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.content_4 .mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{
+	-webkit-box-shadow:0 0 3px rgba(0,0,0,0.5);
+	-moz-box-shadow:0 0 3px rgba(0,0,0,0.5);
+	box-shadow:0 0 3px rgba(0,0,0,0.5);
+}
+/* content_5 scrollbar */
+.content_5>.mCustomScrollBox>.mCSB_scrollTools{
+	width: 98%;
+	margin: 0 1%;
+}
+/* content_6 scrollbar */
+.content_6>.mCustomScrollBox>.mCSB_scrollTools{
+	width:88%;
+	margin: 0 6%;
+}
+/* content_8 scrollbar */
+.content_8 .mCSB_scrollTools .mCSB_draggerRail{
+	width:0px;
+	border-left:1px solid rgba(0,0,0,0.8);
+	border-right:1px solid rgba(255,255,255,0.2);
+}

+ 515 - 0
static/jquery.mCustomScrollbar.min.js

@@ -0,0 +1,515 @@
+(function(c) {
+    var b = { init: function(e) {
+                var f = { set_width: false, set_height: false, horizontalScroll: false, scrollInertia: 950, mouseWheel: true, mouseWheelPixels: "auto", autoDraggerLength: true, autoHideScrollbar: false, snapAmount: null, snapOffset: 0, scrollButtons: { enable: false, scrollType: "continuous", scrollSpeed: "auto", scrollAmount: 40 }, advanced: { updateOnBrowserResize: true, updateOnContentResize: false, autoExpandHorizontalScroll: false, autoScrollOnFocus: true, normalizeMouseWheelDelta: false }, contentTouchScroll: true, callbacks: { onScrollStart: function() {}, onScroll: function() {}, onTotalScroll: function() {}, onTotalScrollBack: function() {}, onTotalScrollOffset: 0, onTotalScrollBackOffset: 0, whileScrolling: function() {} }, theme: "light" },
+                    e = c.extend(true, f, e);
+                return this.each(function() {
+                    var m = c(this);
+                    if (e.set_width) { m.css("width", e.set_width) }
+                    if (e.set_height) { m.css("height", e.set_height) }
+                    if (!c(document).data("mCustomScrollbar-index")) { c(document).data("mCustomScrollbar-index", "1") } else {
+                        var t = parseInt(c(document).data("mCustomScrollbar-index"));
+                        c(document).data("mCustomScrollbar-index", t + 1) }
+                    m.wrapInner("<div class='mCustomScrollBox mCS-" + e.theme + "' id='mCSB_" + c(document).data("mCustomScrollbar-index") + "' style='position:relative; height:100%; overflow:hidden; max-width:100%;' />").addClass("mCustomScrollbar _mCS_" + c(document).data("mCustomScrollbar-index"));
+                    var g = m.children(".mCustomScrollBox");
+                    if (e.horizontalScroll) { g.addClass("mCSB_horizontal").wrapInner("<div class='mCSB_h_wrapper' style='position:relative; left:0; width:999999px;' />");
+                        var k = g.children(".mCSB_h_wrapper");
+                        k.wrapInner("<div class='mCSB_container' style='position:absolute; left:0;' />").children(".mCSB_container").css({ width: k.children().outerWidth(), position: "relative" }).unwrap() } else { g.wrapInner("<div class='mCSB_container' style='position:relative; top:0;' />") }
+                    var o = g.children(".mCSB_container");
+                    if (c.support.touch) { o.addClass("mCS_touch") }
+                    o.after("<div class='mCSB_scrollTools' style='position:absolute;'><div class='mCSB_draggerContainer'><div class='mCSB_dragger' style='position:absolute;' oncontextmenu='return false;'><div class='mCSB_dragger_bar' style='position:relative;'></div></div><div class='mCSB_draggerRail'></div></div></div>");
+                    var l = g.children(".mCSB_scrollTools"),
+                        h = l.children(".mCSB_draggerContainer"),
+                        q = h.children(".mCSB_dragger");
+                    if (e.horizontalScroll) { q.data("minDraggerWidth", q.width()) } else { q.data("minDraggerHeight", q.height()) }
+                    if (e.scrollButtons.enable) {
+                        if (e.horizontalScroll) { l.prepend("<a class='mCSB_buttonLeft' oncontextmenu='return false;'></a>").append("<a class='mCSB_buttonRight' oncontextmenu='return false;'></a>") } else { l.prepend("<a class='mCSB_buttonUp' oncontextmenu='return false;'></a>").append("<a class='mCSB_buttonDown' oncontextmenu='return false;'></a>") } }
+                    g.bind("scroll", function() {
+                        if (!m.is(".mCS_disabled")) { g.scrollTop(0).scrollLeft(0) } });
+                    m.data({ mCS_Init: true, mCustomScrollbarIndex: c(document).data("mCustomScrollbar-index"), horizontalScroll: e.horizontalScroll, scrollInertia: e.scrollInertia, scrollEasing: "mcsEaseOut", mouseWheel: e.mouseWheel, mouseWheelPixels: e.mouseWheelPixels, autoDraggerLength: e.autoDraggerLength, autoHideScrollbar: e.autoHideScrollbar, snapAmount: e.snapAmount, snapOffset: e.snapOffset, scrollButtons_enable: e.scrollButtons.enable, scrollButtons_scrollType: e.scrollButtons.scrollType, scrollButtons_scrollSpeed: e.scrollButtons.scrollSpeed, scrollButtons_scrollAmount: e.scrollButtons.scrollAmount, autoExpandHorizontalScroll: e.advanced.autoExpandHorizontalScroll, autoScrollOnFocus: e.advanced.autoScrollOnFocus, normalizeMouseWheelDelta: e.advanced.normalizeMouseWheelDelta, contentTouchScroll: e.contentTouchScroll, onScrollStart_Callback: e.callbacks.onScrollStart, onScroll_Callback: e.callbacks.onScroll, onTotalScroll_Callback: e.callbacks.onTotalScroll, onTotalScrollBack_Callback: e.callbacks.onTotalScrollBack, onTotalScroll_Offset: e.callbacks.onTotalScrollOffset, onTotalScrollBack_Offset: e.callbacks.onTotalScrollBackOffset, whileScrolling_Callback: e.callbacks.whileScrolling, bindEvent_scrollbar_drag: false, bindEvent_content_touch: false, bindEvent_scrollbar_click: false, bindEvent_mousewheel: false, bindEvent_buttonsContinuous_y: false, bindEvent_buttonsContinuous_x: false, bindEvent_buttonsPixels_y: false, bindEvent_buttonsPixels_x: false, bindEvent_focusin: false, bindEvent_autoHideScrollbar: false, mCSB_buttonScrollRight: false, mCSB_buttonScrollLeft: false, mCSB_buttonScrollDown: false, mCSB_buttonScrollUp: false });
+                    if (e.horizontalScroll) {
+                        if (m.css("max-width") !== "none") {
+                            if (!e.advanced.updateOnContentResize) { e.advanced.updateOnContentResize = true } } } else {
+                        if (m.css("max-height") !== "none") {
+                            var s = false,
+                                r = parseInt(m.css("max-height"));
+                            if (m.css("max-height").indexOf("%") >= 0) { s = r, r = m.parent().height() * s / 100 }
+                            m.css("overflow", "hidden");
+                            g.css("max-height", r) } }
+                    m.mCustomScrollbar("update");
+                    if (e.advanced.updateOnBrowserResize) {
+                        var i, j = c(window).width(),
+                            u = c(window).height();
+                        c(window).bind("resize." + m.data("mCustomScrollbarIndex"), function() {
+                            if (i) { clearTimeout(i) }
+                            i = setTimeout(function() {
+                                if (!m.is(".mCS_disabled") && !m.is(".mCS_destroyed")) {
+                                    var w = c(window).width(),
+                                        v = c(window).height();
+                                    if (j !== w || u !== v) {
+                                        if (m.css("max-height") !== "none" && s) { g.css("max-height", m.parent().height() * s / 100) }
+                                        m.mCustomScrollbar("update");
+                                        j = w;
+                                        u = v } } }, 150) }) }
+                    if (e.advanced.updateOnContentResize) {
+                        var p;
+                        if (e.horizontalScroll) {
+                            var n = o.outerWidth() } else {
+                            var n = o.outerHeight() }
+                        p = setInterval(function() {
+                            if (e.horizontalScroll) {
+                                if (e.advanced.autoExpandHorizontalScroll) { o.css({ position: "absolute", width: "auto" }).wrap("<div class='mCSB_h_wrapper' style='position:relative; left:0; width:999999px;' />").css({ width: o.outerWidth(), position: "relative" }).unwrap() }
+                                var v = o.outerWidth() } else {
+                                var v = o.outerHeight() }
+                            if (v != n) { m.mCustomScrollbar("update");
+                                n = v } }, 300) } }) }, update: function() {
+                var n = c(this),
+                    k = n.children(".mCustomScrollBox"),
+                    q = k.children(".mCSB_container");
+                q.removeClass("mCS_no_scrollbar");
+                n.removeClass("mCS_disabled mCS_destroyed");
+                k.scrollTop(0).scrollLeft(0);
+                var y = k.children(".mCSB_scrollTools"),
+                    o = y.children(".mCSB_draggerContainer"),
+                    m = o.children(".mCSB_dragger");
+                if (n.data("horizontalScroll")) {
+                    var A = y.children(".mCSB_buttonLeft"),
+                        t = y.children(".mCSB_buttonRight"),
+                        f = k.width();
+                    if (n.data("autoExpandHorizontalScroll")) { q.css({ position: "absolute", width: "auto" }).wrap("<div class='mCSB_h_wrapper' style='position:relative; left:0; width:999999px;' />").css({ width: q.outerWidth(), position: "relative" }).unwrap() }
+                    var z = q.outerWidth() } else {
+                    var w = y.children(".mCSB_buttonUp"),
+                        g = y.children(".mCSB_buttonDown"),
+                        r = k.height(),
+                        i = q.outerHeight() }
+                if (i > r && !n.data("horizontalScroll")) { y.css("display", "block");
+                    var s = o.height();
+                    if (n.data("autoDraggerLength")) {
+                        var u = Math.round(r / i * s),
+                            l = m.data("minDraggerHeight");
+                        if (u <= l) { m.css({ height: l }) } else {
+                            if (u >= s - 10) {
+                                var p = s - 10;
+                                m.css({ height: p }) } else { m.css({ height: u }) } }
+                        m.children(".mCSB_dragger_bar").css({ "line-height": m.height() + "px" }) }
+                    var B = m.height(),
+                        x = (i - r) / (s - B);
+                    n.data("scrollAmount", x).mCustomScrollbar("scrolling", k, q, o, m, w, g, A, t);
+                    var D = Math.abs(q.position().top);
+                    n.mCustomScrollbar("scrollTo", D, { scrollInertia: 0, trigger: "internal" }) } else {
+                    if (z > f && n.data("horizontalScroll")) { y.css("display", "block");
+                        var h = o.width();
+                        if (n.data("autoDraggerLength")) {
+                            var j = Math.round(f / z * h),
+                                C = m.data("minDraggerWidth");
+                            if (j <= C) { m.css({ width: C }) } else {
+                                if (j >= h - 10) {
+                                    var e = h - 10;
+                                    m.css({ width: e }) } else { m.css({ width: j }) } } }
+                        var v = m.width(),
+                            x = (z - f) / (h - v);
+                        n.data("scrollAmount", x).mCustomScrollbar("scrolling", k, q, o, m, w, g, A, t);
+                        var D = Math.abs(q.position().left);
+                        n.mCustomScrollbar("scrollTo", D, { scrollInertia: 0, trigger: "internal" }) } else { k.unbind("mousewheel focusin");
+                        if (n.data("horizontalScroll")) { m.add(q).css("left", 0) } else { m.add(q).css("top", 0) }
+                        y.css("display", "none");
+                        q.addClass("mCS_no_scrollbar");
+                        n.data({ bindEvent_mousewheel: false, bindEvent_focusin: false }) } } }, scrolling: function(h, p, m, j, w, e, A, v) {
+                var k = c(this);
+                if (!k.data("bindEvent_scrollbar_drag")) {
+                    var n, o;
+                    if (c.support.msPointer) { j.bind("MSPointerDown", function(H) { H.preventDefault();
+                            k.data({ on_drag: true });
+                            j.addClass("mCSB_dragger_onDrag");
+                            var G = c(this),
+                                J = G.offset(),
+                                F = H.originalEvent.pageX - J.left,
+                                I = H.originalEvent.pageY - J.top;
+                            if (F < G.width() && F > 0 && I < G.height() && I > 0) { n = I;
+                                o = F } });
+                        c(document).bind("MSPointerMove." + k.data("mCustomScrollbarIndex"), function(H) { H.preventDefault();
+                            if (k.data("on_drag")) {
+                                var G = j,
+                                    J = G.offset(),
+                                    F = H.originalEvent.pageX - J.left,
+                                    I = H.originalEvent.pageY - J.top;
+                                D(n, o, I, F) } }).bind("MSPointerUp." + k.data("mCustomScrollbarIndex"), function(x) { k.data({ on_drag: false });
+                            j.removeClass("mCSB_dragger_onDrag") }) } else { j.bind("mousedown touchstart", function(H) { H.preventDefault();
+                            H.stopImmediatePropagation();
+                            var G = c(this),
+                                K = G.offset(),
+                                F, J;
+                            if (H.type === "touchstart") {
+                                var I = H.originalEvent.touches[0] || H.originalEvent.changedTouches[0];
+                                F = I.pageX - K.left;
+                                J = I.pageY - K.top } else { k.data({ on_drag: true });
+                                j.addClass("mCSB_dragger_onDrag");
+                                F = H.pageX - K.left;
+                                J = H.pageY - K.top }
+                            if (F < G.width() && F > 0 && J < G.height() && J > 0) { n = J;
+                                o = F } }).bind("touchmove", function(H) { H.preventDefault();
+                            H.stopImmediatePropagation();
+                            var K = H.originalEvent.touches[0] || H.originalEvent.changedTouches[0],
+                                G = c(this),
+                                J = G.offset(),
+                                F = K.pageX - J.left,
+                                I = K.pageY - J.top;
+                            D(n, o, I, F) });
+                        c(document).bind("mousemove." + k.data("mCustomScrollbarIndex"), function(H) {
+                            if (k.data("on_drag")) {
+                                var G = j,
+                                    J = G.offset(),
+                                    F = H.pageX - J.left,
+                                    I = H.pageY - J.top;
+                                D(n, o, I, F) } }).bind("mouseup." + k.data("mCustomScrollbarIndex"), function(x) { k.data({ on_drag: false });
+                            j.removeClass("mCSB_dragger_onDrag") }) }
+                    k.data({ bindEvent_scrollbar_drag: true }) }
+
+                function D(G, H, I, F) {
+                    if (k.data("horizontalScroll")) { k.mCustomScrollbar("scrollTo", (j.position().left - (H)) + F, { moveDragger: true, trigger: "internal" }) } else { k.mCustomScrollbar("scrollTo", (j.position().top - (G)) + I, { moveDragger: true, trigger: "internal" }) } }
+                if (c.support.touch && k.data("contentTouchScroll")) {
+                    if (!k.data("bindEvent_content_touch")) {
+                        var l, B, r, s, u, C, E;
+                        p.bind("touchstart", function(x) { x.stopImmediatePropagation();
+                            l = x.originalEvent.touches[0] || x.originalEvent.changedTouches[0];
+                            B = c(this);
+                            r = B.offset();
+                            u = l.pageX - r.left;
+                            s = l.pageY - r.top;
+                            C = s;
+                            E = u });
+                        p.bind("touchmove", function(x) { x.preventDefault();
+                            x.stopImmediatePropagation();
+                            l = x.originalEvent.touches[0] || x.originalEvent.changedTouches[0];
+                            B = c(this).parent();
+                            r = B.offset();
+                            u = l.pageX - r.left;
+                            s = l.pageY - r.top;
+                            if (k.data("horizontalScroll")) { k.mCustomScrollbar("scrollTo", E - u, { trigger: "internal" }) } else { k.mCustomScrollbar("scrollTo", C - s, { trigger: "internal" }) } }) } }
+                if (!k.data("bindEvent_scrollbar_click")) { m.bind("click", function(F) {
+                        var x = (F.pageY - m.offset().top) * k.data("scrollAmount"),
+                            y = c(F.target);
+                        if (k.data("horizontalScroll")) { x = (F.pageX - m.offset().left) * k.data("scrollAmount") }
+                        if (y.hasClass("mCSB_draggerContainer") || y.hasClass("mCSB_draggerRail")) { k.mCustomScrollbar("scrollTo", x, { trigger: "internal", scrollEasing: "draggerRailEase" }) } });
+                    k.data({ bindEvent_scrollbar_click: true }) }
+                if (k.data("mouseWheel")) {
+                    if (!k.data("bindEvent_mousewheel")) { h.bind("mousewheel", function(H, J) {
+                            var G, F = k.data("mouseWheelPixels"),
+                                x = Math.abs(p.position().top),
+                                I = j.position().top,
+                                y = m.height() - j.height();
+                            if (k.data("normalizeMouseWheelDelta")) {
+                                if (J < 0) { J = -1 } else { J = 1 } }
+                            if (F === "auto") { F = 100 + Math.round(k.data("scrollAmount") / 2) }
+                            if (k.data("horizontalScroll")) { I = j.position().left;
+                                y = m.width() - j.width();
+                                x = Math.abs(p.position().left) }
+                            if ((J > 0 && I !== 0) || (J < 0 && I !== y)) { H.preventDefault();
+                                H.stopImmediatePropagation() }
+                            G = x - (J * F);
+                            k.mCustomScrollbar("scrollTo", G, { trigger: "internal" }) });
+                        k.data({ bindEvent_mousewheel: true }) } }
+                if (k.data("scrollButtons_enable")) {
+                    if (k.data("scrollButtons_scrollType") === "pixels") {
+                        if (k.data("horizontalScroll")) { v.add(A).unbind("mousedown touchstart MSPointerDown mouseup MSPointerUp mouseout MSPointerOut touchend", i, g);
+                            k.data({ bindEvent_buttonsContinuous_x: false });
+                            if (!k.data("bindEvent_buttonsPixels_x")) { v.bind("click", function(x) { x.preventDefault();
+                                    q(Math.abs(p.position().left) + k.data("scrollButtons_scrollAmount")) });
+                                A.bind("click", function(x) { x.preventDefault();
+                                    q(Math.abs(p.position().left) - k.data("scrollButtons_scrollAmount")) });
+                                k.data({ bindEvent_buttonsPixels_x: true }) } } else { e.add(w).unbind("mousedown touchstart MSPointerDown mouseup MSPointerUp mouseout MSPointerOut touchend", i, g);
+                            k.data({ bindEvent_buttonsContinuous_y: false });
+                            if (!k.data("bindEvent_buttonsPixels_y")) { e.bind("click", function(x) { x.preventDefault();
+                                    q(Math.abs(p.position().top) + k.data("scrollButtons_scrollAmount")) });
+                                w.bind("click", function(x) { x.preventDefault();
+                                    q(Math.abs(p.position().top) - k.data("scrollButtons_scrollAmount")) });
+                                k.data({ bindEvent_buttonsPixels_y: true }) } }
+
+                        function q(x) {
+                            if (!j.data("preventAction")) { j.data("preventAction", true);
+                                k.mCustomScrollbar("scrollTo", x, { trigger: "internal" }) } } } else {
+                        if (k.data("horizontalScroll")) { v.add(A).unbind("click");
+                            k.data({ bindEvent_buttonsPixels_x: false });
+                            if (!k.data("bindEvent_buttonsContinuous_x")) { v.bind("mousedown touchstart MSPointerDown", function(y) { y.preventDefault();
+                                    var x = z();
+                                    k.data({ mCSB_buttonScrollRight: setInterval(function() { k.mCustomScrollbar("scrollTo", Math.abs(p.position().left) + x, { trigger: "internal", scrollEasing: "easeOutCirc" }) }, 17) }) });
+                                var i = function(x) { x.preventDefault();
+                                    clearInterval(k.data("mCSB_buttonScrollRight")) };
+                                v.bind("mouseup touchend MSPointerUp mouseout MSPointerOut", i);
+                                A.bind("mousedown touchstart MSPointerDown", function(y) { y.preventDefault();
+                                    var x = z();
+                                    k.data({ mCSB_buttonScrollLeft: setInterval(function() { k.mCustomScrollbar("scrollTo", Math.abs(p.position().left) - x, { trigger: "internal", scrollEasing: "easeOutCirc" }) }, 17) }) });
+                                var g = function(x) { x.preventDefault();
+                                    clearInterval(k.data("mCSB_buttonScrollLeft")) };
+                                A.bind("mouseup touchend MSPointerUp mouseout MSPointerOut", g);
+                                k.data({ bindEvent_buttonsContinuous_x: true }) } } else { e.add(w).unbind("click");
+                            k.data({ bindEvent_buttonsPixels_y: false });
+                            if (!k.data("bindEvent_buttonsContinuous_y")) { e.bind("mousedown touchstart MSPointerDown", function(y) { y.preventDefault();
+                                    var x = z();
+                                    k.data({ mCSB_buttonScrollDown: setInterval(function() { k.mCustomScrollbar("scrollTo", Math.abs(p.position().top) + x, { trigger: "internal", scrollEasing: "easeOutCirc" }) }, 17) }) });
+                                var t = function(x) { x.preventDefault();
+                                    clearInterval(k.data("mCSB_buttonScrollDown")) };
+                                e.bind("mouseup touchend MSPointerUp mouseout MSPointerOut", t);
+                                w.bind("mousedown touchstart MSPointerDown", function(y) { y.preventDefault();
+                                    var x = z();
+                                    k.data({ mCSB_buttonScrollUp: setInterval(function() { k.mCustomScrollbar("scrollTo", Math.abs(p.position().top) - x, { trigger: "internal", scrollEasing: "easeOutCirc" }) }, 17) }) });
+                                var f = function(x) { x.preventDefault();
+                                    clearInterval(k.data("mCSB_buttonScrollUp")) };
+                                w.bind("mouseup touchend MSPointerUp mouseout MSPointerOut", f);
+                                k.data({ bindEvent_buttonsContinuous_y: true }) } }
+
+                        function z() {
+                            var x = k.data("scrollButtons_scrollSpeed");
+                            if (k.data("scrollButtons_scrollSpeed") === "auto") { x = Math.round((k.data("scrollInertia") + 100) / 40) }
+                            return x } } }
+                if (k.data("autoScrollOnFocus")) {
+                    if (!k.data("bindEvent_focusin")) { h.bind("focusin", function() { h.scrollTop(0).scrollLeft(0);
+                            var x = c(document.activeElement);
+                            if (x.is("input,textarea,select,button,a[tabindex],area,object")) {
+                                var G = p.position().top,
+                                    y = x.position().top,
+                                    F = h.height() - x.outerHeight();
+                                if (k.data("horizontalScroll")) { G = p.position().left;
+                                    y = x.position().left;
+                                    F = h.width() - x.outerWidth() }
+                                if (G + y < 0 || G + y > F) { k.mCustomScrollbar("scrollTo", y, { trigger: "internal" }) } } });
+                        k.data({ bindEvent_focusin: true }) } }
+                if (k.data("autoHideScrollbar")) {
+                    if (!k.data("bindEvent_autoHideScrollbar")) { h.bind("mouseenter", function(x) { h.addClass("mCS-mouse-over");
+                            d.showScrollbar.call(h.children(".mCSB_scrollTools")) }).bind("mouseleave touchend", function(x) { h.removeClass("mCS-mouse-over");
+                            if (x.type === "mouseleave") { d.hideScrollbar.call(h.children(".mCSB_scrollTools")) } });
+                        k.data({ bindEvent_autoHideScrollbar: true }) } } }, scrollTo: function(e, f) {
+                var i = c(this),
+                    o = { moveDragger: false, trigger: "external", callbacks: true, scrollInertia: i.data("scrollInertia"), scrollEasing: i.data("scrollEasing") },
+                    f = c.extend(o, f),
+                    p, g = i.children(".mCustomScrollBox"),
+                    k = g.children(".mCSB_container"),
+                    r = g.children(".mCSB_scrollTools"),
+                    j = r.children(".mCSB_draggerContainer"),
+                    h = j.children(".mCSB_dragger"),
+                    t = draggerSpeed = f.scrollInertia,
+                    q, s, m, l;
+                if (!k.hasClass("mCS_no_scrollbar")) { i.data({ mCS_trigger: f.trigger });
+                    if (i.data("mCS_Init")) { f.callbacks = false }
+                    if (e || e === 0) {
+                        if (typeof(e) === "number") {
+                            if (f.moveDragger) { p = e;
+                                if (i.data("horizontalScroll")) { e = h.position().left * i.data("scrollAmount") } else { e = h.position().top * i.data("scrollAmount") }
+                                draggerSpeed = 0 } else { p = e / i.data("scrollAmount") } } else {
+                            if (typeof(e) === "string") {
+                                var v;
+                                if (e === "top") { v = 0 } else {
+                                    if (e === "bottom" && !i.data("horizontalScroll")) { v = k.outerHeight() - g.height() } else {
+                                        if (e === "left") { v = 0 } else {
+                                            if (e === "right" && i.data("horizontalScroll")) { v = k.outerWidth() - g.width() } else {
+                                                if (e === "first") { v = i.find(".mCSB_container").find(":first") } else {
+                                                    if (e === "last") { v = i.find(".mCSB_container").find(":last") } else { v = i.find(e) } } } } } }
+                                if (v.length === 1) {
+                                    if (i.data("horizontalScroll")) { e = v.position().left } else { e = v.position().top }
+                                    p = e / i.data("scrollAmount") } else { p = e = v } } }
+                        if (i.data("horizontalScroll")) {
+                            if (i.data("onTotalScrollBack_Offset")) { s = -i.data("onTotalScrollBack_Offset") }
+                            if (i.data("onTotalScroll_Offset")) { l = g.width() - k.outerWidth() + i.data("onTotalScroll_Offset") }
+                            if (p < 0) { p = e = 0;
+                                clearInterval(i.data("mCSB_buttonScrollLeft"));
+                                if (!s) { q = true } } else {
+                                if (p >= j.width() - h.width()) { p = j.width() - h.width();
+                                    e = g.width() - k.outerWidth();
+                                    clearInterval(i.data("mCSB_buttonScrollRight"));
+                                    if (!l) { m = true } } else { e = -e } }
+                            var n = i.data("snapAmount");
+                            if (n) { e = Math.round(e / n) * n - i.data("snapOffset") }
+                            d.mTweenAxis.call(this, h[0], "left", Math.round(p), draggerSpeed, f.scrollEasing);
+                            d.mTweenAxis.call(this, k[0], "left", Math.round(e), t, f.scrollEasing, { onStart: function() {
+                                    if (f.callbacks && !i.data("mCS_tweenRunning")) { u("onScrollStart") }
+                                    if (i.data("autoHideScrollbar")) { d.showScrollbar.call(r) } }, onUpdate: function() {
+                                    if (f.callbacks) { u("whileScrolling") } }, onComplete: function() {
+                                    if (f.callbacks) { u("onScroll");
+                                        if (q || (s && k.position().left >= s)) { u("onTotalScrollBack") }
+                                        if (m || (l && k.position().left <= l)) { u("onTotalScroll") } }
+                                    h.data("preventAction", false);
+                                    i.data("mCS_tweenRunning", false);
+                                    if (i.data("autoHideScrollbar")) {
+                                        if (!g.hasClass("mCS-mouse-over")) { d.hideScrollbar.call(r) } } } }) } else {
+                            if (i.data("onTotalScrollBack_Offset")) { s = -i.data("onTotalScrollBack_Offset") }
+                            if (i.data("onTotalScroll_Offset")) { l = g.height() - k.outerHeight() + i.data("onTotalScroll_Offset") }
+                            if (p < 0) { p = e = 0;
+                                clearInterval(i.data("mCSB_buttonScrollUp"));
+                                if (!s) { q = true } } else {
+                                if (p >= j.height() - h.height()) { p = j.height() - h.height();
+                                    e = g.height() - k.outerHeight();
+                                    clearInterval(i.data("mCSB_buttonScrollDown"));
+                                    if (!l) { m = true } } else { e = -e } }
+                            var n = i.data("snapAmount");
+                            if (n) { e = Math.round(e / n) * n - i.data("snapOffset") }
+                            d.mTweenAxis.call(this, h[0], "top", Math.round(p), draggerSpeed, f.scrollEasing);
+                            d.mTweenAxis.call(this, k[0], "top", Math.round(e), t, f.scrollEasing, { onStart: function() {
+                                    if (f.callbacks && !i.data("mCS_tweenRunning")) { u("onScrollStart") }
+                                    if (i.data("autoHideScrollbar")) { d.showScrollbar.call(r) } }, onUpdate: function() {
+                                    if (f.callbacks) { u("whileScrolling") } }, onComplete: function() {
+                                    if (f.callbacks) { u("onScroll");
+                                        if (q || (s && k.position().top >= s)) { u("onTotalScrollBack") }
+                                        if (m || (l && k.position().top <= l)) { u("onTotalScroll") } }
+                                    h.data("preventAction", false);
+                                    i.data("mCS_tweenRunning", false);
+                                    if (i.data("autoHideScrollbar")) {
+                                        if (!g.hasClass("mCS-mouse-over")) { d.hideScrollbar.call(r) } } } }) }
+                        if (i.data("mCS_Init")) { i.data({ mCS_Init: false }) } } }
+
+                function u(w) { this.mcs = { top: k.position().top, left: k.position().left, draggerTop: h.position().top, draggerLeft: h.position().left, topPct: Math.round((100 * Math.abs(k.position().top)) / Math.abs(k.outerHeight() - g.height())), leftPct: Math.round((100 * Math.abs(k.position().left)) / Math.abs(k.outerWidth() - g.width())) };
+                    switch (w) {
+                        case "onScrollStart":
+                            i.data("mCS_tweenRunning", true).data("onScrollStart_Callback").call(i, this.mcs);
+                            break;
+                        case "whileScrolling":
+                            i.data("whileScrolling_Callback").call(i, this.mcs);
+                            break;
+                        case "onScroll":
+                            i.data("onScroll_Callback").call(i, this.mcs);
+                            break;
+                        case "onTotalScrollBack":
+                            i.data("onTotalScrollBack_Callback").call(i, this.mcs);
+                            break;
+                        case "onTotalScroll":
+                            i.data("onTotalScroll_Callback").call(i, this.mcs);
+                            break } } }, stop: function() {
+                var g = c(this),
+                    e = g.children().children(".mCSB_container"),
+                    f = g.children().children().children().children(".mCSB_dragger");
+                d.mTweenAxisStop.call(this, e[0]);
+                d.mTweenAxisStop.call(this, f[0]) }, disable: function(e) {
+                var j = c(this),
+                    f = j.children(".mCustomScrollBox"),
+                    h = f.children(".mCSB_container"),
+                    g = f.children(".mCSB_scrollTools"),
+                    i = g.children().children(".mCSB_dragger");
+                f.unbind("mousewheel focusin mouseenter mouseleave touchend");
+                h.unbind("touchstart touchmove");
+                if (e) {
+                    if (j.data("horizontalScroll")) { i.add(h).css("left", 0) } else { i.add(h).css("top", 0) } }
+                g.css("display", "none");
+                h.addClass("mCS_no_scrollbar");
+                j.data({ bindEvent_mousewheel: false, bindEvent_focusin: false, bindEvent_content_touch: false, bindEvent_autoHideScrollbar: false }).addClass("mCS_disabled") }, destroy: function() {
+                var e = c(this);
+                e.removeClass("mCustomScrollbar _mCS_" + e.data("mCustomScrollbarIndex")).addClass("mCS_destroyed").children().children(".mCSB_container").unwrap().children().unwrap().siblings(".mCSB_scrollTools").remove();
+                c(document).unbind("mousemove." + e.data("mCustomScrollbarIndex") + " mouseup." + e.data("mCustomScrollbarIndex") + " MSPointerMove." + e.data("mCustomScrollbarIndex") + " MSPointerUp." + e.data("mCustomScrollbarIndex"));
+                c(window).unbind("resize." + e.data("mCustomScrollbarIndex")) } },
+        d = { showScrollbar: function() { this.stop().animate({ opacity: 1 }, "fast") }, hideScrollbar: function() { this.stop().animate({ opacity: 0 }, "fast") }, mTweenAxis: function(g, i, h, f, o, y) {
+                var y = y || {},
+                    v = y.onStart || function() {},
+                    p = y.onUpdate || function() {},
+                    w = y.onComplete || function() {};
+                var n = t(),
+                    l, j = 0,
+                    r = g.offsetTop,
+                    s = g.style;
+                if (i === "left") { r = g.offsetLeft }
+                var m = h - r;
+                q();
+                e();
+
+                function t() {
+                    if (window.performance && window.performance.now) {
+                        return window.performance.now() } else {
+                        if (window.performance && window.performance.webkitNow) {
+                            return window.performance.webkitNow() } else {
+                            if (Date.now) {
+                                return Date.now() } else {
+                                return new Date().getTime() } } } }
+
+                function x() {
+                    if (!j) { v.call() }
+                    j = t() - n;
+                    u();
+                    if (j >= g._time) { g._time = (j > g._time) ? j + l - (j - g._time) : j + l - 1;
+                        if (g._time < j + 1) { g._time = j + 1 } }
+                    if (g._time < f) { g._id = _request(x) } else { w.call() } }
+
+                function u() {
+                    if (f > 0) { g.currVal = k(g._time, r, m, f, o);
+                        s[i] = Math.round(g.currVal) + "px" } else { s[i] = h + "px" }
+                    p.call() }
+
+                function e() { l = 1000 / 60;
+                    g._time = j + l;
+                    _request = (!window.requestAnimationFrame) ? function(z) { u();
+                        return setTimeout(z, 0.01) } : window.requestAnimationFrame;
+                    g._id = _request(x) }
+
+                function q() {
+                    if (g._id == null) {
+                        return }
+                    if (!window.requestAnimationFrame) { clearTimeout(g._id) } else { window.cancelAnimationFrame(g._id) }
+                    g._id = null }
+
+                function k(B, A, F, E, C) {
+                    switch (C) {
+                        case "linear":
+                            return F * B / E + A;
+                            break;
+                        case "easeOutQuad":
+                            B /= E;
+                            return -F * B * (B - 2) + A;
+                            break;
+                        case "easeInOutQuad":
+                            B /= E / 2;
+                            if (B < 1) {
+                                return F / 2 * B * B + A }
+                            B--;
+                            return -F / 2 * (B * (B - 2) - 1) + A;
+                            break;
+                        case "easeOutCubic":
+                            B /= E;
+                            B--;
+                            return F * (B * B * B + 1) + A;
+                            break;
+                        case "easeOutQuart":
+                            B /= E;
+                            B--;
+                            return -F * (B * B * B * B - 1) + A;
+                            break;
+                        case "easeOutQuint":
+                            B /= E;
+                            B--;
+                            return F * (B * B * B * B * B + 1) + A;
+                            break;
+                        case "easeOutCirc":
+                            B /= E;
+                            B--;
+                            return F * Math.sqrt(1 - B * B) + A;
+                            break;
+                        case "easeOutSine":
+                            return F * Math.sin(B / E * (Math.PI / 2)) + A;
+                            break;
+                        case "easeOutExpo":
+                            return F * (-Math.pow(2, -10 * B / E) + 1) + A;
+                            break;
+                        case "mcsEaseOut":
+                            var D = (B /= E) * B,
+                                z = D * B;
+                            return A + F * (0.499999999999997 * z * D + -2.5 * D * D + 5.5 * z + -6.5 * D + 4 * B);
+                            break;
+                        case "draggerRailEase":
+                            B /= E / 2;
+                            if (B < 1) {
+                                return F / 2 * B * B * B + A }
+                            B -= 2;
+                            return F / 2 * (B * B * B + 2) + A;
+                            break } } }, mTweenAxisStop: function(e) {
+                if (e._id == null) {
+                    return }
+                if (!window.requestAnimationFrame) { clearTimeout(e._id) } else { window.cancelAnimationFrame(e._id) }
+                e._id = null }, rafPolyfill: function() {
+                var f = ["ms", "moz", "webkit", "o"],
+                    e = f.length;
+                while (--e > -1 && !window.requestAnimationFrame) { window.requestAnimationFrame = window[f[e] + "RequestAnimationFrame"];
+                    window.cancelAnimationFrame = window[f[e] + "CancelAnimationFrame"] || window[f[e] + "CancelRequestAnimationFrame"] } } };
+    d.rafPolyfill.call();
+    c.support.touch = !!("ontouchstart" in window);
+    c.support.msPointer = window.navigator.msPointerEnabled;
+    var a = ("https:" == document.location.protocol) ? "https:" : "http:";
+    c.event.special.mousewheel || document.write('<script src="' + a + '//cdnjs.cloudflare.com/ajax/libs/jquery-mousewheel/3.0.6/jquery.mousewheel.min.js"><\/script>');
+    c.fn.mCustomScrollbar = function(e) {
+        if (b[e]) {
+            return b[e].apply(this, Array.prototype.slice.call(arguments, 1)) } else {
+            if (typeof e === "object" || !e) {
+                return b.init.apply(this, arguments) } else { c.error("Method " + e + " does not exist") } } } })(jQuery);

+ 221 - 0
static/jquery.mousewheel.js

@@ -0,0 +1,221 @@
+/*!
+ * jQuery Mousewheel 3.1.13
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ */
+
+(function (factory) {
+    if ( typeof define === 'function' && define.amd ) {
+        // AMD. Register as an anonymous module.
+        define(['jquery'], factory);
+    } else if (typeof exports === 'object') {
+        // Node/CommonJS style for Browserify
+        module.exports = factory;
+    } else {
+        // Browser globals
+        factory(jQuery);
+    }
+}(function ($) {
+
+    var toFix  = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'],
+        toBind = ( 'onwheel' in document || document.documentMode >= 9 ) ?
+                    ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'],
+        slice  = Array.prototype.slice,
+        nullLowestDeltaTimeout, lowestDelta;
+
+    if ( $.event.fixHooks ) {
+        for ( var i = toFix.length; i; ) {
+            $.event.fixHooks[ toFix[--i] ] = $.event.mouseHooks;
+        }
+    }
+
+    var special = $.event.special.mousewheel = {
+        version: '3.1.12',
+
+        setup: function() {
+            if ( this.addEventListener ) {
+                for ( var i = toBind.length; i; ) {
+                    this.addEventListener( toBind[--i], handler, false );
+                }
+            } else {
+                this.onmousewheel = handler;
+            }
+            // Store the line height and page height for this particular element
+            $.data(this, 'mousewheel-line-height', special.getLineHeight(this));
+            $.data(this, 'mousewheel-page-height', special.getPageHeight(this));
+        },
+
+        teardown: function() {
+            if ( this.removeEventListener ) {
+                for ( var i = toBind.length; i; ) {
+                    this.removeEventListener( toBind[--i], handler, false );
+                }
+            } else {
+                this.onmousewheel = null;
+            }
+            // Clean up the data we added to the element
+            $.removeData(this, 'mousewheel-line-height');
+            $.removeData(this, 'mousewheel-page-height');
+        },
+
+        getLineHeight: function(elem) {
+            var $elem = $(elem),
+                $parent = $elem['offsetParent' in $.fn ? 'offsetParent' : 'parent']();
+            if (!$parent.length) {
+                $parent = $('body');
+            }
+            return parseInt($parent.css('fontSize'), 10) || parseInt($elem.css('fontSize'), 10) || 16;
+        },
+
+        getPageHeight: function(elem) {
+            return $(elem).height();
+        },
+
+        settings: {
+            adjustOldDeltas: true, // see shouldAdjustOldDeltas() below
+            normalizeOffset: true  // calls getBoundingClientRect for each event
+        }
+    };
+
+    $.fn.extend({
+        mousewheel: function(fn) {
+            return fn ? this.bind('mousewheel', fn) : this.trigger('mousewheel');
+        },
+
+        unmousewheel: function(fn) {
+            return this.unbind('mousewheel', fn);
+        }
+    });
+
+
+    function handler(event) {
+        var orgEvent   = event || window.event,
+            args       = slice.call(arguments, 1),
+            delta      = 0,
+            deltaX     = 0,
+            deltaY     = 0,
+            absDelta   = 0,
+            offsetX    = 0,
+            offsetY    = 0;
+        event = $.event.fix(orgEvent);
+        event.type = 'mousewheel';
+
+        // Old school scrollwheel delta
+        if ( 'detail'      in orgEvent ) { deltaY = orgEvent.detail * -1;      }
+        if ( 'wheelDelta'  in orgEvent ) { deltaY = orgEvent.wheelDelta;       }
+        if ( 'wheelDeltaY' in orgEvent ) { deltaY = orgEvent.wheelDeltaY;      }
+        if ( 'wheelDeltaX' in orgEvent ) { deltaX = orgEvent.wheelDeltaX * -1; }
+
+        // Firefox < 17 horizontal scrolling related to DOMMouseScroll event
+        if ( 'axis' in orgEvent && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
+            deltaX = deltaY * -1;
+            deltaY = 0;
+        }
+
+        // Set delta to be deltaY or deltaX if deltaY is 0 for backwards compatabilitiy
+        delta = deltaY === 0 ? deltaX : deltaY;
+
+        // New school wheel delta (wheel event)
+        if ( 'deltaY' in orgEvent ) {
+            deltaY = orgEvent.deltaY * -1;
+            delta  = deltaY;
+        }
+        if ( 'deltaX' in orgEvent ) {
+            deltaX = orgEvent.deltaX;
+            if ( deltaY === 0 ) { delta  = deltaX * -1; }
+        }
+
+        // No change actually happened, no reason to go any further
+        if ( deltaY === 0 && deltaX === 0 ) { return; }
+
+        // Need to convert lines and pages to pixels if we aren't already in pixels
+        // There are three delta modes:
+        //   * deltaMode 0 is by pixels, nothing to do
+        //   * deltaMode 1 is by lines
+        //   * deltaMode 2 is by pages
+        if ( orgEvent.deltaMode === 1 ) {
+            var lineHeight = $.data(this, 'mousewheel-line-height');
+            delta  *= lineHeight;
+            deltaY *= lineHeight;
+            deltaX *= lineHeight;
+        } else if ( orgEvent.deltaMode === 2 ) {
+            var pageHeight = $.data(this, 'mousewheel-page-height');
+            delta  *= pageHeight;
+            deltaY *= pageHeight;
+            deltaX *= pageHeight;
+        }
+
+        // Store lowest absolute delta to normalize the delta values
+        absDelta = Math.max( Math.abs(deltaY), Math.abs(deltaX) );
+
+        if ( !lowestDelta || absDelta < lowestDelta ) {
+            lowestDelta = absDelta;
+
+            // Adjust older deltas if necessary
+            if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) {
+                lowestDelta /= 40;
+            }
+        }
+
+        // Adjust older deltas if necessary
+        if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) {
+            // Divide all the things by 40!
+            delta  /= 40;
+            deltaX /= 40;
+            deltaY /= 40;
+        }
+
+        // Get a whole, normalized value for the deltas
+        delta  = Math[ delta  >= 1 ? 'floor' : 'ceil' ](delta  / lowestDelta);
+        deltaX = Math[ deltaX >= 1 ? 'floor' : 'ceil' ](deltaX / lowestDelta);
+        deltaY = Math[ deltaY >= 1 ? 'floor' : 'ceil' ](deltaY / lowestDelta);
+
+        // Normalise offsetX and offsetY properties
+        if ( special.settings.normalizeOffset && this.getBoundingClientRect ) {
+            var boundingRect = this.getBoundingClientRect();
+            offsetX = event.clientX - boundingRect.left;
+            offsetY = event.clientY - boundingRect.top;
+        }
+
+        // Add information to the event object
+        event.deltaX = deltaX;
+        event.deltaY = deltaY;
+        event.deltaFactor = lowestDelta;
+        event.offsetX = offsetX;
+        event.offsetY = offsetY;
+        // Go ahead and set deltaMode to 0 since we converted to pixels
+        // Although this is a little odd since we overwrite the deltaX/Y
+        // properties with normalized deltas.
+        event.deltaMode = 0;
+
+        // Add event and delta to the front of the arguments
+        args.unshift(event, delta, deltaX, deltaY);
+
+        // Clearout lowestDelta after sometime to better
+        // handle multiple device types that give different
+        // a different lowestDelta
+        // Ex: trackpad = 3 and mouse wheel = 120
+        if (nullLowestDeltaTimeout) { clearTimeout(nullLowestDeltaTimeout); }
+        nullLowestDeltaTimeout = setTimeout(nullLowestDelta, 200);
+
+        return ($.event.dispatch || $.event.handle).apply(this, args);
+    }
+
+    function nullLowestDelta() {
+        lowestDelta = null;
+    }
+
+    function shouldAdjustOldDeltas(orgEvent, absDelta) {
+        // If this is an older event and the delta is divisable by 120,
+        // then we are assuming that the browser is treating this as an
+        // older mouse wheel event and that we should divide the deltas
+        // by 40 to try and get a more usable deltaFactor.
+        // Side note, this actually impacts the reported scroll distance
+        // in older browsers and can cause scrolling to be slower than native.
+        // Turn this off by setting $.event.special.mousewheel.settings.adjustOldDeltas to false.
+        return special.settings.adjustOldDeltas && orgEvent.type === 'mousewheel' && absDelta % 120 === 0;
+    }
+
+}));

+ 28 - 0
static/jquery.qrcode.min.js

@@ -0,0 +1,28 @@
+(function(r){r.fn.qrcode=function(h){var s;function u(a){this.mode=s;this.data=a}function o(a,c){this.typeNumber=a;this.errorCorrectLevel=c;this.modules=null;this.moduleCount=0;this.dataCache=null;this.dataList=[]}function q(a,c){if(void 0==a.length)throw Error(a.length+"/"+c);for(var d=0;d<a.length&&0==a[d];)d++;this.num=Array(a.length-d+c);for(var b=0;b<a.length-d;b++)this.num[b]=a[b+d]}function p(a,c){this.totalCount=a;this.dataCount=c}function t(){this.buffer=[];this.length=0}u.prototype={getLength:function(){return this.data.length},
+write:function(a){for(var c=0;c<this.data.length;c++)a.put(this.data.charCodeAt(c),8)}};o.prototype={addData:function(a){this.dataList.push(new u(a));this.dataCache=null},isDark:function(a,c){if(0>a||this.moduleCount<=a||0>c||this.moduleCount<=c)throw Error(a+","+c);return this.modules[a][c]},getModuleCount:function(){return this.moduleCount},make:function(){if(1>this.typeNumber){for(var a=1,a=1;40>a;a++){for(var c=p.getRSBlocks(a,this.errorCorrectLevel),d=new t,b=0,e=0;e<c.length;e++)b+=c[e].dataCount;
+for(e=0;e<this.dataList.length;e++)c=this.dataList[e],d.put(c.mode,4),d.put(c.getLength(),j.getLengthInBits(c.mode,a)),c.write(d);if(d.getLengthInBits()<=8*b)break}this.typeNumber=a}this.makeImpl(!1,this.getBestMaskPattern())},makeImpl:function(a,c){this.moduleCount=4*this.typeNumber+17;this.modules=Array(this.moduleCount);for(var d=0;d<this.moduleCount;d++){this.modules[d]=Array(this.moduleCount);for(var b=0;b<this.moduleCount;b++)this.modules[d][b]=null}this.setupPositionProbePattern(0,0);this.setupPositionProbePattern(this.moduleCount-
+7,0);this.setupPositionProbePattern(0,this.moduleCount-7);this.setupPositionAdjustPattern();this.setupTimingPattern();this.setupTypeInfo(a,c);7<=this.typeNumber&&this.setupTypeNumber(a);null==this.dataCache&&(this.dataCache=o.createData(this.typeNumber,this.errorCorrectLevel,this.dataList));this.mapData(this.dataCache,c)},setupPositionProbePattern:function(a,c){for(var d=-1;7>=d;d++)if(!(-1>=a+d||this.moduleCount<=a+d))for(var b=-1;7>=b;b++)-1>=c+b||this.moduleCount<=c+b||(this.modules[a+d][c+b]=
+0<=d&&6>=d&&(0==b||6==b)||0<=b&&6>=b&&(0==d||6==d)||2<=d&&4>=d&&2<=b&&4>=b?!0:!1)},getBestMaskPattern:function(){for(var a=0,c=0,d=0;8>d;d++){this.makeImpl(!0,d);var b=j.getLostPoint(this);if(0==d||a>b)a=b,c=d}return c},createMovieClip:function(a,c,d){a=a.createEmptyMovieClip(c,d);this.make();for(c=0;c<this.modules.length;c++)for(var d=1*c,b=0;b<this.modules[c].length;b++){var e=1*b;this.modules[c][b]&&(a.beginFill(0,100),a.moveTo(e,d),a.lineTo(e+1,d),a.lineTo(e+1,d+1),a.lineTo(e,d+1),a.endFill())}return a},
+setupTimingPattern:function(){for(var a=8;a<this.moduleCount-8;a++)null==this.modules[a][6]&&(this.modules[a][6]=0==a%2);for(a=8;a<this.moduleCount-8;a++)null==this.modules[6][a]&&(this.modules[6][a]=0==a%2)},setupPositionAdjustPattern:function(){for(var a=j.getPatternPosition(this.typeNumber),c=0;c<a.length;c++)for(var d=0;d<a.length;d++){var b=a[c],e=a[d];if(null==this.modules[b][e])for(var f=-2;2>=f;f++)for(var i=-2;2>=i;i++)this.modules[b+f][e+i]=-2==f||2==f||-2==i||2==i||0==f&&0==i?!0:!1}},setupTypeNumber:function(a){for(var c=
+j.getBCHTypeNumber(this.typeNumber),d=0;18>d;d++){var b=!a&&1==(c>>d&1);this.modules[Math.floor(d/3)][d%3+this.moduleCount-8-3]=b}for(d=0;18>d;d++)b=!a&&1==(c>>d&1),this.modules[d%3+this.moduleCount-8-3][Math.floor(d/3)]=b},setupTypeInfo:function(a,c){for(var d=j.getBCHTypeInfo(this.errorCorrectLevel<<3|c),b=0;15>b;b++){var e=!a&&1==(d>>b&1);6>b?this.modules[b][8]=e:8>b?this.modules[b+1][8]=e:this.modules[this.moduleCount-15+b][8]=e}for(b=0;15>b;b++)e=!a&&1==(d>>b&1),8>b?this.modules[8][this.moduleCount-
+b-1]=e:9>b?this.modules[8][15-b-1+1]=e:this.modules[8][15-b-1]=e;this.modules[this.moduleCount-8][8]=!a},mapData:function(a,c){for(var d=-1,b=this.moduleCount-1,e=7,f=0,i=this.moduleCount-1;0<i;i-=2)for(6==i&&i--;;){for(var g=0;2>g;g++)if(null==this.modules[b][i-g]){var n=!1;f<a.length&&(n=1==(a[f]>>>e&1));j.getMask(c,b,i-g)&&(n=!n);this.modules[b][i-g]=n;e--; -1==e&&(f++,e=7)}b+=d;if(0>b||this.moduleCount<=b){b-=d;d=-d;break}}}};o.PAD0=236;o.PAD1=17;o.createData=function(a,c,d){for(var c=p.getRSBlocks(a,
+c),b=new t,e=0;e<d.length;e++){var f=d[e];b.put(f.mode,4);b.put(f.getLength(),j.getLengthInBits(f.mode,a));f.write(b)}for(e=a=0;e<c.length;e++)a+=c[e].dataCount;if(b.getLengthInBits()>8*a)throw Error("code length overflow. ("+b.getLengthInBits()+">"+8*a+")");for(b.getLengthInBits()+4<=8*a&&b.put(0,4);0!=b.getLengthInBits()%8;)b.putBit(!1);for(;!(b.getLengthInBits()>=8*a);){b.put(o.PAD0,8);if(b.getLengthInBits()>=8*a)break;b.put(o.PAD1,8)}return o.createBytes(b,c)};o.createBytes=function(a,c){for(var d=
+0,b=0,e=0,f=Array(c.length),i=Array(c.length),g=0;g<c.length;g++){var n=c[g].dataCount,h=c[g].totalCount-n,b=Math.max(b,n),e=Math.max(e,h);f[g]=Array(n);for(var k=0;k<f[g].length;k++)f[g][k]=255&a.buffer[k+d];d+=n;k=j.getErrorCorrectPolynomial(h);n=(new q(f[g],k.getLength()-1)).mod(k);i[g]=Array(k.getLength()-1);for(k=0;k<i[g].length;k++)h=k+n.getLength()-i[g].length,i[g][k]=0<=h?n.get(h):0}for(k=g=0;k<c.length;k++)g+=c[k].totalCount;d=Array(g);for(k=n=0;k<b;k++)for(g=0;g<c.length;g++)k<f[g].length&&
+(d[n++]=f[g][k]);for(k=0;k<e;k++)for(g=0;g<c.length;g++)k<i[g].length&&(d[n++]=i[g][k]);return d};s=4;for(var j={PATTERN_POSITION_TABLE:[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,
+78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],G15:1335,G18:7973,G15_MASK:21522,getBCHTypeInfo:function(a){for(var c=a<<10;0<=j.getBCHDigit(c)-j.getBCHDigit(j.G15);)c^=j.G15<<j.getBCHDigit(c)-j.getBCHDigit(j.G15);return(a<<10|c)^j.G15_MASK},getBCHTypeNumber:function(a){for(var c=a<<12;0<=j.getBCHDigit(c)-
+j.getBCHDigit(j.G18);)c^=j.G18<<j.getBCHDigit(c)-j.getBCHDigit(j.G18);return a<<12|c},getBCHDigit:function(a){for(var c=0;0!=a;)c++,a>>>=1;return c},getPatternPosition:function(a){return j.PATTERN_POSITION_TABLE[a-1]},getMask:function(a,c,d){switch(a){case 0:return 0==(c+d)%2;case 1:return 0==c%2;case 2:return 0==d%3;case 3:return 0==(c+d)%3;case 4:return 0==(Math.floor(c/2)+Math.floor(d/3))%2;case 5:return 0==c*d%2+c*d%3;case 6:return 0==(c*d%2+c*d%3)%2;case 7:return 0==(c*d%3+(c+d)%2)%2;default:throw Error("bad maskPattern:"+
+a);}},getErrorCorrectPolynomial:function(a){for(var c=new q([1],0),d=0;d<a;d++)c=c.multiply(new q([1,l.gexp(d)],0));return c},getLengthInBits:function(a,c){if(1<=c&&10>c)switch(a){case 1:return 10;case 2:return 9;case s:return 8;case 8:return 8;default:throw Error("mode:"+a);}else if(27>c)switch(a){case 1:return 12;case 2:return 11;case s:return 16;case 8:return 10;default:throw Error("mode:"+a);}else if(41>c)switch(a){case 1:return 14;case 2:return 13;case s:return 16;case 8:return 12;default:throw Error("mode:"+
+a);}else throw Error("type:"+c);},getLostPoint:function(a){for(var c=a.getModuleCount(),d=0,b=0;b<c;b++)for(var e=0;e<c;e++){for(var f=0,i=a.isDark(b,e),g=-1;1>=g;g++)if(!(0>b+g||c<=b+g))for(var h=-1;1>=h;h++)0>e+h||c<=e+h||0==g&&0==h||i==a.isDark(b+g,e+h)&&f++;5<f&&(d+=3+f-5)}for(b=0;b<c-1;b++)for(e=0;e<c-1;e++)if(f=0,a.isDark(b,e)&&f++,a.isDark(b+1,e)&&f++,a.isDark(b,e+1)&&f++,a.isDark(b+1,e+1)&&f++,0==f||4==f)d+=3;for(b=0;b<c;b++)for(e=0;e<c-6;e++)a.isDark(b,e)&&!a.isDark(b,e+1)&&a.isDark(b,e+
+2)&&a.isDark(b,e+3)&&a.isDark(b,e+4)&&!a.isDark(b,e+5)&&a.isDark(b,e+6)&&(d+=40);for(e=0;e<c;e++)for(b=0;b<c-6;b++)a.isDark(b,e)&&!a.isDark(b+1,e)&&a.isDark(b+2,e)&&a.isDark(b+3,e)&&a.isDark(b+4,e)&&!a.isDark(b+5,e)&&a.isDark(b+6,e)&&(d+=40);for(e=f=0;e<c;e++)for(b=0;b<c;b++)a.isDark(b,e)&&f++;a=Math.abs(100*f/c/c-50)/5;return d+10*a}},l={glog:function(a){if(1>a)throw Error("glog("+a+")");return l.LOG_TABLE[a]},gexp:function(a){for(;0>a;)a+=255;for(;256<=a;)a-=255;return l.EXP_TABLE[a]},EXP_TABLE:Array(256),
+LOG_TABLE:Array(256)},m=0;8>m;m++)l.EXP_TABLE[m]=1<<m;for(m=8;256>m;m++)l.EXP_TABLE[m]=l.EXP_TABLE[m-4]^l.EXP_TABLE[m-5]^l.EXP_TABLE[m-6]^l.EXP_TABLE[m-8];for(m=0;255>m;m++)l.LOG_TABLE[l.EXP_TABLE[m]]=m;q.prototype={get:function(a){return this.num[a]},getLength:function(){return this.num.length},multiply:function(a){for(var c=Array(this.getLength()+a.getLength()-1),d=0;d<this.getLength();d++)for(var b=0;b<a.getLength();b++)c[d+b]^=l.gexp(l.glog(this.get(d))+l.glog(a.get(b)));return new q(c,0)},mod:function(a){if(0>
+this.getLength()-a.getLength())return this;for(var c=l.glog(this.get(0))-l.glog(a.get(0)),d=Array(this.getLength()),b=0;b<this.getLength();b++)d[b]=this.get(b);for(b=0;b<a.getLength();b++)d[b]^=l.gexp(l.glog(a.get(b))+c);return(new q(d,0)).mod(a)}};p.RS_BLOCK_TABLE=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],
+[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,
+116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,
+43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,
+3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,
+55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,
+45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]];p.getRSBlocks=function(a,c){var d=p.getRsBlockTable(a,c);if(void 0==d)throw Error("bad rs block @ typeNumber:"+a+"/errorCorrectLevel:"+c);for(var b=d.length/3,e=[],f=0;f<b;f++)for(var h=d[3*f+0],g=d[3*f+1],j=d[3*f+2],l=0;l<h;l++)e.push(new p(g,j));return e};p.getRsBlockTable=function(a,c){switch(c){case 1:return p.RS_BLOCK_TABLE[4*(a-1)+0];case 0:return p.RS_BLOCK_TABLE[4*(a-1)+1];case 3:return p.RS_BLOCK_TABLE[4*
+(a-1)+2];case 2:return p.RS_BLOCK_TABLE[4*(a-1)+3]}};t.prototype={get:function(a){return 1==(this.buffer[Math.floor(a/8)]>>>7-a%8&1)},put:function(a,c){for(var d=0;d<c;d++)this.putBit(1==(a>>>c-d-1&1))},getLengthInBits:function(){return this.length},putBit:function(a){var c=Math.floor(this.length/8);this.buffer.length<=c&&this.buffer.push(0);a&&(this.buffer[c]|=128>>>this.length%8);this.length++}};"string"===typeof h&&(h={text:h});h=r.extend({},{render:"canvas",width:256,height:256,typeNumber:-1,
+correctLevel:2,background:"#ffffff",foreground:"#000000"},h);return this.each(function(){var a;if("canvas"==h.render){a=new o(h.typeNumber,h.correctLevel);a.addData(h.text);a.make();var c=document.createElement("canvas");c.width=h.width;c.height=h.height;for(var d=c.getContext("2d"),b=h.width/a.getModuleCount(),e=h.height/a.getModuleCount(),f=0;f<a.getModuleCount();f++)for(var i=0;i<a.getModuleCount();i++){d.fillStyle=a.isDark(f,i)?h.foreground:h.background;var g=Math.ceil((i+1)*b)-Math.floor(i*b),
+j=Math.ceil((f+1)*b)-Math.floor(f*b);d.fillRect(Math.round(i*b),Math.round(f*e),g,j)}}else{a=new o(h.typeNumber,h.correctLevel);a.addData(h.text);a.make();c=r("<table></table>").css("width",h.width+"px").css("height",h.height+"px").css("border","0px").css("border-collapse","collapse").css("background-color",h.background);d=h.width/a.getModuleCount();b=h.height/a.getModuleCount();for(e=0;e<a.getModuleCount();e++){f=r("<tr></tr>").css("height",b+"px").appendTo(c);for(i=0;i<a.getModuleCount();i++)r("<td></td>").css("width",
+d+"px").css("background-color",a.isDark(e,i)?h.foreground:h.background).appendTo(f)}}a=c;jQuery(a).appendTo(this)})}})(jQuery);

+ 90 - 0
static/kline.css

@@ -0,0 +1,90 @@
+blockquote,
+q {
+    quotes: none;
+}
+
+blockquote:before,
+blockquote:after,
+q:before,
+q:after {
+    content: '';
+    content: none;
+}
+
+table {
+    border-collapse: collapse;
+    border-spacing: 0;
+}
+
+
+canvas {
+    display: block;
+    display: none
+}
+
+#loading {
+    background-image: url(./img/loading.gif);
+    z-index: 9999;
+    position: absolute;
+
+    top: 200px;
+    width: 100px;
+    height: 100px;
+    display: none
+}
+
+.canvas_group {
+    position: relative
+}
+
+.canvas_group canvas {
+    left: 0;
+    position: absolute;
+    top: 0;
+}
+
+
+/* Box Model */
+
+*,
+*:before,
+*:after {
+    -moz-box-sizing: border-box;
+    -webkit-box-sizing: border-box;
+    box-sizing: border-box;
+}
+
+.plot_container {
+  /*min-width: 100%;*/
+    width: 100%;
+    height:100px;
+    position: inherit;
+    display: inline-block;
+    top: 0px;
+    left: 0px;
+    right: 0px;
+    bottom: 3px;
+    overflow-x: none ;
+    align-content: center;
+    
+}
+#background{
+
+    position:absolute;
+     // width: 100%;
+    // height:100px;
+    background: url(./img/Klogo.png) 10% no-repeat;
+     opacity: 0.3;
+    background-size:100%;
+    width: 440px;
+    height: 170px;
+    line-height: 170px;
+    vertical-align: middle;
+    text-align: center;
+}
+
+
+
+
+
+

BIN
static/myassets/BCC.png


BIN
static/myassets/BTC.png


BIN
static/myassets/BTS.png


BIN
static/myassets/ETC.png


BIN
static/myassets/ETH.png


BIN
static/myassets/LTC.png


BIN
static/myassets/SC.png


BIN
static/myassets/SE.png


BIN
static/myassets/ZEC.png


Some files were not shown because too many files changed in this diff