├── src
├── cmd
│ ├── show_tables.txt
│ ├── table_dump.txt
│ ├── table_info.txt
│ ├── table_delete.txt
│ └── table_add.txt
├── handle
│ ├── readme.md
│ └── s1_smac.txt
├── show_sw_tables.py
├── simple_switch_CLI
├── show_table_info.py
├── show_table_entry.py
├── table_delete_entry.py
└── table_add_entry.py
├── p4web
├── P4_tools
│ ├── host.png
│ ├── switch.png
│ ├── switch2.png
│ ├── fonts
│ │ └── glyphicons-halflings-regular.woff
│ ├── .idea
│ │ ├── vcs.xml
│ │ ├── modules.xml
│ │ ├── misc.xml
│ │ ├── P4_tools.iml
│ │ └── workspace.xml
│ ├── js
│ │ ├── xx.html
│ │ ├── intputGroup.js
│ │ ├── bootstrap.min.js
│ │ └── jtopo-0.4.6-min.js
│ ├── css
│ │ ├── styles.css
│ │ └── bootstrap-table.css
│ ├── test.html
│ └── index.html
└── p4web.py
├── init
├── topo.txt
├── simple_switch_CLI
└── run_demo.sh
├── cleanup.sh
├── env.sh
├── script
├── veth_setup.sh
└── topo.py
├── p4src
├── includes
│ ├── headers.p4
│ └── parser.p4
└── switch.p4
├── README.md
└── LICENSE
/src/cmd/show_tables.txt:
--------------------------------------------------------------------------------
1 | show_tables
2 |
--------------------------------------------------------------------------------
/src/cmd/table_dump.txt:
--------------------------------------------------------------------------------
1 | table_dump smac
2 |
--------------------------------------------------------------------------------
/src/cmd/table_info.txt:
--------------------------------------------------------------------------------
1 | table_info smac
2 |
--------------------------------------------------------------------------------
/src/cmd/table_delete.txt:
--------------------------------------------------------------------------------
1 | table_delete dmac 0
2 |
--------------------------------------------------------------------------------
/src/handle/readme.md:
--------------------------------------------------------------------------------
1 | handle of table entries
2 |
--------------------------------------------------------------------------------
/src/handle/s1_smac.txt:
--------------------------------------------------------------------------------
1 | 0
2 | 16777216
3 | 0
4 |
--------------------------------------------------------------------------------
/src/cmd/table_add.txt:
--------------------------------------------------------------------------------
1 | table_add smac mac_learn 656 =>
2 |
--------------------------------------------------------------------------------
/p4web/P4_tools/host.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FZU-SDN/NSP4/HEAD/p4web/P4_tools/host.png
--------------------------------------------------------------------------------
/p4web/P4_tools/switch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FZU-SDN/NSP4/HEAD/p4web/P4_tools/switch.png
--------------------------------------------------------------------------------
/p4web/P4_tools/switch2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FZU-SDN/NSP4/HEAD/p4web/P4_tools/switch2.png
--------------------------------------------------------------------------------
/init/topo.txt:
--------------------------------------------------------------------------------
1 | switches 4
2 | hosts 6
3 | h1 s1
4 | h2 s1
5 | h3 s1
6 | h4 s4
7 | h5 s4
8 | h6 s4
9 | s1 s2
10 | s2 s4
11 | s1 s3
12 | s3 s4
13 |
--------------------------------------------------------------------------------
/p4web/P4_tools/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FZU-SDN/NSP4/HEAD/p4web/P4_tools/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/cleanup.sh:
--------------------------------------------------------------------------------
1 | # FuZhou University SDNLab
2 | # Added by Chen, 2017.4.30
3 |
4 | # WARNNING: Don't move this file!
5 |
6 | rm -rf init/*.pcap
7 | rm -rf init/*.json
8 | rm -rf script/*.pyc
9 | sudo mn -c
10 |
--------------------------------------------------------------------------------
/p4web/P4_tools/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/env.sh:
--------------------------------------------------------------------------------
1 | THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
2 |
3 | # ---------------- EDIT THIS ------------------
4 | BMV2_PATH=/home/wpq/bmv2
5 | # e.g. BMV2_PATH=$THIS_DIR/../bmv2
6 | P4C_BM_PATH=/home/wpq/p4c-bm
7 | # e.g P4C_BM_PATH=$THIS_DIR/../p4c-bm
8 | # ---------------- END ------------------
9 |
--------------------------------------------------------------------------------
/p4web/P4_tools/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/p4web/P4_tools/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/p4web/P4_tools/.idea/P4_tools.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/show_sw_tables.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import argparse
4 | from time import sleep
5 | import os
6 | import subprocess
7 |
8 | _THIS_DIR = os.path.dirname(os.path.realpath(__file__))
9 | _THRIFT_BASE_PORT = 22222
10 |
11 | parser = argparse.ArgumentParser(description='P4 demo')
12 | parser.add_argument('--swname', help='Switch Name',
13 | type=str, action="store", required=True)
14 | args = parser.parse_args()
15 |
16 | def main():
17 | # Get Thrift Port
18 | sw_name = args.swname
19 | index = int(sw_name[1:])-1
20 | thrift_port = _THRIFT_BASE_PORT+index
21 |
22 | cmd = "python /home/wpq/NSP4/src/simple_switch_CLI --thrift-port %d < /home/wpq/NSP4/src/cmd/show_tables.txt" % thrift_port
23 | os.system(cmd)
24 |
25 | if __name__ == '__main__':
26 | main()
27 |
--------------------------------------------------------------------------------
/script/veth_setup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | noOfVeths=18
3 | if [ $# -eq 1 ]; then
4 | noOfVeths=$1
5 | fi
6 | echo "No of Veths is $noOfVeths"
7 | idx=0
8 | let "vethpairs=$noOfVeths/2"
9 | while [ $idx -lt $vethpairs ]
10 | do
11 | intf0="veth$(($idx*2))"
12 | intf1="veth$(($idx*2+1))"
13 | idx=$((idx + 1))
14 | if ! ip link show $intf0 &> /dev/null; then
15 | ip link add name $intf0 type veth peer name $intf1
16 | ip link set dev $intf0 up
17 | ip link set dev $intf1 up
18 | TOE_OPTIONS="rx tx sg tso ufo gso gro lro rxvlan txvlan rxhash"
19 | for TOE_OPTION in $TOE_OPTIONS; do
20 | /sbin/ethtool --offload $intf0 "$TOE_OPTION" off
21 | /sbin/ethtool --offload $intf1 "$TOE_OPTION" off
22 | done
23 | fi
24 | sysctl net.ipv6.conf.$intf0.disable_ipv6=1
25 | sysctl net.ipv6.conf.$intf1.disable_ipv6=1
26 | done
27 |
--------------------------------------------------------------------------------
/init/simple_switch_CLI:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 |
3 | # Copyright 2013-present Barefoot Networks, Inc.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 | #
17 |
18 | #
19 | # Antonin Bas (antonin@barefootnetworks.com)
20 | #
21 | #
22 |
23 | # This is just a wrapper script around sswitch_CLI.py
24 | # It makes sure that the script works correctly no matter where Python
25 | # dependencies are installed
26 |
27 | import sys
28 | sys.path.append("/usr/local/lib/python2.7/dist-packages")
29 |
30 | import sswitch_CLI
31 | sswitch_CLI.main()
32 |
--------------------------------------------------------------------------------
/src/simple_switch_CLI:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 |
3 | # Copyright 2013-present Barefoot Networks, Inc.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 | #
17 |
18 | #
19 | # Antonin Bas (antonin@barefootnetworks.com)
20 | #
21 | #
22 |
23 | # This is just a wrapper script around sswitch_CLI.py
24 | # It makes sure that the script works correctly no matter where Python
25 | # dependencies are installed
26 |
27 | import sys
28 | sys.path.append("/usr/local/lib/python2.7/dist-packages")
29 |
30 | import sswitch_CLI
31 | sswitch_CLI.main()
32 |
--------------------------------------------------------------------------------
/src/show_table_info.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import argparse
4 | from time import sleep
5 | import os
6 | import subprocess
7 |
8 | _THIS_DIR = os.path.dirname(os.path.realpath(__file__))
9 | _THRIFT_BASE_PORT = 22222
10 |
11 | parser = argparse.ArgumentParser(description='P4 demo')
12 | parser.add_argument('--swname', help='Switch Name',
13 | type=str, action="store", required=True)
14 | parser.add_argument('--table-name', help='Table Name',
15 | type=str, action="store", required=True)
16 | args = parser.parse_args()
17 |
18 | def main():
19 | # Get Thrift Port
20 | sw_name = args.swname
21 | index = int(sw_name[1:])-1
22 | thrift_port = _THRIFT_BASE_PORT+index
23 |
24 | # Get Table Name
25 | table_name = args.table_name
26 |
27 | table_info_cmd = "echo 'table_info %s' > /home/wpq/NSP4/src/cmd/table_info.txt" % table_name
28 | os.system(table_info_cmd)
29 | cmd = "python /home/wpq/NSP4/src/simple_switch_CLI --thrift-port %d < /home/wpq/NSP4/src/cmd/table_info.txt" % thrift_port
30 | os.system(cmd)
31 | os.system("rm -rf cmd/table_info.txt")
32 |
33 | if __name__ == '__main__':
34 | main()
35 |
--------------------------------------------------------------------------------
/src/show_table_entry.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import argparse
4 | from time import sleep
5 | import os
6 | import subprocess
7 |
8 | _THIS_DIR = os.path.dirname(os.path.realpath(__file__))
9 | _THRIFT_BASE_PORT = 22222
10 |
11 | parser = argparse.ArgumentParser(description='P4 demo')
12 | parser.add_argument('--swname', help='Switch Name',
13 | type=str, action="store", required=True)
14 | parser.add_argument('--table-name', help='Table Name',
15 | type=str, action="store", required=True)
16 | args = parser.parse_args()
17 |
18 | def main():
19 | # Get Thrift Port
20 | sw_name = args.swname
21 | index = int(sw_name[1:])-1
22 | thrift_port = _THRIFT_BASE_PORT+index
23 |
24 | # Get Table Name
25 | table_name = args.table_name
26 |
27 | table_info_cmd = "echo 'table_dump %s' > /home/wpq/NSP4/src/cmd/table_dump.txt" % table_name
28 | os.system(table_info_cmd)
29 | cmd = "python /home/wpq/NSP4/src/simple_switch_CLI --thrift-port %d < /home/wpq/NSP4/src/cmd/table_dump.txt" % thrift_port
30 | os.system(cmd)
31 | os.system("rm -rf cmd/table_info.txt")
32 |
33 | if __name__ == '__main__':
34 | main()
35 |
--------------------------------------------------------------------------------
/init/run_demo.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Copyright 2013-present Barefoot Networks, Inc.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
18 |
19 | source $THIS_DIR/../env.sh
20 |
21 | P4C_BM_SCRIPT=$P4C_BM_PATH/p4c_bm/__main__.py
22 |
23 | SWITCH_PATH=$BMV2_PATH/targets/simple_switch/simple_switch
24 |
25 | CLI_PATH=$THIS_DIR/../script/simple_switch_CLI.py
26 |
27 | $P4C_BM_SCRIPT ../p4src/switch.p4 --json switch.json
28 | sudo PYTHONPATH=$PYTHONPATH:$BMV2_PATH/mininet/ python ../script/topo.py \
29 | --behavioral-exe $SWITCH_PATH \
30 | --json switch.json \
31 | --cli $CLI_PATH \
32 | --mode l2 #\
33 | # --controller-ip 127.0.0.1 \
34 | # --controller-port 6653
35 |
--------------------------------------------------------------------------------
/p4web/P4_tools/js/xx.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 |
9 |
10 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/table_delete_entry.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import re
4 | import argparse
5 | from time import sleep
6 | import os
7 | import subprocess
8 |
9 | _THIS_DIR = os.path.dirname(os.path.realpath(__file__))
10 | _THRIFT_BASE_PORT = 22222
11 |
12 | parser = argparse.ArgumentParser(description='P4 demo')
13 | parser.add_argument('--swname', help='Switch Name',
14 | type=str, action="store", required=True)
15 | parser.add_argument('--table-name', help='Table Name',
16 | type=str, action="store", required=True)
17 | parser.add_argument('--handle', help='Handle',
18 | type=str, action="store", required=True)
19 | #parser.add_argument('--ops-num', help='Operation Number',
20 | # type=int, action="store", required=True)
21 | args = parser.parse_args()
22 |
23 | def main():
24 | # Get Thrift Port
25 | sw_name = args.swname
26 | index = int(sw_name[1:])-1
27 | thrift_port = _THRIFT_BASE_PORT+index
28 |
29 | # Get Table Name
30 | table_name = args.table_name
31 |
32 | # Get Handle
33 | table_handle = args.handle
34 |
35 | runtime_cmd = "table_delete %s %s" % (table_name, table_handle)
36 | os.system('echo %s > /home/wpq/NSP4/src/cmd/table_delete.txt' % runtime_cmd)
37 | os.system("python /home/wpq/NSP4/src/simple_switch_CLI --thrift-port %d < /home/wpq/NSP4/src/cmd/table_delete.txt" % thrift_port)
38 | os.system('rm -rf /home/wpq/NSP4/src/cmd/table_delete.txt')
39 |
40 | """
41 | # Get Operation Number
42 | number = args.ops_num
43 |
44 | handle_file = 'handle/%s_%s.txt' % (sw_name, table_name)
45 | # remove the entry
46 | i, text = 1, open(handle_file, "r")
47 | for line in text.readlines():
48 | if i != number :
49 | i = i+1
50 | else :
51 | table_handle = int(line)
52 | os.system("echo 'table_delete %s %s' > cmd/table_delete.txt" % (table_name, table_handle))
53 | os.system("./simple_switch_CLI --thrift-port %d < cmd/table_delete.txt" % (thrift_port))
54 | #os.system("rm -rf cmd/table_delete.txt")
55 | break
56 | """
57 |
58 | if __name__ == '__main__':
59 | main()
60 |
--------------------------------------------------------------------------------
/p4src/includes/headers.p4:
--------------------------------------------------------------------------------
1 | /*********************************
2 | FuZhou University, SDNLab
3 | Added by Chen, 2017.3.29
4 | *********************************/
5 |
6 | /* Copyright 2017 FuZhou University SDNLab, Edu.
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 | http://www.apache.org/licenses/LICENSE-2.0
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License. */
16 |
17 | /*********************************
18 | template: header.p4
19 | *********************************/
20 |
21 | header_type ethernet_t {
22 | fields {
23 | dstAddr : 48;
24 | srcAddr : 48;
25 | etherType : 16;
26 | }
27 | }
28 |
29 | header_type intrinsic_metadata_t {
30 | fields {
31 | mcast_grp : 4;
32 | egress_rid : 4;
33 | mcast_hash : 16;
34 | lf_field_list: 32;
35 | }
36 | }
37 |
38 | header_type ipv4_t {
39 | fields {
40 | version : 4;
41 | ihl : 4;
42 | diffserv : 8;
43 | totalLen : 16;
44 | identification : 16;
45 | flags : 3;
46 | fragOffset : 13;
47 | ttl : 8;
48 | protocol : 8;
49 | hdrChecksum : 16;
50 | srcAddr : 32;
51 | dstAddr: 32;
52 | }
53 | }
54 |
55 | header_type icmp_t {
56 | fields {
57 | typeCode : 16;
58 | hdrChecksum : 16;
59 | }
60 | }
61 |
62 | header_type tcp_t {
63 | fields {
64 | srcPort : 16;
65 | dstPort : 16;
66 | seqNo : 32;
67 | ackNo : 32;
68 | dataOffset : 4;
69 | res : 4;
70 | flags : 8;
71 | window : 16;
72 | checksum : 16;
73 | urgentPtr : 16;
74 | }
75 | }
76 |
77 | header_type udp_t {
78 | fields {
79 | srcPort : 16;
80 | dstPort : 16;
81 | length_ : 16;
82 | checksum : 16;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/p4web/P4_tools/css/styles.css:
--------------------------------------------------------------------------------
1 | /*Global Styles*/
2 |
3 | body {
4 | background: #f1f4f7;
5 | padding-top: 50px;
6 | width: auto;
7 | font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
8 | font-size: 14px;
9 | color: #999999;
10 | line-height: 25px;
11 | letter-spacing: 1px
12 | }
13 |
14 | p {
15 | color: #777;
16 | }
17 |
18 |
19 | .panel-heading {
20 | font-size: 20px;
21 | font-weight: 300;
22 | letter-spacing: 0.025em;
23 | line-height: 45px;
24 | }
25 |
26 |
27 | .navbar-header .navbar-brand {
28 | color: #fff;
29 | font-size: 16px;
30 | text-transform: uppercase;
31 | font-weight: 500;
32 | letter-spacing: 2px;
33 | }
34 |
35 | .navbar-brand span {
36 | color: #30a5ff;
37 | }
38 |
39 |
40 | /*Navbar*/
41 |
42 | .navbar {
43 | border: 0;
44 | }
45 |
46 | .user-menu {
47 | display: inline-block;
48 | margin-top: 14px;
49 | margin-right: 10px;
50 | float: right;
51 | list-style: none;
52 | padding: 0;
53 | }
54 |
55 | .user-menu a {
56 | color: #fff;
57 | }
58 |
59 | .user-menu a:hover {
60 | text-decoration: none;
61 | }
62 |
63 |
64 | /* Sidebar */
65 |
66 | .sidebar {
67 | display: block;
68 | background-color: #fff;
69 | padding: 0;
70 | display: none;
71 | }
72 |
73 | .sidebar form {
74 | padding: 20px 15px 5px 15px;
75 | border-bottom: 1px solid #eee;
76 | margin-bottom: 20px;
77 | }
78 |
79 | @media (min-width: 768px) {
80 | .sidebar {
81 | display: block;
82 | position: fixed;
83 | top: 50px;
84 | bottom: 0;
85 | left: 0;
86 | z-index: 1000;
87 | display: block;
88 | margin: 0;
89 | padding: 0;
90 | overflow-x: hidden;
91 | overflow-y: auto;
92 | background-color: #fff;
93 | box-shadow: 1px 0px 10px rgba(0, 0, 0, .05);
94 | }
95 | .navbar-header {
96 | width: 100%;
97 | }
98 | }
99 |
100 | .sidebar ul.nav li.divider {
101 | border-bottom: 1px solid #eee;
102 | margin: 20px 0;
103 | }
104 |
105 | .sidebar ul.nav .active a {
106 | color: #fff;
107 | background-color: #30a5ff;
108 | }
109 |
110 | .input-group{
111 | width: 450px;
112 | }
113 |
114 | .input-group-addon{
115 | width: 120px;
116 | }
--------------------------------------------------------------------------------
/p4src/switch.p4:
--------------------------------------------------------------------------------
1 | /*********************************
2 | FuZhou University, SDNLab
3 | Added by Chen, 2017.3.29
4 | *********************************/
5 |
6 | /* Copyright 2017 FuZhou University SDNLab, Edu.
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 | http://www.apache.org/licenses/LICENSE-2.0
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License. */
16 |
17 | /*********************************
18 | template: switch.p4
19 | *********************************/
20 |
21 | #include "includes/headers.p4"
22 | #include "includes/parser.p4"
23 | // TODO: add your blocks
24 |
25 | // table and action
26 |
27 | action _drop() {
28 | drop();
29 | }
30 |
31 | action _nop() {
32 | }
33 |
34 | #define MAC_LEARN_RECEIVER 1024
35 |
36 | field_list mac_learn_digest {
37 | ethernet.srcAddr;
38 | standard_metadata.ingress_port;
39 | }
40 |
41 | action mac_learn() {
42 | generate_digest(MAC_LEARN_RECEIVER, mac_learn_digest);
43 | }
44 |
45 | table smac {
46 | reads {
47 | ethernet.srcAddr : exact;
48 | }
49 | actions {mac_learn; _nop;}
50 | size : 512;
51 | }
52 |
53 | action forward(port) {
54 | modify_field(standard_metadata.egress_spec, port);
55 | }
56 |
57 | action broadcast() {
58 | modify_field(intrinsic_metadata.mcast_grp, 1);
59 | }
60 |
61 | table dmac {
62 | reads {
63 | ethernet.dstAddr : exact;
64 | //ethernet.srcAddr : exact; // test
65 | }
66 | actions {
67 | forward;
68 | broadcast;
69 | }
70 | size : 512;
71 | }
72 |
73 | table mcast_src_pruning {
74 | reads {
75 | standard_metadata.instance_type : exact;
76 | }
77 | actions {_nop; _drop;}
78 | size : 1;
79 | }
80 |
81 | // TODO: add your own control logic to the pipeline
82 |
83 | control ingress {
84 | apply(smac);
85 | apply(dmac);
86 | }
87 |
88 | control egress {
89 | if (standard_metadata.ingress_port == standard_metadata.egress_port) {
90 | apply(mcast_src_pruning);
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/table_add_entry.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import re
4 | import argparse
5 | from time import sleep
6 | import os
7 | import subprocess
8 |
9 | _THIS_DIR = os.path.dirname(os.path.realpath(__file__))
10 | _THRIFT_BASE_PORT = 22222
11 |
12 | parser = argparse.ArgumentParser(description='P4 demo')
13 | parser.add_argument('--swname', help='Switch Name',
14 | type=str, action="store", required=True)
15 | parser.add_argument('--table-name', help='Table Name',
16 | type=str, action="store", required=True)
17 | parser.add_argument('--key', help='Match Key', nargs='*',
18 | type=str, action="store", required=True)
19 | parser.add_argument('--action', help='Action',
20 | type=str, action="store", required=True)
21 | parser.add_argument('para', nargs='*', type=str)
22 | args = parser.parse_args()
23 |
24 | def main():
25 | # Get Thrift Port
26 | sw_name = args.swname
27 | index = int(sw_name[1:])-1
28 | thrift_port = _THRIFT_BASE_PORT+index
29 |
30 | # Get Table Name
31 | table_name = args.table_name
32 |
33 | key = ''
34 | # Get Match Key
35 | for i in args.key:
36 | key = key+' '
37 | key = key+i
38 |
39 | # Get Action
40 | action = args.action
41 |
42 | paras = ''
43 |
44 | if args.para :
45 | para = args.para
46 | for i in args.para :
47 | paras = paras+' '
48 | paras = paras+i
49 | table_info_cmd = "echo 'table_add %s %s%s =>%s' > /home/wpq/NSP4/src/cmd/table_add.txt" % (table_name, action, key, paras)
50 | else :
51 | table_info_cmd = "echo 'table_add %s %s%s =>' > /home/wpq/NSP4/src/cmd/table_add.txt" % (table_name, action, key)
52 |
53 |
54 | # Debug
55 | #print(table_info_cmd)
56 |
57 | os.system(table_info_cmd)
58 | cmd = "python /home/wpq/NSP4/src/simple_switch_CLI --thrift-port %d < /home/wpq/NSP4/src/cmd/table_add.txt" % thrift_port
59 | os.system(cmd)
60 | #os.system("%s > handle_tmp.txt" % cmd)
61 | os.system("rm -rf cmd/table_add.txt")
62 |
63 | """
64 | # Get Handle
65 | text = open('handle_tmp.txt', "r")
66 | for line in text.readlines():
67 | if line[0] == 'E':
68 | for i in range(len(line)):
69 | if line[i].isdigit():
70 | break
71 | handle = line[i:-1]
72 | os.system("echo '%s' >> handle/%s_%s.txt" % (handle, sw_name, table_name))
73 | os.system("rm -rf handle_tmp.txt")
74 | """
75 |
76 | if __name__ == '__main__':
77 | main()
78 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NSP4: A Network Simulator for the P4 language
2 |
3 | **NSP4 is still under developing so that many functions are not supported in NSP4 yet. We invite you to extend NSP4 to create a better environment for learning the P4 language.**
4 |
5 | [发表在SDNLAB上的NSP4中文文档](https://www.sdnlab.com/19370.html)
6 |
7 | ## Experiment Preparation
8 |
9 | 1、In the directory of **`src/`**,change the path information from ```/home/wpq``` to the NSP4 directory information. The code need to modify contain the following file:
10 |
11 | - show_sw_tables.py
12 | - show_table_entry.py
13 | - show_table_info.py
14 | - table_add_entry.py
15 | - table_delete_entry.py
16 |
17 | Example, for the ```show_sw_tables.py```, you should change the sentence from
18 |
19 | ```
20 | cmd = "python /home/wpq/NSP4/src/simple_switch_CLI --thrift-port %d < /home/wpq/NSP4/src/cmd/show_tables.txt" % thrift_port
21 | ```
22 |
23 | to
24 |
25 | ```
26 | cmd = "python /src/simple_switch_CLI --thrift-port %d < /home/wpq/NSP4/src/cmd/show_tables.txt" % thrift_port
27 | ```
28 |
29 | 2、In the directory of **p4web**, change some path information in the code of the file ```p4web.py```.
30 |
31 | Like 1, you just modify the information from ```/home/wpq``` to the NSP4 directory, the line number of code includes 70、77、94、118、162、177、201.
32 |
33 | ## Hands-on Steps
34 |
35 | 1、Put the P4 code which is correct to the directory of **p4src/**. Note that the P4 program which contains the control flows "ingress" and "egress" must be given with the name "switch.p4".
36 |
37 | 2、Start up the ```p4web.py``` by the Ryu command **ryu-manager**.
38 |
39 | ```
40 | ryu-manager ./p4web.py
41 | ```
42 |
43 | 3、Type 127.0.0.1:8080 on your browser,you will see the following interface.
44 |
45 | 
46 |
47 | 4、Input the information of topology on the interface, and click the button of **提交**, you will find the GUI of topology appear the browser. Then start up the mininet with P4 by the following command.
48 |
49 | 
50 |
51 | 
52 |
53 | ```
54 | cd init
55 | sudo ./run_demo.sh
56 | ```
57 |
58 | 5、Then you can choose the switch by the switch number to config the P4 switch table.
59 |
60 | For example:
61 |
62 | 5-1、Choose S1
63 |
64 | 
65 |
66 | 5-2、Add flow entry to the table of **dmac**
67 |
68 | 
69 |
70 | 
71 |
72 | 5-3、Then you can fine the flow entry just downloaded appear the interface
73 |
74 | 
75 |
76 | 5-4、Delete the flow entry
77 |
78 | 
79 |
80 | ## Existing Problems
81 |
82 | - The path information is complex
83 | - Some function such as counter is not supported
84 | - Non-support of P4-16 language
85 |
--------------------------------------------------------------------------------
/p4web/P4_tools/js/intputGroup.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by DreamBoy on 2016/6/4.
3 | */
4 | /**
5 | * Created by DreamBoy on 2016/4/29.
6 | */
7 | $(function() {
8 | $.fn.initInputGroup = function (options) {
9 | //1.Settings 初始化设置
10 | var c = $.extend({
11 | widget: 'input',
12 | add: "",
13 | del: "",
14 | field: '',
15 | data: []
16 | }, options);
17 |
18 | var _this = $(this);
19 |
20 | //添加序号为1的输入框组
21 | addInputGroup(1);
22 |
23 | /**
24 | * 添加序号为order的输入框组
25 | * @param order 输入框组的序号
26 | * @param data 初始化输入框组中的数据
27 | */
28 | function addInputGroup(order) {
29 |
30 | //1.创建输入框组
31 | var inputGroup = $("");
32 | //2.输入框组的序号
33 | var inputGroupAddon1 = $("");
34 | //3.设置输入框组的序号
35 | inputGroupAddon1.html(" " + order + " ");
36 |
37 | //4.创建输入框组中的输入控件(input或textarea)
38 | var widget = '', inputGroupAddon2;
39 | if(c.widget == 'textarea') {
40 | widget = $("");
41 | widget.html(c.data[order - 1]);
42 | inputGroupAddon2 = $("");
43 | } else if(c.widget == 'input') {
44 | widget = $("");
45 | widget.val(c.data[order - 1]);
46 | inputGroupAddon2 = $("");
47 | }
48 |
49 | //5.设置表单提交时的字段名
50 | if(c.field.length == 0) {
51 | widget.prop('name', c.widget + 'Data[]');
52 | } else {
53 | widget.prop('name', c.field + '[]');
54 | }
55 |
56 |
57 | //6.创建输入框组中最后面的操作按钮
58 | var addBtn = $("");
59 | addBtn.appendTo(inputGroupAddon2).on('click', function() {
60 | //7.响应删除和添加操作按钮事件
61 | if($(this).html() == c.del) {
62 | $(this).parents('.input-group').remove();
63 | } else if($(this).html() == c.add) {
64 | $(this).html(c.del);
65 | addInputGroup(order+1);
66 | }
67 | //8.重新排序输入框组的序号
68 | resort();
69 | });
70 |
71 | inputGroup.append(inputGroupAddon1).append(widget).append(inputGroupAddon2);
72 |
73 | _this.append(inputGroup);
74 |
75 | if(order + 1 > c.data.length) {
76 | return;
77 | }
78 | addBtn.trigger('click');
79 | }
80 |
81 | function resort() {
82 | var child = _this.children();
83 | $.each(child, function(i) {
84 | $(this).find(".input-group-addon").eq(0).html(' ' + (i + 1) + ' ');
85 | });
86 | }
87 | }
88 | });
--------------------------------------------------------------------------------
/p4src/includes/parser.p4:
--------------------------------------------------------------------------------
1 | /*********************************
2 | FuZhou University, SDNLab
3 | Added by Chen, 2017.3.29
4 | *********************************/
5 |
6 | /* Copyright 2017 FuZhou University SDNLab, Edu.
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 | http://www.apache.org/licenses/LICENSE-2.0
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License. */
16 |
17 | /*********************************
18 | template: parser.p4
19 | *********************************/
20 |
21 | parser start {
22 | return parse_ethernet;
23 | }
24 |
25 | header ethernet_t ethernet;
26 | metadata intrinsic_metadata_t intrinsic_metadata;
27 |
28 | #define ETHERTYPE_BF_FABRIC 0x9000
29 | #define ETHERTYPE_VLAN 0x8100
30 | #define ETHERTYPE_QINQ 0x9100
31 | #define ETHERTYPE_MPLS 0x8847
32 | #define ETHERTYPE_IPV4 0x0800
33 | #define ETHERTYPE_IPV6 0x86dd
34 | #define ETHERTYPE_ARP 0x0806
35 | #define ETHERTYPE_RARP 0x8035
36 | #define ETHERTYPE_NSH 0x894f
37 | #define ETHERTYPE_ETHERNET 0x6558
38 | #define ETHERTYPE_ROCE 0x8915
39 | #define ETHERTYPE_FCOE 0x8906
40 | #define ETHERTYPE_TRILL 0x22f3
41 | #define ETHERTYPE_VNTAG 0x8926
42 | #define ETHERTYPE_LLDP 0x88cc
43 | #define ETHERTYPE_LACP 0x8809
44 |
45 | #define IPV4_MULTICAST_MAC 0x01005E
46 | #define IPV6_MULTICAST_MAC 0x3333
47 |
48 | parser parse_ethernet {
49 | extract(ethernet);
50 | return select(latest.etherType) {
51 | ETHERTYPE_IPV4 : parse_ipv4;
52 | default: ingress;
53 | }
54 | }
55 |
56 | #define IP_PROTOCOLS_ICMP 1
57 | #define IP_PROTOCOLS_IGMP 2
58 | #define IP_PROTOCOLS_IPV4 4
59 | #define IP_PROTOCOLS_TCP 6
60 | #define IP_PROTOCOLS_UDP 17
61 | #define IP_PROTOCOLS_IPV6 41
62 | #define IP_PROTOCOLS_GRE 47
63 | #define IP_PROTOCOLS_IPSEC_ESP 50
64 | #define IP_PROTOCOLS_IPSEC_AH 51
65 | #define IP_PROTOCOLS_ICMPV6 58
66 | #define IP_PROTOCOLS_EIGRP 88
67 | #define IP_PROTOCOLS_OSPF 89
68 | #define IP_PROTOCOLS_PIM 103
69 | #define IP_PROTOCOLS_VRRP 112
70 |
71 | #define IP_PROTOCOLS_IPHL_ICMP 0x501
72 | #define IP_PROTOCOLS_IPHL_IPV4 0x504
73 | #define IP_PROTOCOLS_IPHL_TCP 0x506
74 | #define IP_PROTOCOLS_IPHL_UDP 0x511
75 | #define IP_PROTOCOLS_IPHL_IPV6 0x529
76 | #define IP_PROTOCOLS_IPHL_GRE 0x52f
77 |
78 | header ipv4_t ipv4;
79 |
80 | parser parse_ipv4 {
81 | extract(ipv4);
82 | return select(latest.fragOffset, latest.ihl, latest.protocol) {
83 | IP_PROTOCOLS_IPHL_ICMP : parse_icmp;
84 | IP_PROTOCOLS_IPHL_TCP : parse_tcp;
85 | IP_PROTOCOLS_IPHL_UDP : parse_udp;
86 | default: ingress;
87 | }
88 | }
89 |
90 | #define UDP_PORT_BOOTPS 67
91 | #define UDP_PORT_BOOTPC 68
92 | #define UDP_PORT_RIP 520
93 | #define UDP_PORT_RIPNG 521
94 | #define UDP_PORT_DHCPV6_CLIENT 546
95 | #define UDP_PORT_DHCPV6_SERVER 547
96 | #define UDP_PORT_HSRP 1985
97 | #define UDP_PORT_BFD 3785
98 | #define UDP_PORT_LISP 4341
99 | #define UDP_PORT_VXLAN 4789
100 | #define UDP_PORT_VXLAN_GPE 4790
101 | #define UDP_PORT_ROCE_V2 4791
102 | #define UDP_PORT_GENV 6081
103 | #define UDP_PORT_SFLOW 6343
104 |
105 | header icmp_t icmp;
106 |
107 | parser parse_icmp {
108 | extract(icmp);
109 | return select(latest.typeCode) {
110 | default: ingress;
111 | }
112 | }
113 |
114 | header tcp_t tcp;
115 |
116 | parser parse_tcp {
117 | extract(tcp);
118 | return select(latest.dstPort) {
119 | default: ingress;
120 | }
121 | }
122 |
123 | header udp_t udp;
124 |
125 | parser parse_udp {
126 | extract(udp);
127 | return select(latest.dstPort) {
128 | default: ingress;
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/script/topo.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | # Copyright 2013-present Barefoot Networks, Inc.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | from mininet.net import Mininet
18 | from mininet.topo import Topo
19 | from mininet.log import setLogLevel, info
20 | from mininet.cli import CLI
21 |
22 | from p4_mininet import P4Switch, P4Host
23 |
24 | import argparse
25 | from time import sleep
26 | import os
27 | import subprocess
28 |
29 | _THIS_DIR = os.path.dirname(os.path.realpath(__file__))
30 | _THRIFT_BASE_PORT = 22222
31 |
32 | parser = argparse.ArgumentParser(description='Mininet demo')
33 | parser.add_argument('--behavioral-exe', help='Path to behavioral executable',
34 | type=str, action="store", required=True)
35 | parser.add_argument('--json', help='Path to JSON config file',
36 | type=str, action="store", required=True)
37 | parser.add_argument('--cli', help='Path to BM CLI',
38 | type=str, action="store", required=True)
39 | parser.add_argument('--mode', choices=['l2', 'l3'], type=str, default='l3')
40 |
41 | args = parser.parse_args()
42 |
43 | sw_macs = []
44 | sw_addrs = []
45 |
46 | class MyTopo(Topo):
47 | def __init__(self, sw_path, json_path, nb_hosts, nb_switches, links, **opts):
48 | # Initialize topology and default options
49 | Topo.__init__(self, **opts)
50 |
51 | for i in xrange(nb_switches):
52 | self.addSwitch('s%d' % (i + 1),
53 | sw_path = sw_path,
54 | json_path = json_path,
55 | thrift_port = _THRIFT_BASE_PORT + i,
56 | pcap_dump = True,
57 | device_id = i)
58 |
59 | for h in xrange(nb_hosts):
60 | self.addHost('h%d' % (h + 1), ip="10.0.0.%d" % (h + 1),
61 | mac="00:00:00:00:00:0%d" % (h+1))
62 | addrv = "10.0.0.%d" % (h+1)
63 | macv = "00:00:00:00:00:0%d" % (h+1)
64 | sw_addrs.append(addrv)
65 | sw_macs.append(macv)
66 |
67 | for a, b in links:
68 | self.addLink(a, b)
69 |
70 | def read_topo():
71 | nb_hosts = 0
72 | nb_switches = 0
73 | links = []
74 | with open("topo.txt", "r") as f:
75 | line = f.readline()[:-1]
76 | w, nb_switches = line.split()
77 | assert(w == "switches")
78 | line = f.readline()[:-1]
79 | w, nb_hosts = line.split()
80 | assert(w == "hosts")
81 | for line in f:
82 | if not f: break
83 | a, b = line.split()
84 | links.append( (a, b) )
85 | return int(nb_hosts), int(nb_switches), links
86 |
87 |
88 | def main():
89 | nb_hosts, nb_switches, links = read_topo()
90 |
91 | mode = args.mode
92 |
93 | topo = MyTopo(args.behavioral_exe,
94 | args.json,
95 | nb_hosts, nb_switches, links)
96 |
97 | net = Mininet(topo = topo,
98 | host = P4Host,
99 | switch = P4Switch,
100 | controller = None )
101 | net.start()
102 |
103 | for n in xrange(nb_hosts):
104 | h = net.get('h%d' % (n + 1))
105 |
106 | for off in ["rx", "tx", "sg"]:
107 | cmd = "/sbin/ethtool --offload eth0 %s off" % off
108 | print cmd
109 | h.cmd(cmd)
110 |
111 | print "disable ipv6"
112 | h.cmd("sysctl -w net.ipv6.conf.all.disable_ipv6=1")
113 | h.cmd("sysctl -w net.ipv6.conf.default.disable_ipv6=1")
114 | h.cmd("sysctl -w net.ipv6.conf.lo.disable_ipv6=1")
115 | h.cmd("sysctl -w net.ipv4.tcp_congestion_control=reno")
116 | h.cmd("iptables -I OUTPUT -p icmp --icmp-type destination-unreachable -j DROP")
117 |
118 | if mode == "l2":
119 | h.setDefaultRoute("dev eth0")
120 | else:
121 | h.setARP(sw_addrs[n], sw_macs[n])
122 | h.setDefaultRoute("dev eth0 via %s" % sw_addrs[n])
123 |
124 | for n in xrange(nb_hosts):
125 | h = net.get('h%d' % (n + 1))
126 | h.describe()
127 |
128 | sleep(1)
129 |
130 | print "Ready !"
131 |
132 | CLI( net )
133 | net.stop()
134 |
135 | if __name__ == '__main__':
136 | setLogLevel( 'info' )
137 | main()
138 |
--------------------------------------------------------------------------------
/p4web/P4_tools/css/bootstrap-table.css:
--------------------------------------------------------------------------------
1 | .table {
2 | margin-bottom: 0 !important;
3 | border-bottom: 1px solid #dddddd;
4 | border-collapse: collapse !important;
5 | border-radius: 1px;
6 | }
7 |
8 | .fixed-table-container {
9 | position: relative;
10 | clear: both;
11 | border: 1px solid #dddddd;
12 | border-radius: 4px;
13 | -webkit-border-radius: 4px;
14 | -moz-border-radius: 4px;
15 | }
16 |
17 | .fixed-table-header {
18 | overflow: hidden;
19 | border-radius: 4px 4px 0 0;
20 | -webkit-border-radius: 4px 4px 0 0;
21 | -moz-border-radius: 4px 4px 0 0;
22 | }
23 |
24 | .fixed-table-body {
25 | overflow-x: auto;
26 | overflow-y: auto;
27 | height: 100%;
28 | }
29 |
30 | .fixed-table-container table {
31 | width: 100%;
32 | }
33 |
34 | .fixed-table-container thead th {
35 | height: 0;
36 | padding: 0;
37 | margin: 0;
38 | border-left: 1px solid #dddddd;
39 | }
40 |
41 | .fixed-table-container thead th:first-child {
42 | border-left: none;
43 | }
44 |
45 | .fixed-table-container thead th .th-inner {
46 | padding: 8px;
47 | line-height: 24px;
48 | vertical-align: top;
49 | overflow: hidden;
50 | text-overflow: ellipsis;
51 | white-space: nowrap;
52 | }
53 |
54 | .fixed-table-container thead th .sortable {
55 | cursor: pointer;
56 | }
57 |
58 | .fixed-table-container tbody td {
59 | border-left: 1px solid #dddddd;
60 | }
61 |
62 | .fixed-table-container tbody tr:first-child td {
63 | border-top: none;
64 | }
65 |
66 | .fixed-table-container tbody td:first-child {
67 | border-left: none;
68 | }
69 |
70 | /* the same color with .active */
71 | .fixed-table-container tbody .selected td {
72 | background-color: #f5f5f5;
73 | }
74 |
75 | .fixed-table-container .bs-checkbox {
76 | text-align: center;
77 | }
78 |
79 | .fixed-table-container .bs-checkbox .th-inner {
80 | padding: 8px 0;
81 | }
82 |
83 | .fixed-table-container input[type="radio"],
84 | .fixed-table-container input[type="checkbox"] {
85 | margin: 0 auto !important;
86 | }
87 |
88 | .fixed-table-container .no-records-found {
89 | text-align: center;
90 | }
91 |
92 |
93 | .fixed-table-pagination .pagination,
94 | .fixed-table-pagination .pagination-detail {
95 | margin-top: 10px;
96 | margin-bottom: 10px;
97 | }
98 |
99 | .fixed-table-pagination .pagination a {
100 | padding: 6px 12px;
101 | line-height: 1.428571429;
102 | }
103 |
104 | .fixed-table-pagination .pagination-info {
105 | line-height: 34px;
106 | margin-right: 5px;
107 | }
108 |
109 | .fixed-table-pagination .btn-group {
110 | position: relative;
111 | display: inline-block;
112 | vertical-align: middle;
113 | }
114 |
115 | .fixed-table-pagination .dropup .dropdown-menu {
116 | margin-bottom: 0;
117 | }
118 |
119 | .fixed-table-pagination .page-list {
120 | display: inline-block;
121 | }
122 |
123 | .fixed-table-toolbar .columns {
124 | margin-left: 5px;
125 | }
126 |
127 | .fixed-table-toolbar .columns label {
128 | display: block;
129 | padding: 3px 20px;
130 | clear: both;
131 | font-weight: normal;
132 | line-height: 1.428571429;
133 | }
134 |
135 | .fixed-table-toolbar .bars,
136 | .fixed-table-toolbar .search,
137 | .fixed-table-toolbar .columns {
138 | position: relative;
139 | margin-top: 10px;
140 | margin-bottom: 10px;
141 | line-height: 34px;
142 | }
143 |
144 | .fixed-table-pagination li.disabled a {
145 | pointer-events: none;
146 | cursor: default;
147 | }
148 |
149 | .fixed-table-loading {
150 | display: none;
151 | position: absolute;
152 | top: 42px;
153 | right: 0;
154 | bottom: 0;
155 | left: 0;
156 | z-index: 99;
157 | background-color: #fff;
158 | text-align: center;
159 | }
160 |
161 | .fixed-table-body .card-view .title {
162 | font-weight: bold;
163 | display: inline-block;
164 | min-width: 30%;
165 | text-align: left !important;
166 | }
167 |
168 | /* support bootstrap 2 */
169 | .fixed-table-body thead th .th-inner {
170 | box-sizing: border-box;
171 | }
172 |
173 | .table th, .table td {
174 | vertical-align: middle;
175 | box-sizing: border-box;
176 | }
177 |
178 | .fixed-table-toolbar .dropdown-menu {
179 | text-align: left;
180 | max-height: 300px;
181 | overflow: auto;
182 | }
183 |
184 | .fixed-table-toolbar .btn-group>.btn-group {
185 | display: inline-block;
186 | margin-left: -1px !important;
187 | }
188 |
189 | .fixed-table-toolbar .btn-group>.btn-group>.btn {
190 | border-radius: 0;
191 | }
192 |
193 | .fixed-table-toolbar .btn-group>.btn-group:first-child>.btn {
194 | border-top-left-radius: 4px;
195 | border-bottom-left-radius: 4px;
196 | }
197 |
198 | .fixed-table-toolbar .btn-group>.btn-group:last-child>.btn {
199 | border-top-right-radius: 4px;
200 | border-bottom-right-radius: 4px;
201 | }
202 |
203 | .table>thead>tr>th {
204 | vertical-align: bottom;
205 | border-bottom: 2px solid #ddd;
206 | }
207 |
208 | /* support bootstrap 3 */
209 | .table thead>tr>th {
210 | padding: 0;
211 | margin: 0;
212 | }
213 |
214 | .pull-right .dropdown-menu {
215 | right: 0;
216 | left: auto;
217 | }
218 |
219 | /* calculate scrollbar width */
220 | p.fixed-table-scroll-inner {
221 | width: 100%;
222 | height: 200px;
223 | }
224 |
225 | div.fixed-table-scroll-outer {
226 | top: 0;
227 | left: 0;
228 | visibility: hidden;
229 | width: 200px;
230 | height: 150px;
231 | overflow: hidden;
232 | }
--------------------------------------------------------------------------------
/p4web/p4web.py:
--------------------------------------------------------------------------------
1 | # -- coding: utf-8 --
2 | import os
3 | import commands
4 | import re
5 | from webob.static import DirectoryApp
6 |
7 | from ryu.app.wsgi import ControllerBase, WSGIApplication, route
8 | from ryu.base import app_manager
9 | import json
10 |
11 |
12 |
13 | PATH = os.path.dirname(__file__)
14 |
15 |
16 | # Serving static files
17 | class GUIServerApp(app_manager.RyuApp):
18 | _CONTEXTS = {
19 | 'wsgi': WSGIApplication,
20 | }
21 |
22 | def __init__(self, *args, **kwargs):
23 | super(GUIServerApp, self).__init__(*args, **kwargs)
24 |
25 | wsgi = kwargs['wsgi']
26 | wsgi.register(GUI_P4_ServerController)
27 |
28 | class GUI_P4_ServerController(ControllerBase):
29 | def __init__(self, req, link, data, **config):
30 | super(GUI_P4_ServerController, self).__init__(req, link, data, **config)
31 | path = "%s/P4_tools" % PATH
32 | self.static_app = DirectoryApp(path)
33 |
34 | @route('topology', '/{filename:.*}', methods=['GET'])
35 | def static_handler(self, req, **kwargs):
36 | if kwargs['filename']:
37 | print kwargs['filename']
38 | if kwargs['filename'] == "ok":
39 |
40 | # 用于创建拓扑文件
41 | switches = req.GET['switches']
42 | hosts = req.GET['hosts']
43 |
44 | switches = req.GET['switches']
45 | switches = switches.encode('utf-8')
46 | switches = int(switches)
47 |
48 | hosts = req.GET['hosts']
49 | hosts = hosts.encode('utf-8')
50 | hosts = int(hosts)
51 |
52 | linksnum = req.GET['linksnum']
53 | linksnum = linksnum.encode('utf-8')
54 | linksnum = int(linksnum)
55 |
56 | link_information = req.GET['link_information']
57 | link_information = link_information.encode('utf-8')
58 |
59 | #正则匹配得到对应的链路信息,从而写到topo.txt中去
60 | match_links = re.findall(r'(.*?),', link_information, re.M | re.I)
61 | links = match_links
62 |
63 |
64 | topo_file = open('topo.txt', 'w')
65 | topo_file.write('switches ' + str(switches) + '\n')
66 | topo_file.write('hosts ' + str(hosts) + '\n')
67 | for i in range(linksnum):
68 | topo_file.write(links[i] + '\n')
69 | topo_file.close()
70 |
71 | print 'switches=%d' % switches
72 | print "hosts=%d" % hosts
73 | status, output = commands.getstatusoutput('cp -f topo.txt /home/wpq/NSP4/init')
74 |
75 | elif kwargs['filename'] == "table":
76 | #显示流表专用
77 | switch_no = req.GET['switch_no']
78 | switch_no = switch_no.encode('utf-8')
79 |
80 | #--------得到交换机内所有的【表名】(以------为该部分功能的结尾)
81 |
82 | cmd_str = 'python /home/wpq/NSP4/src/show_sw_tables.py --swname s' + switch_no
83 | status, output = commands.getstatusoutput(cmd_str)
84 | #正则匹配得到交换机内所有的【表名】
85 | matchObj = re.findall('(\S+)(?=[\s]*\[i.*\])', output, re.M | re.I)
86 |
87 | table_number = len(matchObj)
88 | # -----------得到交换机内所有的【表名】----------------#
89 | data_json = {}
90 |
91 | # print matchObj
92 | data_json['table-number'] = table_number
93 | table = []
94 | for i in range(table_number):
95 | table_infor = {}
96 | table_name = matchObj[i]
97 | table_infor['table-name'] = table_name
98 |
99 | #查询对应表的匹配项以及动作
100 | cmd_str = 'python /home/wpq/NSP4/src/show_table_info.py --swname s' + switch_no + ' --table-name ' + table_name
101 | status, output = commands.getstatusoutput(cmd_str)
102 |
103 | #得到该表对应的匹配项
104 | match_table_key = re.findall('[=\t](\S*)(?=\(.*\,.*\))', output, re.M | re.I)
105 | #得到该表对应的动作
106 | match_action_key = re.findall('[\n](\S+)(?=[\s]*\[(.*)\])', output, re.M | re.I)
107 |
108 |
109 | match_key_num = len(match_table_key)
110 | key = []
111 | for j in range(match_key_num):
112 | key.append(match_table_key[j])
113 |
114 | table_infor['key-number'] = match_key_num
115 | table_infor['key'] = key
116 |
117 | match_action_num = len(match_action_key)
118 | action = []
119 | for j in range(match_action_num):
120 | action.append(match_action_key[j][0])
121 |
122 | table_infor['action-number'] = match_action_num
123 | table_infor['action'] = action
124 |
125 | #查询对应表,所对应的表项
126 | cmd_str = 'python /home/wpq/NSP4/src/show_table_entry.py --swname s' + switch_no + ' --table-name ' + table_name
127 | status, output = commands.getstatusoutput(cmd_str)
128 |
129 | print output
130 |
131 | #matchObj0 对应 表项 的 handle(唯一值)
132 | matchObj0 = re.findall('(0x[\S]+)', output, re.M | re.I)
133 |
134 | matchObj1 = re.findall('\*\s(\S+)(?=\s*:\s)', output, re.M | re.I)
135 | matchObj2 = re.findall('[\s] (\S+)(?=\n)', output, re.M | re.I)
136 | #matchObj3 对应的动作,以及动作参数
137 | matchObj3 = re.findall('(\S+)\s- ?([\S ]*)', output, re.M | re.I)
138 |
139 | table_entry = [
140 | ]
141 |
142 |
143 | for j in range(len(matchObj0)):
144 | entry = {}
145 | entry['handle'] = int(matchObj0[j], 16)
146 | entry[matchObj1[j]] = matchObj2[j]
147 | entry["action"] = matchObj3[j][0]
148 | entry["action-parameter"] = matchObj3[j][1]
149 | table_entry.append(entry)
150 |
151 | table_infor['table-entry'] = table_entry
152 | table_infor['table-entry-number'] = len(table_entry)
153 | table.append(table_infor)
154 |
155 | data_json['table'] = table
156 | return json.dumps(data_json)
157 |
158 | elif kwargs['filename'] == 'add_entry':
159 | #添加表项
160 |
161 | switch_no = req.GET['switch-name']
162 | table_name = req.GET['table-name']
163 | action = req.GET['action']
164 | action_parameter = req.GET['action_parameter']
165 |
166 | switch_no = switch_no.encode('utf-8')
167 | switch_no = re.findall('([0-9]+)', switch_no, re.M | re.I)
168 | switch_no = switch_no[0]
169 |
170 | table_name = table_name.encode('utf-8')
171 | action = action.encode('utf-8')
172 | action_parameter = action_parameter.encode('utf-8')
173 |
174 | action_sum = action + ' ' + action_parameter
175 |
176 | cmd_str = 'python /home/wpq/NSP4/src/show_table_info.py --swname s' + switch_no + ' --table-name ' + table_name
177 | status, output = commands.getstatusoutput(cmd_str)
178 |
179 | match_table_key = re.findall('[=\t](\S*)(?=\(.*\,.*\))', output, re.M | re.I)
180 |
181 | match_key_num = len(match_table_key)
182 |
183 | key = []
184 | match_key_value = ''
185 | for j in range(match_key_num):
186 | match_key_value += req.GET[match_table_key[j]].encode('utf-8') + ' '
187 | key.append(match_table_key[j])
188 |
189 | print "match_key_value"
190 | print match_key_value
191 | cmd_str = 'python /home/wpq/NSP4/src/table_add_entry.py --swname s' + switch_no + ' --table-name ' + table_name + ' --key ' + match_key_value + '--action ' + action_sum
192 | status, output = commands.getstatusoutput(cmd_str)
193 |
194 | print cmd_str
195 |
196 | output = re.findall('(Error|Invalid)', output, re.M | re.I)
197 |
198 | if len(output) < 1:
199 | return "add_entry success!"
200 | elif output[0] == 'Error':
201 | return "input Error!"
202 | elif output[0] == 'Invalid':
203 | return "input Invalid!"
204 | return json.dumps(output)
205 |
206 | elif kwargs['filename'] == 'del_entry':
207 | #删除表项
208 | handle = req.GET['handle'].encode('utf-8')
209 | table_name = req.GET['table-name'].encode('utf-8')
210 | switch_no = req.GET['switch-name'].encode('utf-8')
211 |
212 | switch_no = re.findall('([0-9]+)', switch_no, re.M | re.I)
213 | switch_no = switch_no[0]
214 |
215 | cmd_str = 'python /home/wpq/NSP4/src/table_delete_entry.py --swname s' + switch_no + ' --table-name ' + table_name + ' --handle ' + handle
216 |
217 | print cmd_str
218 | status, output = commands.getstatusoutput(cmd_str)
219 |
220 | return "delete success"
221 |
222 | req.path_info = kwargs['filename']
223 | return self.static_app(req)
224 |
225 |
226 |
227 |
--------------------------------------------------------------------------------
/p4web/P4_tools/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | P4 tools
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
36 |
37 |
41 |
151 |
152 |
273 |
274 |
275 |
276 |
277 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/p4web/P4_tools/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | P4 tools
7 |
8 |
9 |
10 |
11 |
12 |
13 |
26 |
27 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
拓扑图
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
交换机流表信息
66 |
67 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
388 |
389 |
390 |
--------------------------------------------------------------------------------
/p4web/P4_tools/js/bootstrap.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap v3.2.0 (http://getbootstrap.com)
3 | * Copyright 2011-2014 Twitter, Inc.
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
5 | */
6 | if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.2.0",d.prototype.close=function(b){function c(){f.detach().trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",c).emulateTransitionEnd(150):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.2.0",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),d[e](null==f[b]?this.options[b]:f[b]),setTimeout(a.proxy(function(){"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b).on("keydown.bs.carousel",a.proxy(this.keydown,this)),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.2.0",c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},c.prototype.keydown=function(a){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.to=function(b){var c=this,d=this.getItemIndex(this.$active=this.$element.find(".item.active"));return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}if(e.hasClass("active"))return this.sliding=!1;var j=e[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:g});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,f&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(e)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:g});return a.support.transition&&this.$element.hasClass("slide")?(e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.one("bsTransitionEnd",function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(1e3*d.css("transition-duration").slice(0,-1))):(d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger(m)),f&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b);!e&&f.toggle&&"show"==b&&(b=!b),e||d.data("bs.collapse",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};c.VERSION="3.2.0",c.DEFAULTS={toggle:!0},c.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},c.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var c=a.Event("show.bs.collapse");if(this.$element.trigger(c),!c.isDefaultPrevented()){var d=this.$parent&&this.$parent.find("> .panel > .in");if(d&&d.length){var e=d.data("bs.collapse");if(e&&e.transitioning)return;b.call(d,"hide"),e||d.data("bs.collapse",null)}var f=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[f](0),this.transitioning=1;var g=function(){this.$element.removeClass("collapsing").addClass("collapse in")[f](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return g.call(this);var h=a.camelCase(["scroll",f].join("-"));this.$element.one("bsTransitionEnd",a.proxy(g,this)).emulateTransitionEnd(350)[f](this.$element[0][h])}}},c.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(d,this)).emulateTransitionEnd(350):d.call(this)}}},c.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var d=a.fn.collapse;a.fn.collapse=b,a.fn.collapse.Constructor=c,a.fn.collapse.noConflict=function(){return a.fn.collapse=d,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(c){var d,e=a(this),f=e.attr("data-target")||c.preventDefault()||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),g=a(f),h=g.data("bs.collapse"),i=h?"toggle":e.data(),j=e.attr("data-parent"),k=j&&a(j);h&&h.transitioning||(k&&k.find('[data-toggle="collapse"][data-parent="'+j+'"]').not(e).addClass("collapsed"),e[g.hasClass("in")?"addClass":"removeClass"]("collapsed")),b.call(g,i)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=c(a(this)),e={relatedTarget:this};d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown",e)),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown",e))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.2.0",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('').insertAfter(a(this)).on("click",b);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus"),f.toggleClass("open").trigger("shown.bs.dropdown",h)}return!1}},g.prototype.keydown=function(b){if(/(38|40|27)/.test(b.keyCode)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled")){var e=c(d),g=e.hasClass("open");if(!g||g&&27==b.keyCode)return 27==b.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.divider):visible a",i=e.find('[role="menu"]'+h+', [role="listbox"]'+h);if(i.length){var j=i.index(i.filter(":focus"));38==b.keyCode&&j>0&&j--,40==b.keyCode&&j').appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(a){a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus.call(this.$element[0]):this.hide.call(this))},this)),e&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;e?this.$backdrop.one("bsTransitionEnd",b).emulateTransitionEnd(150):b()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var f=function(){c.removeBackdrop(),b&&b()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",f).emulateTransitionEnd(150):f()}else b&&b()},c.prototype.checkScrollbar=function(){document.body.clientWidth>=window.innerWidth||(this.scrollbarWidth=this.scrollbarWidth||this.measureScrollbar())},c.prototype.setScrollbar=function(){var a=parseInt(this.$body.css("padding-right")||0,10);this.scrollbarWidth&&this.$body.css("padding-right",a+this.scrollbarWidth)},c.prototype.resetScrollbar=function(){this.$body.css("padding-right","")},c.prototype.measureScrollbar=function(){var a=document.createElement("div");a.className="modal-scrollbar-measure",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=b,a.fn.modal.Constructor=c,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(c){var d=a(this),e=d.attr("href"),f=a(d.attr("data-target")||e&&e.replace(/.*(?=#[^\s]+$)/,"")),g=f.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is("a")&&c.preventDefault(),f.one("show.bs.modal",function(a){a.isDefaultPrevented()||f.one("hidden.bs.modal",function(){d.is(":visible")&&d.trigger("focus")})}),b.call(f,g,this)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof b&&b;(e||"destroy"!=b)&&(e||d.data("bs.tooltip",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null,this.init("tooltip",a,b)};c.VERSION="3.2.0",c.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(this.options.viewport.selector||this.options.viewport);for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show()},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var c=a.contains(document.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!c)return;var d=this,e=this.tip(),f=this.getUID(this.type);this.setContent(),e.attr("id",f),this.$element.attr("aria-describedby",f),this.options.animation&&e.addClass("fade");var g="function"==typeof this.options.placement?this.options.placement.call(this,e[0],this.$element[0]):this.options.placement,h=/\s?auto?\s?/i,i=h.test(g);i&&(g=g.replace(h,"")||"top"),e.detach().css({top:0,left:0,display:"block"}).addClass(g).data("bs."+this.type,this),this.options.container?e.appendTo(this.options.container):e.insertAfter(this.$element);var j=this.getPosition(),k=e[0].offsetWidth,l=e[0].offsetHeight;if(i){var m=g,n=this.$element.parent(),o=this.getPosition(n);g="bottom"==g&&j.top+j.height+l-o.scroll>o.height?"top":"top"==g&&j.top-o.scroll-l<0?"bottom":"right"==g&&j.right+k>o.width?"left":"left"==g&&j.left-kg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.width&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.validate=function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){clearTimeout(this.timeout),this.hide().$element.off("."+this.type).removeData("bs."+this.type)};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||"destroy"!=b)&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.2.0",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").empty()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},c.prototype.tip=function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){var e=a.proxy(this.process,this);this.$body=a("body"),this.$scrollElement=a(a(c).is("body")?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",e),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.2.0",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b="offset",c=0;a.isWindow(this.$scrollElement[0])||(b="position",c=this.$scrollElement.scrollTop()),this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight();var d=this;this.$body.find(this.selector).map(function(){var d=a(this),e=d.data("target")||d.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[b]().top+c,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){d.offsets.push(this[0]),d.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b<=e[0])return g!=(a=f[0])&&this.activate(a);for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(!e[a+1]||b<=e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,a(this.selector).parentsUntil(this.options.target,".active").removeClass("active");var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.2.0",c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a")[0],f=a.Event("show.bs.tab",{relatedTarget:e});if(b.trigger(f),!f.isDefaultPrevented()){var g=a(d);this.activate(b.closest("li"),c),this.activate(g,g.parent(),function(){b.trigger({type:"shown.bs.tab",relatedTarget:e})})}}},c.prototype.activate=function(b,c,d){function e(){f.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),g?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var f=c.find("> .active"),g=d&&a.support.transition&&f.hasClass("fade");g?f.one("bsTransitionEnd",e).emulateTransitionEnd(150):e(),f.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this},a(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(c){c.preventDefault(),b.call(a(this),"show")})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=this.unpin=this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.2.0",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=a(document).height(),d=this.$target.scrollTop(),e=this.$element.offset(),f=this.options.offset,g=f.top,h=f.bottom;"object"!=typeof f&&(h=g=f),"function"==typeof g&&(g=f.top(this.$element)),"function"==typeof h&&(h=f.bottom(this.$element));var i=null!=this.unpin&&d+this.unpin<=e.top?!1:null!=h&&e.top+this.$element.height()>=b-h?"bottom":null!=g&&g>=d?"top":!1;if(this.affixed!==i){null!=this.unpin&&this.$element.css("top","");var j="affix"+(i?"-"+i:""),k=a.Event(j+".bs.affix");this.$element.trigger(k),k.isDefaultPrevented()||(this.affixed=i,this.unpin="bottom"==i?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(j).trigger(a.Event(j.replace("affix","affixed"))),"bottom"==i&&this.$element.offset({top:b-this.$element.height()-h}))}}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},d.offsetBottom&&(d.offset.bottom=d.offsetBottom),d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);
--------------------------------------------------------------------------------
/p4web/P4_tools/js/jtopo-0.4.6-min.js:
--------------------------------------------------------------------------------
1 | eval(function(p,a,c,k,e,d){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('b8(b4(h,b,j,f,g,i){g=b4(a){b5(a35?bb.hi(a+29):a.e9(36))};if(!"".b6(/^/,bb)){b7(j--){i[g(j)]=f[j]||g(j)}f=[b4(a){b5 i[a]}];g=b4(){b5"\\\\w+"};j=1}b7(j--){if(f[j]){h=h.b6(b9 dT("\\\\b"+g(j)+"\\\\b","g"),f[j])}}b5 h}(\'!E(1g){E 4k(){D.14=E(){D.1R="3C",D.1A=["1R"],D.51=[],D.8F=""+(V 8x).8M()},D.8A=E(){},D.4w=E(){},D.8g=E(a,b){P(J!=a&&J!=b)D[a]=b;1O P(J!=a)G D[a];G D},D.1p=E(){F a=D,b={};D.1A.1a(E(c){b[c]=a[c]}),D.51.U(b)},D.1v=E(){F a,b;J!=D.51&&0!=D.51.K&&(a=D,b=D.51.8O(),D.1A.1a(E(c){a[c]=b[c]}))},D.3p=E(){F a=D,b="{",c=D.1A.K;G D.1A.1a(E(d,e){F f=a[d];"3u"==2g f&&(f=\\\'"\\\'+f+\\\'"\\\'),b+=\\\'"\\\'+d+\\\'":\\\'+f,c>e+1&&(b+=",")}),b+="}"}}84.X.5S=E(a,b,c,d,e){"89"==2g e&&(e=5),D.1b(),D.2p(a+e,b),D.1F(a+c-e,b),D.4F(a+c,b,a+c,b+e),D.1F(a+c,b+d-e),D.4F(a+c,b+d,a+c-e,b+d),D.1F(a+e,b+d),D.4F(a,b+d,a,b+d-e),D.1F(a,b+e),D.4F(a,b,a+e,b),D.1h()},84.X.8j=E(a,b,c,d,e){F f,g,h,i,j,k,l;N("89"==2g e&&(e=5),f=c-a,g=d-b,h=L.3Y(L.65(f*f+g*g)),i=0>=e?h:h/e,j=g/h*e,k=f/h*e,D.1b(),l=0;i>l;l++)l%2?D.1F(a+l*k,b+l*j):D.2p(a+l*k,b+l*j);D.1B()},17={6s:"0.4.6",8p:1,8d:2,8u:3,27:{2o:"2o",4E:"4E",4I:"4I",4x:"4x"},2T:{2o:"5O",6p:"6p",8U:"85-2V",8L:"n-2V",8J:"8e-2V",8H:"e-2V",8D:"e-2V",8E:"8e-2V",9C:"n-2V",9L:"85-2V",5w:"5w",7j:"86(./6f/5K/9p.5K) 8 8, 5O",5E:"86(./6f/5K/9a.5K) 8 8, 5O"},98:E(8k,M){F W,k,2H;8t("F 5B = "+8k),W=V 17.3Q(M);N(k 21 5B)"O"!=k&&(W[k]=5B[k]);G 2H=5B.O,2H.1a(E(a){F c,d,b=V 17.4R(W);N(c 21 a)"O"!=c&&(b[c]=a[c]),"3m"==c&&(b.3m=a[c]);d=a.O,d.1a(E(a){F e,c=J,d=a.1R;"5g"==d?c=V 17.2c:"5Y"==d&&(c=V 17.5Y);N(e 21 a)c[e]=a[e];b.3j(c)})}),W}},17.4k=4k,1g.17=17}(1g),E(17){E 2F(a){F b=D;D.94=a,D.3l={},D.6b=0,D.4Y=E(a,d){F e=b.3l[a];J==e&&(b.3l[a]=[]),b.3l[a].U(d),b.6b++},D.5m=E(a){F c=b.3l[a];J!=c&&(b.3l[a]=J,96 b.3l[a],b.6b--)},D.4S=E(a,c,d){F f,e=b.3l[a];P(J!=e)N(f=0;fd.x&&(b.T=d.x,b.6n=d),b.15d.y&&(b.Y=d.y,b.6t=d),b.1db)){F e=0;f(e)}}E 3S(a){F c,b={};N(c 21 a)"5T"!=c&&"9n"!=c&&(b[c]=a[c]);G b}E 4q(a){F c,b={};N(c 21 a)b[c]=a[c];G b}E 6H(a,b){F c=b.x,d=b.y,e=b.H,f=b.I;G a.x>c&&a.xd&&a.y0&&(c+=","),e=a[b[d]],"3u"==2g e?e=\\\'"\\\'+e+\\\'"\\\':1D 0==e&&(e=J),c+=b[d]+":"+e;G c}E 6M(8n,M){F k,2H,i,54,3x,p,68,3A,m,52,5X,3C,5b,66=8t(8n),W=V 17.3Q(M);N(k 21 9o)P("2H"!=k)W[k]=66[k];1O N(2H=66.2H,i=0;i<2H.K;i++){54=2H[i],3x=V 17.4R(W);N(p 21 54)P("3A"!=p)3x[p]=54[p];1O N(68={},3A=54.3A,m=0;m<3A.K;m++){52=3A[m],5X=52.1R,"2c"==5X&&(3C=V 17.2c);N(5b 21 52)3C[5b]=52[5b];68[3C.1m]=3C,3x.3j(3C)}}G 5j.6F(W),W}E 3p(a){F e,f,g,h,b="5P,1l,1I,2f,1f,18,19,4B,1o,1s,5I,3J".2s(","),c="1m,1R,x,y,H,I,1l,1f,2f,18,19,2K,4B,43,2m,2D,3K,3F,1t,1N,3V,2v,2w".2s(","),d="{";N(d+="2k:"+a.2k,d+=", 2H:[",e=0;e0&&(d+=","),d+="{",d+=6a(h,c),d+="}";d+="]}"}G d+="]",d+="}"}E 7r(a,b,c,d,e){F h,i,j,k,l,m,f=M.H=b.H,g=M.I=b.I;N(a.5U(0,0,M.H,M.I),a.3G(b,0,0),h=a.7V(0,0,b.H,b.I),i=h.9f,j=0;f>j;j++)N(k=0;g>k;k++)l=4*(j+k*f),0!=i[l+3]&&(J!=c&&(i[l+0]+=c),J!=d&&(i[l+1]+=d),J!=e&&(i[l+2]+=e));G a.7J(h,0,0,0,0,b.H,b.I),m=M.7M(),42[b.2S]=m,m}E 5H(a,b){J==b&&(b=1j);7W{P(42[a.2S])G 42[a.2S];F c=V 5A;G c.2S=7r(2N,a,b),42[a.2S]=c,c}7S(d){}G J}E 5V(a){F b,c,d,e,f,g,h,i;P(!a)G{T:0,Y:0};P(b=0,c=0,"7n"21 1Y.7m)d=a.7n(),e=a.9j,f=e.4V,g=e.7m,h=g.62||f.62||0,i=g.69||f.69||0,b=d.Y+(7s.9l||g&&g.6c||f.6c)-h,c=d.T+(7s.92||g&&g.60||f.60)-i;1O 97 b+=a.4g||0,c+=a.4s||0,a=a.9c;9b(a);G{T:c,Y:b}}E 3f(a,b,c,d){E g(a){G a*e+f}F e=(d-b)/(c-a),f=b-a*e;G g.k=e,g.b=f,g.46=a,g.7t=c,g.7g=b,g.7a=d,g}E 61(a,b,c){F d=L.1E(b-c),e=L.1E(b-a),f=L.1E(c-a),g=L.1E(d-(e+f));G 1e-6>g?!0:!1}E 5Z(a,b,c){G 61(a,c.46,c.7t)&&61(b,c.7g,c.7a)}E 3y(a,b){F c,d;G a.k==b.k?J:(1/0==a.k?(c=a.46,d=b(a.46)):1/0==b.k?(c=b.46,d=a(b.46)):(c=(b.b-a.b)/(a.k-b.k),d=a(c)),0==5Z(c,d,a)?J:0==5Z(c,d,b)?J:{x:c,y:d})}E 5o(a,b){F c=17.11.3f(b.T,b.Y,b.T,b.1d),d=17.11.3y(a,c);G J==d&&(c=17.11.3f(b.T,b.Y,b.15,b.Y),d=17.11.3y(a,c),J==d&&(c=17.11.3f(b.15,b.Y,b.15,b.1d),d=17.11.3y(a,c),J==d&&(c=17.11.3f(b.T,b.1d,b.15,b.1d),d=17.11.3y(a,c)))),d}F M,2N,42;7h=1g.7h||1g.9G||1g.9F||1g.9E||1g.9D||E(a){2b(a,2Q/24)},7e.X.4v=E(a){P("9H"!=2g a){N(F b=0;ba?D:D.5p(0,a).2l(D.5p(a+1,D.K))},[].4T||(7e.X.4T=E(a){N(F b=0;b0,7B:!(!1g.91||-1!==6C.6y.4T("9v")),9w:J!=6C.6y.9y().5F(/9x/),4q:4q,6H:6H,5n:5n,55:55,3S:3S,6d:6d,6N:6N,3p:3p,6M:6M,2G:2G,5H:5H,5V:5V,3f:3f,3y:3y,5o:5o},1g.$N=$N,1g.$6L=$6L}(17),E(a){E b(a){G{6x:16,1l:!1,2q:1Y.6J("M"),6g:E(b,c){F g,d=a.2L(),e=1,f=1;G D.2q.H=a.M.H,D.2q.I=a.M.I,J!=b&&J!=c?(D.2q.H=b,D.2q.I=c,e=b/d.H,f=c/d.I):(d.H>a.M.H&&(D.2q.H=d.H),d.I>a.M.I&&(D.2q.I=d.I)),g=D.2q.5W("2d"),a.O.K>0&&(g.1p(),g.5U(0,0,D.2q.H,D.2q.I),a.O.1a(E(a){1==a.1l&&(a.1p(),a.1o=0,a.1s=0,a.18=1,a.19=1,g.3q(e,f),d.T<0&&(a.1o=L.1E(d.T)),d.Y<0&&(a.1s=L.1E(d.Y)),a.3J=!0,a.3B(g),a.3J=!1,a.1v())}),g.1v()),D.2q.7M("1L/7A")},M:1Y.6J("M"),6h:E(){D.57=D.6j(a)},2P:E(a,b){D.H=D.M.H=a,D.I=D.M.I=b},6j:E(b,c){E e(a){F b=a.W.M.H,c=a.W.M.I,d=b/a.18/2,e=c/a.19/2;G{1o:a.1o+d-d*a.18,1s:a.1s+e-e*a.19}}F d,f,g,h,i,j,k,l;P(J!=j&&J!=k?D.2P(b,c):D.2P(8I,8v),d=D.M.5W("2d"),a.O.K>0){d.1p(),d.5U(0,0,D.M.H,D.M.I),a.O.1a(E(a){1==a.1l&&(a.1p(),a.5e(J,J,d),a.3B(d),a.1v())}),f=e(a.O[0]),g=f.1o*D.M.H/a.M.H*a.O[0].18,h=f.1s*D.M.I/a.M.I*a.O[0].19,i=a.2L(),j=a.M.H/a.O[0].18/i.H,k=a.M.I/a.O[0].19/i.I,j>1&&(j=1),k>1&&(j=1),g*=j,h*=k,i.T<0&&(g-=L.1E(i.T)*(D.H/i.H)),i.Y<0&&(h-=L.1E(i.Y)*(D.I/i.I)),d.1p(),d.3k=1,d.1P="Z(1j,0,0,1)",d.8y(-g,-h,d.M.H*j,d.M.I*k),d.1v(),l=J;7W{l=d.7V(0,0,d.M.H,d.M.I)}7S(m){}G l}G J},1w:E(){P(J!=D.57){F b=a.2N;b.1p(),b.1i="Z(6K,6K,6K,0.3)",b.70(a.M.H-D.M.H-2*D.6x,a.M.I-D.M.I-1,a.M.H-D.M.H,D.M.I+1),b.1M(),b.7J(D.57,a.M.H-D.M.H-D.6x,a.M.I-D.M.I),b.1v()}1O D.57=D.6j(a)},7H:E(a,b,c){F f,g,h,i,j,d=b.x,e=b.y;G d>c.M.H-D.M.H&&e>c.M.I-D.M.I?(d=b.x-D.M.H,e=b.y-D.M.I,"2C"==a&&(D.2X=c.O[0].1o,D.2U=c.O[0].1s),"2M"==a&&c.O.K>0&&(f=b.1n,g=b.1z,h=c.2L(),i=D.M.H/c.O[0].18/h.H,j=D.M.I/c.O[0].19/h.I,c.O[0].1o=D.2X-f/i,c.O[0].1s=D.2U-g/j),1D 0):1D 0}}}E c(c){E f(b){F c=a.11.5z(b),e=a.11.5V(d.M);G c.4s=c.6k-e.T,c.4g=c.7y-e.Y,c.x=c.4s,c.y=c.4g,c.1U=J,c}E g(a){e=!1,1Y.7x=E(){G!1},D.7F=!0;F b=f(a);d.2n("2y",b),d.13("2y",b)}E h(a){e=!0,1Y.7x=E(){G!0};F b=f(a);d.2n("2t",b),d.13("2t",b),d.3P=0==d.7v?!1:!0}E i(a){F b=f(a);d.3D=!0,d.4p=b.x,d.4o=b.y,d.2n("2C",b),d.13("2C",b)}E j(a){F b=f(a);d.2n("35",b),d.13("35",b),d.3D=!1,d.3P=0==d.7v?!1:!0}E k(a){F b=f(a);d.3D?0==a.8W&&(b.1n=b.x-d.4p,b.1z=b.y-d.4o,d.2n("2M",b),d.13("2M",b),1==d.2a.1l&&d.2a.6h()):(d.2n("2I",b),d.13("2I",b))}E l(a){F b=f(a);d.2n("2z",b),d.13("2z",b)}E m(a){F b=f(a);d.2n("3t",b),d.13("3t",b)}E n(a){F b=f(a);d.2n("3w",b),d.13("3w",b),J!=d.3H&&(a.3R?a.3R():(a=a||1g.6e,a.5T=!1),1==d.2a.1l&&d.2a.6h())}E o(b){a.11.7B||!1g.1C?(b.8B=h,b.8C=g,b.8X=i,b.90=j,b.8R=k,b.8P=l,b.8N=m,b.8Z=n,b.4L=i,b.4M=k,b.4N=j):(b.1C("2t",h),b.1C("2y",g),b.1C("2C",i),b.1C("35",j),b.1C("2I",k),b.1C("2z",l),b.1C("8V",m),a.11.7D?b.1C("8w",n):b.1C("3w",n)),1g.1C&&(1g.1C("49",E(b){d.2n("49",a.11.3S(b));F c=b.7q;(37==c||38==c||39==c||40==c)&&(b.3R?b.3R():(b=b||1g.6e,b.5T=!1))},!0),1g.1C("3I",E(b){d.2n("3I",a.11.3S(b));F c=b.7q;(37==c||38==c||39==c||40==c)&&(b.3R?b.3R():(b=b||1g.6e,b.5T=!1))},!0))}F d,e,p,q;a.W=D,d=D,D.14=E(c){o(c),D.M=c,D.2N=c.5W("2d"),D.O=[],D.2k=24,D.1J=V a.11.2F,D.2a=b(D),D.3H=J,D.4p=0,D.4o=0,D.3D=!1,D.7F=!1,D.3P=!0,D.1A=["2k","3H"]},J!=c&&D.14(c),e=!0,1Y.aF=E(){G e},D.2n=E(a,b){F c,d;G 0!=D.2k&&(D.3P=!0),1==D.2a.1l&&-1!=a.4T("aH")&&(c=b.x,d=b.y,c>D.H-D.2a.H&&d>D.I-D.2a.I)?(D.2a.7H(a,b,D),1D 0):(D.O.1a(E(c){P(1==c.1l){F d=c[a+"7C"];P(J==d)64 V 63("aG aI aM:"+a+"7C");d.47(c,b)}}),1D 0)},D.3j=E(a){N(F b=0;b"),D},D.az=E(a,b){F c=D.2a.6g(a,b);G c.aB("1L/7A","1L/aA-aO"),1g.8s.5x=c,D},D.1w=E(){J!=D.M&&(D.2N.1p(),D.2N.5U(0,0,D.H,D.I),D.O.1a(E(a){1==a.1l&&a.3B(d.2N)}),1==D.2a.1l&&D.2a.1w(D),D.2N.1v())},D.3B=E(){0!=D.2k&&(D.2k<0&&0==D.3P||(D.1w(),D.2k<0&&(D.3P=!1)))},D.4y=E(a){D.O.1a(E(b){0!=b.1l&&b.4y(a)})},D.5c=E(a){D.O.1a(E(b){0!=b.1l&&b.5c(a)})},D.5d=E(a){D.O.1a(E(b){0!=b.1l&&b.5d(a)})},D.5e=E(){D.O.1a(E(a){0!=a.1l&&a.5e()})},D.8b=E(a,b){F c=D;D.O.1a(E(d){F e=a-c.M.H/2,f=b-c.M.I/2;d.1o=-e,d.1s=-f})},D.2L=E(){F a={T:3h.5L,15:3h.5C,Y:3h.5L,1d:3h.5C};G D.O.1a(E(b){F c=b.2G();c.Ta.15&&(a.15=c.15,a.6u=c.6u),c.1d>a.1d&&(a.1d=c.1d,a.6v=c.6v)}),a.H=a.15-a.T,a.I=a.1d-a.Y,a},D.3p=E(){F b=D,c=\\\'{"6s":"\\\'+a.6s+\\\'",\\\';G D.1A.K,D.1A.1a(E(a){F e=b[a];"3u"==2g e&&(e=\\\'"\\\'+e+\\\'"\\\'),c+=\\\'"\\\'+a+\\\'":\\\'+e+","}),c+=\\\'"O":[\\\',D.O.1a(E(a){c+=a.3p()}),c+="]",c+="}"},E(){0==d.2k?2b(1k.6r,2r):d.2k<0?(d.3B(),2b(1k.6r,2Q/-d.2k)):(d.3B(),2b(1k.6r,2Q/d.2k))}(),2b(E(){d.3w(E(a){F b=J==a.7K?a.aP:a.7K;J!=D.3H&&(b>0?D.5d(D.3H):D.5c(D.3H))}),d.1w()},aU),2b(E(){d.1w()},2Q),2b(E(){d.1w()},at)}c.X={2Z H(){G D.M.H},2Z I(){G D.M.I},3g 23(a){D.M.3Z.23=a},2Z 23(){G D.M.3Z.23},3g 1I(a){D.O.1a(E(b){b.1I=a})}},a.3Q=c}(17),E(a){E b(c){E e(a,b,c,d){G E(e){e.1b(),e.1P="Z(0,0,4r,0.5)",e.1i="Z(0,0,4r,0.1)",e.2E(a,b,c,d),e.1M(),e.1B(),e.1h()}}F f,g,d=D;G D.14=E(){b.X.14.1T(D,1k),D.1J=V a.11.2F,D.1R="3x",D.O=[],D.2B={},D.2A=[],D.5P="1j,1j,1j",D.1l=!0,D.1f=0,D.18=1,D.19=1,D.1I=a.27.2o,D.2j=!0,D.1o=0,D.1s=0,D.2X=0,D.2U=0,D.3D=!1,D.4p=J,D.4o=J,D.3W=J,D.5I=!0,D.4U=[],D.1V=[],D.3J=!1;F c="3m,5P,1I,3J,5I,2j,1o,1s,a2,a1,1f,1l,18,19".2s(",");D.1A=D.1A.2l(c)},D.14(),D.au=E(a){D.3m=a},D.6o=E(a){D.W!==a&&J!=a&&(D.W=a)},J!=c&&(c.3j(D),D.6o(c)),D.a3=E(){D.1l=!0},D.a4=E(){D.1l=!1},D.1w=E(a){P(0!=D.1l&&J!=D.W){P(a.1p(),D.7u(a),a.1v(),a.1p(),a.3q(D.18,D.19),1==D.2j){F b=D.5Q(a);a.2j(b.1o,b.1s)}D.7P(a),a.1v(),a.1p(),D.7O(a,D.4U),a.1v()}},D.3B=E(a){0!=D.1l&&D.1w(a)},D.7u=E(a){J!=D.3m?a.3G(D.3m,0,0,a.M.H,a.M.I):(a.1b(),a.1i="Z("+D.5P+","+D.1f+")",a.70(0,0,a.M.H,a.M.I),a.1h())},D.a5=E(){F b,c,d,e,f,a=[];N(b=0;bD.W.M.H||e>D.W.M.I||0>f||0>g?!1:!0)},D.7O=E(a,b){N(F c=0;c=0;e--)N(f=D.2A[e],g=D.2B[f],h=g.K-1;h>=0;h--)P(i=g[h],i 1Q a.4f&&D.56(i)&&i.4z(b,c))G d=i;G d},D.3j=E(a){D.O.U(a),J==D.2B[a.2m]&&(D.2B[a.2m]=[],D.2A.U(a.2m),D.2A.9P(E(a,b){G a-b})),D.2B[""+a.2m].U(a)},D.3o=E(b){D.O=a.11.55(D.O,b);F c=D.2B[b.2m];c&&(D.2B[b.2m]=a.11.55(c,b)),b.4w(D)},D.7o=E(){F a=D;D.O.1a(E(b){b.4w(a)}),D.O=[],D.4U=[],D.2A=[],D.2B={}},D.6l=E(a){D.1V.U(a)},D.5f=E(a){N(F b=0;b=f?f:b,i=c>=g?g:c,j=L.1E(a.1n)*D.18,k=L.1E(a.1z)*D.19,l=V e(h,i,j,k);N(d.6m().7Y(l),b=a.x,c=a.y,f=D.3W.x,g=D.3W.y,h=b>=f?f:b,i=c>=g?g:c,j=L.1E(a.1n),k=L.1E(a.1z),m=h+j,n=i+k,o=0;oh&&p.x+p.Hi&&p.y+p.I1)G;D.4y(i,i)}D.4y(a,b)},D.4P=E(){G{x:d.W.M.H/2,y:d.W.M.I/2}},D.7k=E(a){a&&a(D,D.O)},D.3p=E(){F d,a=D,b="{";G D.1A.K,D.1A.1a(E(c){F e=a[c];"3m"==c&&(e=a.5a.2S),"3u"==2g e&&(e=\\\'"\\\'+e+\\\'"\\\'),b+=\\\'"\\\'+c+\\\'":\\\'+e+","}),b+=\\\'"O":[\\\',d=D.O.K,D.O.1a(E(a,c){b+=a.3p(),d>c+1&&(b+=",")}),b+="]",b+="}"},d}b.X=V a.4k;F c={};6T.72(b.X,{3m:{2Z:E(){G D.5a},3g:E(a){P("3u"==2g a){F d=c[a];J==d&&(d=V 5A,d.2S=a,d.8m=E(){c[a]=d}),D.5a=d}1O D.5a=a}}}),a.4R=b}(17),E(a){E b(){D.14=E(){b.X.14.1T(D,1k),D.1R="aj",D.x=0,D.y=0,D.H=32,D.I=32,D.1l=!0,D.1f=1,D.2f=0,D.18=1,D.19=1,D.4A="22,6O,1j",D.6S="22,6O,1j",D.2K="22,6O,1j",D.4B=!1,D.4D=5,D.3N="Z(0,0,0,0.5)",D.3T=3,D.3U=6,D.43=!1,D.2m=0;F a="x,y,H,I,1l,1f,2f,18,19,4A,2K,4B,3N,3T,3U,43,2m".2s(",");D.1A=D.1A.2l(a)},D.14(),D.1w=E(a){a.1b(),a.1i="Z("+D.2K+","+D.1f+")",a.2E(-D.H/2,-D.I/2,D.H,D.I),a.1M(),a.1B(),a.1h()},D.ap=E(){G{x:D.x,y:D.y}},D.26=E(a,b){G D.x=a,D.y=b,D},D.4P=E(){G{x:D.x+D.H/2,y:D.y+D.I/2}},D.7R=E(a,b){G D.x=a-D.H/2,D.y=b-D.I/2,D},D.ao=E(){G{H:D.H,I:D.al}},D.2P=E(a,b){G D.H=a,D.I=b,D},D.2L=E(){G{T:D.x,Y:D.y,15:D.x+D.H,1d:D.y+D.I,H:D.H,I:D.I}},D.am=E(a,b,c,d){G D.26(a,b),D.2P(c,d),D},D.an=E(){G{T:D.x,Y:D.y,15:D.x+D.H*D.18,1d:D.y+D.I*D.19}},D.9U=E(){G{H:D.H*D.18,I:D.I*D.19}},D.8h=E(a){F c,b=D.2L();G"4t"==a?c={x:b.T,y:b.Y}:"4K"==a?c={x:D.1x,y:b.Y}:"4J"==a?c={x:b.15,y:b.Y}:"4j"==a?c={x:b.T,y:D.1u}:"6R"==a?c={x:D.1x,y:D.1u}:"4O"==a?c={x:b.15,y:D.1u}:"4H"==a?c={x:b.T,y:b.1d}:"3r"==a?c={x:D.1x,y:b.1d}:"4G"==a&&(c={x:b.15,y:b.1d}),c}}E c(){F b,d;D.14=E(){c.X.14.1T(D,1k),D.1R="9R",D.2D=!1,D.3K=!1,D.3F=!0,D.29=J,D.3E=!1;F a="2D,3K,3F,3E".2s(",");D.1A=D.1A.2l(a)},D.14(),D.3e=E(a){0!=D.3F&&(a.1p(),a.1b(),a.1P="Z(4a,4d,1j, 0.9)",a.1i="Z(4a,4d,4r,0.7)",a.2E(-D.H/2-3,-D.I/2-3,D.H+6,D.I+6),a.1M(),a.1B(),a.1h(),a.1v())},D.8l=E(a){G D.3e(a)},D.4z=E(a,b){G a>D.x&&aD.y&&bf.T&&af.Y&&c1&&(D.H=d)):"4j"==D.2h?(d=D.1X.H-a.1n,b=D.29.x+a.1n,b1&&(D.H=d)):"4O"==D.2h?(d=D.1X.H+a.1n,d>1&&(D.H=d)):"4H"==D.2h?(d=D.1X.H-a.1n,b=D.29.x+a.1n,d>1&&(D.x=b,D.H=d),e=D.1X.I+a.1z,e>1&&(D.I=e)):"3r"==D.2h?(e=D.1X.I+a.1z,e>1&&(D.I=e)):"4G"==D.2h&&(d=D.1X.H+a.1n,d>1&&(D.H=d),e=D.1X.I+a.1z,e>1&&(D.I=e)),D.13("2V",a))}}b.X=V a.4k,6T.72(b.X,{1x:{2Z:E(){G D.x+D.H/2},3g:E(a){D.x=a-D.H/2}},1u:{2Z:E(){G D.y+D.I/2},3g:E(a){D.y=a-D.I/2}}}),c.X=V b,d.X=V c,a.aJ=b,a.4f=c,a.87=d}(17),E(a){E c(d){D.14=E(b){c.X.14.1T(D,1k),D.1R="5g",D.2m=a.8u,D.1m=b,D.1t="78 6Z",D.1N="1j,1j,1j",D.36=J,D.2D=!0,D.3V="3r",D.2v=0,D.2w=0,D.43=!0,D.1W=J,D.1S=J;F d="1m,1t,1N,3V,2v,2w,36".2s(",");D.1A=D.1A.2l(d)},D.14(d),D.1w=E(a){D.1L?a.3G(D.1L,-D.H/2,-D.I/2,D.H,D.I):(a.1b(),a.1i="Z("+D.2K+","+D.1f+")",J==D.36?a.2E(-D.H/2,-D.I/2,D.H,D.I,D.36):a.5S(-D.H/2,-D.I/2,D.H,D.I,10),a.1M(),a.1h()),D.31(a),D.4m(a)},D.31=E(a){F c,d,e,b=D.1m;J!=b&&""!=b&&(a.1b(),a.1t=D.1t,c=a.1G(b).H,d=a.1G("田").H,a.1i="Z("+D.1N+", "+D.1f+")",e=D.5N(D.3V,c,d),a.2u(b,e.x,e.y),a.1h())},D.5N=E(a,b,c){F d=J;G J==a||"3r"==a?d={x:-D.H/2+(D.H-b)/2,y:D.I/2+c}:"4K"==a?d={x:-D.H/2+(D.H-b)/2,y:-D.I/2-c/2}:"4J"==a?d={x:D.H/2,y:-D.I/2-c/2}:"4t"==a?d={x:-D.H/2-b,y:-D.I/2-c/2}:"4G"==a?d={x:D.H/2,y:D.I/2+c}:"4H"==a?d={x:-D.H/2-b,y:D.I/2+c}:"6R"==a?d={x:-D.H/2+(D.H-b)/2,y:c/2}:"4O"==a?d={x:D.H/2,y:c/2}:"4j"==a&&(d={x:-D.H/2-b,y:c/2}),J!=D.2v&&(d.x+=D.2v),J!=D.2w&&(d.y+=D.2w),d},D.4X=E(c,d){F e,f;P(J==c)64 V 63("2c.4X(): 参数5A对象为空!");e=D,"3u"==2g c?(f=b[c],J==f?(f=V 5A,f.2S=c,f.8m=E(){b[c]=f,1==d&&e.2P(f.H,f.I);F g=a.11.5H(f);g&&(f.3c=g),e.1L=f}):(d&&D.2P(f.H,f.I),D.1L=f)):(D.1L=c,1==d&&D.2P(c.H,c.I))},D.4w=E(a){F b=D;D.1S&&(D.1S.1a(E(c){c.Q===b&&a.3o(c)}),D.1S=J),D.1W&&(D.1W.1a(E(c){c.R===b&&a.3o(c)}),D.1W=J)}}E d(){d.X.14.1T(D,1k)}E e(a){D.14(),D.1m=a,D.1R="83",D.1w=E(a){a.1b(),a.1t=D.1t,D.H=a.1G(D.1m).H,D.I=a.1G("田").H,a.1P="Z("+D.1N+", "+D.1f+")",a.1i="Z("+D.1N+", "+D.1f+")",a.2u(D.1m,-D.H/2,D.I/2),a.1h(),D.4m(a)},D.3e=E(a){a.1p(),a.1b(),a.1t=D.1t,a.1P="Z(4a,4d,1j, 0.9)",a.1i="Z(4a,4d,4r,0.7)",a.2E(-D.H/2-3,-D.I/2-3,D.H+6,D.I+6),a.1M(),a.1B(),a.1h(),a.1v()}}E f(a,b,c){D.14(),D.1m=a,D.5x=b,D.1U=c,D.1R="8a",D.74=!1,D.5G=J,D.1w=E(a){a.1b(),a.1t=D.1t,D.H=a.1G(D.1m).H,D.I=a.1G("田").H,D.74&&J!=D.5G?(a.1P="Z("+D.5G+", "+D.1f+")",a.1i="Z("+D.5G+", "+D.1f+")"):(a.1P="Z("+D.1N+", "+D.1f+")",a.1i="Z("+D.1N+", "+D.1f+")"),a.2u(D.1m,-D.H/2,D.I/2),D.3E&&(a.2p(-D.H/2,D.I),a.1F(D.H/2,D.I),a.1B()),a.1h()},D.3e=E(){},D.2I(E(){F b,a=1Y.7w("M");P(a&&a.K>0)N(b=0;b0)N(b=0;b=D.5R.K){P(!D.58)G;D.2i=0}D.4X(D.5R[D.2i],c),2b(E(){e.3s()},d/a.K)}}}E i(a,b,c,d,e){F f,g;D.14(),f=D,D.4X(a),D.2i=0,D.79=!0,D.58=!1,g=d||2Q,e=e||0,D.1w=E(a){F b,d,f,g;D.1L&&(b=D.H,d=D.I,a.1p(),a.1b(),a.1i="Z("+D.2K+","+D.1f+")",f=(L.3Y(D.2i/c)+e)*d,g=L.3Y(D.2i%c)*b,a.3G(D.1L,g,f,b,d,-b/2,-d/2,b,d),a.1M(),a.1h(),a.1v())},D.3s=E(){P(!D.48){P(D.2i++,D.2i>=b*c){P(!D.58)G;D.2i=0}2b(E(){f.48||f.3s()},g/(b*c))}}}E j(){F a=J;G a=1k.K<=3?V h(1k[0],1k[1],1k[2]):V i(1k[0],1k[1],1k[2],1k[3],1k[4],1k[5]),a.1y=E(){a.48=!0},a.7p=E(){a.48=!1,a.2i=0,a.3s()},a}F b={};c.X=V a.87,d.X=V c,e.X=V d,f.X=V e,g.X=V d,6T.72(g.X,{1Z:{2Z:E(){G D.4i},3g:E(a){F b,c;D.4i=a,b=2*D.1Z,c=2*D.1Z,D.H=b,D.I=c}},H:{2Z:E(){G D.7Z},3g:E(a){D.4i=a/2,D.7Z=a}},I:{2Z:E(){G D.82},3g:E(a){D.4i=a/2,D.82=a}}}),h.X=V d,i.X=V d,j.X=V d,a.2c=d,a.83=e,a.8a=f,a.5Y=g,a.b1=j}(17),E(a){E b(a,b){F d,e,f,g,c=[];P(J==a||J==b)G c;P(a&&b&&a.1S&&b.1W)N(d=0;d0&&(D.3z=a-1)},D.14(b,c,g),D.4w=E(){F b,a=D;D.Q&&D.Q.1S&&(D.Q.1S=D.Q.1S.33(E(b){G b!==a})),D.R&&D.R.1W&&(D.R.1W=D.R.1W.33(E(b){G b!==a})),b=d(D),b.1a(E(a,b){a.3z=b})},D.3X=E(){F a={x:D.Q.1x,y:D.Q.1u};G a},D.4c=E(){F a;G J!=D.3O&&(a=h(D.R,D.Q)),J==a&&(a={x:D.R.1x,y:D.R.1u}),a},D.5t=E(){F f,g,h,i,j,k,l,m,n,o,b=[],c=D.3X(),d=D.4c();G D.Q===D.R?[c,d]:(f=e(D.Q,D.R),1==f?[c,d]:(g=L.4Q(d.y-c.y,d.x-c.x),h={x:c.x+D.4u*L.1K(g),y:c.y+D.4u*L.1H(g)},i={x:d.x+D.4u*L.1K(g-L.1c),y:d.y+D.4u*L.1H(g-L.1c)},j=g-L.1c/2,k=g-L.1c/2,l=f*D.2x/2-D.2x/2,m=D.2x*D.3z,n={x:h.x+m*L.1K(j),y:h.y+m*L.1H(j)},o={x:i.x+m*L.1K(k),y:i.y+m*L.1H(k)},n={x:n.x+l*L.1K(j-L.1c),y:n.y+l*L.1H(j-L.1c)},o={x:o.x+l*L.1K(k-L.1c),y:o.y+l*L.1H(k-L.1c)},b.U({x:c.x,y:c.y}),b.U({x:n.x,y:n.y}),b.U({x:o.x,y:o.y}),b.U({x:d.x,y:d.y}),b))},D.6Y=E(a,b){F c,d,e;P(D.Q===D.R)G D.6W(a),1D 0;N(a.1b(),a.2p(b[0].x,b[0].y),c=1;c0&&D.31(a,b)}};F i=-(L.1c/2+L.1c/4);D.31=E(a,b){F e,f,g,h,j,c=b[0],d=b[b.K-1];4==b.K&&(c=b[1],d=b[2]),D.1m&&D.1m.K>0&&(e=(d.x+c.x)/2+D.2v,f=(d.y+c.y)/2+D.2w,a.1p(),a.1b(),a.1t=D.1t,g=a.1G(D.1m).H,h=a.1G("田").H,a.1i="Z("+D.1N+", "+D.1f+")",D.Q===D.R?(j=D.2x*(D.3z+1)/2,e=D.Q.x+j*L.1K(i),f=D.Q.y+j*L.1H(i),a.2u(D.1m,e,f)):a.2u(D.1m,e-g/2,f-h/2),a.1B(),a.1h(),a.1v())},D.3e=E(a){a.4D=10,a.3N="Z(0,0,0,1)",a.3T=0,a.3U=0},D.4z=E(b,c){F d,e,f,g,h,i;P(D.Q===D.R)G d=D.2x*(D.3z+1)/2,e=a.11.3b(D.Q,{x:b,y:c})-d,L.1E(e)<=3;N(f=!1,g=1;ga.x?a.x+=D.Q.H/2:a.x-=D.Q.H/2:D.R.1u>a.y?a.y+=D.Q.I/2:a.y-=D.Q.I/2,a},D.4c=E(){F a={x:D.R.1x,y:D.R.1u};G"3n"==D.2Y?D.Q.1u0&&(c=b[1],d=c.x+D.2v,e=c.y+D.2w,a.1p(),a.1b(),a.1t=D.1t,f=a.1G(D.1m).H,g=a.1G("田").H,a.1i="Z("+D.1N+", "+D.1f+")",a.2u(D.1m,d-f/2,e-g/2),a.1B(),a.1h(),a.1v())}}E h(a,b,c){D.14=E(){h.X.14.1T(D,1k),D.2Y="7Q",D.81=44},D.14(a,b,c),D.3X=E(){F a={x:D.Q.1x,y:D.Q.1u};G"3n"==D.2Y?a.x=D.R.1xD.R.1x&&(i=-i),d.U({x:b.x,y:b.y+h}),d.U({x:b.x+i,y:b.y+h}),d.U({x:c.x-i,y:c.y+h}),d.U({x:c.x,y:c.y+h})):(D.Q.1u>D.R.1u&&(i=-i),d.U({x:b.x+h,y:b.y}),d.U({x:b.x+h,y:b.y+i}),d.U({x:c.x+h,y:c.y-i}),d.U({x:c.x+h,y:c.y})),d)}}E i(a,b,c){D.14=E(){i.X.14.1T(D,1k)},D.14(a,b,c),D.6Y=E(a,b){F c,d,e,f,g,h,i;P(D.Q===D.R)G D.6W(a),1D 0;N(a.1b(),a.2p(b[0].x,b[0].y),c=1;ck;k++)N(l=0;b>l;l++)P(m=d[j++],n=e.T+g/2+l*g,o=e.Y+h/2+k*h,m.26(n,o),j>=d.K)G}}E c(a,b){G J==a&&(a=0),J==b&&(b=0),E(c){F e,f,g,h,i,d=c.O;P(!(d.K<=0))N(e=c.2L(),f=e.T,g=e.Y,h=0;h=e.15&&(f=e.T,g+=b+i.I),i.26(f,g),f+=a+i.H}}E d(){G E(a,b){F c,d,e,f,g,h,i,j;P(b.K>0){N(c=5D,d=-5D,e=5D,f=-5D,g=d-c,h=f-e,i=0;i=d&&(d=j.x),j.y<=e&&(e=j.y),j.y>=f&&(f=j.y),g=d-c+j.H,h=f-e+j.I;a.x=c,a.y=e,a.H=g,a.I=h}}}E e(b){F c=[],d=b.33(E(b){G b 1Q a.2W?!0:(c.U(b),!1)});G b=c.33(E(a){N(F b=0;b=0;q--)N(r=k[""+q].5J,s=k[""+q].O,m=0;m0?"3M"==b||"4l"==b?t.x=(u[0].x+u[u.K-1].x)/2:("T"==b||"15"==b)&&(t.y=(u[0].y+u[u.K-1].y)/2):m>0&&("3M"==b||"4l"==b?t.x=r[m-1].x+r[m-1].H+c:("T"==b||"15"==b)&&(t.y=r[m-1].y+r[m-1].I+c)),m>0)P("3M"==b||"4l"==b){P(t.x0&&(j(e.O,k[0]),l=a.11.2G(e.O),m=e.4P(),n=m.x-(l.T+l.15)/2,o=m.y-(l.Y+l.1d)/2,e.O.1a(E(b){b 1Q a.2c&&(b.x+=n,b.y+=o)}))}}E j(b){G E(c){E d(a,c,e){F g,f=q(a,c);0!=f.K&&(J==e&&(e=b),g=2*L.1c/f.K,f.1a(E(b,f){F j,h=c.x+e*L.1K(g*f),i=c.y+e*L.1H(g*f);b.26(h,i),j=e/2,d(a,b,j)}))}F f,g,h,i,e=a.2e.73(c.O);e.K>0&&(d(c.O,e[0]),f=a.11.2G(c.O),g=c.4P(),h=g.x-(f.T+f.15)/2,i=g.y-(f.Y+f.1d)/2,c.O.1a(E(b){b 1Q a.2c&&(b.x+=h,b.y+=i)}))}}E k(a,b,c,d,e,f){F h,i,g=[];N(h=0;c>h;h++)N(i=0;d>i;i++)g.U({x:a+i*e,y:b+h*f});G g}E l(a,b,c,d,e,f){F l,m,n,g=e?e:0,h=f?f:2*L.1c,i=h-g,j=i/c,k=[];N(g+=j/2,l=g;h>=l;l+=j)m=a+L.1K(l)*d,n=b+L.1H(l)*d,k.U({x:m,y:n});G k}E m(a,b,c,d,e,f){F i,j,g=f||"1d",h=[];P("1d"==g)N(i=a-c/2*d+d/2,j=0;c>=j;j++)h.U({x:i+j*d,y:b+e});1O P("Y"==g)N(i=a-c/2*d+d/2,j=0;c>=j;j++)h.U({x:i+j*d,y:b-e});1O P("15"==g)N(i=b-c/2*d+d/2,j=0;c>=j;j++)h.U({x:a+e,y:i+j*d});1O P("T"==g)N(i=b-c/2*d+d/2,j=0;c>=j;j++)h.U({x:a-e,y:i+j*d});G h}E k(a,b,c,d,e,f){F h,i,g=[];N(h=0;c>h;h++)N(i=0;d>i;i++)g.U({x:a+i*e,y:b+h*f});G g}E o(a,b){F c,d,e,f,g,h,i,j;P(a.2e){P(c=a.2e,d=c.5X,e=J,"9W"==d)f=c.1Z||L.9T(a.H,a.I),e=l(a.1x,a.1u,b.K,f,a.2e.9S,a.2e.9O);1O P("9Q"==d)g=c.H||50,h=c.I||50,i=c.2Y,e=m(a.1x,a.1u,b.K,g,h,i);1O{P("a7"!=d)G;e=k(a.x,a.y,c.9Z,c.aS,c.3n||0,c.7Q||0)}N(j=0;j7z)){N(F a=0;ac&&(c=e),g=0;gL.1c/2&&k<=L.1c?l-=i:k>L.1c&&k<3*2*L.1c/4?l-=i:k>.75*2*L.1c,a.1i="#5v",a.2u(h,l,m),a.2p(D.1Z*L.1K(k),D.1Z*L.1H(k)),k>L.1c/2&&k<3*2*L.1c/4&&(l-=i),k>L.1c,a.1M(),a.1B(),a.1h(),e+=g},b}E c(){F b=V a.2c;G b.3F=!1,b.H=8T,b.I=8Y,b.59=["#7I","#7T","#7L"],b.2R=[.3,.3,.4],b.5q=["A","B","C"],b.1w=E(a){F f,g,h,i,j,k,l,d=3,e=(D.H-d)/D.2R.K;N(a.1p(),a.1b(),a.1i="#5v",a.1P="#5v",a.2p(-D.H/2-1,-D.I/2),a.1F(-D.H/2-1,D.I/2+3),a.1F(D.H/2+d+1,D.I/2+3),a.1B(),a.1h(),a.1v(),f=0;f0&&a[b]>=D.53||D.41<0&&a[b]<=D.53;G c}};G l=V b(E(){F d,g,b=!0;N(d 21 c)h[d].7N(d)||(a[d]+=h[d].41,b=!1);P(b){P(!e)G D.1y();N(d 21 c)f?(g=h[d].53,h[d].53=h[d].5k,h[d].5k=g,h[d].41=-h[d].41):a[d]=h[d].5k}G D},g)}E f(a){F b,c,d,f;G J==a&&(a={}),b=a.7l||.1,c=a.9s||.8,d=a.9t||0,a.9I||0,f=a.9q||0,{5s:[],5u:J,79:!1,99:E(a,b){F c={5g:a,1U:b,4W:0,4b:0};G D.5s.U(c),D},7p:E(a){D.1y(),a=J==a?2Q/24:a;F b=D;D.5u=3d(E(){b.3s()},a)},1y:E(){J!=D.5u&&1g.3i(D.5u)},3s:E(){F a,e,g,h,i,j,k,l,m,n,o;N(a=0;a2*L.1c&&(a.2f=0),1D 0)},2r),e}E h(){G 1g.3i(d),e.1r&&e.1r(a),e}F d,e,f;G b.34,d=J,e={},f=b.v,e.3a=g,e.1y=h,e.1r=E(a){G e.1r=a,e},e}E j(a,b){E g(){G 1g.3i(e),f.1r&&f.1r(a),f}E h(){F h=b.1n||0,j=b.1z||2;G e=3d(E(){G i?(f.1y(),1D 0):(j+=d,a.y+a.If.W.M.H||a.y>f.W.M.I)&&(j.1r&&j.1r(a),g(a)),1D 0)},50),j}E l(){1g.3i(h)}F c=.8,f=b.34,h=J,j={};G j.1r=E(a){G j.1r=a,j},j.3a=k,j.1y=l,j}E m(){i=!0}E n(){i=!1}E o(b,c){E o(){G n=3d(E(){P(i)G m.1y(),1D 0;F a=d.y+g+L.1H(k)*j;b.26(b.x,a),k+=l},2r),m}E p(){1g.3i(n)}F g,h,j,k,l,m,n,d=c.9Y,e=c.8K;G c.34,g=d.x+(e.x-d.x)/2,h=d.y+(e.y-d.y)/2,j=a.11.3b(d,e)/2,k=L.4Q(h,g),l=c.93||.2,m={},n=J,m.3a=o,m.1y=p,m}E p(a,b){E h(){G g=3d(E(){F b,d,g,h;G i?(f.1y(),1D 0):(b=c.x-a.x,d=c.y-a.y,g=b*e,h=d*e,a.x+=g,a.y+=h,.8r>g&&.1>h&&j(),1D 0)},2r),f}E j(){1g.3i(g)}F e,f,g,c=b.7b;G b.34,e=b.9h||.2,f={},g=J,f.1r=E(a){G f.1r=a,f},f.3a=h,f.1y=j,f}E q(a,b){E k(){G j=3d(E(){a.18+=f,a.19+=f,a.18>=e&&l()},2r),i}E l(){i.1r&&i.1r(a),a.18=g,a.19=h,1g.3i(j)}F e,f,g,h,i,j;G b.7b,b.34,e=b.3q||1,f=.9g,g=a.18,h=a.19,i={},j=J,i.1r=E(a){G i.1r=a,i},i.3a=k,i.1y=l,i}a.28={},a.6U={};F i=!1;a.6U.7l=f,a.6U.3L=c,a.28.9e=d,a.28.2f=h,a.28.3q=q,a.28.5w=p,a.28.aW=o,a.28.aR=l,a.28.a6=k,a.28.3L=j,a.28.9V=n,a.28.a9=m}(17),E(a){E c(a,b){F d,e,f,g,h,i,j,c=[];G 0==a.K?c:(d=b.5F(/^\\\\s*(\\\\w+)\\\\s*$/),J!=d?(e=a.33(E(a){G a.1R==d[1]}),J!=e&&e.K>0&&(c=c.2l(e))):(f=!1,d=b.5F(/\\\\s*(\\\\w+)\\\\s*\\\\[\\\\s*(\\\\w+)\\\\s*([>=<])\\\\s*[\\\'"](\\\\S+)[\\\'"]\\\\s*\\\\]\\\\s*/),(J==d||d.K<5)&&(d=b.5F(/\\\\s*(\\\\w+)\\\\s*\\\\[\\\\s*(\\\\w+)\\\\s*([>=<])\\\\s*(\\\\d+(\\\\.\\\\d+)?)\\\\s*\\\\]\\\\s*/),f=!0),J!=d&&d.K>=5&&(g=d[1],h=d[2],i=d[3],j=d[4],e=a.33(E(a){P(a.1R!=g)G!1;F b=a[h];G 1==f&&(b=7d(b)),"="==i?b==j:">"==i?b>j:"<"==i?j>b:"<="==i?j>=b:">="==i?b>=j:"!="==i?b!=j:!1}),J!=e&&e.K>0&&(c=c.2l(e)))),c)}E d(a){F c,d,f;P(a.6I=E(a){G e.47(D,a)},b.1a(E(b){a[b]=E(a){N(F c=0;c0){c=a[0];N(d 21 c)f=c[d],"E"==2g f&&E(b){a[d]=E(){F d,c=[];N(d=0;d
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
67 |
68 |
69 |
70 | h1-h2
71 | pre
72 | body
73 | is_first
74 | 交换机流表
75 | 删除
76 | re
77 | match
78 | #
79 | window.location.href
80 | getdate
81 | deldata
82 | deldate
83 | switch_no_int
84 | sessionStorage.switch_no
85 | alert
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 | true
106 | DEFINITION_ORDER
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 | project
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 | project
219 |
220 |
221 | true
222 |
223 |
224 |
225 | DIRECTORY
226 |
227 | false
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 | 1494928828063
241 |
242 |
243 | 1494928828063
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
633 |
634 |
635 |
636 |
637 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
652 |
653 |
654 |
655 |
656 |
657 |
658 |
659 |
660 |
661 |
662 |
663 |
664 |
665 |
666 |
667 |
668 |
669 |
670 |
671 |
672 |
673 |
674 |
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 |
683 |
684 |
685 |
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
709 |
710 |
711 |
712 |
713 |
714 |
715 |
716 |
717 |
718 |
719 |
720 |
721 |
722 |
723 |
724 |
725 |
726 |
727 |
728 |
729 |
730 |
731 |
732 |
733 |
734 |
735 |
736 |
737 |
738 |
739 |
740 |
741 |
742 |
743 |
744 |
745 |
746 |
747 |
748 |
749 |
750 |
751 |
752 |
753 |
754 |
755 |
756 |
757 |
758 |
759 |
760 |
761 |
762 |
763 |
764 |
765 |
766 |
767 |
768 |
769 |
770 |
771 |
772 |
773 |
774 |
775 |
776 |
777 |
778 |
779 |
780 |
781 |
782 |
783 |
784 |
785 |
786 |
787 |
788 |
789 |
790 |
791 |
792 |
793 |
794 |
795 |
796 |
797 |
798 |
799 |
800 |
801 |
802 |
803 |
804 |
805 |
806 |
807 |
808 |
809 |
810 |
811 |
812 |
813 |
814 |
815 |
816 |
817 |
818 |
819 |
820 |
821 |
822 |
823 |
824 |
825 |
826 |
827 |
828 |
829 |
830 |
831 |
832 |
833 |
834 |
835 |
836 |
837 |
838 |
839 |
840 |
841 |
842 |
843 |
844 |
845 |
846 |
847 |
848 |
849 |
850 |
851 |
852 |
853 |
854 |
855 |
856 |
857 |
858 |
859 |
860 |
861 |
862 |
863 |
864 |
865 |
866 |
867 |
868 |
869 |
870 |
871 |
872 |
873 |
874 |
875 |
876 |
877 |
878 |
879 |
880 |
881 |
882 |
883 |
884 |
885 |
886 |
887 |
888 |
889 |
890 |
891 |
892 |
893 |
894 |
895 |
896 |
897 |
898 |
899 |
900 |
901 |
902 |
903 |
904 |
905 |
906 |
907 |
908 |
909 |
910 |
911 |
912 |
913 |
914 |
915 |
916 |
917 |
918 |
919 |
920 |
921 |
922 |
923 |
924 |
925 |
926 |
927 |
928 |
929 |
930 |
931 |
932 |
933 |
934 |
935 |
936 |
937 |
938 |
939 |
940 |
941 |
942 |
943 |
944 |
945 |
946 |
947 |
948 |
949 |
950 |
951 |
952 |
953 |
954 |
955 |
956 |
957 |
958 |
959 |
960 |
961 |
962 |
963 |
964 |
965 |
966 |
967 |
968 |
969 |
970 |
971 |
972 |
973 |
974 |
--------------------------------------------------------------------------------